const { execFileSync } = require('child_process'); const fs = require('fs'); const path = require('path'); const repoRoot = path.resolve(__dirname, '..'); const rulesPath = path.join(repoRoot, 'database', 'rules', 'rules-database.json'); describe('mid-play rules database', () => { const db = JSON.parse(fs.readFileSync(rulesPath, 'utf8')); const rules = db.rules || []; test('contains required live-play entries with provenance', () => { const required = [ 'Dodge', 'Parry', 'Full Auto Burst', 'Semi-Auto Burst', 'Suppressing Fire', 'Overwatch', 'Pinning', 'Righteous Fury', 'Critical Damage', 'Hordes', 'Cohesion Damage', 'Maintaining Squad Mode', 'Requisition', 'Renown', 'Fear' ]; for (const title of required) { const rule = rules.find(r => r.title === title); expect(rule).toBeTruthy(); expect(rule.sourceAbbr).toBeTruthy(); expect(rule.sourceMethod).toBeTruthy(); expect(Number(rule.confidence)).toBeGreaterThanOrEqual(0.7); expect(Number(rule.midgamePriority)).toBeGreaterThanOrEqual(70); } }); test('uses the enriched schema needed by the UI', () => { expect(db.metadata && db.metadata.builder).toBe('scripts/build-midgame-rules.py'); for (const rule of rules) { expect(rule.rule_id || rule.id).toBeTruthy(); expect(rule.title).toBeTruthy(); expect(rule.summary).toBeDefined(); expect(Array.isArray(rule.tags)).toBe(true); expect(Array.isArray(rule.aliases)).toBe(true); expect(Array.isArray(rule.relatedRules)).toBe(true); } }); test('simulates GM and player lookups during play', () => { const output = execFileSync('node', ['scripts/simulate-midplay-rules.js'], { cwd: repoRoot, encoding: 'utf8' }); expect(output).toContain('All mid-play lookup scenarios passed.'); }); });