/* eslint-env jest */ import { act } from 'react'; import { createRoot, type Root } from 'react-dom/client'; import { BARE_FIELD } from '../../bare-field'; import { HomeComposer, StarterPrompts } from '../HomeComposer'; ( globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean } ).IS_REACT_ACT_ENVIRONMENT = true; let root: Root; let host: HTMLDivElement; beforeEach(() => { host = document.createElement('div'); document.body.appendChild(host); root = createRoot(host); }); afterEach(() => { act(() => root.unmount()); host.remove(); }); const render = ( props: Partial[0]> = {} ): { onSend: jest.Mock; onStop: jest.Mock; box: HTMLTextAreaElement; } => { const onSend = jest.fn(); const onStop = jest.fn(); act(() => { root.render( undefined} placeholder="Ask" {...props} /> ); }); return { onSend, onStop, box: host.querySelector('textarea') as HTMLTextAreaElement, }; }; const type = (box: HTMLTextAreaElement, value: string): void => { const setValue = Object.getOwnPropertyDescriptor( HTMLTextAreaElement.prototype, 'value' )?.set; act(() => { setValue?.call(box, value); box.dispatchEvent(new Event('input', { bubbles: true })); }); }; const press = ( box: HTMLTextAreaElement, key: string, init: KeyboardEventInit = {} ): void => { act(() => { box.dispatchEvent( new KeyboardEvent('keydown', { key, bubbles: true, ...init }) ); }); }; it('sends the question on Enter and empties the box', () => { const { onSend, box } = render(); const send = host.querySelector( 'button[aria-label="Send"]' ) as HTMLButtonElement; expect(send.disabled).toBe(true); type(box, ' How is my visibility? '); expect(send.disabled).toBe(false); press(box, 'Enter', { shiftKey: true }); expect(onSend).not.toHaveBeenCalled(); press(box, 'Enter'); expect(onSend).toHaveBeenCalledWith('How is my visibility?'); expect(box.value).toBe(''); }); it('stops the answer on Escape while one is being written', () => { const { onStop, onSend, box } = render({ isStreaming: true }); type(box, 'Next question'); press(box, 'Enter'); expect(onSend).not.toHaveBeenCalled(); press(box, 'Escape'); expect(onStop).toHaveBeenCalledTimes(1); expect(host.querySelector('button[aria-label="Stop"]')).not.toBeNull(); }); it('keeps the thinking toggle and the notice inside its own box', () => { const { box } = render(); const form = host.querySelector('form') as HTMLFormElement; expect(form.querySelector('[role="radiogroup"]')).not.toBeNull(); expect(form.textContent).toContain('15 credits an answer'); expect(form.textContent).toContain('Recomaze can make mistakes.'); // wp-admin borders every textarea; the box inside the composer has none. BARE_FIELD.split(' ').forEach((name: string) => { expect(box.classList.contains(name)).toBe(true); }); }); it('sends a starter question when it is tapped', () => { const onPick = jest.fn(); act(() => { root.render(); }); const buttons = host.querySelectorAll('button'); expect(buttons).toHaveLength(2); act(() => buttons[1].click()); expect(onPick).toHaveBeenCalledWith('Two?'); });