Files
chimera-Public/test/server/ch-1305-ps5-fpkg-ux.test.js
T

113 lines
6.5 KiB
JavaScript

'use strict';
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const test = require('node:test');
const vm = require('node:vm');
const root = path.resolve(__dirname, '../..');
const read = file => fs.readFileSync(path.join(root, file), 'utf8');
test('PS5 product surface is an evidence-first fPKG backup and restore workflow', () => {
const html = read('renderer/index.html');
assert.match(html, /PS5 fPKG Backup & Restore/);
for (const phase of ['Capture', 'Analyze', 'Build fPKG', 'Verify', 'Restore', 'Launch verify']) assert.match(html, new RegExp(`>${phase}<`));
assert.match(html, /PS5 fPKG means a finalized FIH \.pkg/);
assert.match(html, /\.ffpkg remains a separate UFS mount image and is never a fallback/);
assert.doesNotMatch(html, /PS5 Native PKG Lab|Build genuine debug PKG set|Guarded experimental restore/);
});
test('backup safety readiness and restore qualification are separate accessible live evidence', () => {
const html = read('renderer/index.html');
for (const id of ['ps5-native-preservation-evidence', 'ps5-native-fpkg-readiness-evidence', 'ps5-native-restore-evidence']) assert.match(html, new RegExp(`id="${id}"`));
assert.match(html, /class="ps5-fpkg-evidence-grid"[^>]*aria-label=/);
assert.match(html, /id="ps5-native-package-readiness"[^>]*role="status"[^>]*aria-live="polite"/);
assert.match(html, /id="ps5-native-package-launch"[^>]*disabled/);
assert.match(html, /data-i18n-aria-label="ps5NativePackages\.phase\.aria"/);
});
test('renderer presents installed pending failed and process-qualified states without conflation', () => {
const modal = read('renderer/modules/modal.js');
for (const state of ['installed_observed', 'launching', 'launch_failed', 'launch_verified', 'outcome_unknown']) assert.match(modal, new RegExp(state));
assert.match(modal, /Installed · launch verification pending/);
assert.match(modal, /Installed — launch failed\. Not qualified for restore/);
assert.match(modal, /Installed · Launch verified · Qualified for restore/);
assert.match(modal, /ps5NativePackageRestoreLaunchPlan/);
assert.match(modal, /showExactConfirmation[\s\S]*plan\.confirmation/);
assert.match(modal, /ps5NativePackageRestoreLaunchStatus/);
assert.doesNotMatch(modal, /operation\.status === 'completed'[^\n]*ps5NativePackages\.verify\.completed/);
});
test('launch qualification selects durable launch evidence instead of the newest install attempt', () => {
const modal = read('renderer/modules/modal.js');
assert.match(modal, /function selectPs5RestoreQualificationOperation\(installs, titleId\)/);
assert.match(modal, /\['installed_observed', 'launch_test_pending', 'launching', 'launch_verified', 'launch_failed'\]\.includes\(item\.status\)/);
assert.match(modal, /item\.status === 'interrupted' && item\.launchOutcome === 'outcome_unknown'/);
assert.match(modal, /Number\(b\.updatedAt \|\| b\.createdAt \|\| 0\) - Number\(a\.updatedAt \|\| a\.createdAt \|\| 0\)/);
assert.match(modal, /renderPs5RestoreQualification\(qualificationOperation\)/);
assert.doesNotMatch(modal, /renderPs5RestoreQualification\(titleInstalls\[0\]/);
const source = modal.match(/function selectPs5RestoreQualificationOperation\(installs, titleId\) \{[\s\S]*?\n\}/)?.[0];
assert.ok(source);
const select = vm.runInNewContext(`(${source})`);
const selected = select([
{ id: 'newer-install', titleId: 'FAKE00000', status: 'completed', createdAt: 300, updatedAt: 310 },
{ id: 'launch-ready', titleId: 'FAKE00000', status: 'installed_observed', createdAt: 200, updatedAt: 400 },
{ id: 'other-title', titleId: 'PPSA99099', status: 'launch_verified', createdAt: 500, updatedAt: 500 },
], 'fake00000');
assert.equal(selected.id, 'launch-ready');
});
test('the exact pinned FAKE00000 launch reference can reach the guarded native workspace', () => {
const modal = read('renderer/modules/modal.js');
assert.match(modal, /function isPs5NativeWorkspaceTitle\(gameId\)/);
assert.match(modal, /=== 'FAKE00000'/);
assert.match(modal, /btn-modal-ps5-native-packages'\)\.hidden = !isPs5NativeWorkspaceTitle\(game_id\)/);
assert.match(modal, /refreshPs5NativePackageWorkspace\(\)[\s\S]*!isPs5NativeWorkspaceTitle\(game\.game_id\)/);
assert.match(modal, /openPs5NativePackageWorkspace\(\)[\s\S]*!isPs5NativeWorkspaceTitle\(game\.game_id\)/);
assert.doesNotMatch(modal, /\^\(PPSA\|FAKE\)/, 'do not widen arbitrary PS5 title validation');
});
test('Electron and web bridges expose only semantic launch qualification calls', () => {
const preload = read('preload.js');
const web = read('renderer/pork-web-shim.js');
const main = read('main.js');
for (const source of [preload, web]) {
assert.match(source, /ps5NativePackageRestoreLaunchPlan/);
assert.match(source, /ps5NativePackageRestoreLaunchStatus/);
assert.match(source, /ps5-native-packages:restore-launch/);
}
for (const command of ['restore-launch-plan', 'restore-launch', 'restore-launch-status']) assert.match(main, new RegExp(`ps5-native-packages:${command}`));
assert.doesNotMatch(modalUnsafeSurface(web), /callerHost|remotePath|shellCommand/);
});
function modalUnsafeSurface(source) {
const start = source.indexOf('ps5NativePackageRestoreLaunchPlan');
return start < 0 ? '' : source.slice(start, start + 700);
}
test('new visible fPKG copy has English and Dutch catalog parity', () => {
const en = JSON.parse(read('build/lang/en.json')).strings;
const nl = JSON.parse(read('build/lang/nl.json')).strings;
const keys = [
'ps5NativePackages.title', 'ps5NativePackages.phase.capture', 'ps5NativePackages.phase.analyze',
'ps5NativePackages.phase.launch', 'ps5NativePackages.evidence.backup', 'ps5NativePackages.evidence.readiness',
'ps5NativePackages.evidence.restore', 'ps5NativePackages.evidence.backupSafe',
'ps5NativePackages.evidence.buildBlocked', 'ps5NativePackages.launch.action',
'ps5NativePackages.launch.pending', 'ps5NativePackages.launch.failed',
'ps5NativePackages.launch.qualified', 'ps5NativePackages.launch.boundary',
];
for (const key of keys) {
assert.equal(typeof en[key], 'string', `missing English ${key}`);
assert.equal(typeof nl[key], 'string', `missing Dutch ${key}`);
assert.notEqual(en[key], key);
assert.notEqual(nl[key], key);
}
});
test('clean upstream UI no longer exposes legacy V16 builder tuning', () => {
const settings = read('renderer/modules/settings.js');
assert.doesNotMatch(settings, /ps5-native-package-compression-workers|ps5-native-package-fast-store-threshold/);
});