caterium-app/tests/account-access.spec.mjs
2026-09-18 20:43:09 +03:00

101 lines
7.3 KiB
JavaScript

import fs from 'node:fs';
import {test,expect} from '@playwright/test';
test('retired device PIN cannot lock an authenticated account or replace email login',async({page})=>{
await page.addInitScript(()=>{localStorage.setItem('sunCloudQuickPinV3:pin-test','legacy-device-pin');localStorage.setItem('unrelated-preference','keep')});
await page.route('https://**',r=>r.abort());
await page.goto('/index.html',{waitUntil:'domcontentloaded'});
await expect(page.locator('#sunGateEmailV3')).toBeVisible();
await expect(page.locator('#sunGatePasswordV3')).toBeVisible();
await page.evaluate(()=>{
window.SunCloudV2={getSession:()=>({user:{id:'pin-test',email:'pin@example.invalid'}}),getWorkspace:()=>({id:'pin-company',role:'admin'}),status:()=>({connected:true,signedIn:true,membershipsLoaded:true}),hasPermission:()=>true,getClient:()=>null};
window.dispatchEvent(new Event('sun:cloud-permissions-changed'));
});
await expect(page.locator('body > header')).toBeVisible();
await page.getByRole('button',{name:'Настройки',exact:true}).click();
await expect(page.locator('#sunCloudPinLockV3,#sunCloudQuickPinCardV3,#sunSetQuickPinV3')).toHaveCount(0);
expect(await page.evaluate(()=>({pin:localStorage.getItem('sunCloudQuickPinV3:pin-test'),preference:localStorage.getItem('unrelated-preference')}))).toEqual({pin:null,preference:'keep'});
});
test('anonymous login stays closed with an old local-mode preference and an unavailable backend',async({page})=>{
await page.addInitScript(()=>localStorage.setItem('sunLocalOnlyModeV1','1'));
await page.route('**://api.caterium.ru/**',r=>r.abort());
await page.route('**://*.supabase.co/**',r=>r.abort());
await page.goto('/index.html',{waitUntil:'domcontentloaded'});
await expect(page.locator('#sunGateEmailV3')).toBeVisible();
await expect(page.locator('#sunGatePasswordV3')).toBeVisible();
await expect(page.locator('#sunGateLocalOnlyV1')).toHaveCount(0);
await expect(page.locator('body > header')).toBeHidden();
expect(await page.evaluate(()=>localStorage.getItem('sunLocalOnlyModeV1'))).toBeNull();
expect(await page.evaluate(()=>{localStorage.setItem('sunLocalOnlyModeV1','1');return window.SunAdminRBACV3.hasPermission('orders.create')})).toBe(false);
});
test('workspace changes isolate client caches and ignore delayed responses from the previous company',async({page})=>{
await page.route('**/index.html',r=>r.fulfill({contentType:'text/html',body:'<!doctype html><html><body></body></html>'}));
await page.goto('/index.html');
await page.addScriptTag({url:'/core/sun-safe.js'});
await page.addScriptTag({url:'/core/cloud-transport.js'});
const runtime=fs.readFileSync('public/app-runtime.js','utf8');
let cloud=runtime.slice(runtime.indexOf('/* ===== MODULE: cloud-sync-v2.js'),runtime.indexOf('/* ===== MODULE: admin-rbac-v3.js'));
cloud=cloud.replace('async function boot(){','async function boot(){return;');
cloud=cloud.replace('window.SunCloudV2={',`window.SunCloudV2={
testSwitch:async id=>{workspace=id?{id}:null;return switchTenantLocal(id)},
testRefresh:refreshRuntime,`);
await page.addScriptTag({content:'var orders=[];var boxes=[];'+cloud});
expect(await page.evaluate(async()=>{
localStorage.setItem('cateriumClientsV1772','{"old-anonymous":{"name":"Old anonymous customer"}}');
localStorage.setItem('sunBoxes','[{"id":"old-anonymous-box"}]');
await window.SunCloudV2.testSwitch('company-a');
return {clients:localStorage.getItem('cateriumClientsV1772'),catalog:localStorage.getItem('sunBoxes')};
})).toEqual({clients:null,catalog:null});
await page.evaluate(async()=>{
await window.SunCloudV2.adoptCurrentLocalAsWorkspace('company-a');
await window.SunCloudV2.testSwitch('company-a');
orders=[{id:1,contact:'Клиент A',phone:'79990000001',address:'Адрес A',total:1234}];
boxes=[{id:'a',name:'Бокс A',price:1234,photo:'private-photo-a'}];
localStorage.setItem('sunOrders',JSON.stringify(orders));localStorage.setItem('sunBoxes',JSON.stringify(boxes));
localStorage.setItem('sunClientCommunicationV1','{}');
localStorage.setItem('cateriumClientsV1772',JSON.stringify({'p:79990000002':{key:'p:79990000002',name:'Ручной клиент A',phone:'79990000002',latestAddress:'Ещё адрес A'}}));
localStorage.setItem('sunTelegramImportArchiveV1','{"messages":[{"text":"Private A"}]}');
window.pendingRpc=[];window.rpcCalls=[];
window.SunCloudV2.getSession=()=>({user:{id:'test-user'}});
window.SunCloudV2.hasPermission=()=>true;
window.SunCloudV2.getClient=()=>({rpc:(name,args)=>{window.rpcCalls.push({name,workspace:args.p_workspace});return new Promise(resolve=>window.pendingRpc.push(()=>resolve({data:name.includes('snapshot')?[{client_key:'old-server-a',name:'Сервер A'}]:{version:99}})))}});
});
await page.addScriptTag({url:'/core/data-layer-v1773.js'});
const result=await page.evaluate(async()=>{
const c=window.SunCloudV2,d=window.CateriumDataV1773;
const refresh=d.clients.refreshServer({force:true}),push=d.clients.pushAll();
await c.testSwitch('company-b');c.testRefresh();
window.pendingRpc.splice(0).forEach(resolve=>resolve());
const staleResults=[await refresh,await push];
await new Promise(resolve=>setTimeout(resolve,300));
const empty={clients:d.clients.list().length,orders:d.orders.list().length,boxes:d.catalog.list().length,archive:localStorage.getItem('sunTelegramImportArchiveV1'),cache:localStorage.getItem('cateriumClientsV1772'),server:localStorage.getItem('cateriumClientsServerV1773')};
await c.testSwitch('company-a');c.testRefresh();
return {empty,staleResults,calls:window.rpcCalls,restored:{clients:d.clients.list().map(c=>c.name).sort(),orders:d.orders.list().length,boxes:d.catalog.list(),archive:localStorage.getItem('sunTelegramImportArchiveV1')}};
});
expect(result.empty).toEqual({clients:0,orders:0,boxes:0,archive:null,cache:null,server:null});
expect(result.staleResults[0].status).toBe('stale');
expect(result.staleResults[1]).toHaveLength(1);
expect(result.calls.every(c=>c.workspace==='company-a')).toBe(true);
expect(result.restored.clients).toEqual(['Клиент A','Ручной клиент A']);
expect(result.restored.orders).toBe(1);
expect(result.restored.boxes[0].photo).toBe('private-photo-a');
expect(result.restored.archive).toContain('Private A');
});
test('a developer with a personal company opens the ordinary app before choosing developer tools',async({page})=>{
await page.route('**://api.caterium.ru/**',r=>r.abort());
await page.route('**://*.supabase.co/**',r=>r.abort());
await page.goto('/index.html',{waitUntil:'domcontentloaded'});
await expect(page.locator('#sunGateEmailV3')).toBeVisible();
await page.evaluate(()=>{
window.SunCloudV2={getSession:()=>({user:{id:'developer-test',email:'developer@example.invalid'}}),getWorkspace:()=>({id:'developer-workspace',name:'Тестовая компания',role:'admin'}),status:()=>({connected:true,signedIn:true,membershipsLoaded:true}),hasPermission:()=>true,getClient:()=>null};
window.dispatchEvent(new Event('sun:cloud-permissions-changed'));
});
await expect(page.locator('#sunCloudAuthGateV3')).toHaveCount(0);
await expect(page.locator('body > header')).toBeVisible();
await expect(page.locator('#sun-developer-console-v22.on')).toHaveCount(0);
expect(await page.evaluate(()=>({orders:orders.length,boxes:boxes.length}))).toEqual({orders:0,boxes:0});
});