You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jest、Mongoose和MongoMemoryServer测试时触发栈溢出错误

Jest测试Express应用时MongoDB栈溢出错误解决

错误信息

FAIL  src/routes/__test__/signUp.test.ts
  ● Test suite failed to run

    RangeError: Maximum call stack size exceeded

      at Object.get [as ObjectId] (node_modules/mongodb/src/bson.ts:39:3)
      at Object.get [as ObjectId] (node_modules/mongodb/src/bson.ts:39:3)
      at Object.get [as ObjectId] (node_modules/mongodb/src/bson.ts:39:3)

测试代码

import request from 'supertest';
import { app } from 'app';

it('Returns a 201 on successful signup', async () => {
  return request(app)
    .post('/api/users/signup')
    .send({
      email: 'test@test.com',
      password: 'password',
    })
    .expect(201);
});

测试配置代码

import mongoose from 'mongoose';
import { MongoMemoryServer } from 'mongodb-memory-server';

let mongo: MongoMemoryServer;

beforeAll(async () => {
  process.env.JWT_KEY = 'whateverfornow';

  mongo = await MongoMemoryServer.create();
  const mongoUri = mongo.getUri();

  await mongoose.connect(mongoUri, {});
});

beforeEach(async () => {
  const collections = await mongoose.connection.db.collections();

  for (let collection of collections) {
    await collection.deleteMany({});
  }
});

afterAll(async () => {
  if (mongo) {
    await mongo.stop();
  }

  await mongoose.connection.close();
});

问题分析与解决方案

这个栈溢出错误是由于ObjectId的getter方法无限递归导致的,通常和依赖版本不兼容、测试配置中的集合操作触发循环引用有关,可按以下步骤解决:

1. 对齐依赖版本

检查package.json中的依赖版本,确保:

  • mongoose与mongodb版本兼容(mongoose的peer依赖会指定mongodb的兼容范围)
  • mongodb-memory-server版本支持当前使用的mongodb版本

比如,若使用mongoose 7.x,需确保mongodb版本在4.7.x以上,mongodb-memory-server至少为8.x版本。

2. 修改集合清理逻辑

原配置中直接调用mongoose.connection.db.collections()可能在某些版本组合下触发bson相关的循环引用,改用以下两种方式之一:

方式一:通过listCollections获取集合并删除

beforeEach(async () => {
  const collections = await mongoose.connection.db.listCollections().toArray();
  for (const collection of collections) {
    await mongoose.connection.db.dropCollection(collection.name);
  }
});

方式二:通过mongoose模型清理数据

beforeEach(async () => {
  await Promise.all(Object.values(mongoose.models).map(model => model.deleteMany({})));
});

3. 手动绑定ObjectId(可选)

若版本调整后仍有问题,可手动指定ObjectId避免循环引用:

import mongoose from 'mongoose';
import { MongoMemoryServer } from 'mongodb-memory-server';
import { ObjectId } from 'mongodb';

// 手动绑定ObjectId
mongoose.Types.ObjectId = ObjectId;

let mongo: MongoMemoryServer;

// 后续配置代码不变...

内容的提问来源于stack exchange,提问作者Vladyslav Makarenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 08:30:47