Complete full-app network fixture and preserve workspace across startup

This commit is contained in:
pavlov346346-source 2026-09-19 08:05:27 +03:00
parent 006ba12f98
commit 262711daab

View File

@ -120,30 +120,41 @@ test('a delayed menu editor cannot move back into a section that was already lef
test('full app stays stable across settings, menu, calendar and delayed background refreshes',async({page})=>{ test('full app stays stable across settings, menu, calendar and delayed background refreshes',async({page})=>{
const errors=[];page.on('pageerror',e=>errors.push(String(e))); const errors=[];page.on('pageerror',e=>errors.push(String(e)));
const workspaceId='22222222-2222-4222-8222-222222222222',servedRpcs=new Set();
const expires=Math.floor(Date.now()/1000)+3600,user={id:'11111111-1111-4111-8111-111111111111',aud:'authenticated',role:'authenticated',email:'ui-test@example.invalid',app_metadata:{provider:'email'},user_metadata:{}}; const expires=Math.floor(Date.now()/1000)+3600,user={id:'11111111-1111-4111-8111-111111111111',aud:'authenticated',role:'authenticated',email:'ui-test@example.invalid',app_metadata:{provider:'email'},user_metadata:{}};
const token=[{alg:'HS256',typ:'JWT'},{sub:user.id,role:'authenticated',aud:'authenticated',exp:expires,iat:expires-3600,aal:'aal1'},'test'].map(x=>typeof x==='string'?x:Buffer.from(JSON.stringify(x)).toString('base64url')).join('.'); const token=[{alg:'HS256',typ:'JWT'},{sub:user.id,role:'authenticated',aud:'authenticated',exp:expires,iat:expires-3600,aal:'aal1'},'test'].map(x=>typeof x==='string'?x:Buffer.from(JSON.stringify(x)).toString('base64url')).join('.');
const session={access_token:token,refresh_token:'test-refresh',token_type:'bearer',expires_in:3600,expires_at:expires,user}; const session={access_token:token,refresh_token:'test-refresh',token_type:'bearer',expires_in:3600,expires_at:expires,user};
await page.addInitScript(value=>localStorage.setItem('sb-usfjwhztqoopzzfmfbis-auth-token',JSON.stringify(value)),session); await page.addInitScript(({session,workspaceId})=>{
localStorage.setItem('sb-usfjwhztqoopzzfmfbis-auth-token',JSON.stringify(session));
// This test starts inside an existing workspace. Onboarding/reload is covered
// separately; do not abort a background request by switching tenants here.
localStorage.setItem('sunCloudV2Config',JSON.stringify({workspaceId,localWorkspaceId:workspaceId,tenantStorageReady:true}));
},{session,workspaceId});
await page.route('https://**',r=>r.abort()); await page.route('https://**',r=>r.abort());
const handle=async route=>{ const handle=async route=>{
const url=new URL(route.request().url()),path=url.searchParams.get('__caterium_path')||url.pathname; const url=new URL(route.request().url()),path=url.searchParams.get('__caterium_path')||url.pathname;
const headers={'access-control-allow-origin':'*','access-control-allow-headers':'authorization,apikey,content-type,x-client-info','access-control-allow-methods':'GET,POST,OPTIONS'}; const requestHeaders=await route.request().allHeaders();
// Test-only CORS response: acknowledge the headers actually sent by the SDK,
// including metadata headers added by new SDK versions and browser preflights.
const headers={'access-control-allow-origin':requestHeaders.origin||'http://127.0.0.1:4173','access-control-allow-credentials':'true','access-control-allow-headers':requestHeaders['access-control-request-headers']||Object.keys(requestHeaders).join(','),'access-control-allow-methods':'GET,POST,OPTIONS'};
if(route.request().method()==='OPTIONS')return route.fulfill({status:204,headers}); if(route.request().method()==='OPTIONS')return route.fulfill({status:204,headers});
let data=null; let data=null;
if(path==='/auth/v1/user')data=user; if(path==='/auth/v1/user')data=user;
else if(path.endsWith('/sun_my_workspaces'))data=[{id:'22222222-2222-4222-8222-222222222222',name:'Тестовая компания',role:'admin',is_active:true,permissions:{}}]; else if(path.endsWith('/sun_my_workspaces'))data=[{id:workspaceId,name:'Тестовая компания',role:'admin',is_active:true,permissions:{}}];
else if(path.endsWith('/sun_is_platform_admin'))data=false; else if(path.endsWith('/sun_is_platform_admin'))data=false;
else if(path.endsWith('/caterium_trial_demo_status'))data={canInstall:false,canUpgrade:false};
else if(path.endsWith('/sun_subscription_snapshot'))data={plan_id:'full',plan_name:'Полный',status:'active',access_mode:'full',features:Object.fromEntries('orders calendar clients catalog_view catalog_edit production shopping stock routes mailings money stats_basic stats_advanced team suppliers print settings branding client_offers offer_templates backups audit users_manage'.split(' ').map(k=>[k,true]))}; else if(path.endsWith('/sun_subscription_snapshot'))data={plan_id:'full',plan_name:'Полный',status:'active',access_mode:'full',features:Object.fromEntries('orders calendar clients catalog_view catalog_edit production shopping stock routes mailings money stats_basic stats_advanced team suppliers print settings branding client_offers offer_templates backups audit users_manage'.split(' ').map(k=>[k,true]))};
else if(path.endsWith('/sun_fetch_app_state'))data=url.searchParams.get('select')==='revision'?{revision:1}:[{revision:1,payload:{format:'sun-cloud-v2',version:2,storage:{sunOrders:{t:'j',v:[]},sunBoxes:{t:'j',v:[]}}}}]; else if(path.endsWith('/sun_fetch_app_state'))data=url.searchParams.get('select')==='revision'?{revision:1}:[{revision:1,payload:{format:'sun-cloud-v2',version:2,storage:{sunOrders:{t:'j',v:[]},sunBoxes:{t:'j',v:[]}}}}];
return route.fulfill({contentType:'application/json',body:JSON.stringify(data),headers}); await route.fulfill({contentType:'application/json',body:JSON.stringify(data),headers});
if(path.includes('/rpc/'))servedRpcs.add(path.split('/').pop());
}; };
// The real transport can use either configured proxy while the first document // Both configured transports stay within the mocked backend.
// reloads after workspace discovery. Both belong to this local server fixture.
await page.route('**://api.caterium.ru/**',handle); await page.route('**://api.caterium.ru/**',handle);
await page.route('**/api/index.php?**',handle); await page.route('**/api/index.php?**',handle);
await page.goto('/index.html',{waitUntil:'domcontentloaded'}); await page.goto('/index.html',{waitUntil:'domcontentloaded'});
await expect(page.locator('body > header')).toBeVisible({timeout:20000}); await expect(page.locator('body > header')).toBeVisible({timeout:20000});
await page.waitForFunction(()=>window.SunOpsUXV1762&&window.SunSaaSV16?.getSnapshot()); await page.waitForFunction(()=>window.SunOpsUXV1762&&window.SunSaaSV16?.getSnapshot());
await expect.poll(()=>servedRpcs.has('caterium_trial_demo_status')).toBe(true);
const nav=page.locator('header nav'); const nav=page.locator('header nav');
for(const name of ['Настройки','Меню','Календарь','Заказы','Настройки']){ for(const name of ['Настройки','Меню','Календарь','Заказы','Настройки']){
await nav.getByRole('button',{name,exact:true}).click(); await nav.getByRole('button',{name,exact:true}).click();