diff --git a/src/tests/wave16_toast_reducer.test.ts b/src/tests/wave16_toast_reducer.test.ts new file mode 100644 index 0000000..55cc579 --- /dev/null +++ b/src/tests/wave16_toast_reducer.test.ts @@ -0,0 +1,57 @@ +describe('Wave 16 Zenith: Real-time Toast Notification State Reducer', () => { + interface Toast { + id: string; + type: 'success' | 'error' | 'info'; + message: string; + timestamp: number; + } + + interface ToastState { + toasts: Toast[]; + maxToasts: number; + } + + const toastReducer = (state: ToastState, action: { type: 'ADD_TOAST' | 'DISMISS_TOAST'; payload?: any }): ToastState => { + switch (action.type) { + case 'ADD_TOAST': { + const next = [action.payload, ...state.toasts].slice(0, state.maxToasts); + return { ...state, toasts: next }; + } + case 'DISMISS_TOAST': { + return { + ...state, + toasts: state.toasts.filter(t => t.id !== action.payload.id) + }; + } + default: + return state; + } + }; + + it('should add new payment toast and respect max toast limit', () => { + const initialState: ToastState = { toasts: [], maxToasts: 3 }; + let state = toastReducer(initialState, { + type: 'ADD_TOAST', + payload: { id: 't1', type: 'success', message: 'Payment settled', timestamp: 1000 } + }); + state = toastReducer(state, { + type: 'ADD_TOAST', + payload: { id: 't2', type: 'info', message: 'Processing intent', timestamp: 2000 } + }); + expect(state.toasts.length).toBe(2); + expect(state.toasts[0].id).toBe('t2'); + }); + + it('should dismiss toast by unique identifier', () => { + const initialState: ToastState = { + toasts: [ + { id: 't1', type: 'success', message: 'Tx 1', timestamp: 1000 }, + { id: 't2', type: 'error', message: 'Tx 2', timestamp: 2000 } + ], + maxToasts: 5 + }; + const nextState = toastReducer(initialState, { type: 'DISMISS_TOAST', payload: { id: 't1' } }); + expect(nextState.toasts.length).toBe(1); + expect(nextState.toasts[0].id).toBe('t2'); + }); +});