Express Jest 和 Supertest 如何用参数模拟中间件

The*_*o L 6 mocking node.js express supertest jestjs

我已经尝试了几个小时,用 Jest、Supertest 和 Express 测试我的 Rest api 的端点。

该端点受到名为“ ”的身份验证中间件的保护advancedAuthGuard

所以我试图模拟这个中间件,以便跳过端点测试的身份验证检查

//./router.js 
router.get('/route1', advancedAuthGuard(false), controller);
Run Code Online (Sandbox Code Playgroud)

重要:advancedAuthGuard是一个接受配置参数的中间件(柯里化中间件)

//./middleware/advancedAuthGuard.js
const advancedAuthGuard = (additionalCondition) => (req,res,next) => {

  //Check authentication logic ...
  const isAuth = true

  if (isAuth && !additionalCondition)
    next()
  else
    next(new Error('Please auth'))
}
Run Code Online (Sandbox Code Playgroud)

当我运行以下测试来检查是否收到状态代码 '200' 时。测试在运行前失败。

//./test.js
import supertest from "supertest"
import app from './app.js'
import { advancedAuthGuard } from "./middlewares/advancedAuthGuard";

jest.mock("./middlewares/advancedAuthGuard")

const request = supertest(app)

beforeEach(()=>{
  jest.clearAllMocks()
})

it("should '/route1' respond with 200 status", async ()=>{
  const mockedMiddleware = jest.fn().mockImplementation((res, req, next)=> next() )
  advancedAuthGuard.mockReturnValue(mockedMiddleware)
  const res = await request.get("/route1")
  expect(res.status).toEqual(200)
})
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

Test suite failed to run
Route.get() requires a callback function but got a [object Undefined]


> 10 | router.get('/route1', advancedAuthGuard(false), controller);
     |        ^

Run Code Online (Sandbox Code Playgroud)

因此我推断问题来自模拟......

当我通过 console.log 调试它时,我意识到我得到了一个不完整的模拟:

  • 我能够验证函数 ( advancedAuthGuard(false)) 的模拟是否存在
  • 但是这个模拟应该返回类型的第二个模拟function (req,res,next){},但是它只返回undefined

我还注意到:

  • 此模拟问题仅发生在柯里化中间件(带有输入参数的中间件)中
  • 仅当在 Express 路由器中执行柯里化中间件时,才会出现此模拟问题。(当我尝试模拟外部快速路由器时,模拟显示正确)

所以我想知道为什么我不可能用Jest 和 Supertest 模拟 Expressjs 端点中使用的柯里化中间件(带参数的中间件)。

这是一个 github 链接,其中包含最小的express、jest、supertest配置,您可以通过运行test.js文件来重现此问题。https://github.com/enzo-cora/jest-mock-middleware

har*_*rry 6

不知道为什么它不能按照您尝试的方式工作,但如果您将模拟实现传递给 autoMock 函数,它就会成功。

import supertest from "supertest";
import app from "./app";


jest.mock("./middlewares/simpleAuthGuard", () => ({
  simpleAuthGuard: (_, __, next) => next()
}));
jest.mock("./middlewares/advancedAuthGuard", () => ({
  advancedAuthGuard: () => (_, __, next) => next()
}));

const request = supertest(app);

describe('My tests', () => {
  beforeEach(() => jest.clearAllMocks());

  it("should '/route1' with advanced middleware work", async () => {
    const res = await request.get("/route1");
    expect(res.status).toEqual(200);
  });

  it("should '/route2' with simple middleware work", async () => {
    const res = await request.get("/route2")
    expect(res.status).toEqual(200)
  });
});

Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这至少可以验证测试。但是:但是,我需要能够通过各种测试来控制“advancedAuthGuard”的实现。(有时,我希望发送身份验证成功,有时我希望发送身份验证失败)在您的解决方案中,“advancedAuthGuard”对于所有测试都是相同的。所以我无法在我的测试套件中创建不同的身份验证结果场景。 (2认同)