/* eslint-env jest */ import { copilotReducer, dismissSetupReminder, initialCopilotState, isSetupReminderDismissed, } from '../copilot-helpers'; describe('a prompt that arrives by link', () => { it('waits in the composer instead of being sent', () => { const state = copilotReducer(initialCopilotState, { type: 'draftCopilotTurn', prompt: 'Fix the SEO of the category Guides.', }); expect(state.isOpen).toBe(true); expect(state.pendingDraft).toBe('Fix the SEO of the category Guides.'); expect(state.pendingPrompt).toBeNull(); expect( copilotReducer(state, { type: 'clearPendingDraft' }).pendingDraft ).toBeNull(); }); it('a button in the app still sends its turn', () => { const state = copilotReducer(initialCopilotState, { type: 'requestCopilotTurn', prompt: 'Explain the checkup.', }); expect(state.pendingPrompt).toBe('Explain the checkup.'); expect(state.pendingDraft).toBeNull(); }); }); describe('a turn a page sends for the merchant', () => { it('stays in the thread, marked, so the reply keeps its question', () => { const state = copilotReducer(initialCopilotState, { type: 'addUserMessage', content: 'Write a meta description for these pages.', hidden: true, }); expect(state.messages).toEqual([ { role: 'user', content: 'Write a meta description for these pages.', hidden: true, }, ]); const typed = copilotReducer(state, { type: 'addUserMessage', content: 'Make them shorter.', }); expect(typed.messages[1]).toEqual({ role: 'user', content: 'Make them shorter.', }); }); }); describe('the reminder to finish setting up', () => { const nudge = { quest_id: 'q1', type: 'catalog', title: 'Fix 12 product titles', description: '', status: 'open', points: 10, }; const overview = (done: string[]) => ({ open: [nudge], resolved_count: 0, earned_points: 0, quest_pillar_score: 0, history: [], platform: 'CUSTOM', pending_steps: ['import_products', 'scan'].filter( name => !done.includes(name) ), setup_steps: ['connect', 'import_products', 'scan'].map(name => ({ name, completed: name === 'connect' || done.includes(name), })), is_new_merchant: false, nudge, }); const show = (state: typeof initialCopilotState, done: string[]) => copilotReducer(state, { type: 'setQuestOverview', overview: overview(done), }); beforeEach(() => window.localStorage.clear()); it('stays away once put away, until another step is done', () => { const shown = show(initialCopilotState, []); expect(shown.setupReminder).toBe(true); expect(shown.questNotification).toBe( "Let's finish setting up Recomaze. I can guide you." ); dismissSetupReminder(shown.setupSteps); const again = show(shown, []); expect(again.questNotification).toBeNull(); expect(again.setupReminder).toBe(false); const stepDone = show(again, ['import_products']); expect(stepDone.questNotification).toMatch(/is done! Next up/); expect(show(stepDone, ['import_products']).setupReminder).toBe(true); }); it('shows when the browser keeps nothing', () => { const getItem = jest .spyOn(Storage.prototype, 'getItem') .mockImplementation(() => { throw new Error('blocked'); }); expect(isSetupReminderDismissed(overview([]).setup_steps)).toBe(false); getItem.mockRestore(); }); }); describe('an answer that never came', () => { it('is marked as failed, with what happened, and streaming stops', () => { let state = copilotReducer(initialCopilotState, { type: 'addUserMessage', content: 'How is my SEO?', }); state = copilotReducer(state, { type: 'startAssistantMessage' }); state = copilotReducer( { ...state, isStreaming: true }, { type: 'failLastAssistant', message: 'No answer came back.' } ); expect(state.isStreaming).toBe(false); expect(state.messages.at(-1)).toEqual({ role: 'assistant', content: 'No answer came back.', failed: true, }); }); });