I'm really trying to get an understanding of how to properly unit test with React TS, but it's really been tough going so far. I have two very simple components I'm using to isolate things. I'll include the components at the bottom so I don't clutter things too much.
Pretty simple, click the Button and the change from 'hello' to 'world' in the state variable data is displayed in InnerComponent. From everything I've seen, the pattern is to test for side effects in the document rather than trying to test the state changes themselves (and thank goodness for that, I had a nightmare of a time trying to access state in the wrapper instance with Typescript). However, eslint hates screen and TS cannot find findByText. Instead I get the error Property 'findByText' does not exist on type 'Screen'.ts(2339) on the noted lines in the test below:
/* OuterComponent.test.tsx */
import { findByText } from '@testing-library/react';
import { mount } from 'enzyme';
import React from 'react';
import OuterComponent from './OuterComponent';
describe('OuterComponent', () => {
it('does something on click', async () => {
const wrapper = mount(<OuterComponent />);
/* eslint-disable-next-line no-restricted-globals */
expect(await screen.findByText('hello')).not.toBe(null); // error here
wrapper.find('Button').simulate('click');
/* eslint-disable-next-line no-restricted-globals */
expect(await screen.findByText('world')).not.toBe(null); // error here
});
});
This feels like a pretty standard scenario, so how do those of you who use TS test this type of thing? Here is OuterComponent:
/* OuterComponent.tsx */
import React, { useState } from 'react';
import { Button } from 'react-bootstrap';
import InnerComponent from './InnerComponent';
const initialData = 'hello';
const OuterComponent: React.FC = () => {
const [data, setData] = useState<string>(initialData);
const clickHandler = () => {
if (data === 'hello') {
setData('world');
} else {
setData('hello');
}
};
return (
<div className="Outer">
<Button onClick={clickHandler}>Click</Button>
<InnerComponent data={data} />
</div>
);
};
export default OuterComponent;
and here is InnerComponent:
/* InnerComponent.tsx */
import React from 'react';
import { Card } from 'react-bootstrap';
interface TheseProps {
data: string;
}
const InnerComponent: React.FC<TheseProps> = ({ data }) => {
return (
<div className="Inner">
<Card>
<Card.Text>{data}</Card.Text>
</Card>
</div>
);
};
export default InnerComponent;
CodePudding user response:
There is a separate "screen" object exported from '@testing-library/react'. that has the findByText method. you unfortunately have to manually grab screen out of the library as auto imports just think its the global "screen" when you don't import explicitly.
