/** * OOC State Transition Unit Tests * DataOoc 상태 전이 로직 단위 테스트 */ import { isValidOocState, isValidOocTransition } from '../../../../test/helpers/workflow-helpers' import { DataOocStatus } from '../../../../test/entities/schemas' describe('OOC State Transition Logic', () => { describe('isValidOocState', () => { it('ISSUED 상태는 유효해야 한다', () => { const dataOoc = { state: DataOocStatus.ISSUED } as any expect(isValidOocState(dataOoc)).toBe(true) }) it('REVIEWED 상태는 유효해야 한다', () => { const dataOoc = { state: DataOocStatus.REVIEWED } as any expect(isValidOocState(dataOoc)).toBe(true) }) it('CORRECTED 상태는 유효해야 한다', () => { const dataOoc = { state: DataOocStatus.CORRECTED } as any expect(isValidOocState(dataOoc)).toBe(true) }) it('REJECTED 상태는 유효해야 한다', () => { const dataOoc = { state: DataOocStatus.REJECTED } as any expect(isValidOocState(dataOoc)).toBe(true) }) it('유효하지 않은 상태는 false를 반환해야 한다', () => { const dataOoc = { state: 'INVALID_STATE' } as any expect(isValidOocState(dataOoc)).toBe(false) }) }) describe('isValidOocTransition', () => { describe('유효한 상태 전이', () => { it('ISSUED -> REVIEWED 전이는 유효해야 한다', () => { expect(isValidOocTransition(DataOocStatus.ISSUED, DataOocStatus.REVIEWED)).toBe(true) }) it('REVIEWED -> CORRECTED 전이는 유효해야 한다', () => { expect(isValidOocTransition(DataOocStatus.REVIEWED, DataOocStatus.CORRECTED)).toBe(true) }) }) describe('유효하지 않은 상태 전이', () => { it('ISSUED -> CORRECTED 직접 전이는 불가능해야 한다', () => { expect(isValidOocTransition(DataOocStatus.ISSUED, DataOocStatus.CORRECTED)).toBe(false) }) it('REVIEWED -> ISSUED 역방향 전이는 불가능해야 한다', () => { expect(isValidOocTransition(DataOocStatus.REVIEWED, DataOocStatus.ISSUED)).toBe(false) }) it('CORRECTED -> REVIEWED 역방향 전이는 불가능해야 한다', () => { expect(isValidOocTransition(DataOocStatus.CORRECTED, DataOocStatus.REVIEWED)).toBe(false) }) it('CORRECTED -> ISSUED 역방향 전이는 불가능해야 한다', () => { expect(isValidOocTransition(DataOocStatus.CORRECTED, DataOocStatus.ISSUED)).toBe(false) }) it('CORRECTED는 종료 상태이므로 더 이상 전이할 수 없다', () => { expect(isValidOocTransition(DataOocStatus.CORRECTED, DataOocStatus.CORRECTED)).toBe(false) expect(isValidOocTransition(DataOocStatus.CORRECTED, DataOocStatus.REVIEWED)).toBe(false) expect(isValidOocTransition(DataOocStatus.CORRECTED, DataOocStatus.ISSUED)).toBe(false) }) it('REJECTED는 종료 상태이므로 더 이상 전이할 수 없다', () => { expect(isValidOocTransition(DataOocStatus.REJECTED, DataOocStatus.ISSUED)).toBe(false) expect(isValidOocTransition(DataOocStatus.REJECTED, DataOocStatus.REVIEWED)).toBe(false) expect(isValidOocTransition(DataOocStatus.REJECTED, DataOocStatus.CORRECTED)).toBe(false) }) it('같은 상태로의 전이는 불가능해야 한다', () => { expect(isValidOocTransition(DataOocStatus.ISSUED, DataOocStatus.ISSUED)).toBe(false) expect(isValidOocTransition(DataOocStatus.REVIEWED, DataOocStatus.REVIEWED)).toBe(false) }) }) }) describe('DataOocStatus Enum', () => { it('모든 상태 값이 정의되어야 한다', () => { expect(DataOocStatus.ISSUED).toBe('ISSUED') expect(DataOocStatus.REVIEWED).toBe('REVIEWED') expect(DataOocStatus.CORRECTED).toBe('CORRECTED') expect(DataOocStatus.REJECTED).toBe('REJECTED') }) it('총 4개의 상태가 있어야 한다', () => { const statusValues = Object.values(DataOocStatus) expect(statusValues.length).toBe(4) }) }) }) describe('OOC State Rules', () => { describe('ISSUED 상태 규칙', () => { it('OOC 생성 시 초기 상태는 ISSUED여야 한다', () => { // DataOoc이 생성될 때 기본 state는 ISSUED expect(DataOocStatus.ISSUED).toBe('ISSUED') }) it('ISSUED 상태에서는 reviewedAt이 설정되지 않아야 한다', () => { const dataOoc = { state: DataOocStatus.ISSUED, reviewedAt: null, correctedAt: null } expect(dataOoc.reviewedAt).toBeNull() expect(dataOoc.correctedAt).toBeNull() }) }) describe('REVIEWED 상태 규칙', () => { it('REVIEWED로 전이 시 reviewedAt이 설정되어야 한다', () => { const now = new Date() const dataOoc = { state: DataOocStatus.REVIEWED, reviewedAt: now, correctedAt: null } expect(dataOoc.reviewedAt).toEqual(now) expect(dataOoc.correctedAt).toBeNull() }) it('REVIEWED로 전이 시 reviewer가 설정되어야 한다', () => { const reviewer = { id: 'user-1', name: 'Reviewer' } const dataOoc = { state: DataOocStatus.REVIEWED, reviewer } expect(dataOoc.reviewer).toBeDefined() expect(dataOoc.reviewer.id).toBe('user-1') }) it('REVIEWED로 전이 시 correctiveInstruction이 설정될 수 있다', () => { const dataOoc = { state: DataOocStatus.REVIEWED, correctiveInstruction: 'Temperature를 조절하세요' } expect(dataOoc.correctiveInstruction).toBe('Temperature를 조절하세요') }) }) describe('CORRECTED 상태 규칙', () => { it('CORRECTED로 전이 시 correctedAt이 설정되어야 한다', () => { const now = new Date() const dataOoc = { state: DataOocStatus.CORRECTED, reviewedAt: new Date(Date.now() - 3600000), // 1시간 전 correctedAt: now } expect(dataOoc.correctedAt).toEqual(now) }) it('CORRECTED로 전이 시 corrector가 설정되어야 한다', () => { const corrector = { id: 'user-2', name: 'Corrector' } const dataOoc = { state: DataOocStatus.CORRECTED, corrector } expect(dataOoc.corrector).toBeDefined() expect(dataOoc.corrector.id).toBe('user-2') }) it('CORRECTED로 전이 시 correctiveAction이 설정되어야 한다', () => { const dataOoc = { state: DataOocStatus.CORRECTED, correctiveAction: 'Temperature를 정상 범위로 조절함' } expect(dataOoc.correctiveAction).toBe('Temperature를 정상 범위로 조절함') }) it('CORRECTED는 종료 상태이다', () => { // 더 이상 전이 불가 expect(isValidOocTransition(DataOocStatus.CORRECTED, DataOocStatus.ISSUED)).toBe(false) expect(isValidOocTransition(DataOocStatus.CORRECTED, DataOocStatus.REVIEWED)).toBe(false) expect(isValidOocTransition(DataOocStatus.CORRECTED, DataOocStatus.CORRECTED)).toBe(false) }) }) describe('History 추적 규칙', () => { it('상태 전이 시 history에 기록이 추가되어야 한다', () => { const history = [ { user: { id: 'user-1', name: 'Creator' }, state: DataOocStatus.ISSUED, timestamp: '2024-01-01T00:00:00.000Z' }, { user: { id: 'user-2', name: 'Reviewer' }, state: DataOocStatus.REVIEWED, timestamp: '2024-01-01T01:00:00.000Z' } ] expect(history.length).toBe(2) expect(history[0].state).toBe(DataOocStatus.ISSUED) expect(history[1].state).toBe(DataOocStatus.REVIEWED) }) it('history 엔트리에는 user, state, timestamp가 있어야 한다', () => { const historyEntry = { user: { id: 'user-1', name: 'User' }, state: DataOocStatus.ISSUED, timestamp: new Date().toISOString() } expect(historyEntry.user).toBeDefined() expect(historyEntry.user.id).toBeDefined() expect(historyEntry.user.name).toBeDefined() expect(historyEntry.state).toBeDefined() expect(historyEntry.timestamp).toBeDefined() }) it('CORRECTED 전이 시 history에 comment(correctiveAction)가 포함될 수 있다', () => { const historyEntry = { user: { id: 'user-1', name: 'Corrector' }, state: DataOocStatus.CORRECTED, comment: 'Temperature를 정상 범위로 조절함', timestamp: new Date().toISOString() } expect(historyEntry.comment).toBe('Temperature를 정상 범위로 조절함') }) }) })