Files
chimera-Public/test/server/ch-1103-trophy-progression-integration.test.js
T

55 lines
3.4 KiB
JavaScript

'use strict';
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const test = require('node:test');
const { createImportedTrophyDefinitionService } = require('../../src/services/imported-trophy-definition-service');
const { createMemoryTrophyProgressionPlanRepository, createTrophyProgressionPlanner } = require('../../src/services/trophy-progression-planner-service');
const root = path.resolve(__dirname, '../..');
const read = file => fs.readFileSync(path.join(root, file), 'utf8');
test('desktop and web expose planning commands but no live progression apply command', () => {
const main = read('main.js'); const preload = read('preload.js'); const web = read('renderer/pork-web-shim.js');
const server = read('src/server/register-functional-modules.js');
assert.match(main, /_registerTrophyProgression\(ipcMain, \{ app, db \}\)/);
assert.match(read('src/ipc/trophy-progression.js'), /trophy:imported-catalog:import/);
for (const channel of ['status', 'catalogs', 'create', 'plans', 'plan']) {
assert.match(preload, new RegExp(`trophy:progression:${channel}`));
assert.match(web, new RegExp(`trophy:progression:${channel}`));
assert.match(server, new RegExp(`trophy:progression:${channel}`));
}
assert.doesNotMatch(preload, /trophy:progression:apply/);
assert.doesNotMatch(web, /trophy:progression:apply/);
assert.doesNotMatch(server, /name: 'trophy:progression:apply'/);
});
test('progression planning persists locally and remains separated from PSN providers', () => {
const ipc = read('src/ipc/trophy-progression.js');
assert.match(ipc, /createImportedTrophyDefinitionService/);
assert.match(ipc, /createSqliteTrophyProgressionPlanRepository/);
assert.doesNotMatch(ipc, /psn-api|node-fetch|https?:|trophyHistory/);
const service = read('src/services/trophy-progression-planner-service.js');
assert.match(service, /psnWriteCapability: false/);
assert.match(service, /liveApply: \{ available: false/);
});
test('a local definition package can produce a progression preview without PSN import', async t => {
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-progression-catalog-'));
t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
const catalogs = createImportedTrophyDefinitionService({ root: directory });
const catalogKey = 'np:22222222222222222222222222222222';
catalogs.importPackage({ schema: 'chimera-trophy-definition', schemaVersion: 1, catalogKey, revision: 'fixture',
game: { title: 'Offline Fixture', description: '', trophyCount: 2 }, trophies: [
{ id: 0, grade: 'bronze', groupId: 0, hidden: false, name: 'Start', description: 'Begin the story.' },
{ id: 1, grade: 'platinum', groupId: 0, hidden: false, name: 'Done', description: 'Earn all trophies.' },
] });
const planner = createTrophyProgressionPlanner({ repository: createMemoryTrophyProgressionPlanRepository(), catalogProvider: catalogs, now: () => Date.parse('2026-08-11T12:00:00Z') });
const plan = await planner.create({ catalogKey, mode: 'synthetic_unlock', trophyIds: [0, 1], strategy: 'balanced', minimumIntervalMinutes: 30,
startDateTime: '2021-01-01T00:00:00Z', endDateTime: '2021-01-03T00:00:00Z' });
assert.equal(plan.provenance.psnImportRequired, false);
assert.deepEqual(plan.items.map(item => item.trophyId), [0, 1]);
});