The problem:
I have a react component with a simple form and an area to display output on submit.
I have manually tested and confirmed that submitting the form outputs the values as expected. However I cannot get React Testing Library to make the same assertion.
From what I can gather it doesn't seem to be seeing the updated page content.
Here's the output of the test failure:
● User should be able to submit their first name
expect(element).toHaveTextContent()
Expected element to have text content:
firstName: Matthew
Received:
firstName:
47 |
48 | expect(output.firstName).toHaveTextContent("firstName:");
> 49 | expect(output.firstName).toHaveTextContent("firstName: Matthew");
| ^
50 | });
51 |
52 | /*
Here is the component:
import React, { useState } from "react";
import './Playground.css';
const Playground = ({
firstName,
lastName,
email,
subject,
message
}) => {
let [myState, setMyState] = useState({
firstName: firstName ? firstName : "",
lastName: lastName ? lastName : "",
email: email ? email : "",
subject: subject ? subject : "",
message: message ? message : ""
});
function submit(event) {
event.preventDefault();
const form = event.target;
setMyState({
...myState,
firstName: form?.firstName?.value ? form?.firstName?.value : myState.firstName,
lastName: form?.lastName?.value ? form.lastName?.value : myState.lastName,
email: form?.email?.value ? form?.email?.value : myState.email,
subject: form?.subject?.value ? form?.subject?.value : myState.subject,
message: form?.message?.value ? form?.message?.value : myState.message
});
}
return (
<section data-testid="playground">
<h1>Form</h1>
<section data-testid="input">
<form onSubmit={submit}>
<label htmlFor="firstName">First Name</label>
<input type="text" id="firstName" placeholder="Jane" />
<label htmlFor="lastName">Last Name</label>
<input type="text" id="lastName" placeholder="Doe" />
<label htmlFor="email">Email</label>
<input type="text" id="email" placeholder="jane.doe@example.com" />
<label htmlFor="subject">Subject</label>
<input type="text" id="subject" placeholder="Subject" />
<label htmlFor="message">Message</label>
<textarea rows="3" id="message" type="text" placeholder="Message"></textarea>
<button type="submit" name="update">Update</button>
</form>
</section>
<section data-testid="output">
<div>firstName: {myState.firstName}</div>
<div>lastName: {myState.lastName}</div>
<div>email: {myState.email}</div>
<div>subject: {myState.subject}</div>
<div>message: {myState.message}</div>
</section>
</section>
);
};
export default Playground;
Here is the test in question (which fails on the assertion on line 49):
import React from 'react';
import {render, screen} from "@testing-library/react";
import userEvent from '@testing-library/user-event';
import Playground from "./Playground";
function getFormFields (screen) {
const formFields = {};
formFields.firstName = screen.getByLabelText(/first name/i);
formFields.lastName = screen.getByLabelText(/last name/i);
formFields.email = screen.getByLabelText(/email/i);
formFields.subject = screen.getByLabelText(/subject/i);
formFields.message = screen.getByLabelText(/^message$/i);
return formFields;
}
function getOutput (screen) {
const output = {};
output.firstName = screen.getByText(/^firstname:/i);
output.lastName = screen.getByText(/^lastname:/i);
output.email = screen.getByText(/^email:/i);
output.subject = screen.getByText(/^subject:/i);
output.message = screen.getByText(/^message:/i);
return output;
}
test('Should have an editable First Name field', () => {
render(<Playground />)
const fields = getFormFields(screen);
userEvent.type(fields.firstName, "Matthew");
expect(fields.firstName).toHaveValue("Matthew");
});
test('User should be able to submit their first name', async () => {
render(<Playground />)
const fields = getFormFields(screen),
submit = screen.getByRole('button', { name: /update/i }),
output = getOutput(screen);
userEvent.type(fields.firstName, "Matthew");
userEvent.click(submit);
expect(output.firstName).toHaveTextContent("firstName:");
expect(output.firstName).toHaveTextContent("Matthew");
});
Things I've tried
- Using findBy instead of getBy for text content
- Declaring the target element for the assertion after the update click has been performed
- Using await
- Lots of other stuff I've now forgotten
Final thought
This is driving me bonkers as it seems like a really simple issue (I'm not exactly doing rocket surgery). I'll be really grateful for any help I can get!
Thanks!