43 lines
7.8 KiB
JavaScript
43 lines
7.8 KiB
JavaScript
// Changed UUID consumers only. Existing A/B and C37 acceptance is preserved.
|
||
const fs=require('node:fs'),path=require('node:path'),assert=require('node:assert/strict'),crypto=require('node:crypto');
|
||
const {chromium}=require('C:/Users/macbook/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright');
|
||
const ROOT=path.resolve(__dirname,'..'),DIR=path.join(ROOT,'storage/app/private/investmoz-v2/portal-audit');
|
||
const plan=JSON.parse(fs.readFileSync(path.join(DIR,'portal-stability-latest.json'))),BASE=plan.consumer_environment.base,TARGET=plan.consumer_environment.target.database+':55441';
|
||
const actors=JSON.parse(fs.readFileSync(path.join(DIR,'profiles-v1-actors-private.json')));
|
||
actors.geo=JSON.parse(fs.readFileSync(path.join(DIR,'i0-qa-actor-private.json')));
|
||
const receipt=path.join(DIR,'portal-stability-action-diagnosis.json');
|
||
if(fs.existsSync(receipt))fs.copyFileSync(receipt,receipt.replace('.json','-attempt-'+Date.now()+'.json'));
|
||
const proof={at:new Date().toISOString(),origin:BASE,target:TARGET,checks:[],operations:[],errors:[],active_writes:0,AB_C37_not_repeated:true};
|
||
const resume=process.argv.includes('--resume');
|
||
if(resume){const prior=JSON.parse(fs.readFileSync(receipt));assert.equal(prior.target,TARGET);assert.equal(prior.errors.length,0);assert.equal(prior.checks.length,7);assert(prior.new_opportunity_id&&prior.new_partnership_path);fs.copyFileSync(receipt,receipt.replace('.json','-before-consent-retry.json'));Object.assign(proof,prior,{at:new Date().toISOString(),previous_harness_missing_consent:prior.failure});delete proof.failure;delete proof.result;}
|
||
const remaining=process.argv.includes('--remaining');
|
||
if(remaining){const prior=JSON.parse(fs.readFileSync(receipt));assert.equal(prior.target,TARGET);assert.equal(prior.errors.length,0);assert.equal(prior.checks.length,15);fs.copyFileSync(receipt,receipt.replace('.json','-before-geometry-memory-correction.json'));Object.assign(proof,prior,{at:new Date().toISOString(),previous_missing_geometry_exemplar:prior.failure});delete proof.failure;delete proof.result;}
|
||
const save=()=>fs.writeFileSync(receipt,JSON.stringify(proof,null,2));
|
||
const redact=e=>Object.values(actors).reduce((s,a)=>['password','totp_secret','secret'].reduce((v,k)=>a[k]?v.replaceAll(a[k],'[REDACTED]'):v,s),String(e.message||e)).split('\nCall log:')[0].replace(/\b\d{6}\b/g,'[OTP OMITTED]').slice(0,1200);
|
||
function otp(secret){let bits=0,v=0;const b=[],abc='ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';for(const c of secret.toUpperCase().replace(/=+$/,'')){v=(v<<5)|abc.indexOf(c);bits+=5;if(bits>=8){b.push((v>>>(bits-8))&255);bits-=8;}}const n=Buffer.alloc(8);n.writeBigUInt64BE(BigInt(Math.floor(Date.now()/30000)));const d=crypto.createHmac('sha1',Buffer.from(b)).update(n).digest(),o=d[19]&15;return String((d.readUInt32BE(o)&0x7fffffff)%1000000).padStart(6,'0');}
|
||
(async()=>{const browser=await chromium.launch({headless:true,executablePath:'C:/Users/macbook/AppData/Local/ms-playwright/chromium-1243/chrome-win64/chrome.exe',args:['--host-resolver-rules=MAP portal-investidor.test 127.0.0.1','--no-proxy-server']});let ctx,page,role;
|
||
async function actor(name){if(ctx)await ctx.close();role=name;ctx=await browser.newContext({ignoreHTTPSErrors:false,viewport:{width:1440,height:1000}});
|
||
await ctx.addInitScript(()=>Object.defineProperty(Crypto.prototype,'randomUUID',{value:undefined,configurable:true}));
|
||
await ctx.route('**/*',r=>new URL(r.request().url()).origin===BASE?r.continue():r.abort());page=await ctx.newPage();page.setDefaultTimeout(35000);
|
||
page.on('pageerror',e=>{proof.errors.push({role,path:new URL(page.url()).pathname,message:redact(e)});save();});
|
||
page.on('request',r=>{if(!['POST','PUT'].includes(r.method())||['/login','/two-factor-challenge'].includes(new URL(r.url()).pathname))return;
|
||
let data;try{data=r.postDataJSON();}catch{return;}for(const key of ['client_key','creation_key','idempotency_key'])if(data?.[key]){
|
||
assert.match(data[key],/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
|
||
proof.operations.push({role,path:new URL(r.url()).pathname,method:r.method(),key_field:key,key_sha256:crypto.createHash('sha256').update(data[key]).digest('hex')});save();}});
|
||
await open('/login');const a=actors[name];await page.locator('#email').fill(a.email);await page.locator('#password').fill(a.password);await page.locator('[data-test="login-button"]').click();
|
||
await page.waitForURL(u=>u.pathname!=='/login');if(new URL(page.url()).pathname==='/two-factor-challenge'){await page.waitForTimeout(30500-(Date.now()%30000));await page.locator('input[name="code"]').fill(otp(a.totp_secret??a.secret));await page.getByRole('button',{name:'Continue',exact:true}).click();await page.waitForURL(u=>!['/login','/two-factor-challenge'].includes(u.pathname));}}
|
||
async function open(route){const r=await page.goto(BASE+route,{waitUntil:'networkidle'});assert.equal(r.headers()['x-investmoz-qa-target'],TARGET);return r;}
|
||
async function observed(component,route,expected=200){const r=await open(route);assert.equal(r.status(),expected);await page.locator('h1').first().waitFor();assert(await page.evaluate(()=>isSecureContext&&typeof crypto.randomUUID==='undefined'&&typeof crypto.getRandomValues==='function'));
|
||
const row={component,role,route,status:r.status(),uuid_api_absent:true,visible_heading:(await page.locator('h1').first().innerText()).slice(0,150),errors:proof.errors.length};proof.checks.push(row);save();return row;}
|
||
async function recover(route,label){await open(route);await page.reload({waitUntil:'networkidle'});assert(await page.locator('h1').first().isVisible());proof.checks.push({criterion:label,role,route,refresh_recovery:true});save();}
|
||
try{
|
||
await actor('promoter');await open('/minhas-oportunidades/53/resources');
|
||
if(!process.argv.includes('--room-only')){
|
||
proof.resource_before=await page.locator('article').allTextContents();
|
||
await page.getByRole('button',{name:'Ver / editar / restaurar',exact:true}).last().click();await page.getByLabel('Título',{exact:true}).fill('Synthetic stability recoverable location edited');await page.getByLabel('Motivo (20–1000 caracteres)').fill('Synthetic QA edit: preserve existing location and increase its version');
|
||
const response=page.waitForResponse(r=>r.request().method()==='POST'&&new URL(r.url()).pathname.includes('/53/resources/'));await page.getByRole('button',{name:'Guardar recurso',exact:true}).click();const r=await response;proof.resource_edit_response={status:r.status(),body:await r.json()};save();await page.reload({waitUntil:'networkidle'});proof.resource_visible=await page.locator('article').allTextContents();save();
|
||
}
|
||
await open('/parcerias/salas/1');for(let n=1;n<=2;n++){const text='Isolated trace for consecutive QA room messages '+n;await page.getByLabel('Mensagem privada',{exact:true}).fill(text);const result=page.waitForResponse(r=>r.request().method()==='POST'&&new URL(r.url()).pathname==='/parcerias/salas/1/mensagens');await page.getByRole('button',{name:'Enviar mensagem',exact:true}).click();const r=await result;const sent=r.request().postDataJSON();proof.checks.push({room_send:n,status:r.status(),body_length:sent.body.length,body_matches_entered:sent.body===text});save();await page.waitForTimeout(1000);proof.checks.at(-1).visible=await page.getByText(text,{exact:true}).count();proof.checks.at(-1).errors=await page.getByRole('alert').allTextContents();save();}
|
||
await page.reload({waitUntil:'networkidle'});proof.room_recovery=await page.locator('article').allTextContents();proof.result='diagnosed';save();console.log(JSON.stringify({result:proof.result,resource_status:proof.resource_edit_response?.status,room:proof.checks}));
|
||
}catch(e){proof.result='failed';proof.failure=redact(e);if(page&&!page.isClosed())proof.visible_status=await page.getByRole('status').allTextContents();save();console.log(JSON.stringify({result:'failed',failure:proof.failure}));process.exitCode=1;}finally{if(ctx)await ctx.close();await browser.close();}})();
|