Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

quickshell/nuguland/ui-test.test.mjs

Raw
import assert from 'node:assert/strict';
import { spawn, spawnSync } from 'node:child_process';
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
import { createServer } from 'node:net';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import test from 'node:test';
import { runInNewContext } from 'node:vm';
import { assertCleanLog, assertNiriLog, assertPureService, assertSafeCapture, captureUiFailure, childEnvironment, finishUiRun, replayRequest, stopChild } from './ui-test.mjs';
import { assertSubscription, pngSize } from './test-fixtures/ui/niri-integration.mjs';
import { taskOverlayFixtures } from './test-fixtures/ui/tasks.mjs';

test('named replay defaults to all and rejects invalid selections before execution', () => {
    assert.deepEqual(replayRequest([]), { version: 1, fixture: 'all', command: 'just ui-test all' });
    for (const fixture of ['all', 'controls', 'popouts', 'privilege', 'noko', 'niri', 'tasks']) {
        assert.deepEqual(replayRequest([fixture]), { version: 1, fixture, command: `just ui-test ${fixture}` });
    }
    for (const args of [[''], ['unknown'], ['../controls'], ['all', 'noko'], ['--help']]) {
        assert.throws(() => replayRequest(args), /usage: just ui-test/);
    }
});

test('task geometry and service overlays remain explicit and isolated', () => {
    for (const size of ['1366x768', '2560x1440'])
        assert.deepEqual(replayRequest(['tasks', size]), { version: 1, fixture: 'tasks', size, command: `just ui-test tasks ${size}` });
    for (const args of [['tasks', '0x0'], ['tasks', '../host'], ['all', '1366x768'], ['tasks', '1366x768', 'extra']])
        assert.throws(() => replayRequest(args));
    assert.equal(new Set(taskOverlayFixtures.map(row => row.target)).size, taskOverlayFixtures.length);
    for (const { source, target } of taskOverlayFixtures) {
        assert.match(source, /^test-fixtures\/ui\/(?:task-)?services\/\w+\.qml$/);
        assert.match(target, /^\w+\.qml$/);
        assertPureService(readFileSync(source, 'utf8'));
    }
    const source = readFileSync('test-fixtures/ui/tasks.qml', 'utf8');
    assert.match(source, /N\.Bar\s*\{/);
    assert.match(source, /hasInput.*networkInput\.text\.length > 0/);
    assert.match(source, /knownDraft.*receivedKnownDraft/);
    assert.doesNotMatch(source, /\"(?:text|draft|passphrase)\":\s*(?:networkInput|notificationInput)\.text/);
    const runner = readFileSync('ui-test.mjs', 'utf8');
    assert.match(runner, /for \(const \[target, text\] of taskOriginals\)[\s\S]*?await prepareIntegration\(\)/);
});

test('subscription termination requires an exact native command and direct QML parent', () => {
    const command = '/usr/bin/niri\0msg\0--json\0event-stream\0';
    assert.doesNotThrow(() => assertSubscription(42, 30, 'Name:\tniri\nPPid:\t30\n', command));
    for (const pid of [0, 1, -1, null, '42', 42.5]) {
        assert.throws(() => assertSubscription(pid, 30, 'PPid:\t30\n', command));
    }
    for (const [parent, status, args] of [
        [1, 'PPid:\t1\n', command], [30, 'PPid:\t99\n', command],
        [30, 'Name:\tniri\n', command], [30, 'PPid:\t30\n', '/usr/bin/niri\0'],
        [30, 'PPid:\t30\n', '/other/niri\0msg\0--json\0event-stream\0'],
        [30, 'PPid:\t30\n', command.replace('event-stream', 'outputs')],
        [30, 'PPid:\t30\n', command + 'extra\0']
    ]) assert.throws(() => assertSubscription(42, parent, status, args));
});

test('capture dimensions reject missing, non-PNG, truncated and zero-size headers', () => {
    const bytes = Buffer.alloc(40);
    Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]).copy(bytes);
    bytes.write('IHDR', 12);
    bytes.writeUInt32BE(1280, 16);
    bytes.writeUInt32BE(720, 20);
    assert.deepEqual(pngSize(bytes), { width: 1280, height: 720 });
    for (const invalid of [Buffer.alloc(0), bytes.subarray(0, 32), Buffer.alloc(40), Buffer.from(bytes).fill(0, 16, 20), Buffer.from(bytes).fill(0, 20, 24)]) {
        assert.throws(() => pngSize(invalid));
    }
});

test('niri fixture has a pure vault sink and the real Bar/Niri/Screenshots route', () => {
    assertPureService(readFileSync('test-fixtures/ui/niri-integration-vault.qml', 'utf8'));
    const fixture = readFileSync('test-fixtures/ui/niri-integration.qml', 'utf8');
    for (const type of ['Bar', 'Niri', 'Screenshots']) assert(fixture.includes(`N.${type} {`));
    assert.match(fixture, /function fixtureOutputs\(enabled: bool\)/);
    const runner = readFileSync('ui-test.mjs', 'utf8');
    assert.match(runner, /const integration = replay.fixture === 'all' \|\| replay.fixture === 'niri'/);
    assert.match(runner, /await runNiriIntegration\(/);
});

test('failure screenshots allow masked input but never revealed input or unknown auth state', () => {
    assert.doesNotThrow(() => assertSafeCapture({ auth: { visible: true, hasInput: true, inputMasked: true } }));
    assert.doesNotThrow(() => assertSafeCapture({ auth: { visible: true, hasInput: false, inputMasked: false } }));
    assert.throws(() => assertSafeCapture({ auth: { visible: true, hasInput: true, inputMasked: false } }), /unmasked input/);
    assert.throws(() => assertSafeCapture({ auth: { visible: true } }), /unmasked input/);
    assert.throws(() => assertSafeCapture(null), /snapshot unavailable/);
});

test('failure evidence retains the original error, named phase and last safe snapshot', async () => {
    const calls = [];
    const snapshot = { auth: { visible: true, hasInput: true, inputMasked: true } };
    const error = new Error('original assertion');
    const record = await captureUiFailure(error, {
        evidence: '/evidence', fixture: 'privilege', phase: 'privilege', snapshot,
        screenshot: async name => { calls.push(name); return '/evidence/failure.png'; },
        write: (path, text) => calls.push([path, JSON.parse(text)])
    });
    assert.equal(record.error, error.stack);
    assert.equal(record.fixture, 'privilege');
    assert.equal(record.phase, 'privilege');
    assert.deepEqual(record.snapshot, snapshot);
    assert.equal(record.screenshot, '/evidence/failure.png');
    assert.deepEqual(record.captureErrors, []);
    assert.equal(calls[0], 'failure');
    assert.deepEqual(calls[1], ['/evidence/failure.json', record]);
    const failedCapture = await captureUiFailure(error, {
        evidence: '/evidence', fixture: 'all', phase: 'controls', snapshot,
        screenshot: async () => { throw new Error('capture socket gone'); }, write: () => {}
    });
    assert.equal(failedCapture.error, error.stack);
    assert.equal(failedCapture.screenshot, null);
    assert.match(failedCapture.captureErrors[0], /capture socket gone/);
    assert.deepEqual(failedCapture.snapshot, snapshot);
});

test('runtime gate is captured before teardown; all children and complete logs are still checked', async () => {
    for (const original of [null, new Error('original interaction')]) {
        const calls = [];
        const diagnostic = new Error('WARN private login1');
        await assert.rejects(finishUiRun(original, {
            children: ['weston', 'niri', 'fixture'],
            checkLogs: () => { calls.push('logs'); throw diagnostic; },
            capture: async error => { calls.push(['capture', error]); },
            stop: async child => { calls.push(['stop', child]); }
        }), error => error === (original || diagnostic));
        assert.deepEqual(calls, ['logs', ['capture', original || diagnostic], ['stop', 'fixture'], ['stop', 'niri'], ['stop', 'weston'], 'logs']);
    }
});

test('clean completion checks full logs on both sides of teardown without failure capture', async () => {
    const calls = [];
    const children = ['weston', 'niri'];
    await finishUiRun(null, {
        children,
        checkLogs: () => calls.push('logs'),
        capture: async () => assert.fail('unexpected failure capture'),
        stop: async child => calls.push(child)
    });
    assert.deepEqual(calls, ['logs', 'niri', 'weston', 'logs']);
    assert.deepEqual(children, ['weston', 'niri']);
});

test('capture and teardown errors cannot replace the original error or skip sibling cleanup', async () => {
    const original = new Error('original assertion');
    const stopped = [];
    const secondary = [];
    await assert.rejects(finishUiRun(original, {
        children: ['weston', 'niri', 'fixture'],
        checkLogs: () => {},
        capture: async () => { throw new Error('evidence unwritable'); },
        stop: async child => { stopped.push(child); if (child === 'fixture') throw new Error('teardown error'); },
        report: error => secondary.push(error.message)
    }), error => error === original);
    assert.deepEqual(stopped, ['fixture', 'niri', 'weston']);
    assert.deepEqual(secondary, ['evidence unwritable', 'teardown error']);
});

test('diagnostics produced only during teardown still fail the run', async () => {
    const diagnostic = new Error('ERROR during shutdown');
    let stopped = false;
    let captured;
    await assert.rejects(finishUiRun(null, {
        children: ['niri'],
        checkLogs: () => { if (stopped) throw diagnostic; },
        capture: async error => { captured = error; },
        stop: async () => { stopped = true; }
    }), error => error === diagnostic);
    assert.equal(captured, diagnostic);
});

test('fixture snapshots serialize predicates, never editable contents', () => {
    const controls = readFileSync('ui-test.qml', 'utf8');
    assert(!/query: root\.query|text: field\.text/.test(controls));
    assert.match(controls, /queryMatchesInput: root\.query === field\.text/);
    const refactor = readFileSync('test-fixtures/ui/refactor.qml', 'utf8');
    assert.match(refactor, /child\.echoMode === undefined/);
    assert.match(refactor, /hasInput: input \? input\.text\.length > 0 : false/);
    assert.match(refactor, /inputMasked: input \? input\.echoMode === TextInput\.Password : false/);
});

test('snapshot predicates and visual-text selection redact hostile editable values', () => {
    const sentinel = 'fixture-only\"\\nhttps://private.invalid/account';
    const controls = readFileSync('ui-test.qml', 'utf8');
    const body = controls.match(/function snapshot\(\): string \{([\s\S]*?)\n        \}/)[1];
    const field = { text: sentinel, input: {} };
    const state = JSON.parse(runInNewContext(`(function () { ${body} })()`, {
        root: { query: sentinel, rect: () => ({ x: 1, y: 2, width: 3, height: 4 }) },
        field, window: {}, mute: {}, slider: { Accessible: {} }, surface: {},
        actionCard: {}, nestedAction: {}, iconAction: { Accessible: {} }, disabledAction: {},
        longAction: {}, iconField: { input: { text: sentinel } }
    }));
    assert.equal(state.queryMatchesInput, true);
    assert.equal(state.queryIsHeadphones, false);
    assert(!JSON.stringify(state).includes('fixture-only'));
    const refactor = readFileSync('test-fixtures/ui/refactor.qml', 'utf8');
    const visibleText = refactor.match(/function visibleText\(item: var, window: var\): var \{([\s\S]*?)\n    \}/)[1];
    for (const echoMode of [0, 1, 2, 3]) {
        const rows = runInNewContext(`(function (item, window) { ${visibleText} })(null, null)`, {
            tree: () => [{ visible: true, font: {}, text: sentinel, echoMode }, { visible: true, font: {}, text: 'safe label' }],
            rect: () => ({ x: 1, y: 2, width: 3, height: 4 })
        });
        assert.equal(rows.length, 1);
        assert.equal(rows[0].text, 'safe label');
        assert(!JSON.stringify(rows).includes('fixture-only'));
    }
});

test('input targets must be real sockets inside the owned runtime', async () => {
    const runtime = mkdtempSync(join(tmpdir(), 'ui-boundary-'));
    const outside = mkdtempSync(join(tmpdir(), 'ui-parent-'));
    const servers = [];
    async function socket(path) {
        const server = createServer();
        await new Promise((resolve, reject) => {
            server.once('error', reject);
            server.listen(path, resolve);
        });
        servers.push(server);
        return path;
    }
    try {
        const display = await socket(join(runtime, 'wayland-1'));
        const ipc = await socket(join(runtime, 'niri.wayland-1.42.sock'));
        const parent = await socket(join(outside, 'wayland-0'));
        const weston = await socket(join(runtime, 'weston-headless'));
        const env = childEnvironment(runtime, display, ipc);
        assert.equal(env.WAYLAND_DISPLAY, display);
        assert.equal(env.NIRI_SOCKET, ipc);
        assert.equal(env.XDG_RUNTIME_DIR, runtime);
        assert.throws(() => childEnvironment(runtime, parent, ipc), /refusing non-child socket/);
        assert.throws(() => childEnvironment(runtime, weston, ipc), /regular expression/);
        const file = join(runtime, 'wayland-2');
        writeFileSync(file, 'not a socket');
        assert.throws(() => childEnvironment(runtime, file, ipc), /must be a socket/);
        assert.throws(() => childEnvironment(runtime, ipc, display), /regular expression/);
    } finally {
        for (const server of servers) await new Promise(resolve => server.close(resolve));
        rmSync(runtime, { recursive: true });
        rmSync(outside, { recursive: true });
    }
});

test('runtime diagnostics fail rather than being filtered or downgraded', () => {
    assert.doesNotThrow(() => assertCleanLog('INFO: Configuration Loaded\n'));
    for (const diagnostic of ['WARN: unresolved binding', 'WARNING: unresolved binding', 'warning: deprecated API', 'Could not bind', 'failed to load', 'ERROR: creation failed', 'ReferenceError: missing', 'TypeError: wrong value', 'binding loop detected', 'Error parsing file']) {
        assert.throws(() => assertCleanLog(diagnostic));
    }
});

const niriRecord = (level, source, message) => `2026-09-06T14:51:45.642004Z ${level} ${source}: ${message}\n`;
const softwareFallback = niriRecord('DEBUG', 'niri::backend::winit', 'failed building default dmabuf feedback, falling back to v3: error getting EGL device render node\n\nCaused by:\n    None of the following EGL extensions is supported by the underlying EGL implementation, at least one is required: ["EGL_EXT_device_drm"]');
const failedDestination = niriRecord('DEBUG', 'niri::niri', 'saving screenshot to "/evidence/missing-directory/native-failure.png"');
const nativeWriteWarning = niriRecord('WARN', 'niri::niri', 'error saving screenshot image: Os { code: 2, kind: NotFound, message: "No such file or directory" }');

test('only the exact Niri software fallback at DEBUG is a sandbox diagnostic exception', () => {
    assert.deepEqual(assertNiriLog(''), { softwareFallbacks: 0, expectedWriteFailures: 0 });
    assert.deepEqual(assertNiriLog(softwareFallback), { softwareFallbacks: 1, expectedWriteFailures: 0 });
    assert.deepEqual(assertNiriLog(softwareFallback.replace('DEBUG', '\x1b[34mDEBUG\x1b[0m')), { softwareFallbacks: 1, expectedWriteFailures: 0 });
    for (const invalid of [
        softwareFallback.replace('DEBUG', 'WARN'), softwareFallback.replace('DEBUG', 'ERROR'),
        softwareFallback.replace('niri::backend::winit', 'niri::renderer'),
        softwareFallback.replace('EGL_EXT_device_drm', 'EGL_other_extension'),
        softwareFallback.replace('falling back to v3', 'aborting'),
        softwareFallback + softwareFallback, softwareFallback + 'WARN: unrelated\n',
        niriRecord('DEBUG', 'niri::backend::winit', 'failed to initialize renderer'),
        niriRecord('WARN', 'niri::dbus::freedesktop_login1', 'service absent'),
        niriRecord('WARN', 'niri::dbus::freedesktop_locale1', 'service absent')
    ]) assert.throws(() => assertNiriLog(invalid));
    // Production/default log checking has no exceptions.
    assert.throws(() => assertCleanLog(softwareFallback));
    assert.throws(() => assertCleanLog(nativeWriteWarning));
});

test('native failed-write warning is required exactly once inside its deliberate action interval', () => {
    const before = softwareFallback + niriRecord('INFO', 'niri', 'ready');
    const interval = failedDestination + nativeWriteWarning;
    const after = niriRecord('INFO', 'niri', 'stopped');
    const expected = { start: before.length, end: before.length + interval.length };
    assert.deepEqual(assertNiriLog(before + interval + after, expected), { softwareFallbacks: 1, expectedWriteFailures: 1 });
    for (const body of [
        '', failedDestination, nativeWriteWarning, interval + nativeWriteWarning,
        interval + interval, interval.replace('WARN', 'ERROR'),
        interval.replace('code: 2', 'code: 13'), interval.replace('NotFound', 'PermissionDenied'),
        interval.replace('niri::niri: error', 'other::source: error'),
        interval.replace('missing-directory', 'different-directory'),
        failedDestination + niriRecord('INFO', 'niri', 'different action') + nativeWriteWarning,
        interval + 'TypeError: unrelated failure\n'
    ]) assert.throws(() => assertNiriLog(before + body + after, { start: before.length, end: before.length + body.length }));
    assert.throws(() => assertNiriLog(before + interval + after));
    assert.throws(() => assertNiriLog(nativeWriteWarning + before + interval, { start: nativeWriteWarning.length + before.length, end: nativeWriteWarning.length + before.length + interval.length }));
    assert.throws(() => assertNiriLog(before + interval + nativeWriteWarning, expected));
    for (const range of [{ start: -1, end: 1 }, { start: 0, end: 1e9 }, { start: 1, end: 2 }, { start: 0.5, end: 1 }, { start: 0, end: 0 }])
        assert.throws(() => assertNiriLog(interval, range));
});

test('native diagnostic exceptions apply only to the child compositor and fixtures precede its launch', () => {
    const runner = readFileSync('ui-test.mjs', 'utf8');
    assert.match(runner, /log === join\(evidence, 'niri.log'\)\) diagnostics = assertNiriLog\(text, expectedWriteFailure\)/);
    assert.match(runner, /else assertCleanLog\(text\)/);
    assert(runner.indexOf("await waitFor('private login/locale fixtures'") < runner.indexOf("const compositor = start('niri'"));
    assert.match(runner, /Niri consumed private login\/locale properties/);
    const fixture = readFileSync('test-fixtures/ui/session-bus.c', 'utf8');
    assert.match(fixture, /sd_bus_set_address\(bus, address\)/);
    assert.match(fixture, /strcmp\(address, getenv\("DBUS_SYSTEM_BUS_ADDRESS"\)\)/);
    assert(!/SD_BUS_METHOD|SD_BUS_WRITABLE_PROPERTY|sd_bus_open_system/.test(fixture), 'fixture exports no mutation or implicit system bus access');
});

test('overlay service doubles are pure QtQuick Item state/functions without privileged APIs', () => {
    for (const name of ['CalDav', 'Resources', 'Privilege', 'Noko', 'Niri', 'Audio', 'Network', 'Vault']) {
        assertPureService(readFileSync(`test-fixtures/ui/services/${name}.qml`, 'utf8'));
    }
    for (const body of ['Process {}', 'FileView {}', 'PolkitAgent {}', 'PamContext {}', 'WorkerScript {}', 'function bad() { Qt.openUrlExternally("test"); }', 'function bad() { new XMLHttpRequest(); }', 'function bad() { fetch("test"); }', 'function bad() { eval("test"); }', 'function bad() { Quickshell.execDetached([]); }']) {
        assert.throws(() => assertPureService(`import QtQuick\nItem { ${body} }`));
    }
    assert.throws(() => assertPureService('import QtQuick\nimport Quickshell.Io\nItem {}'));
    assert.throws(() => assertPureService('import "../../"\nItem {}'));
});

test('fixture replacement reaps only its own process, including an uncooperative child', { timeout: 8000 }, async () => {
    const sibling = spawn(process.execPath, ['-e', 'setInterval(() => {}, 1000)']);
    try {
        for (const ignoreTerm of [false, true]) {
            const child = spawn(process.execPath, ['-e', `${ignoreTerm ? 'process.on("SIGTERM", () => {});' : ''} console.log("ready"); setInterval(() => {}, 1000);`]);
            try {
                await new Promise(resolve => child.stdout.once('data', resolve));
                await stopChild(child);
                assert.equal(child.signalCode, ignoreTerm ? 'SIGKILL' : 'SIGTERM');
                assert.equal(sibling.exitCode, null);
                assert.equal(sibling.signalCode, null);
                await stopChild(child);
            } finally {
                await stopChild(child);
            }
        }
    } finally {
        await stopChild(sibling);
    }
});

test('an unsuccessful spawn has nothing to reap', async () => {
    const child = spawn('/nonexistent-nuguland-fixture-command');
    await new Promise(resolve => child.once('error', resolve));
    await stopChild(child);
});

test('invalid invocation and unsandboxed internal invocation fail before launching a compositor', () => {
    for (const args of [['unexpected'], ['--inside'], ['controls', 'noko'], ['--inside', 'invalid']]) {
        const result = spawnSync(process.execPath, ['ui-test.mjs', ...args], { encoding: 'utf8', env: { PATH: process.env.PATH }, timeout: 5000 });
        assert.equal(result.status, 1);
        assert.match(result.stderr, args.length === 1 && args[0] === '--inside' ? /internal mode requires sandbox/ : /usage: just ui-test/);
        assert(!result.stdout.includes('evidence:'));
    }
});

test('named selections reach the sandbox and its original failure evidence is never overwritten', () => {
    const dir = mkdtempSync(join(tmpdir(), 'ui-replay-'));
    try {
        writeFileSync(join(dir, 'bwrap'), `#!${process.execPath}
const fs = require('node:fs');
const args = process.argv.slice(2);
const evidence = args[args.indexOf('/evidence') - 1];
fs.writeFileSync(evidence + '/failure.json', JSON.stringify({ error: 'original inner assertion', fixture: args.at(-1) }));
process.exit(7);
`, { mode: 0o755 });
        for (const fixture of ['all', 'controls', 'popouts', 'privilege', 'noko', 'niri', 'tasks']) {
            const result = spawnSync(process.execPath, ['ui-test.mjs', fixture], { env: { PATH: dir }, encoding: 'utf8', timeout: 5000 });
            const evidence = result.stdout.match(/^evidence: (.+)$/m)?.[1];
            assert(evidence, result.stderr);
            try {
                assert.equal(result.status, 1);
                assert.deepEqual(JSON.parse(readFileSync(join(evidence, 'failure.json'), 'utf8')), { error: 'original inner assertion', fixture });
                assert.deepEqual(JSON.parse(readFileSync(join(evidence, 'replay.json'), 'utf8')), { ...replayRequest([fixture]), phase: 'startup' });
                const { command } = JSON.parse(readFileSync(join(evidence, 'command.json'), 'utf8'));
                assert.deepEqual(command.slice(-2), ['--inside', fixture]);
                assert(!existsSync(command[command.indexOf('/run/user/1000') - 1]));
            } finally {
                rmSync(evidence, { recursive: true });
            }
        }
    } finally {
        rmSync(dir, { recursive: true });
    }
});

test('sandbox failure, spawn error, and interruption remove the owned runtime and fail', { timeout: 10_000 }, async () => {
    const dir = mkdtempSync(join(tmpdir(), 'ui-lifecycle-'));
    try {
        for (const mode of ['failure', 'interrupt', 'stubborn', 'missing']) {
            const executable = join(dir, 'bwrap');
            if (mode === 'missing') rmSync(executable);
            else writeFileSync(executable, `#!${process.execPath}\n${mode === 'failure' ? 'process.exit(7)' : `process.on("SIGTERM", () => { ${mode === 'stubborn' ? '' : 'process.exit(0)'} }); console.log("sandbox-ready"); setInterval(() => {}, 1000)`}\n`, { mode: 0o755 });
            const child = spawn(process.execPath, ['ui-test.mjs'], {
                env: { PATH: dir },
                stdio: ['ignore', 'pipe', 'pipe']
            });
            let stdout = '';
            let stderr = '';
            child.stdout.on('data', data => {
                stdout += data;
                if (['interrupt', 'stubborn'].includes(mode) && stdout.includes('sandbox-ready')) child.kill('SIGINT');
            });
            child.stderr.on('data', data => { stderr += data; });
            const code = await new Promise((resolve, reject) => {
                child.once('error', reject);
                child.once('close', resolve);
            });
            const evidence = stdout.match(/^evidence: (.+)$/m)?.[1];
            assert(evidence, `${mode}: no evidence directory`);
            try {
                assert.equal(code, 1, `${mode}: ${stderr}`);
                const failure = JSON.parse(readFileSync(join(evidence, 'failure.json'), 'utf8'));
                assert.equal(failure.fixture, 'all');
                assert.equal(failure.phase, 'startup');
                assert.equal(failure.snapshot, null);
                assert.equal(failure.screenshot, null);
                assert.match(failure.captureErrors[0], /sandbox unavailable/);
                assert.match(failure.error, mode === 'missing' ? /ENOENT/ : ['interrupt', 'stubborn'].includes(mode) ? /interrupted/ : /nested UI test failed/);
                const replay = JSON.parse(readFileSync(join(evidence, 'replay.json'), 'utf8'));
                assert.deepEqual(replay, { ...replayRequest([]), phase: 'startup' });
                const { command } = JSON.parse(readFileSync(join(evidence, 'command.json'), 'utf8'));
                assert.deepEqual(command.slice(-2), ['--inside', 'all']);
                const runtime = command[command.indexOf('/run/user/1000') - 1];
                assert(runtime.startsWith(join(tmpdir(), 'nuguland-ui-runtime-')));
                assert(!existsSync(runtime), `${mode}: runtime leaked`);
                assert(!command.includes('WAYLAND_DISPLAY'), `${mode}: inherited display configuration`);
                assert(!command.includes('/run/parent-display'), `${mode}: exposed host compositor`);
                if (['interrupt', 'stubborn'].includes(mode)) assert.match(stderr, /interrupted/);
            } finally {
                rmSync(evidence, { recursive: true });
            }
        }
    } finally {
        rmSync(dir, { recursive: true });
    }
});