import { test, expect } from '@playwright/test'; test('legacy localStorage payload cannot execute XSS', async ({ page }) => { const pageErrors=[]; page.on('pageerror',e=>pageErrors.push(String(e))); await page.addInitScript(() => { localStorage.setItem('sunBoxes', JSON.stringify([{id:'1',name:'',price:100,photo:'javascript:alert(1)',ingredients:[['',1,'шт.']]}])); localStorage.setItem('sunOrders', JSON.stringify([{id:1,event:'',date:'2026-09-07',time:'12:00',address:'',status:'Новый',lines:[{id:'1',qty:1}]}])); }); await page.goto('/index.html', { waitUntil:'domcontentloaded' }); await page.waitForTimeout(300); expect(await page.evaluate(()=>window.__cateriumXss)).toBeUndefined(); expect(pageErrors.filter(x=>!x.includes('supabase'))).toEqual([]); }); test('safe insert helper handles foreign reference node', async ({ page }) => { await page.goto('/index.html', { waitUntil:'domcontentloaded' }); const result=await page.evaluate(()=>{const a=document.createElement('div'),b=document.createElement('div'),n=document.createElement('span'),foreign=document.createElement('i');a.appendChild(foreign);document.body.append(a,b);try{window.SunSafe.insertBefore(b,n,foreign);return {ok:true,parent:n.parentNode===b}}catch(e){return {ok:false,error:String(e)}}}); expect(result).toEqual({ok:true,parent:true}); }); test('shared PDF engine produces A4 PDF blob', async ({ page }) => { await page.goto('/index.html', { waitUntil:'domcontentloaded' }); const result=await page.evaluate(async()=>{const fake=new Uint8Array([255,216,255,217]);const blob=window.SunPdfEngine.fromJpegs([{width:1000,height:1414,bytes:fake}]);const head=new TextDecoder().decode(new Uint8Array(await blob.arrayBuffer()).slice(0,8));return {type:blob.type,size:blob.size,head,w:window.SunPdfEngine.PAGE_W,h:window.SunPdfEngine.PAGE_H}}); expect(result.type).toBe('application/pdf'); expect(result.size).toBeGreaterThan(150); expect(result.head.startsWith('%PDF-1.4')).toBeTruthy(); expect(result.w/result.h).toBeCloseTo(1/Math.sqrt(2),3); }); test('mobile body does not overflow viewport', async ({ page }, testInfo) => { test.skip(testInfo.project.name!=='mobile-390'); await page.goto('/index.html', { waitUntil:'domcontentloaded' }); await page.waitForTimeout(500); const dims=await page.evaluate(()=>({innerWidth,scrollWidth:document.documentElement.scrollWidth,bodyWidth:document.body.scrollWidth})); expect(dims.scrollWidth).toBeLessThanOrEqual(dims.innerWidth+2); expect(dims.bodyWidth).toBeLessThanOrEqual(dims.innerWidth+2); });