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

Async setupFiles #11038

Closed
villesau opened this issue Jan 29, 2021 · 11 comments · Fixed by #12042
Closed

Async setupFiles #11038

villesau opened this issue Jan 29, 2021 · 11 comments · Fixed by #12042

Comments

@villesau
Copy link

villesau commented Jan 29, 2021

🚀 Feature Proposal

setupFiles should support module.exports = async () => {/* async setup here */} kind of functionality.

Motivation

Async setupFiles would enable setting up new database for each test file and store the database name to config.js file.

Example

const config = require('../config');
module.exports = async () => {
  const randomDatabaseName = randomName();
  await createDatabase(randomDatabaseName);
  config.DATABASE_NAME = randomDatabaseName
};

config.DATABASE_NAME is then used in the actual tests to establish the actual connection.

Pitch

Why does this feature belong in the Jest core platform?

There is currently no way to achieve this behaviour with synchronous setupFiles nor with custom env, but this would make working with parallel tests using database much easier.

I think this would be the second best option after this: #11039

@SimenB
Copy link
Member

SimenB commented Jan 30, 2021

If you use ESM you can use top level await. So if you name your setup file something.mjs and enable ESM mode.

Not to say we shouldn't support exported functions from setup files, but I think it's cleaner with TLA. Thoughts?

@villesau
Copy link
Author

ESM & TLA sounds like a decent option, didn't think about that 👍 Does Jest wait for it to finish before continuing?

@SimenB
Copy link
Member

SimenB commented Jan 30, 2021

Yes, all ESM module resolution and loading is async and Jest awaits it.

Specifically: https://github.com/facebook/jest/blob/e651a21653b481731b8566ca843501bdc7ad1b75/packages/jest-repl/src/cli/runtime-cli.ts#L106-L114

@villesau
Copy link
Author

It seems that .mjs would be quite hacky solution and it does not have all the necessary variables like __dirname available :/ This could turn out to be usable in future, but right now it's not quite there yet. Also current version of ESlint doesn't seem to like top level awaits yet. So I'd say it's still way too early for ESM.

@kbrueckner
Copy link

I would want to second the feature proposal. In my view it is quite common that you have async operations for setting up your tests. Those could be as already mentioned DB connection handling or reading credentials from an external secret store, ...

@owenbendavies
Copy link

This sounds exactly what I need and cannot currently find an alternative solution.

I am testing a lambda function that sets up a database connection on load, e.g.

// src/handlers/graphql.ts
const loadingConnection = setupDatabase();

export const handler = async (
  event: APIGatewayProxyEvent,
  context: Context,
  callback: Callback
): Promise<APIGatewayProxyResult> => {
  const connection = await loadingConnection;
  ...

Then because my test is importing the file, e.g.

// src/handlers/graphql.spec.ts
import { handler } from './graphql';

describe('handler', () => {
  it('handles graphql queries', async () => {

If I had the database connection set up in the handler, I am able to create the database in a setupFilesAfterEnv file, e.g.

// src/test/setupFilesAfterEnv/database.setup.ts
beforeAll(async () => {
  const dbname = ['graphql', process.env.NODE_ENV, process.env.JEST_WORKER_ID].filter(Boolean).join('-');
  const connectionOptions = await getConnectionOptions();
  await createDatabase({}, {...connectionOptions, dbname});
});

However this doesn't work as the beforeAll runs after the handler file is imported, e.g.

src/test/setupFilesAfterEnv/database.setup.ts root code run    
src/handlers/graphql.ts root code run
src/handlers/graphql.spec.ts root code run
src/test/setupFilesAfterEnv/database.setup.ts beforeAll run
src/handlers/graphql.spec.ts it run
src/handlers/graphql.ts handler run

If anyone has any suggestions, even hacky temporary ones it would be much appreciated!

@SimenB
Copy link
Member

SimenB commented Oct 9, 2021

Trivial to support calling a function exported from the module if it exists and await the result, so I'll happily merge a PR doing so 🙂

@clintonmedbery
Copy link

@owenbendavies Not sure this is your problem or if you found a solution but my beforeAll wouldn't wait and the tests would start. Adding a jest timeout fixed this.

beforeAll(async () => {
  // This timeout need to be here otherwise jest moves on after a few seconds and does not
  // await the TestServer with no warning.
  jest.setTimeout(20000);
  await new TestServer();
});

@owenbendavies
Copy link

@clintonmedbery thank you for the suggestion, unfortunately it's an order issue rather than a time issue so this doesn't help.

@SimenB
Copy link
Member

SimenB commented Mar 1, 2022

@github-actions
Copy link

github-actions bot commented Apr 1, 2022

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 Apr 1, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants