Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react-testing: Introduce a waitFor helper #2536

Open
3 of 7 tasks
karthikiyengar opened this issue Jan 23, 2023 · 3 comments
Open
3 of 7 tasks

react-testing: Introduce a waitFor helper #2536

karthikiyengar opened this issue Jan 23, 2023 · 3 comments
Labels
Area: testing Package: react-testing Type: Feature Request 🙌 Request a new feature or changes to an existing one

Comments

@karthikiyengar
Copy link

karthikiyengar commented Jan 23, 2023

Overview

Relates to: https://github.com/Shopify/pos-channel/issues/9692

It looks like there is no clean way to test certain use cases that involve some state update scenarios within useEffect. Here is a minimal example.

const Component = () => {
  const [counter, setCounter] = useState(0);
  useEffect(() => {
    setTimeout(() => {
      setCounter((counter) => counter + 1);
    }, 0);
  }, []);
  return <p>{counter}</p>;
};

describe('waitFor', () => {
  it('failure', async () => {
    const root = await mount(<Component />);
    expect(root).toContainReactText('0'); // pass
    await root.act(() => {}); // ???
    expect(root).toContainReactText('1'); // fail
  });
});

react-testing-library offers a waitFor method for cases like these. Here is a naive implementation that takes us a bit further.

const waitFor = async (expectation) => {
  const timeout = 4500;
  const interval = 50;
  const maxTries = Math.ceil(timeout / interval);

  let tries = 0;
  return new Promise<void>((resolve, reject) => {
    const rejectOrRerun = (error: Error) => {
      if (tries > maxTries) {
        reject(error);
        return;
      }
      setTimeout(runExpectation, interval);
    };

    function runExpectation() {
      tries += 1;
      try {
        Promise.resolve(expectation())
          .then(() => resolve())
          .catch(rejectOrRerun);
      } catch (error) {
        rejectOrRerun(error);
      }
    }
    setTimeout(runExpectation, 0);
  });
};

And the same test using the above helper

  it('success', async () => {
    const root = await mount(<Component />);
    expect(root).toContainReactText('0'); // pass
    await waitFor(() => {
      expect(root).toContainReactText('1'); // fail
    });
  });

The above test passes, but it still feels a bit dirty considering React fires act warnings:

Warning: An update to Component inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):

Would appreciate some insights on how we could best support this.

References:

Type

  • New feature
  • Changes to existing features

Motivation

What inspired this feature request? What problems were you facing,
or what else makes you think this should be in quilt?

...

Area

  • Add any relevant Area: <area> labels to this issue

Scope

  • Is this issue related to a specific package?

    • Tag it with the Package: <package_name> label.
  • Is it related to a new package?

    • Tag it with the New package Label

Checklist

  • Please delete the labels section before submitting your issue
  • I have described this issue in a way that is actionable (if possible)
@karthikiyengar karthikiyengar added Type: Feature Request 🙌 Request a new feature or changes to an existing one Package: react-testing Area: testing labels Jan 23, 2023
@karthikiyengar
Copy link
Author

@karthikiyengar
Copy link
Author

karthikiyengar commented Feb 15, 2023

Update: We added a stopgap version of this to another repo as part of this PR

@MrHBS
Copy link

MrHBS commented Apr 9, 2023

All links are dead

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: testing Package: react-testing Type: Feature Request 🙌 Request a new feature or changes to an existing one
Projects
None yet
Development

No branches or pull requests

2 participants