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

Jest测试Node-postgres错误处理中间件遇undefined问题排查

404路径测试失败:body.message返回undefined的排查

问题背景

刚接触Jest错误处理测试,基于鸟类PostgreSQL数据库开发接口,测试未匹配路径的404响应时,测试用例因body.message返回undefined而失败。

测试代码(app.test.js)

const request = require("supertest")
const db = require("../db/index.js")
const {wing_shapeData,birdsOrdersData,birdsFamiliesData,birdsData,birdwatchersData,rookeryTourData,watcherTourData} = require("../db/data/test-data/index.js")
const seed = require("../db/seed.js")
const app = require("../app.js")

beforeEach(() => seed({wing_shapeData,birdsOrdersData,birdsFamiliesData,birdsData,birdwatchersData,rookeryTourData,watcherTourData}))

afterAll(() => db.end())


describe("Endpoint(path) is not recognized and cannot be found for rookery",()=>{

    it("Should return status code 404 when passed bad path",()=>{
        return request(app).get('/api/fjrofjiro303gjvn200').expect(404).then(({ body }) => {
            expect(body.msg).toBe('HTTP 404 error: path cannot be found');
          });
    })
})

终端错误输出

__tests__/app.test.js
  Endpoint(path) is not recognized and cannot be found for rookery
    ✕ Should return status code 404 when passed bad path (96 ms)

  ● Endpoint(path) is not recognized and cannot be found for rookery › Should return status code 404 when passed bad path

    expect(received).toBe(expected) // Object.is equality

    Expected: "HTTP 404 error: path cannot be found"
    Received: undefined

      14 |     it("Should return status code 404 when passed bad path",()=>{
      15 |         return request(app).get('/api/fjrofjiro303gjvn200').expect(404).then(({ body }) => {
    > 16 |             expect(body.message).toBe('HTTP 404 error: path cannot be found');
         |                                  ^
      17 |           });
      18 |     })
      19 | })

      at toBe (__tests__/app.test.js:16:34)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        0.337 s, estimated 1 s
Ran all test suites matching /app.test.js/i.

相关业务代码

app.js

const express = require('express');
const app = express();
app.use(express.json())

app.use((req, res, next) => {
    console.log('Request method: ', req.method);
    console.log('Request url: ', req.url);
    let currentdate = new Date(); 
    let datetime = `Date and time request method made(format:day/month/year|hours:minutes:seconds): ${currentdate.getDate()}/${(currentdate.getMonth()+1)}/${currentdate.getFullYear()}|${currentdate.getHours()}:${currentdate.getMinutes()}:${currentdate.getSeconds()}`
    console.log(datetime)
    next()
  });

const errorLogger = (err,req,res,next) =>{
    console.log(`Error : ${err.message}`)
    next(err)
}

const handleNotFound = (req,res,next)=>{   
    res.status(404).send({message: 'HTTP 404 error: path cannot be found'})
    next()
}
const errorResponder = (err,req,res,next) =>{
    if(err.statusCode  && err.message){
        res.status(err.statusCode).send({message: err.message})
    }
    next(err)
}

const handleServerError = (err, req,res,next) => {
    res.status(500).send(err.message)
}

app.use(errorLogger)
app.use(handleNotFound)
app.use(errorResponder)
app.use(handleServerError)

app.get('/api/birds',getAllBirds)

birds.controller.js

exports.getAllBirds = (req,res,next) =>{
 const {order1} = req.query
 const {order2} = req.query
 const {sort_byfirst} = req.query
 const {sort_bysecond} = req.query
 const {diet} = req.query
 selectAllBirds(sort_byfirst,order1,diet,sort_bysecond,order2).then((birds)=> res.status(200).send({birds})).catch(next)
}

birds.models.js

const db = require('../db/index.js')

exports.selectAllBirds = (sort_byfirst,order1,diet,sort_bysecond,order2) =>{
    const sortbyGreenList1 = ['length_cm','weight_g','wingspan_cm']
    const sortbyGreenList2 = ['common_name']
    const orderbyGreenList = ['ASC','DESC']
    let queryValues = [];
    let queryStr = `SELECT bird_id,common_name,species_name,wing_colour,diet,can_Fly
    ,length_cm,weight_g,lay_season,fun_fact,wingspan_cm,f_id FROM birds
     INNER JOIN bird_families ON birds.f_id = bird_families.family_id`;

    if(sort_byfirst && !sortbyGreenList1.includes(sort_byfirst)){
        return Promise.reject({status: 400, message: 'Invalid sort_byfirst query string'})
    }
    if(sort_bysecond && !sortbyGreenList2.includes(sort_bysecond)){
        return Promise.reject({status: 400, message: 'Invalid sort_bysecond query string'})
    }
    if(order1 && !orderbyGreenList.includes(order1.toUpperCase())){
        return Promise.reject({status: 400, message: 'Invalid order1 query string'})
    }
    if(order2 && !orderbyGreenList.includes(order2.toUpperCase())){
        return Promise.reject({status: 400, message: 'Invalid order2 query string'})
    }
   
    if(diet){
        queryValues.push(`%${diet}%`)
        queryStr += ` WHERE diet ILIKE $1`;
    }
    if(sort_byfirst){
        queryStr += ` ORDER BY ${sort_byfirst}`;  
    }
    if(order1 && sort_byfirst){
        queryStr += ` ${order1.toUpperCase()}`;
    }
    if(order2 && sort_bysecond && sort_byfirst){
        queryStr += `, ${sort_bysecond} ${order2.toUpperCase()}`;
    }

    return db.query(queryStr,queryValues).then((result)=>{
        if(!(result.rows.length)){
            return Promise.reject({status: 404, err: 'No results found for query'})
        }else{
            return result.rows
        }
    })
}

问题原因分析

  1. 中间件顺序错误:handleNotFound是处理未匹配路由的中间件,必须放在所有路由定义之后。当前它在app.get('/api/birds')之前,导致所有请求(包括合法路由)都会先进入这个中间件,发送404响应后还调用next(),后续中间件会继续处理,可能导致响应被覆盖或异常。
  2. 断言字段不匹配:测试代码里写的是expect(body.msg).toBe(...),但实际响应返回的是{message: ...},错误信息里显示你又把断言改成了expect(body.message),字段名不一致同时中间件顺序错误导致响应未正确返回。
  3. 不必要的next()调用:handleNotFound里发送响应后调用next()是错误的,响应已经发送完毕,再传递给下一个中间件会导致Express报错,破坏响应结构。

修复方案

1. 调整中间件顺序

把路由定义放在错误处理中间件之前,handleNotFound放在最后:

// 先定义所有路由
app.get('/api/birds',getAllBirds)

// 再挂载错误处理中间件
app.use(errorLogger)
app.use(handleNotFound)
app.use(errorResponder)
app.use(handleServerError)

2. 修正断言与响应字段的一致性

要么修改测试代码的断言:

expect(body.message).toBe('HTTP 404 error: path cannot be found');

要么修改handleNotFound的返回字段:

res.status(404).send({msg: 'HTTP 404 error: path cannot be found'})

3. 移除handleNotFound中的next()

const handleNotFound = (req,res,next)=>{   
    res.status(404).send({message: 'HTTP 404 error: path cannot be found'})
    // 移除next(),响应已发送,无需继续传递
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 05:55:55