caterium-app/tests/company-branding.spec.mjs
2026-09-17 20:27:07 +03:00

119 lines
9.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {test,expect} from '@playwright/test';
async function fixture(page){
await page.route('**/index.html',r=>r.fulfill({contentType:'text/html',body:'<!doctype html><html><head><script src="/core/company-branding.js"></script></head><body><header><div class="brand"></div></header></body></html>'}));
await page.goto('/index.html');
}
async function logo(page,color='#146b3d'){
return page.evaluate(async color=>{
const c=document.createElement('canvas');c.width=48;c.height=24;const x=c.getContext('2d');x.fillStyle=color;x.fillRect(8,4,32,16);
const blob=await new Promise(r=>c.toBlob(r,'image/png'));
return window.CateriumBranding.saveLogo(new File([blob],'logo.png',{type:'image/png'}));
},color);
}
test('company logo preserves transparency, persists and clears without changing product brand',async({page})=>{
await fixture(page);const data=await logo(page);
await page.evaluate(()=>window.CateriumBranding.saveName('Кухня <Гости> & Ко'));
const result=await page.evaluate(async()=>{
const b=window.CateriumBranding,img=new Image();img.src=b.documentImage();await img.decode();const c=document.createElement('canvas');c.width=48;c.height=24;const x=c.getContext('2d');x.drawImage(img,0,0);
return {name:b.documentName(),escaped:b.nameHTML(),alpha:x.getImageData(0,0,1,1).data[3],body:document.querySelector('header').textContent};
});
expect(result).toEqual({name:'Кухня <Гости> & Ко',escaped:'Кухня &lt;Гости&gt; &amp; Ко',alpha:0,body:'Caterium'});
await page.reload();expect(await page.evaluate(()=>window.CateriumBranding.documentLogo())).toBe(data);
await page.evaluate(()=>{localStorage.setItem('sunCompanyProfileV1',JSON.stringify({logo:window.CateriumBranding.documentLogo()}));window.CateriumBranding.clearLogo()});
expect(await page.evaluate(()=>window.CateriumBranding.documentLogo())).toBe('');
expect(await page.evaluate(async()=>{const i=new Image();i.src=window.CateriumBranding.documentImage();await i.decode();return i.naturalWidth})).toBe(1);
});
test('exclusive sidebar is server assigned, resets on account changes and ignores stale replies',async({page})=>{
await fixture(page);
await page.evaluate(async()=>{
window.__user='owner';window.__calls=[];
window.SunCloudV2={getSession:()=>window.__user?{user:{id:window.__user}}:null,getClient:()=>({rpc:async name=>{window.__calls.push(name);return {data:{variant:window.__user==='owner'?'solnce':'caterium'}}}})};
await window.CateriumBranding.refreshSidebar();
});
await expect(page.locator('header .brand')).toHaveText('Солнце Кейтеринг');
await logo(page);await page.evaluate(()=>window.CateriumBranding.saveName('Другой бренд документов'));
await expect(page.locator('header .brand')).toHaveText('Солнце Кейтеринг');
await page.evaluate(async()=>{window.__user='employee';await window.CateriumBranding.refreshSidebar()});
await expect(page.locator('header .brand')).toHaveText('Caterium');
await page.evaluate(async()=>{
window.__user='owner';window.SunCloudV2.getClient=()=>({rpc:()=>new Promise(r=>window.__reply=r)});
const pending=window.CateriumBranding.refreshSidebar();window.__user=null;window.CateriumBranding.resetSidebar();window.__reply({data:{variant:'solnce'}});await pending;
});
await expect(page.locator('header .brand')).toHaveText('Caterium');
});
test('document branding follows workspace storage without leaking the previous company',async({page})=>{
await fixture(page);const first=await logo(page);
await page.evaluate(()=>window.CateriumBranding.saveName('Компания А'));
const saved=await page.evaluate(()=>({...localStorage}));
await page.evaluate(()=>{localStorage.clear();localStorage.setItem('sunCompanyProfileV1',JSON.stringify({name:'Компания Б'}));window.dispatchEvent(new Event('sun:cloud-state-applied'))});
expect(await page.evaluate(()=>window.CateriumBranding.identity())).toMatchObject({name:'Компания Б',logo:''});
const second=await logo(page,'#801599');expect(second).not.toBe(first);
await page.evaluate(saved=>{localStorage.clear();for(const [k,v] of Object.entries(saved))localStorage.setItem(k,v);window.dispatchEvent(new Event('sun:cloud-state-applied'))},saved);
expect(await page.evaluate(()=>window.CateriumBranding.identity())).toMatchObject({name:'Компания А',logo:first});
});
test('every classic and signature PDF uses the supplied company logo and no legacy company text',async({page})=>{
test.setTimeout(60000);await fixture(page);
for(const module of ['classic-offer-pdf-v1767.js','signature-offer-pdf-v18.js'])await page.addScriptTag({url:'/core/'+module});
const data=await logo(page);
const result=await page.evaluate(async data=>{
const texts=[],images=[],proto=CanvasRenderingContext2D.prototype,fill=proto.fillText,draw=proto.drawImage;
proto.fillText=function(t,...a){texts.push(String(t));return fill.call(this,t,...a)};
proto.drawImage=function(i,...a){images.push(i.src);return draw.call(this,i,...a)};
const b={brandName:'Компания Лист',brandCity:'Казань',logo:data,client:'Анна',event:'Обед',items:[],pricing:{total:15000},guests:10};
const counts=[];
try{for(const api of [window.SunClassicOfferPDFV1767,window.SunSignatureOfferPDFV18])for(const id of api.CLASSIC_IDS||api.SIGNATURE_IDS){const before=images.length;await api.renderCover({...b,offerTemplateId:id},id);counts.push({id,logo:images.slice(before).includes(data)})}}finally{proto.fillText=fill;proto.drawImage=draw}
return {counts,legacy:texts.filter(t=>/солнц|SUN \/ CATERING|САНКТ-ПЕТЕРБУРГ/i.test(t))};
},data);
expect(result.counts).toHaveLength(18);expect(result.counts.filter(x=>!x.logo)).toEqual([]);expect(result.legacy).toEqual([]);
});
test('real order blank, receipt and preparation share uploaded company identity',async({page})=>{
await page.goto('/index.html',{waitUntil:'domcontentloaded'});
await page.waitForFunction(()=>Boolean(window.sunShowOrderBlankV5));
const data=await logo(page);
await page.evaluate(()=>window.CateriumBranding.saveName('Компания <Лист>'));
const result=await page.evaluate(()=>{
const out=[];for(const fn of ['sunShowOrderBlankV5','sunShowConfiguredReceipt','openPreview']){
window[fn]();const root=document.querySelector('#preview .dialog');out.push({fn,text:root.textContent,logos:[...root.querySelectorAll('.sun-doc-brand img,.prep-doc-brand img')].map(x=>x.src),unsafe:!!root.querySelector('лист')});
}return out;
});
for(const row of result){expect(row.text).toContain('Компания <Лист>');expect(row.text).not.toMatch(/Солнце|Моя компания/);expect(row.logos).toEqual([data]);expect(row.unsafe).toBe(false)}
await page.evaluate(()=>document.querySelector('header nav button[data-nav-label="Настройки"]').click());
await expect(page.locator('#sunPdfBrandCard')).toHaveAttribute('data-settings-tab','documents');
await page.locator('#sunPdfBrandLogoFile').setInputFiles({name:'company.png',mimeType:'image/png',buffer:Buffer.from(data.split(',')[1],'base64')});
await expect.poll(()=>page.evaluate(()=>window.CateriumBranding.documentLogo())).toBe(data);
});
test('catalog, route sheet and full PDF pages retain the company brand',async({page})=>{
test.setTimeout(60000);
await page.goto('/index.html',{waitUntil:'domcontentloaded'});
await page.waitForFunction(()=>Boolean(window.sunClientOfferDebugPdfPages));
const data=await logo(page);
const result=await page.evaluate(async data=>{
const brand=window.CateriumBranding;brand.saveName('Лист');window.print=()=>{};
boxes.push({id:'brand-catalog-fixture',name:'Бокс компании Лист',price:1200,category:0,photo:'',ingredients:[],composition:[]});
const texts=[],images=[],proto=CanvasRenderingContext2D.prototype,fill=proto.fillText,draw=proto.drawImage;
proto.fillText=function(t,...a){texts.push(String(t));return fill.call(this,t,...a)};
proto.drawImage=function(i,...a){images.push(i.src);return draw.call(this,i,...a)};
const allIds=[...window.SunClassicOfferPDFV1767.CLASSIC_IDS,...window.SunClassicOfferPDFV1767.ARCHIVE_IDS,...window.SunSignatureOfferPDFV18.SIGNATURE_IDS],counts=[];
try{
for(const id of allIds){const pages=await window.sunClientOfferDebugPdfPages({offerTemplateId:id,brandName:'Лист',brandCity:'Казань',logo:data,event:'Обед',items:[],pricing:{total:1000},guests:10});counts.push(pages.length)}
await window.sunCatalogDebugPdfPages(0,1);
}finally{proto.fillText=fill;proto.drawImage=draw}
await window.sunPrintLiveCatalog();
const catalog=document.querySelector('#sunLiveCatalogPrintRoot');const catalogOK=catalog.textContent.includes('ЛИСТ')&&[...catalog.querySelectorAll('.sun-live-catalog-logo')].every(i=>i.src===data);
window.sunOpenRoutes();await document.getElementById('routePrint').onclick();
const route=document.querySelector('#preview .dialog');
const html=window.sunClientOfferDebugHtml({brandName:'Лист',brandCity:'Казань',logo:'',items:[],pricing:{},event:'Обед'});
return {counts,catalogOK,routeName:route.querySelector('.sun-custom-brand')?.textContent,routeLogo:route.querySelector('.sun-custom-brand img')?.src,logoDrawn:images.includes(data),legacy:texts.filter(t=>/солнц|SUN \/ CATERING|САНКТ-ПЕТЕРБУРГ/i.test(t)),neutralHeader:html.includes('<strong>Лист</strong>')};
},data);
expect(result.counts).toHaveLength(21);expect(result.counts.every(n=>n>0)).toBe(true);
expect(result.catalogOK).toBe(true);expect(result.routeName).toContain('Лист');expect(result.routeLogo).toBe(data);
expect(result.logoDrawn).toBe(true);expect(result.legacy).toEqual([]);expect(result.neutralHeader).toBe(true);
});