feat(combat): rejoin the running combat instead of dead-ending
Attacking while a combat is already active returned COMBAT_ALREADY_ACTIVE and left the hunt page showing an error the player could not act on, with no way back into the fight they were already in. Add GET /api/combats/active so the client can resolve that combat, and have the hunt page navigate into it when an attack is rejected for this reason. CombatStore now also exposes the error code so callers can tell this case apart from a genuinely failed attack.
This commit is contained in:
@@ -37,6 +37,7 @@ describe('CombatStore', () => {
|
||||
let api: {
|
||||
startCombat: ReturnType<typeof vi.fn>;
|
||||
getCombat: ReturnType<typeof vi.fn>;
|
||||
getActiveCombat: ReturnType<typeof vi.fn>;
|
||||
performCombatAction: ReturnType<typeof vi.fn>;
|
||||
};
|
||||
let store: CombatStore;
|
||||
@@ -45,6 +46,7 @@ describe('CombatStore', () => {
|
||||
api = {
|
||||
startCombat: vi.fn(() => of(startedCombat)),
|
||||
getCombat: vi.fn(() => of(startedCombat)),
|
||||
getActiveCombat: vi.fn(() => of(startedCombat)),
|
||||
performCombatAction: vi.fn(() => of(afterAttack)),
|
||||
};
|
||||
|
||||
@@ -77,6 +79,37 @@ describe('CombatStore', () => {
|
||||
|
||||
expect(store.combat()).toBeNull();
|
||||
expect(store.error()).toBe('Du befindest dich bereits in einem Kampf.');
|
||||
expect(store.errorCode()).toBe('COMBAT_ALREADY_ACTIVE');
|
||||
});
|
||||
|
||||
it('loads the running combat and clears the error that sent us looking for it', async () => {
|
||||
api.startCombat.mockReturnValue(
|
||||
throwError(
|
||||
() =>
|
||||
new HttpErrorResponse({
|
||||
status: 409,
|
||||
error: { statusCode: 409, code: 'COMBAT_ALREADY_ACTIVE', message: 'Active.' },
|
||||
}),
|
||||
),
|
||||
);
|
||||
await store.startCombat('encounter-1');
|
||||
|
||||
const active = await store.loadActiveCombat();
|
||||
|
||||
expect(api.getActiveCombat).toHaveBeenCalledOnce();
|
||||
expect(active).toEqual(startedCombat);
|
||||
expect(store.combat()).toEqual(startedCombat);
|
||||
expect(store.error()).toBeNull();
|
||||
expect(store.errorCode()).toBeNull();
|
||||
});
|
||||
|
||||
it('resolves null and keeps the combat empty when no fight is running', async () => {
|
||||
api.getActiveCombat.mockReturnValue(of(null));
|
||||
|
||||
const active = await store.loadActiveCombat();
|
||||
|
||||
expect(active).toBeNull();
|
||||
expect(store.combat()).toBeNull();
|
||||
});
|
||||
|
||||
it('loads a combat by id', async () => {
|
||||
|
||||
Reference in New Issue
Block a user