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

Angular+Express+Node单仓中测试服务器响应Mock失败求助

Angular+Express+Node单仓项目服务器单元测试断言失败问题

我有一个基于Angular、Express、Node的单仓(monorepo)项目,测试套件运行和覆盖率报告均正常,但在为主服务器文件index.ts编写单元测试时,第一个断言就失败了。

我猜测问题源于服务器存在全匹配路由,会为任意请求返回Angular应用的index文件,但该文件在测试阶段并不存在——它是前端构建时生成的。我将发送逻辑抽离为sendAngularApp函数,计划在Jasmine中对其进行Mock,但始终无法实现。

测试文件 index.spec.ts

import * as request from 'supertest';
import * as express from 'express';

import { setupApp, sendAngularApp } from './index'; 

describe('Express server', () => {
  let app: express.Application;
  process.env.NODE_ENV = 'production';
  process.env.SERVER_PORT = '9200';
  var server: any;

  beforeEach(() => {
    app = setupApp(); // 使用辅助函数初始化Express应用
    // 保存原始sendFile方法并替换为模拟实现
    server = app.listen(process.env.SERVER_PORT || 3000, () => {
      console.log('Express server is running on ' + (process.env.SERVER_PORT || 3000))
    });
  });

  afterEach(() => {
    server.close();
  });

  describe('GET /', function() {
    it('根路径返回index文件', async () => {
      const response = await request(app).get('/');
      expect(response.status).toBe(200);
      expect(response.headers['content-type']).toBe('text/html; charset=UTF-8');
    });
  });
});

服务器文件 index.ts

import * as path from "path";
import * as express from 'express';
import { Request, Response, NextFunction } from 'express';
import * as pino from 'express-pino-logger';
import config from './config/environment';
import rateLimit from 'express-rate-limit';
import apiRouter from './routes/api';

declare global {
  var cache: {
    [resource: string]: {
      time: Date,
      data: any,
    }
  };
}
global.cache = {};

export function sendAngularApp(req: Request, res: Response) {
  res.sendFile(path.join(__dirname, 'client/dist/angular-boilerplate', 'index.html'));
}

export function setupApp(): express.Application {
  const app = express();

  const logger = pino();
  app.use(logger); // 日志框架
  
  app.use(express.json());
  
  const apiLimiter = rateLimit({
    windowMs: 10 * 60 * 1000, // 10分钟窗口
    max: 2000, // 每个IP在窗口内最多请求2000次
    standardHeaders: true, // 在`RateLimit-*`头中返回限流信息
    legacyHeaders: false, // 禁用`X-RateLimit-*`头
  });
  
  app.use((req: Request, res: Response, next: NextFunction) => {
    console.log('Time:', Date.now());
    next();
  });
  app.use('/api', apiLimiter);
  app.use('/api', apiRouter);
  
  if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'staging' || process.env.NODE_ENV === 'development') {
    // 托管静态文件
    let dirname = __dirname.replace("/server", "")
    app.use(express.static(path.join(dirname, 'client/dist/angular-boilerplate'),{maxAge:3600000}));
  
    // 处理应用路由,所有请求返回Angular应用
    app.get('*', sendAngularApp);
  }
  return app;
}

if (require.main === module) {
  const app = setupApp();
  app.listen(config.server_port || 3000, () => {
    console.log('Express server is running on ' + (config.server_port || 3000))
  });
}

已尝试的方法

  • 参考AI工具的Mock建议,但大多默认使用Jest,针对Jasmine或Sinon spies的有效指导极少
  • 个人更偏好Jest,但前端已使用Jasmine,引入两种测试框架感觉不协调
  • AI建议中常默认index.ts为模块,提到调用index.sendAngularApp,但对Node模块机制不熟悉,不清楚是否需要转换文件结构及具体操作方式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:55:07