import { readFile } from 'node:fs/promises'; import { expect, test } from '@playwright/test'; // The fixture is local-only; no store or generation service can be contacted. test.beforeEach(async ({ context }) => { await context.route('**/*', route => new URL(route.request().url()).origin === 'http://127.0.0.1:4173' ? route.continue() : route.abort()); }); const IMAGE = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M/wHwAF/gL+Xw0YAAAAAElFTkSuQmCC'; for (const width of [1280, 390, 320]) { test(`social formats stay readable with Vela theme at ${width}px`, async ({ page }) => { await page.setViewportSize({ width, height: 960 }); await page.addInitScript((image) => { localStorage.setItem('aisthetix_tryon_consent', '1'); localStorage.setItem('aisthetix-avatar', JSON.stringify({ imageData: `data:image/png;base64,${image}`, createdAt: new Date().toISOString() })); }, IMAGE); await page.route('**/garment.png', route => route.fulfill({ contentType: 'image/png', body: Buffer.from(IMAGE, 'base64') })); await page.route('**/api/storefront/tryon', route => route.fulfill({ contentType: 'application/json', body: JSON.stringify({ image: IMAGE, cached: false }) })); await page.goto('/widget-src/e2e/fixtures/product.html?demo=1'); // Actual Vela customizer declarations, loaded after the plugin stylesheet. await page.addStyleTag({ content: `button { background:#1C2B45!important; color:#FBFAF7!important; border:1px solid #1C2B45!important; border-radius:0!important; text-transform:uppercase; letter-spacing:.13em; font-size:.72rem; font-weight:500; padding:.95em 1.9em; }` }); await page.getByRole('button', { name: 'Try it on', exact: true }).click(); await page.getByRole('button', {name: 'Use This Photo', exact: true}).click(); await page.getByRole('button', { name: 'Share your look', exact: true }).click(); // Full result and narrower saved-look row body. for (const gallery of [false, true]) { if (gallery) { await page.getByRole('button', { name: /Your try-ons/ }).click(); await page.getByRole('button', { name: 'Share', exact: true }).first().click(); } const channels = page.locator('.aisthetix-share__channel'); await expect(channels).toHaveCount(3); await expect(channels).toHaveText(['Instagram', 'WhatsApp', 'Download']); await expect(page.getByRole('button', { name: 'Share image', exact: true })).toHaveCount(0); await expect(page.getByRole('button', { name: 'Download', exact: true })).toBeEnabled(); const menu = page.locator('.aisthetix-share__menu'); await expect(menu.getByRole('link')).toHaveCount(0); await expect(menu.getByRole('button', { name: 'Copy product link' })).toHaveCount(0); const downloaded = page.waitForEvent('download'); await page.getByRole('button', { name: 'Download', exact: true }).click(); const download = await downloaded; expect(download.suggestedFilename()).toBe('aisthetix-try-on-story.png'); const png = await readFile((await download.path())!); expect(png.subarray(1, 4).toString()).toBe('PNG'); expect([png.readUInt32BE(16), png.readUInt32BE(20)]).toEqual([1080, 1920]); await expect(page.getByRole('status')).toBeVisible(); const measurements = await channels.evaluateAll(buttons => buttons.map(button => { const label = button.querySelector('.aisthetix-share__badge') as HTMLElement; const style = getComputedStyle(button); const labelStyle = getComputedStyle(label); const rect = button.getBoundingClientRect(); const labelRect = label.getBoundingClientRect(); return { transform: style.textTransform, spacing: style.letterSpacing, background: style.backgroundColor, fontSize: parseFloat(labelStyle.fontSize), fits: label.scrollWidth <= label.clientWidth && labelRect.left >= rect.left && labelRect.right <= rect.right, inViewport: rect.left >= 0 && rect.right <= innerWidth, height: rect.height }; })); for (const measurement of measurements) { expect(measurement.transform).toBe('none'); expect(measurement.spacing).toBe('normal'); expect(measurement.background).toBe('rgba(0, 0, 0, 0)'); expect(measurement.fontSize).toBeGreaterThanOrEqual(12); expect(measurement.fits).toBe(true); expect(measurement.inViewport).toBe(true); expect(measurement.height).toBeGreaterThanOrEqual(44); } } }); } test('production bundle downloads one card and copies channel messages for the selected variation', async ({ page, context }) => { await context.grantPermissions(['clipboard-read', 'clipboard-write']); await page.addInitScript(image => { localStorage.setItem('aisthetix_tryon_consent','1'); localStorage.setItem('aisthetix-avatar',JSON.stringify({imageData:`data:image/png;base64,${image}`,createdAt:new Date().toISOString()})); }, IMAGE); await page.route('**/garment.png', route => route.fulfill({contentType:'image/png',body:Buffer.from(IMAGE,'base64')})); await page.route('**/api/storefront/tryon', route => route.fulfill({contentType:'application/json',body:JSON.stringify({image:IMAGE,cached:false})})); await page.goto('/widget-src/e2e/fixtures/product.html'); await page.selectOption('[name="attribute_pa_color"]','black'); await page.selectOption('[name="attribute_pa_size"]','m'); await page.getByRole('button',{name:'Try it on',exact:true}).click(); await page.getByRole('button', {name: 'Use This Photo', exact: true}).click(); await page.getByRole('button',{name:'Share your look',exact:true}).click(); const url='https://shop.example/product/garment?variation_id=102&attribute_pa_color=black&attribute_pa_size=m&atx=1'; for(const [name,expected] of [ ['WhatsApp',`Should I get it? ❤️ yes · 😢 no\nBrowser test garment by Fixture Store\nTry it on your own photo 👉 ${url}`], ['Instagram',`Should I get it? ❤️ yes · 😢 no\nBrowser test garment by Fixture Store · try it on your own photo: ${url}`], ]) { const downloaded=page.waitForEvent('download'); await page.getByRole('button',{name,exact:true}).click(); const download=await downloaded; expect(download.suggestedFilename()).toBe('aisthetix-try-on-story.png'); const png=await readFile((await download.path())!); expect([png.readUInt32BE(16),png.readUInt32BE(20)]).toEqual([1080,1920]); await expect.poll(()=>page.evaluate(()=>navigator.clipboard.readText())).toBe(expected); await expect(page.getByRole('status')).toHaveText('Image saved, message copied'); await expect(page.getByRole('status')).toHaveCount(0, { timeout: 4000 }); await download.saveAs(test.info().outputPath(name.replaceAll(' ','-')+'.png')); } }); for (const demo of [false,true]) test(`atx landing confirms a saved photo without generating (${demo?'demo':'merchant'})`,async({page})=>{ await page.addInitScript(image=>{ localStorage.setItem('aisthetix_tryon_consent','1'); localStorage.setItem('aisthetix-avatar',JSON.stringify({imageData:`data:image/png;base64,${image}`,createdAt:new Date().toISOString()})); },IMAGE); let generations=0; await page.route('**/api/storefront/tryon',route=>{generations++;return route.abort();}); await page.goto(`/widget-src/e2e/fixtures/product.html?demo=${demo?'1':'0'}&atx=1#keep`); await expect(page.getByRole('dialog')).toBeVisible(); await expect(page.getByText('Use This Photo',{exact:true})).toBeVisible(); expect(new URL(page.url()).search).toBe(`?demo=${demo?'1':'0'}`); expect(new URL(page.url()).hash).toBe('#keep'); expect(generations).toBe(0); await page.reload(); await expect(page.getByRole('dialog')).toHaveCount(0); expect(generations).toBe(0); });