test: scaffold WP7-05 candidate UI gate
Dada P0-A isolated Windows CI / validate-and-package (push) Failing after 2m18s
Dada P0-A isolated Windows CI / validate-and-package (push) Failing after 2m18s
This commit is contained in:
+3
-1
@@ -92,7 +92,9 @@
|
|||||||
"test:wp5-02:red": "node scripts/run-wp5-02-validation.mjs --phase red",
|
"test:wp5-02:red": "node scripts/run-wp5-02-validation.mjs --phase red",
|
||||||
"preview:wp5-02": "node scripts/run-wp5-02-manual-preview.mjs",
|
"preview:wp5-02": "node scripts/run-wp5-02-manual-preview.mjs",
|
||||||
"test:wp5-03": "node scripts/run-wp5-03-validation.mjs",
|
"test:wp5-03": "node scripts/run-wp5-03-validation.mjs",
|
||||||
"test:wp5-03:red": "node scripts/run-wp5-03-validation.mjs --phase red"
|
"test:wp5-03:red": "node scripts/run-wp5-03-validation.mjs --phase red",
|
||||||
|
"test:wp7-05": "node scripts/run-wp7-05-validation.mjs",
|
||||||
|
"test:wp7-05:unit": "node --test tests/package/wp7-05-ui-gate.test.mjs"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "1.62.0",
|
"@playwright/test": "1.62.0",
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import fs from 'node:fs';
|
||||||
|
|
||||||
|
export const REQUIRED_COVERAGE_UNITS = Object.freeze([
|
||||||
|
'support-gate', 'user-auth', 'workspace', 'current-task', 'projects',
|
||||||
|
'project-detail', 'editor', 'export', 'credits', 'settings',
|
||||||
|
'preview-user-variant', 'admin-auth', 'admin-overview', 'admin-users',
|
||||||
|
'admin-invites', 'admin-models', 'admin-assets', 'admin-preview',
|
||||||
|
'admin-generations', 'admin-services-storage', 'admin-audit', 'system-ui',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const REQUIRED_VIEWPORTS = Object.freeze([
|
||||||
|
{ width: 1920, height: 1080, deviceScaleFactor: 1, zoom: 100 },
|
||||||
|
{ width: 1920, height: 1080, deviceScaleFactor: 1, zoom: 200 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
function blocked(code, details = {}) {
|
||||||
|
return { status: 'externally_blocked', code, ...details };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadCandidateRecord(path) {
|
||||||
|
if (!path || !fs.existsSync(path)) return blocked('candidate_record_missing');
|
||||||
|
try {
|
||||||
|
const record = JSON.parse(fs.readFileSync(path, 'utf8'));
|
||||||
|
if (!Array.isArray(record.browsers) || record.browsers.length !== 2) {
|
||||||
|
return blocked('candidate_browser_record_incomplete');
|
||||||
|
}
|
||||||
|
const names = new Set(record.browsers.map((browser) => browser.name));
|
||||||
|
if (names.size !== 2 || !names.has('Chrome') || !names.has('Edge')) {
|
||||||
|
return blocked('candidate_browser_pair_invalid');
|
||||||
|
}
|
||||||
|
if (record.windows?.build == null || !record.artifact?.sha256 || !record.fixed_port) {
|
||||||
|
return blocked('candidate_identity_incomplete');
|
||||||
|
}
|
||||||
|
if (record.browsers.some((browser) => !browser.full_version || !browser.major)) {
|
||||||
|
return blocked('candidate_full_version_missing');
|
||||||
|
}
|
||||||
|
return { status: 'ready', record };
|
||||||
|
} catch {
|
||||||
|
return blocked('candidate_record_invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateCoverageEvidence(evidence) {
|
||||||
|
if (!evidence || !Array.isArray(evidence.coverage_units)) {
|
||||||
|
return blocked('coverage_evidence_missing');
|
||||||
|
}
|
||||||
|
const actual = new Set(evidence.coverage_units.map((unit) => unit.page_id));
|
||||||
|
const missing = REQUIRED_COVERAGE_UNITS.filter((unit) => !actual.has(unit));
|
||||||
|
if (missing.length) return blocked('coverage_units_incomplete', { missing });
|
||||||
|
const viewportKeys = new Set((evidence.viewports ?? []).map((viewport) => JSON.stringify(viewport)));
|
||||||
|
const missingViewports = REQUIRED_VIEWPORTS.filter((viewport) => !viewportKeys.has(JSON.stringify(viewport)));
|
||||||
|
if (missingViewports.length) return blocked('candidate_viewports_incomplete', { missingViewports });
|
||||||
|
return { status: 'ready' };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runWp705Gate({ candidatePath, evidence, dependencies = {} }) {
|
||||||
|
const candidate = loadCandidateRecord(candidatePath);
|
||||||
|
if (candidate.status !== 'ready') return candidate;
|
||||||
|
const coverage = validateCoverageEvidence(evidence);
|
||||||
|
if (coverage.status !== 'ready') return coverage;
|
||||||
|
const externalBlockers = Object.entries(dependencies)
|
||||||
|
.filter(([, status]) => status === 'externally_blocked')
|
||||||
|
.map(([task]) => task);
|
||||||
|
if (externalBlockers.length) return blocked('upstream_external_blocked', { externalBlockers });
|
||||||
|
return { status: 'ready_for_execution' };
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { runWp705Gate } from './lib/wp7-05-ui-gate.mjs';
|
||||||
|
|
||||||
|
const result = runWp705Gate({
|
||||||
|
candidatePath: process.env.WP7_01_CANDIDATE_RECORD,
|
||||||
|
evidence: null,
|
||||||
|
dependencies: {
|
||||||
|
'TASK-WP7-03': 'externally_blocked',
|
||||||
|
'TASK-WP7-04': 'externally_blocked',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(JSON.stringify({ task: 'TASK-WP7-05', ...result }));
|
||||||
|
process.exitCode = result.status === 'ready_for_execution' ? 0 : 3;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import test from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { validateCoverageEvidence, runWp705Gate, REQUIRED_COVERAGE_UNITS } from '../../scripts/lib/wp7-05-ui-gate.mjs';
|
||||||
|
|
||||||
|
test('WP7-05 requires all 22 coverage units and both exact candidate viewports', () => {
|
||||||
|
const result = validateCoverageEvidence({ coverage_units: [], viewports: [] });
|
||||||
|
assert.equal(result.status, 'externally_blocked');
|
||||||
|
assert.equal(result.code, 'coverage_units_incomplete');
|
||||||
|
assert.equal(result.missing.length, REQUIRED_COVERAGE_UNITS.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('WP7-05 preserves upstream external blockers instead of declaring Green', () => {
|
||||||
|
const result = runWp705Gate({
|
||||||
|
candidatePath: 'missing-release-candidate.json',
|
||||||
|
evidence: null,
|
||||||
|
dependencies: { 'TASK-WP7-03': 'externally_blocked' },
|
||||||
|
});
|
||||||
|
assert.equal(result.status, 'externally_blocked');
|
||||||
|
assert.equal(result.code, 'candidate_record_missing');
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user