/* tslint:disable:function-constructor */ import { parse } from '@babel/parser' import { generateOrderNotificationApiRoute } from '../src/ecommerce/ecommerce-api-routes-generator' import { generateEmailSenderModule } from '../src/ecommerce/email-sender-generator' import type { UIDLEcommerceSettings } from '@teleporthq/teleport-types' import { PHOTO } from './_helpers/product-options-fixtures' import { dataCreateItem } from '../../teleport-plugin-next-workflows/src/nodes/data/data-create-item' /** * The merchant's order email and product options. A line bought with options * shows every answer — what the order is made from — read from the order * line's snapshot through the shared parser (the current form and the compact * one older checkouts wrote), HTML-escaped wherever it lands. A template with * a `{{configuration}}` row token gets the answers there; one written before * options existed gets the short label appended to the product name. A line * without options renders exactly as before. The whole route is EXECUTED * against a fake pool and the real email-sender module. */ const settingsWith = (body: string): UIDLEcommerceSettings => ({ orderNotifications: true, orderNotificationConfig: { provider: 'resend', notificationEmails: ['owner@example.com'], subject: 'New order {{orderNumber}}', body, }, } as unknown as UIDLEcommerceSettings) const ROW_WITH_TOKEN = '
{{product_name}}|{{configuration}}|{{line_total}}
' const ROW_WITHOUT_TOKEN = '{{product_name}}|{{line_total}}
' const ITEMS_COUNT_ONLY = 'Items: {{itemsCount}}
' const SNAPSHOT = JSON.stringify({ v: 1, basePrice: 10, priceDelta: 17, entries: [ { key: 'size', label: 'Size', type: 'choice', value: 'a3', valueLabel: 'A3', priceDelta: 9 }, { key: 'engraving', label: 'Engraving', type: 'text', value: '', valueLabel: '', priceDelta: 0, }, { key: 'your-photo', label: 'Your photo', type: 'upload', value: [PHOTO.id], valueLabel: 'IMG_2231.jpg', priceDelta: 0, files: [PHOTO], }, ], }) const PRINT_ROW = { product_id: 'print', product_name: 'Photo print', variant_label: null, quantity: 1, unit_price: '27.00', total_price: '27.00', currency: 'USD', configuration: SNAPSHOT, configuration_label: 'Size: A3 · Engraving: · Your photo: IMG_2231.jpg', image_url: '', } const MUG_ROW = { product_id: 'mug', product_name: 'Mug', variant_label: null, quantity: 2, unit_price: '12.00', total_price: '24.00', currency: 'USD', configuration: null, configuration_label: null, image_url: '', } const loadSender = (settings: UIDLEcommerceSettings) => { const moduleObj: { exports: any } = { exports: {} } new Function('require', 'module', 'exports', generateEmailSenderModule(settings))( (name: string) => { if (name === 'resend') { return { Resend: class {} } } return { settleSentEmailLog: async () => undefined } }, moduleObj, moduleObj.exports ) return moduleObj.exports } async function sendOrderEmail(options: { body: string rows?: ArrayPhoto print|Size: A3\nEngraving: <script>alert(1)</script>\nYour photo: IMG_2231.jpg|27.00
' + 'Mug||24.00
' ) }) it('appends the short label to the product name when the template has no row token', async () => { const { html } = await sendOrderEmail({ body: ROW_WITHOUT_TOKEN, rows: [PRINT_ROW, MUG_ROW] }) expect(html).toBe( 'Photo print — Size: A3 · Engraving: <script>alert(1)</script> · Your photo: IMG_2231.jpg|27.00
' + 'Mug|24.00
' ) }) it('lists the answers under the line in the injected item list, one per line', async () => { const { html } = await sendOrderEmail({ body: ITEMS_COUNT_ONLY, rows: [PRINT_ROW, MUG_ROW] }) expect(html).toContain( '27.00