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

New internal testing helpers: waitFor, waitForAll, waitForPaint #26285

Merged
merged 2 commits into from
Mar 3, 2023

Commits on Mar 3, 2023

  1. Add internal-test-utils package

    Our internal test utils are currently located in the jest-react
    package. At one point, the idea was to publish some of these as
    public, officially supported APIs, but we abandoned that idea in favor
    of `act`. We should really just delete the jest-react package from
    our repo.
    
    What we can do instead is put our internal test utils into a private
    package. This adds such a package, called internal-test-utils. There are
    no exported APIs yet but I'll add some in the next step.
    acdlite committed Mar 3, 2023
    Configuration menu
    Copy the full SHA
    c600974 View commit details
    Browse the repository at this point in the history
  2. New internal testing helpers: waitFor, waitForAll

    Over the years, we've gradually aligned on a set of best practices for
    for testing concurrent React features in this repo. The default in most
    cases is to use `act`, the same as you would do when testing a real
    React app. However, because we're testing React itself, as opposed to an
    app that uses React, our internal tests sometimes need to make
    assertions on intermediate states that `act` intentionally disallows.
    
    For those cases, we built a custom set of Jest assertion matchers that
    provide greater control over the concurrent work queue. It works by
    mocking the Scheduler package. (When we eventually migrate to using
    native postTask, it would probably work by stubbing that instead.)
    
    A problem with these helpers that we recently discovered is, because
    they are synchronous function calls, they aren't sufficient if the work
    you need to flush is scheduled in a microtask — we don't control the
    microtask queue, and can't mock it.
    
    `act` addresses this problem by encouraging you to await the result of
    the `act` call. (It's not currently required to await, but in future
    versions of React it likely will be.) It will then continue flushing
    work until both the microtask queue and the Scheduler queue is
    exhausted.
    
    We can follow a similar strategy for our custom test helpers, by
    replacing the current set of synchronous helpers with a corresponding
    set of async ones:
    
    - `expect(Scheduler).toFlushAndYield(log)` -> `await waitForAll(log)`
    - `expect(Scheduler).toFlushAndYieldThrough(log)` -> `await waitFor(log)`
    - `expect(Scheduler).toFlushUntilNextPaint(log)` -> `await waitForPaint(log)`
    
    These APIs are inspired by the existing best practice for writing e2e
    React tests. Rather than mock all task queues, in an e2e test you set up
    a timer loop and wait for the UI to match an expecte condition. Although
    we are mocking _some_ of the task queues in our tests, the general
    principle still holds: it makes it less likely that our tests will
    diverge from real world behavior in an actual browser.
    
    In this commit, I've implemented the new testing helpers and converted
    one of the Suspense tests to use them. In subsequent steps, I'll codemod
    the rest of our test suite.
    acdlite committed Mar 3, 2023
    Configuration menu
    Copy the full SHA
    8aadd4f View commit details
    Browse the repository at this point in the history