I am facing an issue with testing a RESTful API (built with Express in TypeScript) using Jest. The test passes successfully on my local Windows machine but times out on CircleCI.
.circleci/config.ylm
version: 2.1
jobs:
build:
docker:
- image: circleci/node:16.3.0
working_directory: ~/Mealplanr-api/api
steps:
- checkout:
path: ~/Mealplanr-api
- run:
name: Install dependencies
command: |
yarn install
- run:
name: Run tests
command: |
yarn test:ci
- store_test_results:
path: test-results
- store_artifacts:
path: test-results
package.json
...
"scripts": {
"start": "nodemon --config nodemon.json src/server.ts",
"test": "jest --watchAll",
"test:ci": "jest"
},
...
jest.config.js
module.exports = {
roots: ['<rootDir>/src'],
testMatch: [
'**/__tests__/**/*.+(ts|tsx|js)',
'**/?(*.)+(spec|test).+(ts|tsx|js)',
],
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest',
},
};
The test description is as follows
users.spec.ts
import request from 'supertest';
import app from '../app';
import { connectDB, closeDB } from '../connect';
describe('POST /users', () => {
beforeAll(async () => {
await connectDB();
});
afterAll(async () => {
await closeDB();
});
it('Should create a new user', async () => {
const res = await request(app).post('/users').send({
email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2d59485e596d59485e590359485e59">[email protected]</a>',
password: '123456',
passwordconfirmation: '123456',
});
const body = res.body;
expect(body?.hasOwnProperty('_id')).toBe(true);
expect(body?.hasOwnProperty('email')).toBe(true);
expect(body?.hasOwnProperty('createdAt')).toBe(true);
expect(body?.hasOwnProperty('updatedAt')).toBe(true);
});
});
The functions used for connection are described here
connect.ts
import { connect, disconnect } from 'mongoose';
import log from './logger';
const mongoose = require('mongoose');
import { Mockgoose } from 'mockgoose';
const mockgoose = new Mockgoose(mongoose);
const dbUri = process.env.DB_URI as string;
export async function connectDB() {
if ((process.env.NODE_ENV as string) === 'test') {
// In the test environment, we don't want to connect to the real DB.
await mockgoose.prepareStorage();
await connect(dbUri, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
}).catch((error) => {
log.error('Error in connecting', error);
});
log.info('Mock connection success');
} else {
// If not in the test environment, connect to the database
await connect(dbUri, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
}).catch((error) => {
log.error('Error in connecting', error);
});
log.info('Connection success');
}
}
export async function closeDB() {
await mockgoose.shutdown();
await disconnect();
}
Output from CircleCI:
#!/bin/bash -eo pipefail
yarn test:ci
yarn run v1.22.5
$ jest
Completed: 100 % (80.8mb / 80.8mbb FAIL src/routes/users.spec.ts (30.653 s)
● POST /users › Should create a new user
thrown: "Exceeded timeout of 5000 ms for a hook.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
5 |
6 | describe('POST /users', () => {
> 7 | beforeAll(async () => {
| ^
8 | await connectDB();
9 | });
10 |
at src/routes/users.spec.ts:7:2
at Object.<anonymous> (src/routes/users.spec.ts:6:1)
at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
at runJest (node_modules/@jest/core/build/runJest.js:387:19)
...
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 30.842 s
Ran all test suites.
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Exited with code exit status 1