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

waitFor does not return the callback's returned value. #73

Open
Izhaki opened this issue May 6, 2022 · 3 comments
Open

waitFor does not return the callback's returned value. #73

Izhaki opened this issue May 6, 2022 · 3 comments

Comments

@Izhaki
Copy link

Izhaki commented May 6, 2022

The waitFor exported by this library does not seem to be complaint with the testing-library API, where it should return the callback's return value.

In the following code, x will have a value, but y wouldn't:

  const y = await waitFor(async () => {
    const $container = await getContainer();
    const x = await queries.findByRole($container, ...parameters);
    console.log(x);
    return x;
  });
  console.log(y);

We have a case where a user action opens a new tab, so we need to retry getting the page itself, not just the dom query.

@Izhaki
Copy link
Author

Izhaki commented May 25, 2022

We have ended up modifying wait-for-expect code to support both return values and timeout adherence. This exclude the handling of Jest fake timers (although can easily be added).

/*
A modification of https://github.com/TheBrainFamily/wait-for-expect/blob/6be6e2ed8e47fd5bc62ab2fc4bd39289c58f2f66/src/index.ts
Which is exported by pptr-testing-library, but has two issues:
- Timeout not adhered to with long promises. https://github.com/TheBrainFamily/wait-for-expect/issues/35
- No return value. https://github.com/testing-library/pptr-testing-library/issues/73
*/

const { now } = Date;

interface Options {
  timeout?: number;
  interval?: number;
}

/**
 * Waits for the expectation to pass and returns a Promise
 *
 * @param  expectation  Function  Expectation that has to complete without throwing
 * @param  timeout  Number  Maximum wait interval, 4500ms by default
 * @param  interval  Number  Wait-between-retries interval, 50ms by default
 * @return  Promise  Promise to return a callback result
 */
export default async function waitFor(
  expectation: () => void | Promise<any>,
  options: Options = {}
): Promise<any> {
  const { timeout = 4500, interval = 50 } = options;
  if (interval < 1) {
    throw new Error("Interval set to a number smaller than 1 ms.");
  }
  const startTime = now();
  return new Promise((resolve, reject) => {
    const rejectOrRerun = (error: Error) => {
      const timeElapsed = now() - startTime;
      if (timeElapsed >= timeout) {
        reject(error);
        return;
      }
      // eslint-disable-next-line no-use-before-define
      setTimeout(runExpectation, interval);
    };
    async function runExpectation() {
      try {
        const result = await expectation();
        resolve(result);
      } catch (error) {
        rejectOrRerun(error as Error);
      }
    }
    setTimeout(runExpectation, 0);
  });
}

@patrickhulce
Copy link
Collaborator

Ah, thanks for filing @Izhaki great find! We're happy to update to latest waitFor version if there's a fix available there.

@Manvel
Copy link

Manvel commented Nov 9, 2022

There seem to be fix for it TheBrainFamily/wait-for-expect#33, but considering the fact that the lib has last been updated 2 years ago, not sure if it's actively being maintained anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants