'use strict'; const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const test = require('node:test'); const { DIFF_STATES, buildTrophyMarkup, canExecute, normalizeOverview } = require('../../src/renderer/trophies'); const root = path.resolve(__dirname, '../..'); const frozenPlan = { id: 'plan-0906', status: 'ready', confirmationPhrase: 'RECONSTRUCT LOCAL TROPHIES 2', backup: { status: 'verified', verified: true }, adapter: { id: 'simulated-local-adapter', version: '1.0.0', available: true }, timestampPolicy: 'preserve_exact', items: [ { title: 'Example', identity: 'NPWR12345_00/default/2', eligible: true, reasons: [] }, { title: 'Blocked', identity: 'NPWR12345_00/default/3', eligible: false, reasons: ['Local scan coverage is partial.'] }, ], }; const overview = { source: { provider: 'json-import', fetchedAt: '2026-07-22T00:00:00.000Z', accountIdentity: 'je***@example' }, local: { profileIdentity: 'local-***-7', coverage: 'complete', differs: true }, diffs: DIFF_STATES.map((state, index) => ({ state, title: `Title ${index}`, identity: `NPWR${index}` })), plan: frozenPlan, }; test('normal mode renders source and all read-only diff states without Expert controls', () => { const markup = buildTrophyMarkup(overview, { expert: false }); assert.match(markup, /Read-only evidence/); assert.match(markup, /Local profile differs/); for (const state of DIFF_STATES) assert.match(markup, new RegExp(`data-diff-state="${state}"`)); assert.doesNotMatch(markup, /trophy-confirmation|trophy-reconstruct-submit|Frozen plan items/); }); test('Expert mode shows exact eligible and ineligible reasons plus safety state', () => { const markup = buildTrophyMarkup(overview, { expert: true }); assert.match(markup, /data-expert-only="true"/); assert.match(markup, /NPWR12345_00\/default\/2/); assert.match(markup, /Local scan coverage is partial/); assert.match(markup, /Verified backup/); assert.match(markup, /simulated-local-adapter 1\.0\.0/); assert.match(markup, /preserve_exact/); assert.match(markup, /Local PS5 only - never written to PSN/); }); test('exact confirmation and every safety gate are required', () => { const safe = { ...overview, plan: { ...frozenPlan, items: [frozenPlan.items[0]] } }; assert.equal(canExecute(safe, { expert: false, confirmation: frozenPlan.confirmationPhrase }), false); assert.equal(canExecute(safe, { expert: true, confirmation: 'RECONSTRUCT' }), false); assert.equal(canExecute(safe, { expert: true, confirmation: frozenPlan.confirmationPhrase }), true); assert.equal(canExecute({ ...safe, plan: { ...safe.plan, backup: { status: 'required', verified: false } } }, { expert: true, confirmation: frozenPlan.confirmationPhrase }), false); assert.equal(canExecute({ ...safe, plan: { ...safe.plan, timestampPolicy: 'current_time_only' } }, { expert: true, confirmation: frozenPlan.confirmationPhrase }), false); assert.equal(canExecute(overview, { expert: true, confirmation: frozenPlan.confirmationPhrase }), false); }); test('UI has no arbitrary trophy ID or unlock-all input and uses local reconstruction language', () => { const markup = buildTrophyMarkup(overview, { expert: true }); assert.doesNotMatch(markup, /name="(?:trophyId|groupId|npCommunicationId)"/i); assert.doesNotMatch(markup, /unlock[- ]?all|sync trophies/i); assert.match(markup, /Reconstruct locally from PSN snapshot/); assert.equal((markup.match(/ { const markup = buildTrophyMarkup(overview, { historyStatus: { configured: true }, historyPreview: { onlineId: 'Nuklear_Rabbit', games: [{ key: 'NPWR1|trophy2', name: 'Native PS5 Game', platform: 'PS5', earned: 4, progress: 50, lastUpdatedDateTime: '2024-01-02T03:04:05Z' }] }, historySelected: new Set(['NPWR1|trophy2']) }); assert.match(markup, /id="trophy-history-online-id"/); assert.match(markup, /Native PS5 Game/); assert.match(markup, /Import selection \(1\)/); assert.match(markup, /Import all games/); assert.match(markup, /preserves earned dates exactly/); }); test('desktop UI offers automated Sony login while retaining manual fallback', () => { const markup = buildTrophyMarkup(overview, { historyStatus: { configured: false }, historyBrowserAuthAvailable: true }); assert.match(markup, /Sign in securely with Sony/); assert.match(markup, /temporary isolated sign-in window/); assert.match(markup, /NPSSO token/); }); test('historical snapshot UI displays PS5 earned state while concealing hidden names by default', () => { const snapshot = { id: `psn-${'a'.repeat(64)}`, account: { onlineId: 'Player_One' }, titleCount: 1, fetchedAt: '2026-08-11T12:00:00Z', titles: [{ name: 'Native PS5 Game', platform: 'PS5', trophies: [{ trophyId: 7, name: 'Secret ending', grade: 'gold', hidden: true, earned: true, earnedDateTime: '2024-02-03T04:05:06.789Z' }] }] }; const concealed = buildTrophyMarkup(overview, { historySnapshots: [snapshot], historyDetail: snapshot }); assert.match(concealed, /Native PS5 Game/); assert.match(concealed, /Hidden trophy/); assert.doesNotMatch(concealed, /Secret ending/); const revealed = buildTrophyMarkup(overview, { historySnapshots: [snapshot], historyDetail: snapshot, revealHidden: true }); assert.match(revealed, /Secret ending/); assert.match(revealed, /2024/); }); test('progression UI works without PSN history and clearly separates preview from live apply', () => { const catalogs = { available: true, games: [{ catalogKey: 'np:11111111111111111111111111111111', catalogSha256: 'a'.repeat(64), revision: 'one', game: { title: 'Local Definition', trophyCount: 2 }, trophies: [ { id: 0, groupId: 0, grade: 'bronze', hidden: false, name: 'First', description: 'Begin', earned: false }, { id: 1, groupId: 0, grade: 'platinum', hidden: false, name: 'Platinum', description: 'All', earned: false }, ] }] }; const plan = { confirmationPhrase: 'APPLY LOCAL PROGRESSION 2 Local Definition', items: [ { trophyId: 0, grade: 'bronze', name: 'First', proposedEarnedDateTime: '2021-01-01T01:00:00.000Z', timestampKind: 'synthetic-estimate', confidence: { level: 'estimated' } }, { trophyId: 1, grade: 'platinum', name: 'Platinum', proposedEarnedDateTime: '2021-01-03T01:00:00.000Z', timestampKind: 'synthetic-estimate', confidence: { level: 'estimated' } }, ] }; const markup = buildTrophyMarkup(overview, { progressionState: { catalogs, catalogKey: catalogs.games[0].catalogKey, selected: new Set([0, 1]), mode: 'synthetic_unlock', strategy: 'balanced', startDateTime: '2021-01-01T00:00', endDateTime: '2021-01-04T00:00', minimumIntervalMinutes: 30, plan } }); assert.match(markup, /Progression timeline planner/); assert.match(markup, /without a PSN import/); assert.match(markup, /Synthetic estimate — not original PSN history/); assert.match(markup, /Live PS5 apply remains unavailable/); assert.match(markup, /id="trophy-progression-create"/); assert.doesNotMatch(markup, /id="trophy-progression-apply"/); const timeline = markup.match(/
[\s\S]*?
    ([\s\S]*?)<\/ol>/); assert.ok(timeline); assert.match(timeline[1], /First<\/strong>[\s\S]*Platinum<\/strong>/); }); test('trophy UI preserves accessibility and English/Dutch i18n contracts', () => { const markup = buildTrophyMarkup(normalizeOverview(overview), { expert: true }); assert.match(markup, /aria-labelledby="trophy-evidence-title"/); assert.match(markup, /aria-live="assertive"/); assert.match(markup, /aria-describedby="trophy-confirm-help"/); assert.match(markup, /