Load the missing promo module, add a prominent creation button and place Promos beside Overview. Use existing AAL2-guarded server RPCs with selected plan, subscription duration and code validity; preserve form input, honest clipboard feedback and scope async responses. Full PR QA succeeded in run 35547013076. No live data, SQL, MFA or unfinished training branch changes. Preserve normal main QA and exact-asset/browser publication verification.
55 lines
4.2 KiB
JavaScript
55 lines
4.2 KiB
JavaScript
import {expect} from '@playwright/test';
|
|
|
|
// Only GET requests for public static assets are allowed. No real account,
|
|
// promo, subscription or backend is read or written, including on production.
|
|
export async function bootPromoFixture(page,base='http://127.0.0.1:4173/'){
|
|
const origin=new URL(base).origin;
|
|
await page.route('**/*',route=>{const r=route.request(),u=new URL(r.url());return r.method()==='GET'&&u.origin===origin&&!u.pathname.startsWith('/api/')?route.continue():route.abort();});
|
|
await page.addInitScript(()=>{
|
|
const user={id:'promo-test-user',email:'promo-ui@example.invalid',email_confirmed_at:'2026-01-01T00:00:00Z'},ws='promo-test-workspace';
|
|
window.promoCalls=[];window.promoRows=[];window.promoCreateError=null;window.promoDelay=false;
|
|
localStorage.setItem('sunCloudV2Config',JSON.stringify({workspaceId:ws,localWorkspaceId:ws,tenantStorageReady:true,autoSync:false}));
|
|
localStorage.setItem('sunBoxes','[]');localStorage.setItem('sunOrders','[]');
|
|
const 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]));
|
|
const sdk={
|
|
auth:{onAuthStateChange:()=>({data:{subscription:{unsubscribe(){}}}}),getSession:async()=>({data:{session:{user}},error:null}),getUser:async()=>({data:{user},error:null}),mfa:{getAuthenticatorAssuranceLevel:async()=>({data:{currentLevel:'aal2'}})}},
|
|
rpc:async(name,args={})=>{
|
|
if(name==='sun_my_workspaces')return {data:[{id:ws,name:'Проверка интерфейса',role:'admin',is_active:true,permissions:{}}]};
|
|
if(name==='sun_subscription_snapshot')return {data:{plan_id:'full',plan_name:'Полный',status:'active',access_mode:'full',features}};
|
|
if(name==='sun_is_platform_admin')return {data:true};
|
|
if(name==='sun_dev_dashboard')return {data:{}};
|
|
if(name==='caterium_trial_demo_status')return {data:{canInstall:false,canUpgrade:false}};
|
|
if(name==='sun_dev_list_trial_promos'){promoCalls.push({name,args});return {data:structuredClone(promoRows)};}
|
|
if(name==='sun_dev_create_trial_promo'){
|
|
promoCalls.push({name,args});if(promoDelay)await new Promise(resolve=>window.completePromo=resolve);
|
|
if(promoCreateError)return {error:{message:promoCreateError}};
|
|
const data={promo_id:'test-code-'+promoRows.length,code:args.p_code||'CTM-UI-TEST',trial_days:args.p_trial_days,valid_until:'2099-01-01T00:00:00Z'};
|
|
promoRows.push({...data,client_email:args.p_email,max_uses:args.p_max_uses,use_count:0,is_active:true});return {data};
|
|
}
|
|
if(name==='sun_dev_set_trial_promo_active'){promoCalls.push({name,args});const r=promoRows.find(r=>r.promo_id===args.p_promo);if(r)r.is_active=args.p_active;return {data:null};}
|
|
return {data:null,error:null};
|
|
},channel:()=>({on(){return this},subscribe(){return this}}),removeChannel(){}
|
|
};
|
|
window.supabase={createClient:()=>sdk};
|
|
});
|
|
await page.goto(base,{waitUntil:'domcontentloaded',timeout:60000});
|
|
await expect(page.locator('body > header')).toBeVisible({timeout:20000});
|
|
await page.waitForFunction(()=>window.SunDeveloperV22&&window.SunDeveloperUXV1768&&window.CateriumTrialPromoDeveloperV181);
|
|
await page.locator('#sunDeveloperNavV22').click();
|
|
await expect(page.locator('#ctmPromoOpen')).toBeVisible();
|
|
}
|
|
export async function exercisePromoCreation(page){
|
|
await page.locator('#ctmPromoOpen').click();
|
|
await expect(page.locator('#ctmPromoPlan')).toBeVisible();
|
|
await expect(page.locator('#ctmPromoPlan option')).toHaveCount(3);
|
|
await page.locator('#ctmPromoPlan').selectOption('professional');
|
|
await page.locator('#ctmPromoTrial').fill('30');
|
|
await page.locator('#ctmPromoValid').fill('7');
|
|
await page.locator('#ctmPromoCreate').click();
|
|
await expect(page.locator('#ctmInvitationText')).toHaveValue(/Профессиональный/);
|
|
await expect(page.locator('#ctmInvitationText')).toHaveValue(/30 дн/);
|
|
await expect(page.locator('#ctmPromoList')).toContainText('CTM-UI-TEST');
|
|
const calls=await page.evaluate(()=>promoCalls.filter(c=>c.name==='sun_dev_create_trial_promo'));
|
|
expect(calls).toHaveLength(1);expect(calls[0].args).toMatchObject({p_plan:'professional',p_trial_days:30,p_valid_days:7,p_max_uses:1,p_code:null});
|
|
}
|