I have this component:
import React, { lazy, Suspense } from 'react';
import { ErrorBoundary } from '../ErrorBoundary';
const FALLBACK = <svg aria-label="" data-testid="icon-fallback" viewBox="0 0 21 21" />;
const ERROR = (
<svg data-testid="icon-notdef" viewBox="0 0 21 21">
<path d="M0.5,0.5v20h20v-20H0.5z M9.1,10.5l-6.6,6.6V3.9L9.1,10.5z M3.9,2.5h13.2l-6.6,6.6L3.9,2.5z M10.5,11.9l6.6,6.6H3.9 L10.5,11.9z M11.9,10.5l6.6-6.6v13.2L11.9,10.5z" />
</svg>
);
export const Icon = ({ ariaLabel, ariaHidden, name, size }) => {
const LazyIcon = lazy(() => import(`../../assets/icons/${size}/${name}.svg`));
return (
<i aria-hidden={ ariaHidden }>
<ErrorBoundary fallback={ ERROR }>
<Suspense fallback={ FALLBACK }>
<LazyIcon aria-label={ ariaLabel } data-testid="icon-module" />
</Suspense>
</ErrorBoundary>
</i>
);
};
I’m trying to test the condition where an SVG is passed in that doesn’t exist, in turn rendering the <ErrorBoundary />
fallback. The ErrorBoundary works in the browser, but not in my test.
This is the failing test:
test('shows notdef icon', async () => {
const { getByTestId } = render(<Icon name='doesnt-exist' />);
const iconModule = await waitFor(() => getByTestId('icon-notdef'));
expect(iconModule).toBeInTheDocument();
});
I get this error message:
TestingLibraryElementError: Unable to find an element by: [data-testid="icon-notdef"]”.
How do I access ErrorBoundary fallback UI in my test?
Edit
This is the code for the <ErrorBoundary />
component:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = {
error: '',
errorInfo: '',
hasError: false,
};
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
console.error({ error, errorInfo });
this.setState({ error, errorInfo });
}
render() {
const { children, fallback } = this.props;
const { error, errorInfo, hasError } = this.state;
// If there is an error AND a fallback UI is passed in…
if (hasError && fallback) {
return fallback;
}
// Otherwise if there is an error with no fallback UI…
if (hasError) {
return (
<details className="error-details">
<summary>There was an error.</summary>
<p style={ { margin: '12px 0 0' } }>{error && error.message}</p>
<pre>
<code>
{errorInfo && errorInfo.componentStack.toString()}
</code>
</pre>
</details>
);
}
// Finally, render the children.
return children;
}
}
ErrorBoundary.propTypes = {
children: PropTypes.oneOfType([PropTypes.object, PropTypes.array]).isRequired,
fallback: PropTypes.node,
};
… and this is the full error with DOM that I get for the test:
shows notdef icon
TestingLibraryElementError: Unable to find an element by: [data-testid="icon-notdef"]
<body>
<div>
<i
aria-hidden="false"
class="Icon Icon--sm"
>
<span
aria-label=""
data-testid="icon-module"
/>
</i>
</div>
</body>
<html>
<head />
<body>
<div>
<i
aria-hidden="false"
class="Icon Icon--sm"
>
<span
aria-label=""
data-testid="icon-module"
/>
</i>
</div>
</body>
</html>Error: Unable to find an element by: [data-testid="icon-notdef"]
Lastly, my SVG mock:
import React from 'react';
const SvgrMock = React.forwardRef(
function mySVG(props, ref) {
return <span { ...props } ref={ ref } />;
},
);
export const ReactComponent = SvgrMock;
export default SvgrMock;
ErrorBoundary
component to the question? – Dosiadebug()
from RTL to check. – Dosiadata-testid="icon-module"
gets rendered that means it's not erroring at all? Could it be the SVG mock interfering? – Dosiareact-test-renderer
directly though rather thanreact-testing-library
. – Escalate