mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 21:56:18 -08:00
* test(e2e): fix type errors in four Electron E2E specs - category-management: the poll's message and 15 s timeout were passed to toBe(), which takes one argument, so the poll ran with the default 10 s timeout and message. Pass them to expect.poll(). - settings: evaluate<void, HTMLVideoElement> set the argument type, not the element type; type the callback parameter instead. - remote-control: keep the poll callback's writes visible to the return and fail with a clear error instead of casting null. - downloads: read the dataset key through its index signature. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(perf): fix type errors in the benchmark harness None of these changes behaviour for a capture the harness produces today: - cancellation report: a null playlist id on the request record now means unknown, like undefined, instead of matching only null DB records. - main capture: type the worker transport map so its unavailable-reason literals stay narrow. - worker request performance: a parsed capture carries non-null work timestamps; only the unavailable fallback reports null. - Xtream iteration: hand the teardown closure the narrowed app and data directory. - Xtream exact schema: return early when the identity is not an exact record instead of re-checking it three times. - Xtream assembly: reject an unpainted UI explicitly; the null-to-0 comparison already rejected it. - Xtream scenario driver: drop the always-null cancellation observer from prepare; trigger() installs it. - Electron process lifecycle: type the child process by the exit subscription it uses, so a test double need not return a ChildProcess. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(perf): fix type errors in the benchmark harness specs The dynamically imported helpers were checked with assert.equal(typeof fn, 'function'), which does not narrow, so later calls used fn?.(). assert.ok(typeof fn === 'function') narrows them. The rest types fixtures by the module under test, keeps closure-assigned callbacks visible after their callbacks run, and narrows nullable fixture values. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(perf): type-check the whole electron-backend-e2e project Widen the spec config's include from the journey harness to src/**/*.ts and the root Playwright configs, with no baseline or ignore list, and update the validation map and the journey checklist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(perf): build a complete renderer fixture in the request-performance spec The fixture was cast through unknown, so the type check accepted an incomplete RendererCaptureMetrics. Fill every required field with neutral values; the summary reads only the probe arrays and heap fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
173 lines
5.5 KiB
TypeScript
173 lines
5.5 KiB
TypeScript
/* eslint-disable playwright/expect-expect -- This is a Node assertion-based performance contract test. */
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import test from 'node:test';
|
|
|
|
interface TestIteration {
|
|
readonly kind: 'diagnostic' | 'measured' | 'warmup';
|
|
readonly main: {
|
|
readonly rendererWindow: {
|
|
readonly rss: {
|
|
readonly identity: {
|
|
readonly creationTime: number;
|
|
readonly pid: number;
|
|
} | null;
|
|
readonly missingSampleCount: number;
|
|
readonly peakRssBytes: number | null;
|
|
readonly unavailableReason: string | null;
|
|
readonly validSampleCount: number;
|
|
};
|
|
};
|
|
};
|
|
readonly runId: string;
|
|
}
|
|
|
|
interface RendererRssValidity {
|
|
readonly invalidMeasuredRuns: readonly {
|
|
readonly missingSampleCount: number;
|
|
readonly reason: string;
|
|
readonly runId: string;
|
|
readonly validSampleCount: number;
|
|
}[];
|
|
readonly measuredRunCount: number;
|
|
readonly validForBenchmark: boolean;
|
|
readonly validForComparison: boolean;
|
|
readonly validMeasuredRunCount: number;
|
|
}
|
|
|
|
interface RendererRssValidityModule {
|
|
assessRendererRssValidity?: (
|
|
iterations: readonly TestIteration[]
|
|
) => RendererRssValidity;
|
|
}
|
|
|
|
const validityModulePromise = import(
|
|
new URL('./renderer-rss-validity.ts', import.meta.url).href
|
|
)
|
|
.then((module) => module as RendererRssValidityModule)
|
|
.catch(() => null);
|
|
|
|
function iteration(
|
|
runId: string,
|
|
kind: TestIteration['kind'],
|
|
input: Partial<TestIteration['main']['rendererWindow']['rss']> = {}
|
|
): TestIteration {
|
|
return {
|
|
kind,
|
|
main: {
|
|
rendererWindow: {
|
|
rss: {
|
|
identity: {
|
|
creationTime: 1_721_234_567_890,
|
|
pid: 42,
|
|
},
|
|
missingSampleCount: 0,
|
|
peakRssBytes: 4_096,
|
|
unavailableReason: null,
|
|
validSampleCount: 3,
|
|
...input,
|
|
},
|
|
},
|
|
},
|
|
runId,
|
|
};
|
|
}
|
|
|
|
test('validates only measured renderer RSS runs and preserves the exact summary shape', async () => {
|
|
const module = await validityModulePromise;
|
|
assert.ok(module, 'generic renderer RSS validity helper must exist');
|
|
const assess = module.assessRendererRssValidity;
|
|
assert.ok(typeof assess === 'function');
|
|
|
|
const result = assess([
|
|
iteration('warmup-invalid', 'warmup', { identity: null }),
|
|
iteration('run-01', 'measured'),
|
|
iteration('diagnostic-invalid', 'diagnostic', {
|
|
unavailableReason: 'renderer-process-gone',
|
|
}),
|
|
]);
|
|
|
|
assert.deepEqual(result, {
|
|
invalidMeasuredRuns: [],
|
|
measuredRunCount: 1,
|
|
validForBenchmark: true,
|
|
validForComparison: true,
|
|
validMeasuredRunCount: 1,
|
|
});
|
|
assert.ok(Object.isFrozen(result));
|
|
assert.ok(Object.isFrozen(result.invalidMeasuredRuns));
|
|
});
|
|
|
|
test('fails every incomplete measured capture without losing its raw reason and counts', async () => {
|
|
const module = await validityModulePromise;
|
|
assert.ok(module);
|
|
const assess = module.assessRendererRssValidity;
|
|
assert.ok(typeof assess === 'function');
|
|
|
|
const result = assess([
|
|
iteration('run-no-identity', 'measured', { identity: null }),
|
|
iteration('run-missing-sample', 'measured', {
|
|
missingSampleCount: 1,
|
|
peakRssBytes: null,
|
|
unavailableReason: 'renderer-process-metric-missing-during-capture',
|
|
validSampleCount: 2,
|
|
}),
|
|
iteration('run-zero-peak', 'measured', { peakRssBytes: 0 }),
|
|
]);
|
|
|
|
assert.deepEqual(result, {
|
|
invalidMeasuredRuns: [
|
|
{
|
|
missingSampleCount: 0,
|
|
reason: 'renderer-rss-capture-invalid',
|
|
runId: 'run-no-identity',
|
|
validSampleCount: 3,
|
|
},
|
|
{
|
|
missingSampleCount: 1,
|
|
reason: 'renderer-process-metric-missing-during-capture',
|
|
runId: 'run-missing-sample',
|
|
validSampleCount: 2,
|
|
},
|
|
{
|
|
missingSampleCount: 0,
|
|
reason: 'renderer-rss-capture-invalid',
|
|
runId: 'run-zero-peak',
|
|
validSampleCount: 3,
|
|
},
|
|
],
|
|
measuredRunCount: 3,
|
|
validForBenchmark: false,
|
|
validForComparison: false,
|
|
validMeasuredRunCount: 0,
|
|
});
|
|
});
|
|
|
|
test('requires at least one measured run', async () => {
|
|
const module = await validityModulePromise;
|
|
assert.ok(module);
|
|
const assess = module.assessRendererRssValidity;
|
|
assert.ok(typeof assess === 'function');
|
|
|
|
assert.deepEqual(assess([iteration('warmup-01', 'warmup')]), {
|
|
invalidMeasuredRuns: [],
|
|
measuredRunCount: 0,
|
|
validForBenchmark: false,
|
|
validForComparison: false,
|
|
validMeasuredRunCount: 0,
|
|
});
|
|
});
|
|
|
|
test('the cancellation report delegates renderer RSS validity to the generic helper', () => {
|
|
const source = readFileSync(
|
|
new URL('./m3u-refresh-cancellation-report.ts', import.meta.url),
|
|
'utf8'
|
|
);
|
|
|
|
assert.match(
|
|
source,
|
|
/import \{ assessRendererRssValidity \} from '\.\/renderer-rss-validity';/
|
|
);
|
|
assert.doesNotMatch(source, /function assessRendererRssValidity\(/);
|
|
});
|