Reputation: 1362
I am trying to test for the existence of my modal using React Testing Library with findByRole. I keep getting an error saying: Unable to find role="dialog"
even though I can see clearly see it printed out in the console of the test.
Here is my test:
import React from "react";
import {
render,
screen,
within,
fireEvent, cleanup, waitFor
} from '@testing-library/react';
import '@testing-library/jest-dom';
import "@testing-library/react/dont-cleanup-after-each";
import Modal from 'react-modal';
import PackagerModal from './PackagerModal';
const mockedEmptyFn = jest.fn();
const mockBaseProps = {
openPackager: true,
setOpenPackager: mockedEmptyFn,
activeOrder: {
// ... // lots of irrelevant properties here
]
},
setOrders: mockedEmptyFn,
customStyles: {
content: {
backgroundColor: "var(--color-primary)",
border: "1px solid #ccc",
boxShadow: "-2rem 2rem 2rem rgba(0, 0, 0, 0.5)",
color: "rgba(var(--RGB-text), 0.8)",
filter: "blur(0)",
fontSize: "1.1em",
fontWeight: "bold",
margin: "50px auto",
opacity: 1,
outline: 0,
position: "relative",
visibility: "visible",
width: "500px"
},
overlay: {
backgroundColor: "rgba(255, 255, 255, 0.9)"
}
},
readOnly: false,
setReadOnly: mockedEmptyFn,
};
Modal.setAppElement('body');
const Component = (props) => <PackagerModal {...mockBaseProps} {...props} />
describe('Packager Modal tests with editable inputs', () => {
afterAll(() => {
cleanup();
});
test('Should show packager modal', async () => {
render(
<Component/>
);
// screen.debug();
const modalWindow = await screen.findByRole('dialog');
expect(modalWindow).toBeInTheDocument();
});
});
And here is my modal:
import ReactModal from 'react-modal';
import React, { useEffect, useRef, useState } from 'react';
import CloseButton from './CloseButton';
import PropTypes from 'prop-types';
const PackagerModal = (props) => {
const {
openPackager,
setOpenPackager,
activeOrder,
setOrders,
customStyles,
readOnly,
setReadOnly,
} = props;
const cleanUpModal = () => {
setReadOnly(false);
setUserInput(initialState);
};
return (
<ReactModal
isOpen={openPackager}
style={customStyles}
className={'order-details-modal'}
closeTimeoutMS={1000}
onAfterClose={cleanUpModal}
>
<CloseButton setOpenModal={setOpenPackager} />
<h2 className={'title'}>Packager Order Checklist</h2>
</ReactModal>
);
};
PackagerModal.propTypes = {
openPackager: PropTypes.bool.isRequired,
setOpenPackager: PropTypes.func.isRequired,
customStyles: PropTypes.object.isRequired,
activeOrder: PropTypes.object.isRequired,
setOrders: PropTypes.func.isRequired,
readOnly: PropTypes.bool.isRequired,
setReadOnly: PropTypes.func.isRequired,
};
export default PackagerModal;
And finally, here is some of the output I see in the console from the test:
● Packager Modal tests with editable inputs › Should show packager modal
Unable to find role="dialog"
Ignored nodes: comments, script, style
<body
aria-hidden="true"
class="ReactModal__Body--open"
>
<div
data-react-modal-body-trap=""
style="position: absolute; opacity: 0;"
tabindex="0"
/>
<div />
<div
data-react-modal-body-trap=""
style="position: absolute; opacity: 0;"
tabindex="0"
/>
<div
class="ReactModalPortal"
>
<div
class="ReactModal__Overlay ReactModal__Overlay--after-open"
style="position: fixed; top: 0px; left: 0px; right: 0px; bottom: 0px; background-color: rgba(255, 255, 255, 0.9);"
>
<div
aria-modal="true"
class="ReactModal__Content ReactModal__Content--after-open order-details-modal"
role="dialog"
style="border: 1px solid #ccc; box-shadow: -2rem 2rem 2rem rgba(0, 0, 0, 0.5); filter: blur(0); font-size: 1.1em; font-weight: bold; margin: 50px auto; opacity: 1; outline: 0; position: relative; visibility: visible; width: 500px;"
tabindex="-1"
>
...
Upvotes: 8
Views: 10908
Reputation: 2857
Though Avi's answer works, it technically isn't the best for testing. I was having the same issue and have realised we also have the same issue with our code so here is what is happening.
The issue is that you are saying Modal.setAppElement('body');
in your test file.
If you read the docs for react-modal, they say you need to tell the modal where your apps content is so that when the modal is open, everything within that element will have aria-hidden: true
so that screen readers don't pick up any of the other content other than whats inside the modal since that gets rendered via a portal appended to the end of your body. So you setting setAppElement
to body is making everything inside that hidden to screen readers, including your modal.
So to solve this you need to set that to something else, I personally have my own render function that has things like providers so I just added a new div in there. But in your case you could add it to your Component
const Component = (props) => <div id="root"><PackagerModal {...mockBaseProps} {...props} /></div>
Then you can chance the line setAppElement line to
Modal.setAppElement('root');
This will mean that you don't have to add the { hidden: true }
option to your queries.
You also dont have to use findBy
since there isn't any async changes happening in your test so far
test('Should show packager modal', () => {
render(<Component/>);
const modalWindow = screen.getByRole('dialog');
expect(modalWindow).toBeInTheDocument();
});
Upvotes: 3
Reputation: 1407
Looks like the body of your test is set to hidden - aria-hidden="true"
(not sure why as I'm not familiar with the package). React Testing Library is heavily accessibility oriented, so by default it ignores any elements that are not accessible.
Try querying your element with the { hidden: true }
option
const myModal = getByRole('dialog', { hidden: true });
Upvotes: 4