使用 MongoDB 的 Express API 开玩笑测试 - 在本地机器上运行,在 CircleCI 上失败(超时)
Jest test of Express API using MongoDB - runs on local machine, fails on CircleCI (Exceeded timeout)
正在使用 Jest 测试 RESTful API(用 Express in TypeScript 编写)。测试在我的本地机器上成功运行 (windows),但似乎在 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',
},
};
测试如下
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: 'test@test.test',
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);
});
});
正在使用的连接函数在这里描述
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 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 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();
}
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)
at _run10000 (node_modules/@jest/core/build/cli/index.js:408:7)
at runCLI (node_modules/@jest/core/build/cli/index.js:261:3)
● Test suite failed to run
TypeError: Cannot read property 'on' of undefined
40 |
41 | export async function closeDB() {
> 42 | await mockgoose.shutdown();
| ^
43 | await disconnect();
44 | }
45 |
at node_modules/mockgoose/built/mockgoose.js:55:54
at Mockgoose.Object.<anonymous>.Mockgoose.shutdown (node_modules/mockgoose/built/mockgoose.js:50:16)
at src/connect.ts:42:18
at step (src/connect.ts:33:23)
at Object.next (src/connect.ts:14:53)
at src/connect.ts:8:71
at Object.<anonymous>.__awaiter (src/connect.ts:4:12)
at closeDB (src/connect.ts:99:12)
at src/routes/users.spec.ts:12:16
at step (src/routes/users.spec.ts:33:23)
at Object.next (src/routes/users.spec.ts:14:53)
at src/routes/users.spec.ts:8:71
at Object.<anonymous>.__awaiter (src/routes/users.spec.ts:4:12)
at src/routes/users.spec.ts:11:11
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
问题似乎是,mockgoose 已被弃用,这导致它在 CircleCI 上 运行 时无法正常工作。一个解决方案是使用 mongodb-memory-server.
Warning: This package has been deprecated! Consider using mongodb-memory-server instead.
这部分解决了问题。我目前使用的唯一版本是在 package.json:
中使用以下内容
"config": {
"mongodbMemoryServer": {
"version": "4.2.3"
}
}
正在使用 Jest 测试 RESTful API(用 Express in TypeScript 编写)。测试在我的本地机器上成功运行 (windows),但似乎在 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',
},
};
测试如下
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: 'test@test.test',
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);
});
});
正在使用的连接函数在这里描述
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 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 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();
}
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)
at _run10000 (node_modules/@jest/core/build/cli/index.js:408:7)
at runCLI (node_modules/@jest/core/build/cli/index.js:261:3)
● Test suite failed to run
TypeError: Cannot read property 'on' of undefined
40 |
41 | export async function closeDB() {
> 42 | await mockgoose.shutdown();
| ^
43 | await disconnect();
44 | }
45 |
at node_modules/mockgoose/built/mockgoose.js:55:54
at Mockgoose.Object.<anonymous>.Mockgoose.shutdown (node_modules/mockgoose/built/mockgoose.js:50:16)
at src/connect.ts:42:18
at step (src/connect.ts:33:23)
at Object.next (src/connect.ts:14:53)
at src/connect.ts:8:71
at Object.<anonymous>.__awaiter (src/connect.ts:4:12)
at closeDB (src/connect.ts:99:12)
at src/routes/users.spec.ts:12:16
at step (src/routes/users.spec.ts:33:23)
at Object.next (src/routes/users.spec.ts:14:53)
at src/routes/users.spec.ts:8:71
at Object.<anonymous>.__awaiter (src/routes/users.spec.ts:4:12)
at src/routes/users.spec.ts:11:11
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
问题似乎是,mockgoose 已被弃用,这导致它在 CircleCI 上 运行 时无法正常工作。一个解决方案是使用 mongodb-memory-server.
Warning: This package has been deprecated! Consider using mongodb-memory-server instead.
这部分解决了问题。我目前使用的唯一版本是在 package.json:
中使用以下内容"config": {
"mongodbMemoryServer": {
"version": "4.2.3"
}
}