Next.js+Cypress环境下Nock无法拦截请求的问题及方案咨询
问题描述
部分页面通过getInitialProps在服务端调用外部接口,CI/CD环境无法访问该外部接口,需要Mock。尝试集中配置Mock服务避免重复初始化:
- 在
cypress.config.ts的e2e配置中添加before:run事件,代码如下:
on('before:run', async (details) => await nock(/.*?(localhost:4000|{_another_endpoints_regex_here}).*?/) .get('/api/') .reply(200, {data:"data"}) })
- 使用正则匹配不同环境URL,已启用
experimentalInteractiveRunEvents标志,事件日志可正常打印,代码移至页面中也能正常工作,但测试中Next.js的请求仍未被Mock,报错:
data: { message: 'request to http://localhost:4000/api/ failed, reason: connect ECONNREFUSED 127.0.0.1:4000', type: 'system', errno: 'ECONNREFUSED', code: 'ECONNREFUSED' }
- 后续尝试MSW,将代码移至
support/e2e.ts的beforeEach钩子中仍未解决。排查发现当前用start-server-and-test包启动项目并执行Cypress测试,导致Cypress与Next.js处于不同Node实例,Nock无法生效。
解决方案:不使用
start-server-and-test同时运行Cypress与Next.js 方式一:用npm脚本并行运行
借助concurrently和wait-on包实现并行启动,先安装依赖:
npm install concurrently wait-on --save-dev
然后在package.json中配置脚本:
{ "scripts": { "dev": "next dev", "cypress:open": "cypress open", "test:e2e": "concurrently \"npm run dev\" \"wait-on http://localhost:3000 && npm run cypress:open\"" } }
concurrently负责同时执行Next.js启动命令和Cypress启动命令wait-on会等待Next.js服务器(默认端口3000,可按需修改)完全启动后,再触发Cypress启动,避免Cypress因提前运行找不到服务
方式二:在Cypress配置中直接启动Next.js服务器
修改cypress.config.ts,在Node事件钩子中启动/关闭Next.js服务器,无需额外依赖:
import { defineConfig } from 'cypress' import { startServer } from 'next/dist/server/lib/start-server' let server: any export default defineConfig({ e2e: { setupNodeEvents(on, config) { on('before:run', async () => { // 启动Next.js开发服务器,指定运行端口 server = await startServer({ dir: process.cwd(), port: 3000, isDev: true, }) }) on('after:run', async () => { // 测试全部结束后关闭服务器 await server.close() }) }, baseUrl: 'http://localhost:3000', }, })
这种方式下,Cypress与Next.js处于同一个Node实例,Nock或MSW的Mock配置能正常作用于服务端请求。
额外注意事项
- 若用Nock做服务端Mock,要确保Mock代码在Next.js所在的Node实例中执行(比如上述方式二的
before:run钩子,或Next.js的自定义服务器文件) - 若使用MSW,需将MSW的服务端Mock逻辑注入到Next.js的服务端上下文,比如在
pages/_app.tsx或自定义server.ts中初始化MSW服务
内容的提问来源于stack exchange,提问作者Frankusky
相关产品推荐
相关产品推荐

