When ReCKoning resolves (beacon ending), drift ending, or dismantle completes, clear G.activeProjects to prevent unrelated normal research from leaking through under the ended game state. Changes: - js/engine.js: Clear activeProjects on drift ending and beacon ending - js/dismantle.js: Clear activeProjects when dismantle completes (stage 10) Closes #130
96 lines
3.2 KiB
JavaScript
96 lines
3.2 KiB
JavaScript
// tests/project_chain.test.cjs
|
|
const assert = require('assert');
|
|
|
|
global.G = {
|
|
buildings: {}, completedProjects: [], activeProjects: [],
|
|
codeBoost: 1, computeBoost: 1, knowledgeBoost: 1,
|
|
userBoost: 1, impactBoost: 1, opsBoost: 1, trustBoost: 1,
|
|
totalCode: 0, totalCompute: 0, totalKnowledge: 0,
|
|
totalImpact: 0, phase: 1, ops: 0, maxOps: 1000, flags: {}
|
|
};
|
|
global.log = function() {};
|
|
global.showToast = function() {};
|
|
global.canAffordProject = function() { return true; };
|
|
global.spendProject = function() {};
|
|
global.Sound = { playProject: function() {} };
|
|
|
|
const fs = require('fs');
|
|
const vm = require('vm');
|
|
const code = fs.readFileSync(__dirname + '/../js/project_chain.js', 'utf8');
|
|
vm.runInThisContext(code);
|
|
|
|
console.log('=== Project Chain Tests ===');
|
|
|
|
// Test 1: Register
|
|
console.log('Test 1: Register project');
|
|
ProjectChain.register({ id: 't1', requires: ['d1'] });
|
|
assert(ProjectChain._deps['t1']);
|
|
console.log(' ✓ Pass');
|
|
|
|
// Test 2: canUnlock no deps
|
|
console.log('Test 2: canUnlock no deps');
|
|
assert(ProjectChain.canUnlock('nonexistent'));
|
|
console.log(' ✓ Pass');
|
|
|
|
// Test 3: canUnlock unmet
|
|
console.log('Test 3: canUnlock unmet');
|
|
G.completedProjects = [];
|
|
ProjectChain.register({ id: 't2', requires: ['d1'] });
|
|
assert(!ProjectChain.canUnlock('t2'));
|
|
console.log(' ✓ Pass');
|
|
|
|
// Test 4: canUnlock met
|
|
console.log('Test 4: canUnlock met');
|
|
G.completedProjects = ['d1'];
|
|
assert(ProjectChain.canUnlock('t2'));
|
|
console.log(' ✓ Pass');
|
|
|
|
// Test 5: canUnlock array
|
|
console.log('Test 5: canUnlock array');
|
|
G.completedProjects = ['d1', 'd2'];
|
|
ProjectChain.register({ id: 't3', requires: ['d1', 'd2'] });
|
|
assert(ProjectChain.canUnlock('t3'));
|
|
console.log(' ✓ Pass');
|
|
|
|
// Test 6: formatCost
|
|
console.log('Test 6: formatCost');
|
|
assert.strictEqual(ProjectChain.formatCost(null), 'Free');
|
|
assert.strictEqual(ProjectChain.formatCost({ ops: 100 }), '100 ops');
|
|
console.log(' ✓ Pass');
|
|
|
|
// Test 7: Chain count
|
|
console.log('Test 7: Chain projects count');
|
|
assert(CHAIN_PROJECTS.length >= 18, 'Need 18+ chain projects');
|
|
console.log(' ✓ Pass (' + CHAIN_PROJECTS.length + ' projects)');
|
|
|
|
// Test 8: Required fields
|
|
console.log('Test 8: Required fields');
|
|
for (const p of CHAIN_PROJECTS) {
|
|
assert(p.id, 'Missing id');
|
|
assert(p.name, 'Missing name');
|
|
assert(p.cost, 'Missing cost');
|
|
assert(p.trigger, 'Missing trigger');
|
|
assert(p.effect, 'Missing effect');
|
|
}
|
|
console.log(' ✓ Pass');
|
|
|
|
// Test 9: Educational tooltips
|
|
console.log('Test 9: Educational tooltips');
|
|
const eduCount = CHAIN_PROJECTS.filter(function(p) { return p.edu; }).length;
|
|
assert(eduCount >= 15, 'Most projects should have edu tooltips');
|
|
console.log(' ✓ Pass (' + eduCount + ' have edu)');
|
|
|
|
// Test 10: Categories
|
|
console.log('Test 10: Categories');
|
|
const cats = new Set(CHAIN_PROJECTS.map(function(p) { return p.category; }));
|
|
assert(cats.size >= 5, 'Need 5+ categories');
|
|
console.log(' ✓ Pass (' + cats.size + ' categories)');
|
|
|
|
// Test 11: Repeatable
|
|
console.log('Test 11: Repeatable projects');
|
|
const rep = CHAIN_PROJECTS.filter(function(p) { return p.repeatable; });
|
|
assert(rep.length >= 3, 'Need 3+ repeatable');
|
|
console.log(' ✓ Pass (' + rep.length + ' repeatable)');
|
|
|
|
console.log('\n=== All Tests Passed ===');
|