Skip to content

Leaking waitFor callback against jasmine when the clock is mocked #1270

Closed
@KevinBon

Description

@KevinBon
  • @testing-library/dom version: 9.3.1
  • @testing-library/react version 14.0.0
  • Testing Framework and version: [email protected]
  • DOM Environment: Chrome (Headful and Headless)

Relevant code or config:

/**
 * For making dom-testing-library compatible with jasmine
 */
function enableFakeJestMode() {
  /**
   * For jestFakeTimersAreEnabled
   * @see https://github.com/testing-library/dom-testing-library/blob/a7b725257e61370675ee043813003d36fae23e9d/src/helpers.ts#L5
   * For usingJestFakeTimers
   * @see https://github.com/testing-library/dom-testing-library/blob/a7b725257e61370675ee043813003d36fae23e9d/src/wait-for.js#L51-L52
   *
   */
  Object.assign(globalThis.setTimeout, { _isMockFunction: true });

  globalThis.jest = {
    /**
     * Use jasmine.clock instead
     */
    advanceTimersByTime: (delay: number) => {
      globalThis.jasmine.clock().tick(delay);
    },
  };
}

describe('jasmine', () => {
  beforeEach(() => {
    enableFakeJestMode();
    jasmine.clock().install();
  });

  afterEach(() => {
    console.log(
      '%c afterEach',
      'color: #f80; font-weight: bold',
      'uninstall:before'
    );
    jasmine.clock().uninstall();
    console.log(
      '%c afterEach',
      'color: #f80; font-weight: bold',
      'uninstall:after'
    );
  });

  it('simulates a timeout', async () => {
    render(<span>Will never be found</span>);

    try {
      await waitFor(
        () => {
          console.log(
            '%c spec',
            'color: lime; font-weight: bold',
            'waitfor:callback'
          );
          // The button shouldn't be found, so it will throw/fail the inner waitFor callback predicate
          screen.getByRole('button');
        },
        { interval: 6000 } // to have less logs
      );
      fail('Should have failed');
    } catch (error) {
      console.log('%c spec', 'color: #f80; font-weight: bold', 'finished ✅');
      expect().nothing();
    }
  });
});

What you did:

I added logs to demonstrate that the waitFor callback has been called even after it has been resolved from a timeout.

What happened:

image

After the waitFor is resolved (see: spec finished: ✅), spec waitfor:callback is still being invoked.

PS: Log points added to surface internal react-testing-library, dom-testing-library and jasmine calls

Reproduction:

Problem description:

The following issue can only be seen when the jasmine.Clock is installed against waitFor.

To prevent any side-effect (e.g: the waitFor callback modifies the global environment), the waitFor callback should never be invoked once it "finishes/resolves"

Suggested solution:

#1271

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions