randomayzer/tests/fsm.test.ts

47 lines
2.4 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { GiveawayFSM, InvalidStateTransitionError } from '../src/core/fsm/giveaway-fsm';
describe('Giveaway Lifecycle State Machine (FSM)', () => {
it('should allow valid happy path state transitions', () => {
expect(GiveawayFSM.canTransition('DRAFT', 'FETCHING')).toBe(true);
expect(GiveawayFSM.canTransition('FETCHING', 'READY')).toBe(true);
expect(GiveawayFSM.canTransition('READY', 'SNAPSHOT_LOCKED')).toBe(true);
expect(GiveawayFSM.canTransition('SNAPSHOT_LOCKED', 'DRAWN')).toBe(true);
expect(GiveawayFSM.canTransition('DRAWN', 'PUBLISHED')).toBe(true);
});
it('should allow unlocking snapshot back to READY or re-fetching', () => {
expect(GiveawayFSM.canTransition('SNAPSHOT_LOCKED', 'READY')).toBe(true);
expect(GiveawayFSM.canTransition('READY', 'FETCHING')).toBe(true);
});
it('should forbid illegal transitions', () => {
expect(GiveawayFSM.canTransition('DRAFT', 'DRAWN')).toBe(false);
expect(GiveawayFSM.canTransition('READY', 'DRAWN')).toBe(false);
expect(GiveawayFSM.canTransition('DRAWN', 'DRAFT')).toBe(false);
expect(GiveawayFSM.canTransition('DRAWN', 'READY')).toBe(false);
expect(GiveawayFSM.canTransition('PUBLISHED', 'DRAFT')).toBe(false);
});
it('should throw InvalidStateTransitionError on illegal validateTransition', () => {
expect(() => {
GiveawayFSM.validateTransition('DRAFT', 'DRAWN');
}).toThrow(InvalidStateTransitionError);
});
it('should strictly forbid drawing when status is not SNAPSHOT_LOCKED', () => {
expect(() => GiveawayFSM.assertCanDraw('DRAFT')).toThrow(/must be "SNAPSHOT_LOCKED"/);
expect(() => GiveawayFSM.assertCanDraw('FETCHING')).toThrow(/must be "SNAPSHOT_LOCKED"/);
expect(() => GiveawayFSM.assertCanDraw('READY')).toThrow(/must be "SNAPSHOT_LOCKED"/);
});
it('should strictly forbid second draw when status is DRAWN', () => {
expect(() => GiveawayFSM.assertCanDraw('DRAWN')).toThrow(/Duplicate draw is strictly forbidden/);
});
it('should forbid modifying participants when snapshot is locked or drawn', () => {
expect(() => GiveawayFSM.assertCanModifyParticipants('SNAPSHOT_LOCKED')).toThrow(/while snapshot is locked/);
expect(() => GiveawayFSM.assertCanModifyParticipants('DRAWN')).toThrow(/final status "DRAWN"/);
expect(() => GiveawayFSM.assertCanModifyParticipants('PUBLISHED')).toThrow(/final status "PUBLISHED"/);
});
});