用于身份验证的异步中间件的开玩笑测试

Jest testing of async middleware for authentication

在使用实际的 postgres 数据库和一些 fetch()-ing 代码进行重构之前,我使用静态数组来构建用户 table。目前,测试工作正常,但显然它们是同步工作的。这是占位符 API 代码:

    // UserAPI.js
    let findUserById = (credentials = {}) => {
      const { userId } = credentials
    
      if (userId) {
        const foundUser = users.find(user => user.id === userId)
        if (foundUser !== undefined) {
          const { password: storedpassword, ...user } = foundUser
          return user
        }
      }
      return null
    }
    exports.byId = findUserById

并举例测试如下:

    // excerpt from TokenAuth.test.js
    const UserAPI = require('../lib/UserAPI')
    
    describe('With TokenAuth middleware', () => {
      beforeEach(() => {
        setStatus(0)
      })
    
      it('should add user to req on authorised requests', () => {
        const token = createToken(fakeUser)
        const authReq = { headers: { authorization: 'Bearer ' + token } }
        const myMiddleware = TokenAuth(UserAPI.byId)
        myMiddleware(authReq, fakeRes, fakeNext)
    
        // expect(authReq.user).toStrictEqual({ id: 1, username: 'smith@example.com' });
        expect(authReq.user.username).toStrictEqual('smith@example.com')
        expect(authReq.user.id).toStrictEqual(1)
      })
    })

这 运行 没问题,连同其他测试提供了我想要的覆盖范围。但是,我现在想检查测试是否会处理我将用于正确 UserAPI.js 文件的 fetch() 代码的 async/await 性质。所以我将占位符代码重写为:

    // UserAPI.js with added async/await pauses ;-)
    let findUserById = async (credentials = {}) => {
      const { userId } = credentials
    
      // simulate url resolution
      await new Promise(resolve => setTimeout(() => resolve(), 100)) // avoid jest open handle error
    
      if (userId) {
        const foundUser = users.find(user => user.id === userId)
        if (foundUser !== undefined) {
          const { password: storedpassword, ...user } = foundUser
          return user
        }
      }
      return null
    }
    exports.byId = findUserById

...此时我开始遇到一些可爱的失败,因为我认为它正在返回未解决的承诺。

我的问题有两个:

  1. 我应该如何更改 UserAPI.test.js 测试以应对 findUserByCredentials() 的新 async 性质?

  2. 我认为 ExpressJS 对异步函数作为请求处理程序感到满意吗?具体来说,由于 UserAPI.findUserByCredentialsasync 性质,这样可以吗?

Main App.js 使用 curried UserAPI.byId() 作为 findUserById.

    // App.js (massively simplified)
    const express = require('express')
    const TokenAuth = require('./middleware/TokenAuth')
    const RequireAuth = require('./middleware/RequireAuth')
    const UserAPI = require('./lib/UserAPI')
    
    let router = express.Router()
    const app = express()
    
    app.use(TokenAuth(UserAPI.byId))
    app.use(RequireAuth)
    app.use('/users', UserRouter)
    module.exports = app

我的 TokenAuth 中间件现在会 运行 按照这些行:

    // TokenAuth.js (simplified)
    const jwt = require('jsonwebtoken')
    require('dotenv').config()
    const signature = process.env.SIGNATURE
    
    let TokenAuth = findUserById => async (req, res, next) => {
      let header = req.headers.authorization || ''
      let [type, token] = header.split(' ')
      if (type === 'Bearer') {
        let payload
        try {
          payload = jwt.verify(token, signature)
        } catch (err) {
          res.sendStatus(401)
          return
        }
    
        let user = await findUserById(payload)
        if (user) {
          req.user = user
        } else {
          res.sendStatus(401)
          return
        }
      }
    
      next()
    }
    
    module.exports = TokenAuth

部分回答我们只是在 middleware 调用中添加一个 async/await:

  it('should add user to req on authorised requests', async () => {
    const token = createToken(fakeUser)
    const authReq = { headers: { authorization: 'Bearer ' + token } }
    const myMiddleware = TokenAuth(UserAPI.byId)
    await myMiddleware(authReq, fakeRes, fakeNext)

    // expect(authReq.user).toStrictEqual({ id: 1, username: 'smith@example.com' });
    expect(authReq.user.username).toStrictEqual('smith@example.com')
    expect(authReq.user.id).toStrictEqual(1)
  })