@reldens/skills
Version:
349 lines (323 loc) • 12.1 kB
JavaScript
/**
*
* Reldens - PhysicalSkillRunner Unit Tests
*
*/
const { describe, it, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert');
const { PhysicalSkillRunner } = require('../../../lib/types/physical-skill-runner');
const SkillsConst = require('../../../lib/constants');
const SkillsEvents = require('../../../lib/skills-events');
const { TestHelpers } = require('../../utils/test-helpers');
const { MockOwner } = require('../../fixtures/mocks/mock-owner');
const { MockTarget } = require('../../fixtures/mocks/mock-target');
describe('PhysicalSkillRunner', () => {
let mockOwner;
let mockTarget;
beforeEach(() => {
mockOwner = new MockOwner();
mockTarget = new MockTarget();
TestHelpers.clearEventListeners();
});
afterEach(() => {
TestHelpers.clearEventListeners();
});
describe('runSkillLogic', () => {
it('should return false when target out of range', async () => {
let skill = {
target: mockTarget,
validateRange: () => false,
owner: mockOwner
};
let result = await PhysicalSkillRunner.runSkillLogic(skill);
assert.strictEqual(result, false);
});
it('should execute physical skill when in range', async () => {
let executed = false;
mockOwner.executePhysicalSkill = async (target, skill) => {
executed = true;
};
let skill = {
target: mockTarget,
validateRange: () => true,
owner: mockOwner
};
await PhysicalSkillRunner.runSkillLogic(skill);
assert.strictEqual(executed, true);
});
it('should return false after execution', async () => {
mockOwner.executePhysicalSkill = async () => {};
let skill = {
target: mockTarget,
validateRange: () => true,
owner: mockOwner
};
let result = await PhysicalSkillRunner.runSkillLogic(skill);
assert.strictEqual(result, false);
});
it('should pass target and skill to executePhysicalSkill', async () => {
let receivedTarget = null;
let receivedSkill = null;
mockOwner.executePhysicalSkill = async (target, skill) => {
receivedTarget = target;
receivedSkill = skill;
};
let skill = {
target: mockTarget,
validateRange: () => true,
owner: mockOwner,
key: 'test-skill'
};
await PhysicalSkillRunner.runSkillLogic(skill);
assert.strictEqual(receivedTarget, mockTarget);
assert.strictEqual(receivedSkill.key, 'test-skill');
});
});
describe('executeOnHit', () => {
it('should fire skill event', async () => {
let eventFired = false;
let skill = {
target: mockTarget,
validateTargetOnHit: false,
fireEvent: async (eventName) => {
if(eventName === SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT){
eventFired = true;
}
}
};
await PhysicalSkillRunner.executeOnHit(
mockTarget,
skill,
SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT,
async () => true
);
assert.strictEqual(eventFired, true);
});
it('should return false when target validation fails', async () => {
let differentTarget = new MockTarget();
differentTarget.id = 'different-id';
let skill = {
target: mockTarget,
validateTargetOnHit: true,
fireEvent: async () => {}
};
let result = await PhysicalSkillRunner.executeOnHit(
differentTarget,
skill,
SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT,
async () => true
);
assert.strictEqual(result, false);
});
it('should skip validation when validateTargetOnHit is false', async () => {
let differentTarget = new MockTarget();
differentTarget.id = 'different-id';
let skill = {
target: mockTarget,
validateTargetOnHit: false,
fireEvent: async () => {}
};
let result = await PhysicalSkillRunner.executeOnHit(
differentTarget,
skill,
SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT,
async () => true
);
assert.strictEqual(result, true);
});
it('should execute callback when valid', async () => {
let callbackExecuted = false;
let skill = {
target: mockTarget,
validateTargetOnHit: false,
fireEvent: async () => {}
};
await PhysicalSkillRunner.executeOnHit(
mockTarget,
skill,
SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT,
async () => {
callbackExecuted = true;
return true;
}
);
assert.strictEqual(callbackExecuted, true);
});
it('should pass target to callback', async () => {
let receivedTarget = null;
let skill = {
target: mockTarget,
validateTargetOnHit: false,
fireEvent: async () => {}
};
await PhysicalSkillRunner.executeOnHit(
mockTarget,
skill,
SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT,
async (target) => {
receivedTarget = target;
return true;
}
);
assert.strictEqual(receivedTarget, mockTarget);
});
it('should return callback result', async () => {
let skill = {
target: mockTarget,
validateTargetOnHit: false,
fireEvent: async () => {}
};
let result = await PhysicalSkillRunner.executeOnHit(
mockTarget,
skill,
SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT,
async () => {
return 'callback-result';
}
);
assert.strictEqual(result, 'callback-result');
});
it('should return false when callback is not a function', async () => {
let skill = {
target: mockTarget,
validateTargetOnHit: false,
fireEvent: async () => {}
};
let result = await PhysicalSkillRunner.executeOnHit(
mockTarget,
skill,
SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT,
'not-a-function'
);
assert.strictEqual(result, false);
});
it('should return false when callback is undefined', async () => {
let skill = {
target: mockTarget,
validateTargetOnHit: false,
fireEvent: async () => {}
};
let result = await PhysicalSkillRunner.executeOnHit(
mockTarget,
skill,
SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT,
undefined
);
assert.strictEqual(result, false);
});
});
describe('Edge Cases', () => {
it('should handle null target in runSkillLogic', async () => {
let skill = {
target: null,
validateRange: () => true,
owner: mockOwner
};
await assert.rejects(async () => {
await PhysicalSkillRunner.runSkillLogic(skill);
});
});
it('should handle null skill in runSkillLogic', async () => {
await assert.rejects(async () => {
await PhysicalSkillRunner.runSkillLogic(null);
});
});
it('should handle missing fireEvent method', async () => {
let skill = {
target: mockTarget,
validateTargetOnHit: false
};
await assert.rejects(async () => {
await PhysicalSkillRunner.executeOnHit(
mockTarget,
skill,
SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT,
async () => true
);
});
});
it('should handle async callback that throws', async () => {
let skill = {
target: mockTarget,
validateTargetOnHit: false,
fireEvent: async () => {}
};
await assert.rejects(async () => {
await PhysicalSkillRunner.executeOnHit(
mockTarget,
skill,
SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT,
async () => {
throw new Error('callback error');
}
);
});
});
});
describe('Integration', () => {
it('should handle complete physical attack flow', async () => {
let executed = false;
let hitExecuted = false;
mockOwner.executePhysicalSkill = async (target, skill) => {
executed = true;
await skill.executeOnHit(target);
};
let skill = {
target: mockTarget,
validateRange: () => true,
validateTargetOnHit: false,
owner: mockOwner,
fireEvent: async () => {},
executeOnHit: async (target) => {
return await PhysicalSkillRunner.executeOnHit(
target,
skill,
SkillsEvents.SKILL_PHYSICAL_ATTACK_HIT,
async () => {
hitExecuted = true;
return true;
}
);
}
};
await PhysicalSkillRunner.runSkillLogic(skill);
assert.strictEqual(executed, true);
assert.strictEqual(hitExecuted, true);
});
});
describe('runSkillLogic - lastState Verification', () => {
it('should set lastState to EXECUTE_PHYSICAL_ATTACK', async () => {
mockOwner.executePhysicalSkill = async () => true;
let skill = {
owner: mockOwner,
target: mockTarget,
validateRange: () => true,
range: 0,
magnitude: 50,
objectWidth: 10,
objectHeight: 10
};
await PhysicalSkillRunner.runSkillLogic(skill);
assert.strictEqual(skill.lastState, SkillsConst.SKILL_STATES.EXECUTE_PHYSICAL_ATTACK);
});
});
describe('executeOnHit - Event Firing Timing', () => {
it('should fire event at correct timing', async () => {
let physicalSkillExecuted = false;
mockOwner.executePhysicalSkill = async (target, skill) => {
physicalSkillExecuted = true;
};
let skill = {
owner: mockOwner,
target: mockTarget,
validateRange: () => true,
range: 0,
magnitude: 50,
objectWidth: 10,
objectHeight: 10
};
await PhysicalSkillRunner.runSkillLogic(skill);
assert.strictEqual(physicalSkillExecuted, true);
});
});
});