// Browser checks run only against the isolated SLICE13 test host. import {chromium,expect} from '@playwright/test'; import fs from 'node:fs/promises'; const [host,port,phase]=process.argv.slice(2); if(!/^conductor-slice13-[a-f0-9]{10}$/.test(host)||!/^\d+$/.test(port)||!['seed','legacy','upgraded'].includes(phase))throw Error('Disposable upgrade fixture required.'); const dir='test-results/slice13',base='https://conductor.customer.test:'+port; const browser=await chromium.launch({headless:true,args:['--host-resolver-rules=MAP conductor.customer.test 127.0.0.1','--no-proxy-server']}); let page; try{ const context=await browser.newContext({baseURL:base,ignoreHTTPSErrors:true,viewport:{width:1400,height:1000}}); page=await context.newPage(); await page.goto('/'); await expect(page.getByLabel('Username',{exact:true})).toBeVisible(); const request=async(method,url,options={})=>{ const value=await page.evaluate(async({method,url,data,headers})=>{ const response=await fetch(url,{method,headers:{...(data?{'Content-Type':'application/json'}:{}),...headers},body:data?JSON.stringify(data):undefined}); return {status:response.status,body:await response.json()}; },{method,url,...options}); return {status:()=>value.status,json:async()=>value.body}; }; let auth; if(phase==='seed'){ const setup=await request('GET','/api/auth/setup'); auth=await request('POST','/api/auth/setup',{headers:{'X-Setup-Token':(await setup.json()).setupToken},data:{username:'customer-admin',password:'disposable-upgrade-password',displayName:'Customer Administrator'}}); expect(auth.status()).toBe(201); }else{ auth=await request('POST','/api/auth/login',{data:{username:'customer-admin',password:'disposable-upgrade-password'}}); expect(auth.status()).toBe(200); } const csrf=(await auth.json()).csrfToken; if(phase==='seed'){ const project=await request('POST','/api/projects',{headers:{'X-CSRF-Token':csrf},data:{name:'Customer project',description:'Preserve my saved work.'}}); expect(project.status()).toBe(201); const publication=await request('POST','/api/admin/published-apps',{headers:{'X-CSRF-Token':csrf},data:{sourceProjectId:(await project.json()).id,slug:'customer-app',displayName:'Customer publication',visibility:'authenticated'}}); expect(publication.status()).toBe(201); } const projects=await (await request('GET','/api/projects')).json(); expect(projects).toHaveLength(1);expect(projects[0].name).toBe('Customer project'); const published=await (await request('GET','/api/admin/published-apps')).json(); expect(published).toHaveLength(1);expect(published[0].slug).toBe('customer-app'); expect(published[0].version).toBe(1); const session=await request('GET','/api/social-scheduler/session'); expect(session.status()).toBe(200);expect((await session.json()).role).toBe('admin'); const snapshot=await (await request('GET','/api/social-scheduler/workspaces/customer')).json(); expect(snapshot.accounts[0].handle).toBe('customer.bsky.social'); expect(snapshot.posts[0].text).toBe('Scheduled before the Conductor upgrade.'); const errors=[];page.on('pageerror',e=>errors.push(e.message)); await page.goto('/');await page.getByRole('navigation').getByRole('button',{name:'Publishing',exact:true}).click(); await expect(page.getByRole('heading',{name:'Social Scheduler',exact:true})).toHaveCount(1); await page.screenshot({path:dir+'/'+phase+'-publishing.png',fullPage:true}); await page.getByRole('link',{name:'Open Social Scheduler',exact:true}).click(); await expect(page.getByRole('heading',{name:'Compose a post',exact:true})).toBeVisible(); await expect(page.getByText('Scheduled before the Conductor upgrade.',{exact:true}).first()).toBeVisible(); if(phase==='upgraded'){ await expect(page).toHaveTitle('Social Scheduler ยท Conductor'); await expect(page.locator('#conductor-favicon')).toHaveAttribute('href','/favicon.svg'); } await page.screenshot({path:dir+'/'+phase+'-social.png',fullPage:true}); await page.goto('/apps/customer-app'); await expect(page.getByText('Customer publication',{exact:true}).first()).toBeVisible(); expect(errors).toEqual([]); await fs.writeFile(dir+'/'+phase+'-browser.json',JSON.stringify({passed:true,phase,checks:['same administrator password','saved project','unchanged published snapshot/version','existing social connection','existing queued post','authenticated API bridge','single included-app card','real Social Scheduler screen',...(phase==='upgraded'?['app browser title','default favicon']:[])]},null,2)); console.log('PASS: '+phase+' browser login, project/publication, app screen and existing connection/queue.'); }catch(error){ if(page)await page.screenshot({path:dir+'/'+phase+'-failure.png',fullPage:true}).catch(()=>{}); throw error; }finally{await browser.close();}