Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions tests/integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ The [initializer acceptance](installed/initializer-acceptance.ts) runs
`npm create cs-object my-report` against a temporary loopback npm registry backed
by actual archives. It installs the Python wheel into the generated project,
starts `npm run dev`, and checks browser edits, the output-only calculation API,
report/PDF evidence and restart. It also replaces the starter with a copy of the
canonical two-panel calculation. Third-party dependencies still need network
report/PDF evidence and restart. It executes the packaged composed-report/figure recipe and follows the shipped
reference-binding recipe with independently established intermediate and output
values. Correct, wrong and unmatched cases, formula/text changes and explicit
rebinding are checked before browser edits, output-only curl and same-run HTML,
PDF and evidence. Automatic results leave visual inspection and engineering
approval separate. It also exercises a copy of the canonical two-panel calculation. Third-party dependencies still need network
access. This tests installation without publishing a release.

The canonical two-panel calculations and metadata stay in `examples/two-panel`.
Expand Down
28 changes: 20 additions & 8 deletions tests/integration/installed/_initializer-browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export async function exerciseBrowser(options: {
readonly outputs: Readonly<Record<string, number>>;
readonly reportId: string;
readonly reportTitle: string;
readonly referenceStatus?: 'passed' | 'not_applicable';
}) {
const browser = await chromium.launch({ headless: true });
try {
Expand Down Expand Up @@ -115,7 +116,10 @@ export async function exerciseBrowser(options: {
assert.equal(await page.locator('[data-slot=sheet-overlay]').count(), 0);
await page.locator('iframe#report').waitFor({ state: 'visible' });
assert(await page.locator('iframe#report').getAttribute('src'));
assert.match(await page.locator('button#pdf').innerText(), /review pending/i);
assert.match(
await page.locator('button#pdf').innerText(),
/review pending/i,
);
assert.equal(await page.locator('#checks').isVisible(), true);
const initialReportText = await page
.frameLocator('iframe#report')
Expand Down Expand Up @@ -152,15 +156,17 @@ export async function exerciseBrowser(options: {
assert(reportMatch?.[1]);
const runBase = `/api/reports/${options.reportId}/runs/${reportMatch[1]}`;
assert.equal(evidencePath, `${runBase}/evidence.json`);
assert.match(
await page.locator('#checks').innerText(),
/Human inspection\s+WIP/i,
);
if (options.reportId === 'rectangle-area')
const checksText = await page.locator('#checks').innerText();
assert.match(checksText, /Human inspection\s+WIP/i);
if (options.referenceStatus)
assert.match(
await page.locator('#checks').innerText(),
/Independent reference\s+WIP/i,
checksText,
options.referenceStatus === 'passed'
? /Independent reference\s+Passed/i
: /Independent reference\s+WIP/i,
);
if (options.reportId === 'rectangle-area')
assert.match(checksText, /Independent reference\s+WIP/i);
await page.setViewportSize({ width: 950, height: 900 });
assert.equal(
await page.evaluate(
Expand Down Expand Up @@ -230,6 +236,11 @@ export async function exerciseBrowser(options: {
evidence.artifacts.pdf?.sha256,
hashBytes(readFileSync(options.downloadPath)),
);
if (options.referenceStatus)
assert.equal(
evidence.checks.independentReferenceAgreement?.status,
options.referenceStatus,
);
if (options.reportId === 'rectangle-area') {
await page.locator('[name=width]').fill('-0');
await page.getByRole('button', { name: 'API', exact: true }).click();
Expand Down Expand Up @@ -270,6 +281,7 @@ export async function exerciseBrowser(options: {
),
);
}
return summary;
} finally {
await browser.close();
}
Expand Down
4 changes: 3 additions & 1 deletion tests/integration/installed/_initializer-evidence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export async function artifactSet(options: {
readonly unit: string;
}[];
readonly referencePath?: string;
readonly referenceStatus?: 'passed' | 'not_applicable';
readonly name: string;
readonly reportId: string;
}) {
Expand Down Expand Up @@ -183,7 +184,8 @@ export async function artifactSet(options: {
assert.equal(evidence.checks.sourceToDocumentConsistency?.status, 'passed');
assert.equal(
evidence.checks.independentReferenceAgreement?.status,
options.referencePath ? 'passed' : 'not_applicable',
options.referenceStatus ??
(options.referencePath ? 'passed' : 'not_applicable'),
);
assert.equal(evidence.checks.documentContent?.status, 'passed');
assert.equal(evidence.checks.rendering?.status, 'passed');
Expand Down
1 change: 1 addition & 0 deletions tests/integration/installed/_initializer-guidance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,5 @@ export async function exerciseGuidance(options: {
'data:image/svg+xml',
])
assert(html.includes(expected), `Missing recipe content: ${expected}`);
return { trial };
}
3 changes: 2 additions & 1 deletion tests/integration/installed/_initializer-processes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type CommandRunner = (options: {
readonly args: readonly string[];
readonly env?: NodeJS.ProcessEnv;
readonly timeoutMs?: number;
readonly expectedStatus?: number;
}) => Promise<string>;

export function createCommandRunner(
Expand Down Expand Up @@ -97,7 +98,7 @@ export function createCommandRunner(
`${options.command} stdout exceeded ${maximumCapturedCharacters} characters; see ${log}`,
),
);
if (status !== 0)
if (status !== (options.expectedStatus ?? 0))
return rejectRun(
new Error(
`${options.command} ${options.args.join(' ')} exited ${status}; see ${log}\n${stderr}${stderrTruncated ? '\n[stderr truncated in memory; full output is in the log]' : ''}`,
Expand Down
Loading
Loading