blob: 93b58e1ebe07b296d1f7fbb71f620ebc55fcc8d4 [file]
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import test from 'node:test';
import {
CU_E2E_ACTIONS,
CU_E2E_SCENARIOS,
evaluateCuE2eScenarioState,
getCuE2eScenario,
validateCuE2eScenario,
validateCuE2eScenarioLibrary,
} from './cu-e2e-scenarios.mjs';
test('scenario library validates and covers every layer', () => {
assert.equal(validateCuE2eScenarioLibrary(), CU_E2E_SCENARIOS);
assert.deepEqual([...new Set(CU_E2E_SCENARIOS.map((scenario) => scenario.level))].sort(), [
'L0',
'L1',
'L2',
'L3',
'L4',
'L5',
]);
assert.equal(
new Set(CU_E2E_SCENARIOS.map((scenario) => scenario.id)).size,
CU_E2E_SCENARIOS.length,
);
});
test('L4 and L5 use dedicated non-mutating runners', () => {
const l4 = getCuE2eScenario('l4-user-concurrency');
const l5 = getCuE2eScenario('l5-provider-matrix');
assert.equal(l4.runner, 'safety-sentinel');
assert.equal(l5.runner, 'provider-matrix');
assert.deepEqual(l4.allowedActions, ['observe', 'screenshot', 'wait']);
assert.deepEqual(l5.allowedActions, ['observe']);
});
test('the first enabled real-model scenario is observe-only', () => {
const first = CU_E2E_SCENARIOS.find((scenario) => scenario.realRunEnabled);
assert.equal(first?.id, 'l0-observe-only');
assert.deepEqual(first?.allowedActions, ['observe']);
assert.deepEqual(first?.requiresExecutionCapabilities, []);
});
test('every scenario carries prompt, fixture, expected state, forbidden effects, and bounded actions', () => {
const knownActions = new Set(CU_E2E_ACTIONS);
for (const scenario of CU_E2E_SCENARIOS) {
assert.ok(scenario.prompt.length >= 20, scenario.id);
assert.ok(scenario.fixtureSetup.windows.length > 0, scenario.id);
assert.ok(scenario.expectedState.length > 0, scenario.id);
assert.ok(scenario.forbiddenEffects.length > 0, scenario.id);
assert.ok(
scenario.allowedActions.includes('screenshot') || scenario.allowedActions.includes('observe'),
scenario.id,
);
assert.ok(
scenario.allowedActions.every((action) => knownActions.has(action)),
scenario.id,
);
assert.equal(typeof scenario.realRunEnabled, 'boolean', scenario.id);
assert.ok(Array.isArray(scenario.requiresExecutionCapabilities), scenario.id);
assert.ok(Array.isArray(scenario.contractChecks), scenario.id);
if (['L0', 'L1', 'L2', 'L3', 'L4'].includes(scenario.level)) {
assert.ok((scenario.minimumActionCounts?.observe ?? 0) >= 1, scenario.id);
assert.ok(Number.isInteger(scenario.maxTotalActions), scenario.id);
assert.ok(scenario.maxTotalActions > 0, scenario.id);
}
}
});
test('layer action budgets increase deliberately', () => {
assert.deepEqual(getCuE2eScenario('l0-observe-only').allowedActions, ['observe']);
assert.ok(getCuE2eScenario('l1-single-click').allowedActions.includes('click_element'));
assert.ok(!getCuE2eScenario('l1-single-click').allowedActions.includes('left_click'));
assert.equal(getCuE2eScenario('l1-single-click').minimumActionCounts.observe, 2);
assert.deepEqual(getCuE2eScenario('l1-single-click').expectedActionSequence, [
'observe',
'observe',
'click_element',
]);
const multi = getCuE2eScenario('l2-multi-control');
assert.ok(multi.allowedActions.includes('scroll'));
assert.ok(multi.allowedActions.includes('left_click_drag'));
assert.ok(multi.allowedActions.includes('type'));
const occlusion = getCuE2eScenario('l3-occlusion');
assert.ok(!occlusion.allowedActions.includes('left_click'));
assert.equal(occlusion.realRunEnabled, true);
assert.equal(getCuE2eScenario('l3-two-window').realRunEnabled, false);
});
test('L3 isolates two-window, stale, and occlusion hazards', () => {
const l3 = CU_E2E_SCENARIOS.filter((scenario) => scenario.level === 'L3');
assert.deepEqual(
l3.map((scenario) => scenario.id),
['l3-two-window', 'l3-stale-window', 'l3-occlusion'],
);
assert.equal(getCuE2eScenario('l3-two-window').fixtureSetup.windows.length, 2);
assert.equal(
getCuE2eScenario('l3-stale-window').fixtureSetup.transitions[0].type,
'replace-window',
);
assert.equal(getCuE2eScenario('l3-occlusion').fixtureSetup.layout, 'overlap');
});
test('L1-L4 declare exact Window/frame, stale, zoom, display, and ownership gates', () => {
const checks = new Set(
CU_E2E_SCENARIOS.filter(({ level }) => ['L1', 'L2', 'L3', 'L4'].includes(level)).flatMap(
({ contractChecks }) => contractChecks,
),
);
assert.deepEqual([...checks].sort(), [
'ax-diff-secondary-oracle',
'duplicate-action-rejection',
'explicit-occurrence-selection',
'focus-cursor-safety',
'fresh-post-action-observation',
'identity-preserving-stale-resolution',
'immediately-preceding-local-screenshot',
'keyboard-ownership',
'mixed-scale-mapping',
'negative-origin-mapping',
'observation-window-frame-binding',
'occlusion-rejection',
'semantic-action-coverage',
'two-window-isolation',
'unrelated-dynamic-content-tolerated',
'zoom-crop-coordinate-space',
]);
});
test('state evaluation reports expected and forbidden-effect failures separately', () => {
const scenario = getCuE2eScenario('l1-single-click');
const passing = evaluateCuE2eScenarioState(scenario, {
target: { primaryClicks: 1, primaryOverClicks: 0, dangerClicks: 0 },
});
assert.equal(passing.pass, true);
const failing = evaluateCuE2eScenarioState(scenario, {
target: { primaryClicks: 2, primaryOverClicks: 1, dangerClicks: 1 },
});
assert.equal(failing.pass, false);
assert.equal(failing.expected.find((result) => result.path === 'primaryClicks').pass, false);
assert.equal(
failing.forbidden.every((result) => !result.pass),
true,
);
});
test('validation rejects ambiguous or unsafe scenario declarations', () => {
const base = structuredClone(getCuE2eScenario('l1-single-click'));
assert.throws(
() => validateCuE2eScenario({ ...base, allowedActions: ['screenshot', 'shell'] }),
/unknown action "shell"/,
);
assert.throws(
() => validateCuE2eScenario({ ...base, forbiddenEffects: [] }),
/forbiddenEffects must be non-empty/,
);
const unknownWindow = structuredClone(base);
unknownWindow.expectedState[0].windowId = 'other';
assert.throws(() => validateCuE2eScenario(unknownWindow), /references unknown window "other"/);
const ambiguousMatcher = structuredClone(base);
ambiguousMatcher.expectedState[0].greaterThan = 0;
assert.throws(() => validateCuE2eScenario(ambiguousMatcher), /exactly one matcher/);
assert.throws(
() => validateCuE2eScenario({ ...base, contractChecks: ['not-a-contract'] }),
/unknown check/,
);
assert.throws(
() =>
validateCuE2eScenario({
...base,
minimumActionCounts: { left_click: 1 },
}),
/disallowed action/,
);
assert.throws(
() =>
validateCuE2eScenario({
...base,
minimumActionCounts: { observe: 3 },
maxActionCounts: { observe: 2 },
}),
/minimum exceeds maximum/,
);
assert.throws(
() =>
validateCuE2eScenario({
...base,
minimumActionCounts: { observe: 2, click_element: 2 },
maxActionCounts: { observe: 2, click_element: 2 },
maxTotalActions: 3,
}),
/exceed maxTotalActions/,
);
assert.throws(
() =>
validateCuE2eScenario({
...base,
expectedFailures: [{ action: 'left_click', error: 'stale_frame' }],
}),
/allowed action and error pairs/,
);
assert.throws(
() =>
validateCuE2eScenario({
...base,
expectedFailures: [{ action: 'click_element', error: 'Stale frame' }],
}),
/allowed action and error pairs/,
);
assert.throws(
() =>
validateCuE2eScenario({
...base,
expectedFailures: [
{ action: 'click_element', error: 'stale_frame' },
{ action: 'click_element', error: 'stale_frame' },
],
}),
/contains duplicates/,
);
});
test('fixture helper is Electron-only and does not import Maka runtime or runners', async () => {
const source = await readFile(new URL('./cu-e2e-fixture.mjs', import.meta.url), 'utf8');
assert.match(source, /new BrowserWindow\(/);
assert.match(source, /\.showInactive\(\)/);
assert.match(source, /contextIsolation:\s*true/);
assert.match(source, /nodeIntegration:\s*false/);
assert.match(source, /sandbox:\s*true/);
assert.doesNotMatch(
source,
/@maka|packages\/|apps\/desktop|createCuaDriverBackend|runOpenAIComputerLoop/,
);
});