This repository has been archived on 2026-11-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
james.maesandClaude Opus 5.5 72de96647f test: expect fixed post-commit receipts in the packaged browser suite (#35)
The 1.0 integration replaced detailed Monarch import and calendar refresh
results with fixed NativeMutationReceipt messages, so a result screen never
outlives the caller's access. The browser suite still expected the old
'Transaction batch ... committed' and 'Connection: CURRENT' text. Expect the
receipts; the suite still verifies the effects on the Transactions and
Calendar pages afterwards. Hosted run 37709773519 showed the failure; the
suite passes locally against current foundation snapshots.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:23:33 -05:00

424 lines
31 KiB
JavaScript

/*
* Copyright (C) 2026 KofTwentyTwo
*/
'use strict';
const { chromium, expect } = require('@playwright/test');
const { spawn } = require('node:child_process');
const { createInterface } = require('node:readline');
const { mkdir, writeFile, rm } = require('node:fs/promises');
const path = require('node:path');
const { cleanupOwnedFixture } = require('./live-evaluation-assertions.cjs');
async function main() {
const [distribution, report, classpath] = process.argv.slice(2);
await mkdir(report, { recursive: true });
const fixture = spawn('java', ['-cp', classpath, 'com.kof22.agentadmin.bootstrap.CarlPackagedVisualFixture', distribution], { stdio: ['pipe', 'pipe', 'pipe'] });
const lines = createInterface({ input: fixture.stdout });
let planSeed;
let restartResolve;
lines.on('line', raw => {
const line = raw.replace(/\u001b\[[0-9;]*m/g, '');
if (line.startsWith('PACKAGED_PLAN_SEED=')) planSeed = JSON.parse(line.slice('PACKAGED_PLAN_SEED='.length));
if (line.startsWith('PACKAGED_PROCESS_RESTART=')) restartResolve?.(JSON.parse(line.slice('PACKAGED_PROCESS_RESTART='.length)));
});
let stderr = '';
fixture.stderr.on('data', bytes => { stderr = (stderr + bytes.toString()).slice(-6000); });
const ready = new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error('Packaged fixture readiness timeout')), 90000);
lines.on('line', raw => { const line = raw.replace(/\u001b\[[0-9;]*m/g, ''); if (line.startsWith('PACKAGED_UI=')) { clearTimeout(timer); resolve(line.slice(12)); } });
fixture.once('exit', code => { clearTimeout(timer); reject(new Error('Packaged fixture exited ' + code + ': ' + stderr)); });
});
let browser;
let page;
const checks = [];
let outcome = { status: 'FAIL', checks, syntheticOnly: true };
try {
const origin = await ready;
browser = await chromium.launch({ headless: true });
let context = await browser.newContext({ ignoreHTTPSErrors: true, viewport: { width: 1440, height: 1000 } });
page = await context.newPage();
page.setDefaultTimeout(20000);
await page.goto(origin, { waitUntil: 'domcontentloaded' });
await page.getByRole('button', { name: 'Sign in as Alice', exact: true }).click();
await expect(page.getByText('Carl AI', { exact: true }).first()).toBeVisible();
checks.push('packaged-relocated-TLS-OIDC-login');
await page.screenshot({ path: path.join(report, '01-carl-home.png'), fullPage: true });
const accounts = page.locator('[data-qqq-id="sidebar-item-carlAccounts"]');
if(!await accounts.isVisible()) {
const money = page.locator('[data-qqq-id="sidebar-collapse-carlMoney"]');
if(!await money.isVisible()) await page.locator('[data-qqq-id="sidebar-collapse-carlAI"]').click();
if(!await accounts.isVisible()) await money.click();
}
await accounts.click();
await expect(page.getByText('Synthetic Checking', { exact: true }).first()).toBeVisible();
checks.push('native-authoritative-financial-account');
await page.screenshot({ path: path.join(report, '02-accounts.png'), fullPage: true });
await page.goto(origin + '/app/carlImportMonarch');
await expect(page.locator('input[type=file]').first()).toBeAttached();
const csv = 'Date,Merchant,Category,Account,Original Statement,Notes,Amount,Tags,Owner,Reviewed,Id\n2026-09-02,Synthetic grocery,Food,Checking,Synthetic,,-12.30,,,Reviewed,100000000000000002\n';
await page.locator('input[type=file]').first().setInputFiles({ name: 'Transactions_synthetic.csv', mimeType: 'text/csv', buffer: Buffer.from(csv) });
await page.locator('input[type=file]').nth(1).setInputFiles({ name: 'Balances_synthetic.csv', mimeType: 'text/csv', buffer: Buffer.from('Date,Balance,Account\n2026-09-02,1987.70,Checking\n') });
await page.getByRole('button', { name: /next|continue|submit/i }).last().click();
await expect(page.getByText(/Transactions: 1 source rows/)).toBeVisible();
await page.screenshot({ path: path.join(report, '03-import-preview.png'), fullPage: true });
await page.getByLabel('I reviewed these imports and account mappings').check();
await page.getByRole('button', { name: /next|continue|submit/i }).last().click();
await expect(page.getByText(/Reviewed import processing finished/)).toBeVisible();
checks.push('native-two-file-upload-preview-confirm-apply');
await page.screenshot({ path: path.join(report, '04-import-complete.png'), fullPage: true });
await page.setViewportSize({width:390,height:844});
await page.goto(origin + '/app/carlImportMonarch');
await page.locator('input[type=file]').first().setInputFiles({name:'Transactions_synthetic.csv',mimeType:'text/csv',buffer:Buffer.from(csv)});
await page.locator('input[type=file]').nth(1).setInputFiles({name:'Balances_synthetic.csv',mimeType:'text/csv',buffer:Buffer.from('Date,Balance,Account\n2026-09-02,1987.70,Checking\n')});
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/Transactions: 1 source rows/)).toBeVisible();
await page.screenshot({path:path.join(report,'04b-narrow-repeat-import-preview.png'),fullPage:true});
await page.getByLabel('I reviewed these imports and account mappings').check();
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/Reviewed import processing finished/)).toBeVisible();
checks.push('native-narrow-two-file-repeat-import');
await page.setViewportSize({width:1440,height:1000});
await page.goto(origin + '/app/carlTransactions');
await expect(page.getByText('Synthetic grocery', { exact: true }).first()).toBeVisible();
checks.push('imported-record-visible-in-QQQ');
await page.getByRole('button', {name: /^Configure columns(?: \(\d+\))?$/}).click();
await page.locator('[data-qqq-id="column-config-hide-all"]').click();
for (const field of ['title','amount','currency','effective_date']) await page.locator('[data-qqq-id="column-toggle-' + field + '"]').click();
const titleHandle=page.getByRole('button', {name: 'Drag to reorder Title', exact: true});
for(let move=0;move<20;move++) await titleHandle.press('ArrowUp');
await page.getByRole('button', {name: 'Close column configuration', exact: true}).click();
checks.push('native-user-column-preference');
await page.setViewportSize({ width: 390, height: 844 });
await page.screenshot({ path: path.join(report, '05-narrow-review.png'), fullPage: true });
await page.getByText('Synthetic grocery', {exact: true}).first().click();
await expect(page.getByRole('heading', {name:'Details',exact:true})).toBeVisible();
await page.screenshot({path:path.join(report,'05b-narrow-record-detail.png'),fullPage:true});
await page.locator('[data-qqq-id="accordion-trigger-section-sources"]').click();
await expect(page.getByRole('heading', {name:'Source evidence',exact:true})).toBeVisible();
await page.getByRole('heading', {name:'Source evidence',exact:true}).scrollIntoViewIfNeeded();
await page.screenshot({path:path.join(report,'05c-narrow-source-evidence.png'),fullPage:true});
checks.push('native-narrow-record-detail');
await page.setViewportSize({ width: 1440, height: 1000 });
await page.goto(origin + '/app/carlPlans');
await expect(page.getByText('Synthetic debt plan', { exact: true }).first()).toBeVisible();
await page.screenshot({ path: path.join(report, '06-plan-records.png'), fullPage: true });
checks.push('persisted-versioned-plan-visible');
expect(planSeed && Number.isSafeInteger(planSeed.planId) && /^[0-9a-f-]{36}$/.test(planSeed.taskId)).toBeTruthy();
const readPlanRecord = async (table, id) => {
const response = await context.request.get(origin + '/qqq/v1/table/' + table + '/' + encodeURIComponent(id));
expect(response.status(), await response.text()).toBe(200);
const values = (await response.json()).record?.values;
expect(values && String(values.id)).toBe(String(id));
return values;
};
const beforePlan = await readPlanRecord('carlPlans', planSeed.planId);
const beforeTask = await readPlanRecord('carlPlanSteps', planSeed.taskId);
const restarted = await new Promise((resolve, reject) => {
const timer = setTimeout(() => { restartResolve = null; reject(new Error('Bounded packaged restart timeout')); }, 60000);
restartResolve = value => { clearTimeout(timer); restartResolve = null; resolve(value); };
fixture.stdin.write('restart\n');
});
expect(restarted.previousTerminal && restarted.ready).toBe(true);
expect(Number.isSafeInteger(restarted.previousPid) && restarted.previousPid > 0).toBe(true);
expect(Number.isSafeInteger(restarted.currentPid) && restarted.currentPid > 0).toBe(true);
expect(restarted.currentPid).not.toBe(restarted.previousPid);
await context.close();
context = await browser.newContext({ ignoreHTTPSErrors: true, viewport: { width: 1440, height: 1000 } });
page = await context.newPage();
page.setDefaultTimeout(20000);
await page.goto(origin);
await page.getByRole('button', { name: 'Sign in as Alice', exact: true }).click();
await expect(page.getByText('Carl AI', { exact: true }).first()).toBeVisible();
const afterPlan = await readPlanRecord('carlPlans', planSeed.planId);
const afterTask = await readPlanRecord('carlPlanSteps', planSeed.taskId);
expect(afterPlan).toEqual(beforePlan);
expect(afterTask).toEqual(beforeTask);
await page.goto(origin + '/app/carlPlanSteps/' + planSeed.taskId);
await expect(page.locator('[data-qqq-id="field-value-status"]')).toBeVisible();
await page.screenshot({ path: path.join(report, '25-plan-task-after-process-restart.png'), fullPage: true });
await writeFile(path.join(report, 'plan-process-restart.json'), JSON.stringify({ syntheticOnly: true, process: restarted, records: { planId: planSeed.planId, taskId: planSeed.taskId, beforePlan, afterPlan, beforeTask, afterTask }, limitation: 'SIGTERM process replacement and durable records are verified; no native state-provider shutdown API or live model qualification is implied.' }, null, 2) + '\n');
checks.push('packaged-process-restart-retains-exact-plan-and-task-records');
await page.goto(origin + '/app/carlExportPlan');
const planChoice = page.locator('[data-qqq-id="planId"]');
await expect(planChoice).toBeVisible();
await planChoice.click();
await expect(planChoice).toHaveAttribute('aria-expanded', 'true');
await page.getByRole('option', { name: /Synthetic debt plan/ }).click();
await page.getByRole('button', { name: /next|continue|submit/i }).last().click();
const downloadLink = page.locator('[data-qqq-id="link-process-download"]');
await expect(downloadLink).toBeVisible();
await page.screenshot({ path: path.join(report, '07-plan-pdf-download.png'), fullPage: true });
const [download] = await Promise.all([page.waitForEvent('download'), downloadLink.click()]);
try {
await download.saveAs(path.join(report, 'synthetic-plan.pdf'));
} catch (error) {
const href = await downloadLink.getAttribute('href');
const direct = await context.request.get(new URL(href, origin).toString(), { headers: { Origin: origin, Referer: page.url() } });
await writeFile(path.join(report, 'download-diagnostic.json'), JSON.stringify({ path: new URL(href, origin).pathname, status: direct.status(), contentType: direct.headers()['content-type'], contentDisposition: direct.headers()['content-disposition'], bytes: (await direct.body()).length, pdfSignature: (await direct.body()).subarray(0,5).toString() === '%PDF-', error: await download.failure() }, null, 2));
throw error;
}
checks.push('native-permission-checked-plan-pdf-download');
for (const [route, title, file] of [
['carlCashPlans', 'Synthetic September cash forecast', '08-cash-forecast.png'],
['carlFinancialGoals', 'Synthetic debt freedom goal', '09-owner-goals.png'],
['carlFinancingOffers', 'Synthetic financing assumption', '10-financing-offers.png'],
['carlProperties','Synthetic rental house','11-rental-property.png'],
['carlRentalUnits','Synthetic unit','12-rental-unit.png'],
['carlExpenses','Synthetic power schedule','14-expense-schedule.png']]) {
await page.goto(origin + '/app/' + route);
await expect(page.getByText(title, { exact: true }).first()).toBeVisible();
await page.screenshot({ path: path.join(report, file), fullPage: true });
checks.push('native-scoped-' + route);
}
await page.goto(origin + '/app/carlTaxPacket');
await page.getByLabel('Property', {exact:false}).click();
await page.getByRole('option',{name:/Synthetic rental house/}).click();
await page.locator('input[name="taxYear"]').fill('2026');
await page.locator('input[name="asOf"]').fill('2026-09-30');
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/No tax liability, filing or entity choice has been calculated/)).toBeVisible();
await page.screenshot({path:path.join(report,'13-tax-preparation-checklist.png'),fullPage:true});
checks.push('native-tax-evidence-checklist');
await page.goto(origin + '/app/carlSyncAgenda');
await page.getByLabel('Collection', {exact:false}).click();
await page.getByRole('option', {name:'events', exact:true}).click();
await page.locator('input[name="from"]').fill('2026-09-30');
await page.locator('input[name="through"]').fill('2026-09-30');
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/Calendar refresh request recorded/)).toBeVisible();
await page.screenshot({path:path.join(report,'15-calendar-refresh.png'),fullPage:true});
checks.push('native-bounded-calendar-refresh-over-controlled-HTTPS');
await page.goto(origin + '/app/carlCalendar');
await expect(page.getByText('Synthetic household review', {exact:true}).first()).toBeVisible();
await page.getByRole('button', {name: /^Configure columns(?: \(\d+\))?$/}).click();
await page.locator('[data-qqq-id="column-config-hide-all"]').click();
for (const field of ['title','start_at','end_at','sync_state']) await page.locator('[data-qqq-id="column-toggle-' + field + '"]').click();
const agendaTitle = page.getByRole('button', {name:'Drag to reorder Title', exact:true});
for(let move=0;move<20;move++) await agendaTitle.press('ArrowUp');
await page.getByRole('button', {name:'Close column configuration', exact:true}).click();
await page.screenshot({path:path.join(report,'16-calendar-agenda.png'),fullPage:true});
checks.push('native-authoritative-calendar-agenda');
await page.goto(origin + '/app/carlSuggestAppointmentWindows');
await page.locator('input[name="date"]').fill('2026-09-30');
await page.locator('input[name="startTime"]').fill('09:00');
await page.locator('input[name="endTime"]').fill('17:00');
await page.locator('input[name="minimumMinutes"]').fill('60');
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/Suggestion — not scheduled/)).toBeVisible();
await expect(page.getByText(/America\/Chicago/).last()).toBeVisible();
await page.screenshot({path:path.join(report,'23-appointment-window-suggestions.png'),fullPage:true});
checks.push('native-scoped-appointment-window-suggestions');
await page.goto(origin + '/app/carlComparePortfolio');
await page.locator('input[name="asOf"]').fill('2026-09-01');
await page.locator('input[name="currency"]').fill('USD');
await page.locator('input[name="monthlyBudget"]').fill('100.00');
await page.locator('input[name="horizonMonths"]').fill('24');
await page.getByLabel('Rollover', {exact:false}).click();
await page.getByRole('option', {name:'AVALANCHE', exact:true}).click();
await page.locator('[name="budgetEvidence"]').fill('Synthetic assumed budget; available cash not qualified');
await page.getByLabel('Account 1', {exact:false}).click();
await page.getByRole('option', {name:/Synthetic Card/}).click();
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/Budget and affordability are not yet qualified/)).toBeVisible();
await page.screenshot({path:path.join(report,'17-portfolio-comparison.png'),fullPage:true});
checks.push('native-selected-portfolio-comparison');
await page.goto(origin + '/app/carlComparePurchaseOptions');
await page.getByLabel('Cash Plan', {exact:false}).click();
await page.getByRole('option', {name:/Synthetic purchase alternatives forecast/}).click();
await page.locator('input[name="purchaseDate"]').fill('2026-09-30');
await page.locator('input[name="allInPrice"]').fill('400.00');
await page.locator('input[name="purpose"]').fill('Kitchen table and chairs');
await page.getByLabel('All In Costs Known', {exact:false}).check();
await page.getByLabel('Optional purchase financing offer 1', {exact:false}).click();
await page.getByRole('option', {name:/Synthetic zero-interest furniture terms/}).click();
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByRole('heading',{name:'Purchase payment choices',exact:true})).toBeVisible();
await expect(page.getByText(/Conditionally prefer CASH/)).toBeVisible();
await expect(page.getByText(/Maximum supported cash budget: \$500\.00 USD/)).toBeVisible();
await page.screenshot({path:path.join(report,'18-purchase-payment-options.png'),fullPage:true});
checks.push('native-cash-versus-store-finance-purchase-guidance');
await page.goto(origin + '/app/carlManualTransaction');
await page.locator('[data-qqq-id=\"account\"]').click();
await page.getByRole('option', {name:/Synthetic Checking/}).click();
await page.locator('input[name="date"]').fill('2026-09-29');
await page.locator('input[name="amount"]').fill('-25.00');
await page.locator('[data-qqq-id=\"classification\"]').click();
await page.getByRole('option', {name:'EXPENSE',exact:true}).click();
await page.locator('[name="category"]').fill('Groceries');
await page.locator('[name="title"]').fill('Synthetic manually recorded groceries');
await page.locator('[name="evidence"]').fill('Synthetic receipt reviewed by household member');
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/saved with original evidence; no external transaction occurred/)).toBeVisible();
checks.push('native-human-transaction-with-source-evidence');
await page.goto(origin + '/app/carlBudgetVariance');
await page.locator('[data-qqq-id=\"budget\"]').click();
await page.getByRole('option',{name:/Synthetic grocery budget/}).click();
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
const actualExpense = page.getByRole('row').filter({ has: page.getByRole('rowheader', { name: 'Actual expenses less refunds', exact: true }) }).getByRole('cell');
await expect(actualExpense).toHaveText('$25.00 USD');
await expect(actualExpense).toHaveCSS('text-align', 'right');
await page.screenshot({path:path.join(report,'19-budget-actuals.png'),fullPage:true});
checks.push('native-category-budget-actuals');
await page.goto(origin + '/app/carlDownloadVendorDraft');
await page.locator('[data-qqq-id=\"draftId\"]').click();
await page.getByRole('option',{name:/VENDOR DRAFT/}).click();
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(downloadLink).toBeVisible();
const [draftDownload] = await Promise.all([page.waitForEvent('download'),downloadLink.click()]);
await draftDownload.saveAs(path.join(report,'synthetic-vendor-draft.txt'));
await page.screenshot({path:path.join(report,'20-vendor-draft-download.png'),fullPage:true});
checks.push('native-protected-vendor-draft-download');
for(const action of ['PUBLISH','SYNCHRONIZE']) {
await page.goto(origin + '/app/carlPublishCalendar');
await page.locator('[data-qqq-id="planId"]').click();
await page.getByRole('option',{name:/Synthetic debt plan/}).click();
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await page.locator('[data-qqq-id=\"collection\"]').click();
await page.getByRole('option',{name:'reminders',exact:true}).click();
await page.locator('[data-qqq-id=\"operation\"]').click();
await page.getByRole('option',{name:action,exact:true}).click();
await page.locator('[data-qqq-id="stepId"]').click();
await page.getByRole('option',{name:/Review statement/}).click();
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(action==='PUBLISH' ? /state=COMPLETE/ : /reminderObservation=/)).toBeVisible();
}
await page.goto(origin + '/app/carlReviewReminder');
await page.locator('[data-qqq-id=\"observation\"]').click();
await page.getByRole('option',{name:/Synthetic debt plan/}).click();
await page.locator('[name="expectedVersion"]').fill('3');
await page.locator('[data-qqq-id=\"decision\"]').click();
await page.getByRole('option',{name:'ACCEPT REPORTED COMPLETE',exact:true}).click();
await page.locator('[name="note"]').fill('Human reviewed shared reminder; no payment was verified');
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/Reported completion is not verified financial execution/)).toBeVisible();
await page.screenshot({path:path.join(report,'21-reminder-human-review.png'),fullPage:true});
checks.push('native-shared-reminder-sync-and-human-reported-completion');
await page.goto(origin + '/app/carlSetReportDetail');
await page.locator('[data-qqq-id=\"scope\"]').click();
await page.getByRole('option',{name:'MEMBER',exact:true}).click();
await page.locator('[data-qqq-id=\"value\"]').click();
await page.getByRole('option',{name:'BRIEF',exact:true}).click();
await page.locator('[name="evidence"]').fill('Explicit synthetic member presentation choice');
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/It does not schedule delivery or change permissions/)).toBeVisible();
await page.screenshot({path:path.join(report,'22-explicit-member-preference.png'),fullPage:true});
checks.push('native-explicit-private-presentation-preference');
await page.goto(origin + '/app/carlStartRentalReview');
await page.locator('[data-qqq-id="transaction"]').click();
await page.getByRole('option',{name:/Synthetic manually recorded groceries/}).click();
await page.locator('input[name="title"]').fill('Synthetic shared rental allocation review');
await page.locator('[data-qqq-id="visibility"]').click();
await page.getByRole('option',{name:'PRIVATE',exact:true}).click();
await page.locator('[name="evidence"]').fill('Synthetic reviewed operating allocation');
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/Add components and property shares/)).toBeVisible();
await page.goto(origin + '/app/carlEditRentalReviewComponent');
await page.locator('[data-qqq-id="review"]').click();
await page.getByRole('option',{name:/Synthetic shared rental allocation review/}).click();
await page.locator('input[name="expectedVersion"]').fill('1');
await page.locator('input[name="component"]').fill('operating');
await page.locator('[data-qqq-id="kind"]').click();
await page.getByRole('option',{name:'OPERATING EXPENSE',exact:true}).click();
await page.locator('input[name="amount"]').fill('25.00');
await page.locator('input[name="outsideFraction"]').fill('0');
await page.locator('[name="evidence"]').fill('Synthetic operating expense');
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/review version 2/)).toBeVisible();
for(const [version,property] of [[2,'Synthetic rental house'],[3,'Synthetic second rental house']]) {
await page.goto(origin + '/app/carlEditRentalReviewShare');
await page.locator('[data-qqq-id="review"]').click();
await page.getByRole('option',{name:/Synthetic shared rental allocation review/}).click();
await page.locator('input[name="expectedVersion"]').fill(String(version));
await page.locator('[data-qqq-id="component"]').click();
await page.getByRole('option',{name:/Synthetic shared rental allocation review.*operating/}).click();
await page.locator('[data-qqq-id="property"]').click();
await page.getByRole('option',{name:property,exact:true}).click();
await page.locator('input[name="fraction"]').fill('0.5');
await page.locator('[name="evidence"]').fill('Synthetic explicit half share');
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(new RegExp('review version '+(version+1)))).toBeVisible();
}
await page.goto(origin + '/app/carlPreviewRentalReview');
await page.locator('[data-qqq-id="review"]').click();
await page.getByRole('option',{name:/Synthetic shared rental allocation review/}).click();
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/Ready for explicit application/)).toBeVisible();
await page.screenshot({path:path.join(report,'24-multi-property-allocation-review.png'),fullPage:true});
await page.goto(origin + '/app/carlApplyRentalReview');
await page.locator('[data-qqq-id="review"]').click();
await page.getByRole('option',{name:/Synthetic shared rental allocation review/}).click();
await page.locator('input[name="expectedVersion"]').fill('4');
await page.locator('[name="evidence"]').fill('Human confirms the reviewed allocation');
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/Confirmed classification/)).toBeVisible();
checks.push('native-saved-multi-property-allocation-preview-apply');
await page.goto(origin + '/app/carlFocusedReport');
await page.locator('[data-qqq-id="focus"]').click();
await page.getByRole('option',{name:'BILLS',exact:true}).click();
await page.locator('input[name="from"]').fill('2026-09-01');
await page.locator('input[name="through"]').fill('2026-09-30');
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/Incomplete focused report/)).toBeVisible();
await page.screenshot({path:path.join(report,'25-focused-report.png'),fullPage:true});
checks.push('native-focused-report-with-source-coverage');
for(const [route,file] of [['carlDownloadReportPdf','synthetic-household-report.pdf'],['carlDownloadReportText','synthetic-household-report.txt']]) {
await page.goto(origin + '/app/' + route);
await page.locator('[data-qqq-id="reportId"]').click();
await page.getByRole('option',{name:'BILL REPORT',exact:true}).first().click();
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(downloadLink).toBeVisible();
const [saved] = await Promise.all([page.waitForEvent('download'),downloadLink.click()]);
await saved.saveAs(path.join(report,file));
}
await page.screenshot({path:path.join(report,'26-protected-report-download.png'),fullPage:true});
checks.push('native-protected-report-pdf-and-text-downloads');
await page.goto(origin + '/app/carlBalanceSources');
for(const title of ['Synthetic Checking','Synthetic rental house']) {
await page.getByRole('row').filter({has:page.getByText(title,{exact:true})}).getByRole('checkbox').check();
}
await page.getByRole('button',{name:'Actions',exact:true}).click();
await page.getByRole('menuitem',{name:'Review Selected Accounts and Properties',exact:true}).click();
await expect(page.getByText('Synthetic Checking',{exact:true}).first()).toBeVisible();
await expect(page.getByText('Synthetic rental house',{exact:true}).first()).toBeVisible();
await page.locator('input[name="asOf"]').fill('2026-09-30');
await page.locator('input[name="maximumAgeDays"]').fill('30');
await page.locator('[data-qqq-id="propertyPolicy"]').click();
await page.getByRole('option',{name:"Use each property's supplied valuation",exact:true}).click();
await page.screenshot({path:path.join(report,'27-selected-balance-input.png'),fullPage:true});
await page.getByRole('button',{name:/next|continue|submit/i}).last().click();
await expect(page.getByText(/Saved selected balance sheet/)).toBeVisible();
await page.screenshot({path:path.join(report,'28-selected-balance-result.png'),fullPage:true});
checks.push('native-selected-account-property-balance-review');
const oldSession = (await context.cookies()).find(cookie => cookie.name === 'sessionUUID');
expect(oldSession && oldSession.httpOnly && oldSession.secure && oldSession.sameSite === 'Strict').toBeTruthy();
await page.locator('[data-qqq-id="sidebar-user-button"]').click();
await page.getByRole('menuitem',{name:'Log Out',exact:true}).click();
await expect.poll(async () => (await context.request.get(origin + '/metaData')).status()).toBe(401);
expect((await context.cookies()).some(cookie => cookie.name === 'sessionUUID')).toBe(false);
const replay = await browser.newContext({ignoreHTTPSErrors:true});
try {
await replay.addCookies([oldSession]);
expect((await replay.request.get(origin + '/metaData')).status()).toBe(401);
} finally { await replay.close(); }
checks.push('native-logout-and-revoked-session-replay');
await Promise.all(['failure.png','failure.txt','download-diagnostic.json'].map(file => rm(path.join(report,file), {force:true})));
outcome = { status: 'PASS', checks, syntheticOnly: true };
} catch (error) {
outcome = { status: 'FAIL', checks, syntheticOnly: true, error: error.message };
try {
if (page && !page.isClosed()) { await page.screenshot({ path: path.join(report, "failure.png"), fullPage: true }); await writeFile(path.join(report, "failure.txt"), await page.locator("body").innerText()); }
} catch (diagnosticError) { outcome.diagnosticError = diagnosticError.message; }
throw error;
} finally {
if (browser) {
try { await browser.close(); }
catch (error) { outcome.status = 'FAIL'; outcome.browserCleanupError = String(error); }
}
outcome.cleanup = await cleanupOwnedFixture(fixture);
if (!outcome.cleanup.terminal || outcome.cleanup.errors.length || outcome.cleanup.disposition !== 'GRACEFUL') outcome.status = 'FAIL';
if (outcome.status !== 'PASS') process.exitCode = 1;
await writeFile(path.join(report, 'report.json'), JSON.stringify(outcome, null, 2) + '\n');
}
}
main().catch(error => { process.stderr.write(error.stack + '\n'); process.exitCode = 1; });