recipientClipboard.test.ts2.6 KBView on GitHub /**
* Copying a recipient pill (cmd+c on a selected to/cc/bcc badge) must put the bare
* address on the SYSTEM clipboard, not just the in-app one used to move recipients
* between fields. Previously cmd+c only populated the in-app clipboard, so pasting
* the address anywhere outside the composer produced nothing.
*/
import { act, renderHook } from '@testing-library/react';
import { useRecipientClipboard } from '@/modules/drafting/hooks/use-recipient-clipboard';
const writeText = jest.fn<Promise<void>, [string]>(() => Promise.resolve());
beforeEach(() => {
writeText.mockClear();
writeText.mockResolvedValue(undefined);
Object.defineProperty(navigator, 'clipboard', {
value: { writeText },
configurable: true,
writable: true,
});
});
describe('useRecipientClipboard.copyRecipient', () => {
it('writes the address to the system clipboard', () => {
const { result } = renderHook(() => useRecipientClipboard());
act(() => result.current.copyRecipient('<email>', 'to'));
expect(writeText).toHaveBeenCalledWith('<email>');
});
it('strips the display name before writing', () => {
const { result } = renderHook(() => useRecipientClipboard());
act(() => result.current.copyRecipient('Alice Smith <<email>>', 'cc'));
expect(writeText).toHaveBeenCalledWith('<email>');
});
it('still populates the in-app clipboard for cross-field paste', () => {
const { result } = renderHook(() => useRecipientClipboard());
act(() => result.current.copyRecipient('Bob <<email>>', 'bcc'));
expect(result.current.clipboard).toEqual({ email: '<email>', sourceField: 'bcc' });
expect(result.current.pasteRecipient('to')).toEqual({
email: '<email>',
sourceField: 'bcc',
targetField: 'to',
});
});
it('keeps the in-app clipboard working when the system clipboard is denied', () => {
writeText.mockRejectedValue(new Error('NotAllowedError'));
const { result } = renderHook(() => useRecipientClipboard());
act(() => result.current.copyRecipient('<email>', 'to'));
expect(result.current.clipboard?.email).toBe('<email>');
});
it('does not throw when the clipboard API is unavailable', () => {
Object.defineProperty(navigator, 'clipboard', { value: undefined, configurable: true });
const { result } = renderHook(() => useRecipientClipboard());
expect(() => act(() => result.current.copyRecipient('<email>', 'to'))).not.toThrow();
expect(result.current.clipboard?.email).toBe('<email>');
});
});