如何为经过身份验证的Express端点编写Jest测试?

x6yk4ghg  于 12个月前  发布在  Jest
关注(0)|答案(2)|浏览(170)

bounty已结束。回答此问题有资格获得+300声望奖励。奖励宽限期将在4小时后结束。Dycey正在寻找一个规范答案:各种框架都有很多方法,但我似乎找不到任何简单的方法。我真的很想了解这个过程。

我有一个简单的“普通”4文件玩具解决方案。我想为bingo.js认证路由'/'编写一个Jest测试。以下是显示完整设置的四个文件。

  • index.js,Express应用根目录
  • routes/auth.js,一个简单的身份验证POST端点,用于检查用户
  • routes/bingo.js,需要对用户进行身份验证的端点,以及
  • middleware/authentication.js,一个简单的中间件,用于检查会话用户

我正在绞尽脑汁,试图弄清楚如何为bingo.js端点编写单元测试,而不必通过index.js运行整个应用程序-我不需要完整的端到端测试,这就是Cypress测试的目的。
我试着找到只调用auth步骤的方法,我试着模拟会话,我试着弄清楚如何在Supertest上设置会话。
拜托,至少有人能给我指个路吧?

index.js

// index.js

const express = require("express");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const app = express();

const bingoRouter = require("./routes/bingo");
const authRouter = require("./routes/auth");

// middleware
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());

app.use(
  session({
    cookie: { maxAge: 300000 },
    store: new session.MemoryStore(),
    saveUninitialized: true,
    resave: "true",
    secret: "our_really_secret_key",
  })
);

app.use("/bingo", bingoRouter);
app.use("/auth", authRouter);

app.use((req, res) => {
  return res.status(404).json({
    error: "Not Found",
  });
});

app.listen(port);

module.exports = app;

字符串

auth.js

// routes/auth.js
const express = require("express");
const router = express.Router();
const jwt = require("jsonwebtoken");
const secretKey = "our_really_secret_key";

// Authenticate user
router.post("/login", async (req, res) => {
  const { username, password } = req.body;
  const user = { username: "username", password: "password", is_admin: true };
  if (user && user.password === "password") {
    req.session.user = user;
    res.redirect("/bingo");
  } else {
    res.render("auth", { error: "Invalid username or password" });
  }
});

bingo.js

// routes/bingo
const { isAdmin } = require("../middleware/authentication");
const express = require("express");
const router = express.Router();

router.use(isAdmin);

router.get("/", async function (req, res) {
  res.render("bingo", {
    user: req.session.user,
  });
});

module.exports = router;

authentication.js

// middleware/authentication.js
exports.isAdmin = (req, res, next) => {
  if (req.session.user && req.session.user.is_admin) {
    // User is authenticated & admin, allow access to route
    next();
  } else {
    // User is not authenticated or not admin, redirect to login page
    res.redirect("/auth");
  }
};

wyyhbhjk

wyyhbhjk1#

正如morganney在评论中提到的,Nock并不适合您的任务。
它是为HTTP服务器模拟和预期而设计的,主要用于通过拦截传出的HTTP请求并提供编程响应来测试外部服务调用。
虽然它可以用于模拟来自外部服务的响应,但它不能用于Express应用程序中的内部中间件测试,而这正是您所需要的。
您有一个经过身份验证的Express端点:

Client ---> [Express App]
                |
                |-> /auth ---> [Auth Middleware] ---> /bingo
                |
                |-> /bingo ---> [Bingo Router]

字符串
您可以使用supertest向Express应用发出请求并使用jest模拟函数或模块来测试它(Jest中的已验证端点)。如果您有身份验证中间件,则通常会模拟会话或中间件来模拟登录用户。
另请参阅Francisco Mendes的介绍“Testing Express Api with Jest and Supertest“。
由于您希望隔离测试bingo.js端点,因此不需要通过auth.js路由进行身份验证。相反,您可以直接mockisAdmin中间件,以便始终调用next(),就像用户通过身份验证一样。

+--------+      +---------------+      +--------------+      +-------------+
| Client | ---> | Express App   | ---> | isAdmin Mock | ---> | Bingo Route |
+--------+      +---------------+      +--------------+      | (Jest Test) |
                                                             +-------------+


如上所述,使用supertestbingo.js路由发送请求。在测试中,在导入路由器之前模拟isAdmin中间件。
bingo.test.js

const request = require('supertest');
const app = require('../index'); // Import your Express app
const { isAdmin } = require('../middleware/authentication');

// Mock the isAdmin middleware
jest.mock('../middleware/authentication', () => ({
  isAdmin: (req, res, next) => next(),
}));

describe('GET /bingo', () => {
  it('should allow access to an authenticated user', async () => {
    // Set up the mock session or user here if necessary
    
    const response = await request(app).get('/bingo');
    expect(response.statusCode).toBe(200);
    expect(response.body).toHaveProperty('user');
  });
});


这将假定isAdmin是访问/bingo需要传递的唯一中间件。如果有更多中间件层需要mocking,则使用类似的方法。
确保使用--runInBand标志运行Jest测试,以避免会话处理和并发性问题。
如何设置mocking函数来测试未验证的用户是否被重定向?
如何向请求中添加经过身份验证的用户,即将req.session.user设置为已知对象?
要设置一个将req.session.user设置为已知对象的测试,您可以模拟authentication中间件来将用户添加到req.session
您的项目看起来像:

project-root/
│
├── index.js
├── package.json
│
├── routes/
│   ├── auth.js
│   └── bingo.js
│
├── middleware/
│   └── authentication.js
│
└── __tests__/
    └── bingo.test.js  <-- Mock session setup here


bingo.test.js是:

const request = require('supertest');
const app = require('../index'); // Import your Express app

// Mock the session to include an authenticated user
const mockSession = {
  user: {
    username: "authenticatedUser",
    is_admin: true
  }
};

app.use((req, res, next) => {
  req.session = mockSession; // Your mock session object
  next();
});

describe('GET /bingo', () => {
  it('should render bingo for authenticated users', async () => {
    const response = await request(app).get('/bingo');
    expect(response.statusCode).toBe(200);
  });
});


在任何路由处理之前,mockSession被直接注入到req.session中,这应该有效地模拟经过身份验证的用户的会话。
这样,当访问/bingo路由时,req.session.user将被设置为用户已经通过身份验证。

wljmcqd8

wljmcqd82#

要使用Jest和Supertest对bingo.js端点进行单元测试,您可以模拟isAdmin中间件。这种方法允许您模拟经过身份验证的用户,而无需执行实际的身份验证过程。以下是您的操作方法:
1.**模拟isAdmin中间件:**通过模拟isAdmin中间件,您可以绕过身份验证检查,直接测试您的bingo.js路由的行为。模拟将始终调用next(),模拟通过身份验证的用户。
1.测试设置示例:

const request = require('supertest');
const app = require('../index'); // Import your Express app
const { isAdmin } = require('../middleware/authentication');

// Mock the isAdmin middleware
jest.mock('../middleware/authentication', () => ({
  isAdmin: (req, res, next) => next(),
}));

describe('GET /bingo', () => {
  it('should allow access to an authenticated user', async () => {
    const response = await request(app).get('/bingo');
    expect(response.statusCode).toBe(200);
    // Add more assertions as needed
  });
});

字符串
此测试检查经过身份验证的用户是否可以访问/bingo路由。
1.**测试未经身份验证的访问:**要测试未经身份验证的用户的行为,请修改isAdmin的mock以模拟身份验证失败,例如,通过重定向到登录页面。
1.**添加已知用户:**如果您需要在会话中使用特定的用户对象进行测试,可以修改mock添加req.session.user对象。
1.**运行测试:**确保使用--runInBand标志运行Jest测试,以避免会话处理和并发问题。
这种方法将重点放在孤立的bingo.js路由上,对于不需要测试整个应用程序流的单元测试场景非常理想。

相关问题