I am working on Jest tests for a Node/Express TypeScript backend. I recently learnt about global test setup which I am implementing to reduce similar variables and function calls that are executed in all test files.
So for example in the below code I want to make the app and userToken global variables and await initDatabase() function called in the tests setup file.⬇
import initServer from '../initServer';
import { initDatabase } from '../util/databaseHandler';
import loginWithAWS from '../util/loginWithAWS';
const app = initServer();
let userToken: any;
describe(`Test on the GET method of route `, () => {
beforeAll( async() => {
try{
await initDatabase();
userToken = await loginWithAWS('userRole');
}catch(error){
return error;
}
});
});
However, after implementing the global test setup with the variables and function then running the test on terminal/bash/cmd via the command yarn test
this error is thrown: ⬇
The solution in progress which throws the bug is implemented as shown below. Your assistance will be highly valued.:
The test setup file:
testSetup.ts
⬇
import initServer from '../initServer';
import { initDatabase } from '../util/databaseHandler';
import loginWithAWS from '../util/loginWithAWS';
const initializeTestingSetup = async function() {
(global as any).app = initServer();
await initDatabase();
(global as any).userToken = await loginWithAWS('userRole');
};
module.exports = initializeTestingSetup;
Below is my jest config file for the project's tests:
jest.config.js
⬇
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
transform: {
'^. \\.ts$': 'ts-jest',
'^. \\.js$': 'babel-jest',
'^. \\.mjs$': 'babel-jest',
},
moduleDirectories: ['node_modules', '<rootDir>/src'],
moduleNameMapper: {
'@controllers/(.*)': '<rootDir>/src/controllers/$1',
'@middleware/(.*)': '<rootDir>/src/middleware/$1',
'@models/(.*)': '<rootDir>/src/models/$1',
'@routes/(.*)': '<rootDir>/src/routes/$1',
'@types/(.*)': '<rootDir>/src/types/$1',
'@util/(.*)': '<rootDir>/src/util/$1',
},
globals: {
'ts-jest' : {
astTransformers: {
before: [
'ts-jest/dist/transformers/path-mapping'
]
},
}
},
globalSetup: './src/__tests__/testSetup.ts',
};
I would really appreciate your help.
CodePudding user response:
Jest seems to have problems with ES6 import syntax in any globalSetup scripts. I would try to change your testSetup.ts
script to use require
instead of import
so it doesn't have to be an ES6 module. Note that you are mixing CommonJS and ES6/ESM syntax in your testSetup.js
because you have import
, but use module.exports
. Something like this might work perhaps (this is untested):
const initServer = require('../initServer');
const initDatabase = require('../util/databaseHandler');
const loginWithAWS = require('../util/loginWithAWS');
const initializeTestingSetup = async function() {
(global as any).app = initServer();
await initDatabase();
(global as any).userToken = await loginWithAWS('userRole');
};
module.exports = initializeTestingSetup;
UPDATE: What about trying to make the globalsetup more compatible with ESM:
import initServer from '../initServer';
import { initDatabase } from '../util/databaseHandler';
import loginWithAWS from '../util/loginWithAWS';
export default async function setup() {
(global as any).app = initServer();
await initDatabase();
(global as any).userToken = await loginWithAWS('userRole');
};
Does that help?
CodePudding user response:
Ensure that package.json
has the type: module
set. I'm using node14, so I've set my target and lib to have es2020
as suggested here
The tsconfig for tests:
{
"compilerOptions": {
"allowUnreachableCode": false,
"declaration": true,
"target": "es2020",
"lib": ["es2020"],
"importHelpers": true,
"incremental": true,
"module": "es2020",
"esModuleInterop": true,
"moduleResolution": "Node",
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"resolveJsonModule": true,
"sourceMap": true,
"target": "es2020"
},
"include": ["test"],
"exclude": ["build", "node_modules"]
}
I've set esModuleInterop
to avoid any issues that might occur with default imports and set module
to es2020
(which allows for import.meta for __dirname).
We can ask the jest config to treat modules as esm:
{
"preset": "ts-jest",
"testEnvironment": "node",
"testMatch": ["<rootDir>/test/**/*.test.ts"],
"rootDir": ".",
"extensionsToTreatAsEsm": [".ts"],
"globalSetup": "<rootDir>/test/setup.ts",
"globals": {
"ts-jest": "./tsconfig.tests.json"
}
}
In your global setup, stick to esm exports and imports:
import express from "express";
import bodyParser from "body-parser";
import morgan from "morgan";
import helmet from "helmet";
import cors from "cors";
import PicoDb from "picodb";
const app = express();
const logger = morgan("combined");
const jsonParser = bodyParser.json();
const queryParser = bodyParser.urlencoded({ extended: true });
app.use(logger);
app.use(helmet());
app.use(queryParser);
app.use(jsonParser);
app.use(cors());
app.options("*", cors());
export { app };
export default async function globalSetup() {
const db = new PicoDb();
await db.insertMany([{ a: 1 }, { a: 2, b: 2 }]);
app.listen(3000, () => {
console.log("Server listening on port 3000");
});
}
This worked as expected when I was running the tests (with jest not exiting because I did not close the server in a teardown step).