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

support async module mocking #9299

Closed
skeggse opened this issue Dec 13, 2019 · 2 comments
Closed

support async module mocking #9299

skeggse opened this issue Dec 13, 2019 · 2 comments

Comments

@skeggse
Copy link

skeggse commented Dec 13, 2019

🚀 Feature Proposal

In addition to the function-initializer style of jest.mock, support an async variant that accepts a function which returns a promise, and use the resolution from that promise to determine the mocked module's exports:

jest.mock('.../db.js', async () => {
  // Where the import() is transpiled by babel - this is not a feature request for
  // import support.
  const MongoMemoryServer = await import('mongo-memory-server'),
    mongoist = await import('mongoist'),
    mongod = new MongoMemoryServer(),
    uri = await mongod.getConnectionString();
  return mongoist(uri);
});

Motivation

Some information that can be known statically or synchronously in applications is only available asynchronously in test cases. To ease development in this case, we could let the module initializer function be asynchronous to avoid problematic hacks. See workaround in Pitch section.

Additionally, the import statement isn't a supported statement within the normal module initializer function, and tools like babel refuse to transpile it.

Example

(the same as in 🚀 Feature Proposal)

jest.mock('.../db.js', async () => {
  // Where the import() is transpiled by babel - this is not a feature request for
  // import support.
  const MongoMemoryServer = await import('mongo-memory-server'),
    mongoist = await import('mongoist'),
    mongod = new MongoMemoryServer(),
    uri = await mongod.getConnectionString();
  return mongoist(uri);
});

Pitch

Because this isn't a problem easily solved in the wild world of community ecosystem and support. There are fragile and application-specific ways to work around this problem by altering the application code itself in service to the tests, or by monkey patching external dependencies to make them work asynchronously. This is one such approach to working around this:

jest.mock('.../db.js', () => {
  const MongoMemoryServer = require('mongo-memory-server'),
    mongoist = require('mongoist'),
    mongod = new MongoMemoryServer(),
    uri = mongod.getConnectionString(),
    db = mongoist(null);
  db.connect = async function() {
    if (this.connection) {
      return this.connection;
    }

    const connectionString = await uri;
    if (this.connectionString === null) {
      this.connectionString = connectionString;
    }
    return mongoist.Database.prototype.connect.call(this);
  };
  return db;
});

Moreover, it simplifies the adoption of import over require for groups that prefer the former, as tools like babel don't support placing a standard import statement in the mocked function (babel/babel#10864).

@SimenB
Copy link
Member

SimenB commented Mar 14, 2021

We can only support async mocks for ESM, as CJS is synchronous. In your case I'd create a separate file that exports an async function and await (and possibly mock) that instead of having a module with side effects.

Mock of ESM modules (which will support promises) will come in #10976, you can track that

@SimenB SimenB closed this as completed Mar 14, 2021
@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 10, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants