Reputation: 399
I've got a React component that returns an iframe and handles sending messages to and receiving messages from the iframe. I am totally stumped as to how I can mock the iframe and simulate a message being posted in the iframe with React Testing Library. Any ideas or examples would be very helpful.
Component:
const ContextualHelpClient: React.VFC<CHCProps> = ({ onAction, data }) => {
const [iframe, setIframe] = React.useState<HTMLIFrameElement | null>(null);
const handleMessage = React.useCallback((event: MessageEvent<ContextualHelpAction>) => {
onAction(event.data);
}, [onAction])
const contentWindow = iframe?.contentWindow;
React.useEffect(() => {
if (contentWindow) {
contentWindow.addEventListener('message', handleMessage);
return () => contentWindow.removeEventListener('message', handleMessage);
}
}, [handleMessage, contentWindow]);
React.useEffect(() => {
if (contentWindow) {
contentWindow.postMessage({ type: CONTEXTUAL_HELP_CLIENT_DATA, data }, "/");
}
}, [data, contentWindow]);
return <iframe src={IFRAME_SOURCE} width={300} height={300} ref={setIframe} title={IFRAME_TITLE} />;
};
Test:
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import ContextualHelpClient from '../ContextualHelpClient';
import { IFRAME_SOURCE, IFRAME_TITLE } from '../constants';
describe('<ContextualHelpClient />', () => {
it('should call onAction when a message is posted', () => {
const handleAction = jest.fn();
const content = render(<ContextualHelpClient onAction={handleAction} />);
const iframe = content.getByTitle(IFRAME_TITLE);
fireEvent(iframe.contentWindow, new MessageEvent('data'));
expect(handleAction).toBeCalled(); // fails
});
});
Upvotes: 2
Views: 6296
Reputation: 2105
In my case, using the message
type on fireEvent was enough to test this.
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import ContextualHelpClient from '../ContextualHelpClient';
import { IFRAME_SOURCE, IFRAME_TITLE } from '../constants';
describe('<ContextualHelpClient />', () => {
it('should call onAction when a message is posted', () => {
const handleAction = jest.fn();
const content = render(<ContextualHelpClient onAction={handleAction} />);
const iframe = content.getByTitle(IFRAME_TITLE);
fireEvent(
window,
new MessageEvent('message', {origin: window.location.origin}),
);
expect(handleAction).toBeCalled(); // fails
});
});
Upvotes: 5
Reputation: 399
Solved!
it('should call onAction when a message is posted', async () => {
const handleAction = jest.fn();
const content = render(<ContextualHelpClient onAction={handleAction} />);
const iframe = content.getByTitle(IFRAME_TITLE) as HTMLIFrameElement;
const TEST_MESSAGE = 'TEST_MESSAGE';
// https://github.com/facebook/jest/issues/6765
iframe.contentWindow?.postMessage(TEST_MESSAGE, window.location.origin);
await waitFor(() => expect(handleAction).toBeCalledWith(TEST_MESSAGE));
});
Upvotes: 1