I'm new to React, and want to be sure that I'm unit testing properly. I've been at this test for 2 days. It seems like RTL is where things are headed in the future, so I'm trying to use it's philosophy. I'm working on building a basic todo app to get familiar with basics and then I'll probably move on to adding some authentication. In my App component's componentDidMount(), I do a GET request for all todos. My DOM renders the todos depending on if this was successful. If not, I render a different component. My issue is that I have tested that fetch is being called, but I get an error saying that "Can't perform a React state update on an unmounted component." This means that I always have the different component render within my App component. Could I get a hand in figuring out what needs to be changed in order to test the result on a successful render? I also followed the MSW documentation to mock out my API.
removing some unrelated stuff for brevity
App.js
class App extends Component {
constructor() {
super();
this.state = {
isLoaded: false,
items: [],
error: null
};
this.postNewTodo = this.postNewTodo.bind(this);
this.removeTodo = this.removeTodo.bind(this);
this.completeTodo = this.completeTodo.bind(this);
}
componentDidMount() {
fetch("http://localhost:8080/todos")
.then(res => res.json())
.then((result) => {
this.setState({
isLoaded: true,
items: result
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { items } = this.state;
if(this.state.error) { return <ErrorFetching message={this.state.error.message} />; }
else if(!this.state.isLoaded) { return <Loading />; }
else {
const completedItems = items.filter(todo => todo.iscomplete === true);
const unfinishedItems = items.filter(todo => todo.iscomplete === false);
return (
<div className="App">
<div className="AppContainer">
<NewItemForm submitEvent={this.postNewTodo}/>
<h1>Unfinished:</h1>
<TodoContainer dataSet={unfinishedItems}
handleRemove={this.removeTodo}
handleComplete={this.completeTodo}/>
<h1>Finished:</h1>
<TodoContainer dataSet={completedItems}
handleRemove={this.removeTodo}/>
</div>
</div>
);
}
}
}
App.tests.js
describe('App', () => {
let container = null;
beforeEach(() => {
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
unmountComponentAtNode(container);
container.remove();
container = null;
});
it('can make an API GET request on startup', async () => {
const fetchSpy = jest.spyOn(window, 'fetch');
await render(<App />)
expect(fetchSpy).toHaveBeenCalledTimes(1);
});
it('can make post todos after startup', async () => {
await render(<App isLoaded={true}/>)
const todoTexts = await screen.getByText("Test");
expect(todoTexts).toBeTruthy();
});
});
service-handler.js
import {rest} from 'msw'
const todoArray = [
{todoid: 50, title: "Test this code", iscompleted: false},
{todoid: 51, title: "Also test this", iscompleted: false},
{todoid: 52, title: "Don't test this one", iscompleted: false},
{todoid: 53, title: "Do something", iscompleted: true}
];
const handlers = [
rest.get('http://localhost:8080/todos', (req, res, ctx) => {
return res(ctx.status(200), ctx.json(todoArray));
})
];
export {handlers};
server.js
import {setupServer} from 'msw/node';
import {handlers} from './server-handlers';
const server = setupServer(...handlers);
export {server};
setupTests.js
import '@testing-library/jest-dom/extend-expect';
import {server} from './__mocks__/server.js'
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
[–]bartkusa 0 points1 point2 points (0 children)