I am trying to figure out the best way to unit test the following situation
- Parent class component
Appholds the state of number ofattendeesas well a methodhandleAttendeesChange()to update the state Apprenders a child componentAttendeesand passes it 2 props:currentCountandonValueChange
The question is: do I test that the state is changing properly in App.tsx or Attendees.tsx? I've seen examples where I should test the state change in the parent component but those examples show that the parent component displays the value in the DOM instead of the child.
Code is below
App.tsx
import React, { FC, Component } from 'react';
import {Attendees} from './Attendees';
interface AppState {
attendees: number
}
export default class App extends Component<{}, AppState> {
constructor(props:any) {
super(props);
this.handleAttendeesChange = this.handleAttendeesChange.bind(this);
this.state = {
attendees: 0
};
}
handleAttendeesChange(value: number) {
this.setState({ attendees: this.state.attendees + value});
}
render() {
return (
<div>
<h1>Parent Component</h1>
<Attendees currentCount={this.state.attendees} onValueChange={this.handleAttendeesChange} />
</div>
)
}
}
Attendees.tsx
import React, { FC } from 'react';
type AttendeesProps = {
currentCount: number,
onValueChange: (value: number) => void
}
export const Attendees:FC<AttendeesProps> = ({ currentCount, onValueChange }) => {
return (
<div>
<button data-testid="countUp" onClick={() => onValueChange(1)}>
Up
</button >
<button data-testid="countDown" onClick={() => onValueChange(-1)}>
Down
</button >
<p data-testid="currentCount">
{currentCount}
</p>
</div>
)
}
Here's what I am currently testing in Attendeees.test.tsx using react-testing-library
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { unmountComponentAtNode } from "react-dom";
// import { act } from "react-dom/test-utils";
import {Attendees} from './Attendees';
let container: any = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("Main");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
it("Attendees should respond to callback props", () => {
const onValueChange = jest.fn();
const { getByTestId } = render(<Attendees currentCount={0} onValueChange={onValueChange} />, container)
fireEvent.click(getByTestId('countUp'))
expect(onValueChange).toBeCalledWith(1);
expect(onValueChange).toHaveBeenCalledTimes(1);
expect(getByTestId('currentCount').textContent).toBe('1');
})