Testing Lab 6: Testing Forms
Objectives
- Update the Form to be more Accessible
- Test Loading Data into the Form
- Test Updating Form Values
- Test Validation Rules
Steps
Update the Form to be more Accessible
One of the great benefits of using React Testing Library is that it helps us build a more accessible application. The way we initially built our form HTML needs to be updated so we can more easily and realiably select various form elements and errors.
- Update the form to be more accessible. - src\projects\ProjectForm.tsx...function ProjectForm({ project: initialProject, onCancel }: ProjectFormProps) {...return (<formaria-label="Edit a Project"name="projectForm"className="input-group vertical"onSubmit={handleSubmit}><label htmlFor="name">Project Name</label><input+ id="name"type="text"name="name"placeholder="enter name"value={project.name}onChange={handleChange}/>{errors.name.length > 0 && (<div+ role="alert"className="card error"><p>{errors.name}</p></div>)}<label htmlFor="description">Project Description</label><textarea+ id="description"+ aria-label="project description"name="description"placeholder="enter description"value={project.description}onChange={handleChange}/>{errors.description.length > 0 && (<div+ role="alert"className="card error"><p>{errors.description}</p></div>)}<label htmlFor="budget">Project Budget</label><input+ id="budget"type="number"name="budget"placeholder="enter budget"value={project.budget}onChange={handleChange}/>{errors.budget.length > 0 && (<div+ role="alert"className="card error"><p>{errors.budget}</p></div>)}<label htmlFor="isActive">Active?</label><input+ id="isActive"type="checkbox"name="isActive"checked={project.isActive}onChange={handleChange}/><div className="input-group"><button className="primary bordered medium">Save</button><span /><button type="button" className="bordered medium" onClick={onCancel}>cancel</button></div></form>);}export default ProjectForm;
Test Loading Data into the Form
- Create the file - src\projects\__tests__\ProjectForm-test.tsx.
- Add the setup code below to test loading data into the form. - src\projects\__tests__\ProjectForm-test.tsximport React from "react";import { render, screen } from "@testing-library/react";import { MemoryRouter } from "react-router-dom";import { Project } from "../Project";import ProjectForm from "../ProjectForm";import { Provider } from "react-redux";import { store } from "../../state";import userEvent from "@testing-library/user-event";describe("<ProjectForm />", () => {let project: Project;let updatedProject: Project;let handleCancel: jest.Mock;let nameTextBox: any;let descriptionTextBox: HTMLElement;let budgetTextBox: HTMLElement;const setup = () => {render(<Provider store={store}><MemoryRouter><ProjectForm project={project} onCancel={handleCancel} /></MemoryRouter></Provider>);nameTextBox = screen.getByRole("textbox", {name: /project name/i,});descriptionTextBox = screen.getByRole("textbox", {name: /project description/i,});budgetTextBox = screen.getByRole("spinbutton", {name: /project budget/i,});};beforeEach(() => {project = new Project({id: 1,name: "Mission Impossible",description: "This is really difficult",budget: 100,});updatedProject = new Project({name: "Ghost Protocol",description:"Blamed for a terrorist attack on the Kremlin, Ethan Hunt (Tom Cruise) and the entire IMF agency...",});handleCancel = jest.fn();});test("should load project into form", () => {setup();expect(screen.getByRole("form", {name: /edit a project/i,})).toHaveFormValues({name: project.name,description: project.description,budget: project.budget,isActive: project.isActive,});});});
- Verify that the intial test passes. PASS src/projects/__tests__/ProjectForm-test.tsx
Test Updating Form Values
- Test - src\projects\__tests__\ProjectForm-test.tsx...describe('<ProjectForm />', () => {...+ test('should accept input', async () => {+ setup();+ const user = userEvent.setup();+ await user.clear(nameTextBox);+ await user.type(nameTextBox, updatedProject.name);+ expect(nameTextBox).toHaveValue(updatedProject.name);++ await user.clear(descriptionTextBox);+ await user.type(descriptionTextBox, updatedProject.description);+ expect(descriptionTextBox).toHaveValue(updatedProject.description);++ await user.clear(budgetTextBox);+ await user.type(budgetTextBox, updatedProject.budget.toString());+ expect(budgetTextBox).toHaveValue(updatedProject.budget);+ });});
1. **Verify** the **test passes**.
   ```shell
    PASS  src/projects/__tests__/ProjectForm-test.tsx
Test Validation Rules
- Test - src\projects\__tests__\ProjectForm-test.tsx...describe('<ProjectForm />', () => {...+ test('name should display required validation', async () => {+ setup();+ const user = userEvent.setup();+ await user.clear(nameTextBox);+ expect(screen.getByRole('alert')).toBeInTheDocument();+ });++ test('name should display minlength validation', async () => {+ setup();+ const user = userEvent.setup();+ await user.clear(nameTextBox);+ await user.type(nameTextBox, 'ab');+ await expect(screen.getByRole('alert')).toBeInTheDocument();+ await user.type(nameTextBox, 'c');+ expect(screen.queryByRole('alert')).not.toBeInTheDocument();+ });++ test('budget should display not 0 validation', async () => {+ setup();+ const user = userEvent.setup();+ await user.clear(budgetTextBox);+ await user.type(budgetTextBox, '0');+ expect(screen.getByRole('alert')).toBeInTheDocument();+ await user.type(budgetTextBox, '1');+ expect(screen.queryByRole('alert')).not.toBeInTheDocument();+ });});
- Verify all tests pass. PASS src/projects/__tests__/ProjectForm-test.tsx