Skip to content

Instantly share code, notes, and snippets.

@isocroft
Last active November 14, 2025 09:34
Show Gist options
  • Select an option

  • Save isocroft/f66e4062eef20beb867dfc2f0a2046d8 to your computer and use it in GitHub Desktop.

Select an option

Save isocroft/f66e4062eef20beb867dfc2f0a2046d8 to your computer and use it in GitHub Desktop.
This is version 2 of a simple test for how using async/await with react testing library can slow down tests
import React, { useState } from "react";
import { render, act, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { roles, Components } from "constants/ui-copy";
const { _TextBoxes: $RecipeFormTextBoxes, _Buttons: $RecipeFormButtons } = Components.RecipeForm;
function RecipeForm ({ onSubmit }) {
function formToObject(form) {
const formData = new FormData(form);
return Object.fromEntries(formData.entries());
}
return (
<form method="post" onSubmit={(event) => {
event.preventDefault();
onSubmit(formToObject(event.target));
}}>
<h3 role={roles.heading}>Fill Recipe Form</h3>
<input
type="text"
role={roles.textbox}
name={$RecipeFormTextBoxes.title.name}
aria-label={$RecipeFormTextBoxes.title.name}
/>
<input
type="text"
role={roles.textbox}
name={$RecipeFormTextBoxes.description.name}
aria-label={$RecipeFormTextBoxes.description.name}
/>
<input
type="number"
role={roles.spinbutton}
name={$RecipeFormTextBoxes.servings.name}
aria-label={$RecipeFormTextBoxes.servings.name}
/>
<button
role={roles.button}
type="submit"
aria-label={$RecipeFormButtons.submit.name}
>
{$RecipeFormButtons.submit.text}
</button>
</form>
);
}
function setupComponentForUserInteraction(jsx) {
return {
user: userEvent.setup(),
...render(jsx),
};
}
function fillTheRecipeFormAndSubmitFor (user, screen) {
// Fill the form
const titleBoxEntryPromise = user.type(
screen.getByRole(
roles.textbox,
{ name: $RecipeFormTextBoxes.title.name }
),
"Test recipe",
);
const descBoxEntryPromise = user.type(
screen.getByRole(
roles.textbox,
{ name: $RecipeFormTextBoxes.description.name }
),
"Delicious recipe",
);
const servingsBoxEntryPromise = user.type(
screen.getByRole(
roles.spinbutton,
{ name: $RecipeFormTextBoxes.servings.name }
),
"4"
);
return Promise.all([
titleBoxEntryPromise,
descBoxEntryPromise,
servingsBoxEntryPromise
]).then(() => {
// Submit the form
return user.click(
screen.getByRole(
roles.button,
{ name: $RecipeFormButtons.submit.name }
)
);
});
}
it("should submit correct recipe form data", async () => {
const mockSubmit = jest.fn();
const { user, screen } = setupComponentForUserInteraction(
<RecipeForm onSubmit={mockSubmit} />
);
await act(() => {
return fillTheRecipeFormAndSubmitFor(user, screen);
});
expect(mockSubmit).toHaveBeenCalledWith({
name: "Test recipe",
description: "Delicious recipe",
servings: 4,
});
});
@isocroft

isocroft commented Jul 3, 2023

Copy link
Copy Markdown
Author

@isocroft

isocroft commented May 30, 2025

Copy link
Copy Markdown
Author
import React, { useState } from "react";
import { render, act } from "@testing-library/react";

import { arrange, waitFor } from "../helpers/custom-test-utils";
import userEvent from "@testing-library/user-event";
import { roles, Components } from "constants/ui-copy";

const { _TextBoxes: $RecipeFormTextBoxes, _Buttons: $RecipeFormButtons } = Components.RecipeForm;

function RecipeForm ({ onSubmit }) {
  function formToObject(form) {
    const formData = new FormData(form);
    return Object.fromEntries(formData.entries());
  }
  
  return (
    <form method="post" onSubmit={(event) => {
      event.preventDefault();
      onSubmit(formToObject(event.target));
    }}>
      <h3 role={roles.heading}>Fill Recipe Form</h3>
      <input
        type="text"
        role={roles.textbox}
        name={$RecipeFormTextBoxes.title.name}
        aria-label={$RecipeFormTextBoxes.title.name}
      />
      <input
        type="text"
        role={roles.textbox}
        name={$RecipeFormTextBoxes.description.name}
        aria-label={$RecipeFormTextBoxes.description.name}
      />
      <input
        type="number"
        role={roles.spinbutton}
        name={$RecipeFormTextBoxes.servings.name}
        aria-label={$RecipeFormTextBoxes.servings.name}
      />
      <button
        role={roles.button}
        type="submit"
        aria-label={$RecipeFormButtons.submit.name}
      >
        {$RecipeFormButtons.submit.text}
      </button>
    </form>
  );
}


function setupComponentForUserInteraction(jsx) {
  return {
    user: userEvent.setup(),
    ...render(jsx),
  };
}

function fillTheRecipeFormAndSubmitFor (user, screen) {
  // Fill the form
  const titleBoxEntryPromise = user.type(
    screen.getByRole(
      roles.textbox,
      { name: $RecipeFormTextBoxes.title.name }
    ),
    "Test recipe",
  );
  
  const descBoxEntryPromise = user.type(
    screen.getByRole(
      roles.textbox,
      { name: $RecipeFormTextBoxes.description.name }
    ),
    "Delicious recipe",
  );
  
  const servingsBoxEntryPromise = user.type(
    screen.getByRole(
      roles.spinbutton,
      { name: $RecipeFormTextBoxes.servings.name }
    ),
    "4"
  );
  
  return Promise.all([
    titleBoxEntryPromise,
    descBoxEntryPromise,
    servingsBoxEntryPromise
  ]).then(() => {
    // Submit the form
    return user.click(
      screen.getByRole(
        roles.button,
        { name: $RecipeFormButtons.submit.name }
      )
    );
  });
}

it("should submit correct recipe form data", () => {
  const mockSubmit = jest.fn();

/*
  const { user: thisUser, screen } = arrange(() => {
    return setupComponentForUserInteraction(
      <RecipeForm onSubmit={mockSubmit} />
    );
  });
  */
   const { user: thisUser, screen } =  setupComponentForUserInteraction(
      <RecipeForm onSubmit={mockSubmit} />
    );
  
 const promiseOfFilledAndSubmittedForm = act(() => {
    return fillTheRecipeFormAndSubmitFor(thisUser, screen);
  });
  
  return waitFor(promiseOfFilledAndSubmittedForm).then(() => {
    expect(mockSubmit).toHaveBeenCalledWith({
      name: "Test recipe",
      description: "Delicious recipe",
      servings: 4,
    });
  }).end();
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment