test(06-10): cover combined effects and cross-enemy nested auras

- G-06-01-A: four effect kinds together, assert stage order and final
  atk/def/hp/special on the computed enemy
- G-06-01-B: m1 -> A1 -> m2 -> A2 -> all enemies, assert per-enemy final
  atk plus A1 range boundary via special 21 ownership
This commit is contained in:
unanmed 2026-09-15 10:06:26 +08:00
parent fcba44c756
commit ef95cc710f

View File

@ -931,6 +931,56 @@ describe('EnemyContext aura pipeline', () => {
expect(computed.getAttribute('atk')).toBe(9);
});
// 验证多怪跨施加的嵌套光环m1 产生 A1 只命中 m2m2 生成 A2 反向影响全部怪的最终属性
it('propagates a cross-enemy nested aura with observable range boundaries', () => {
const fixture = createContextFixture(5, 3);
fixture.context.bindHero(fixture.hero);
const m1 = createEnemy('m1');
m1.addSpecial(createSpecial(20) as never);
const m2 = createEnemy('m2', { atk: 4 });
const m3 = createEnemy('m3', { atk: 6 });
fixture.context.setEnemyAt({ x: 0, y: 0 }, m1);
fixture.context.setEnemyAt({ x: 1, y: 0 }, m2);
fixture.context.setEnemyAt({ x: 4, y: 0 }, m3);
const a1 = new FakeAura({
priority: 10,
range: new modules.RectRange(),
param: { x: 1, y: 0, w: 1, h: 1 },
couldApplyBase: true,
couldApplySpecial: true,
onApply: handler => handler.enemy.addAttribute('atk', 100),
onApplySpecial: () => ({
add: () => [createSpecial(21) as never],
delete: () => [],
modify: () => false
})
});
const a2 = new FakeAura({
priority: 5,
range: new modules.FullRange(),
param: undefined,
onApply: handler => handler.enemy.addAttribute('atk', 3)
});
const converter = new FakeConverter([20, 21], code =>
code === 20 ? a1 : a2
);
fixture.context.registerAuraConverter(converter);
fixture.context.buildup();
expect(converter.convertCalls).toContain(20);
expect(converter.convertCalls).toContain(21);
const v1 = fixture.context.getEnemyByLoc(0, 0)!.getComputedEnemy();
const v2 = fixture.context.getEnemyByLoc(1, 0)!.getComputedEnemy();
const v3 = fixture.context.getEnemyByLoc(4, 0)!.getComputedEnemy();
expect(v2.hasSpecial(21)).toBe(true);
expect(v1.hasSpecial(21)).toBe(false);
expect(v3.hasSpecial(21)).toBe(false);
expect(v1.getAttribute('atk')).toBe(5);
expect(v2.getAttribute('atk')).toBe(107);
expect(v3.getAttribute('atk')).toBe(9);
});
// 验证新增光环优先级高于当前阶段时告警 99 且不参与后续效果
it('warns 99 and skips a higher-priority nested aura', () => {
const fixture = createContextFixture();
@ -1104,6 +1154,78 @@ describe('EnemyContext effect stage ordering', () => {
expect(seen.finalDef).toBe(1);
});
// 验证四类效果(光环基础 + 常规查询 + 特殊查询 + final同时生效四阶段顺序与最终属性均被断言
it('applies all four effect kinds together and asserts the final attributes', () => {
const fixture = createContextFixture();
fixture.context.bindHero(fixture.hero);
const enemy = createEnemy('e1');
enemy.addSpecial(createSpecial(20) as never);
fixture.context.setEnemyAt({ x: 0, y: 0 }, enemy);
const order: string[] = [];
const aura = new FakeAura({
priority: 1,
range: new modules.FullRange(),
param: undefined,
couldApplyBase: true,
couldApplySpecial: true,
onApply: handler => {
order.push('base');
handler.enemy.addAttribute('atk', 5);
},
onApplySpecial: () => {
order.push('special');
return {
add: () => [createSpecial(21) as never],
delete: () => [],
modify: () => false
};
}
});
fixture.context.registerAuraConverter(
new FakeConverter([20], () => aura)
);
fixture.context.registerCommonQueryEffect(20, {
priority: 1,
apply: handler => {
order.push('query');
handler.enemy.addAttribute('def', 2);
}
});
fixture.context.registerSpecialQueryEffect({
priority: 1,
for: () => ({
shouldQuery: handler => handler.enemy.hasSpecial(21),
add: () => [],
delete: () => [],
modify: () => {
order.push('special-query');
return true;
}
})
});
fixture.context.registerFinalEffect({
priority: 1,
apply: handler => {
order.push('final');
handler.enemy.addAttribute('hp', 4);
}
});
fixture.context.buildup();
const computed = fixture.context
.getEnemyByLoc(0, 0)!
.getComputedEnemy();
expect(order[0]).toBe('special');
expect(order.indexOf('special')).toBeLessThan(order.indexOf('base'));
expect(order.indexOf('base')).toBeLessThan(order.indexOf('query'));
expect(order.indexOf('query')).toBeLessThan(order.indexOf('final'));
expect(computed.getAttribute('atk')).toBe(7);
expect(computed.getAttribute('def')).toBe(2);
expect(computed.getAttribute('hp')).toBe(14);
expect(computed.hasSpecial(21)).toBe(true);
});
// 验证更高优先级的光环与最终效果会更先执行
it('runs higher-priority auras and effects first', () => {
const fixture = createContextFixture();