I have written a component for Modal Window, put it in createPortal. I wanted to write a test for that, but a got an error: console.error Error: Uncaught [Error: Target container is not a DOM element.] For some reasons test did not see my component. I do not have any idea why it work this way. If somebody knows, please write, thank you in advance! My test looks so:
test('modal', () => {
const handleClose = jest.fn();
const {getByText} = render(<Modal onClose={handleClose} isOpen title={'title'} />);
expect(getByText('title')).toBeTruthy();
});
My component looks so:
interface IModalProps {
isOpen: boolean;
title?: string;
className?: string;
onClose: () => void;
content?: React.ReactChildren | React.ReactChild
}
const Modal = ({isOpen, title, content, onClose, className}: IModalProps) => {
const keydownHandler = ({keyCode}:KeyboardEvent) => {
if (keyCode === 27) {
onClose();
}
};
React.useEffect(() => {
document.addEventListener('keydown', keydownHandler);
return () => document.removeEventListener('keydown', keydownHandler);
});
const modalInPortal = () => (
<div
className={classNames(
'modal-overlay',
isOpen && 'active')}
onClick={onClose}
>
<div
className={classNames(
className,
'modal' )}
onClick={(e) => e.stopPropagation()}
>
<div className="modal-block-content">
<span
className="close-btn"
onClick={onClose}
>
×
</span>
<h2 className="modal-title">{title}</h2>
{content && <div className="modal-body">{content}</div>}
<div className="modal-footer">
<Button
color={'light'}
style={{color:'blue'}}
size="lg"
onClick={onClose}
>
Cancel
</Button>
<Button size="lg">Save</Button>
</div>
</div>
</div>
</div>
);
return createPortal( modalInPortal(), document.getElementById('portal'));
};
CodePudding user response:
Most likely, in production, you have a HTML element in your index.html
that has an id
of portal
.
Jest doesn't have that same HTML, so when it tries to portal, it can't find it and blows up.
Usually to fix this, you need to add a setupFilesAfterEnv
to your jest config that points to a new file that builds up that HTML outside of reacts remit.
Inside this file, youd have:
const portalEl = document.createElement('div')
portalEl.setAttribute('id', 'portal')
document.body.appendChild(portalEl)
Now the test environment is like your real one for all tests (this file is globally applied).
When asserting on the contents you will also probably need to use screen
since the actual modal is loaded outside the container.