Skip to content

support async module mocking #9299

Closed
Closed
@skeggse

Description

@skeggse

🚀 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).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions