如何在Cypress中Mock Vite项目的自定义TypeScript函数返回结果?
问题:如何在Cypress测试中Mock自定义TypeScript模块的方法?
我在本地环境创建了一个新的Vite TypeScript项目,项目入口代码如下:
import './style.css' import { add } from './calculator' document.querySelector<HTMLSpanElement>('#app')!.innerHTML = add(2, 3).toString()
同时新增了calculator.ts文件,包含add方法:
export function add(a: number, b: number): number { return a + b }
已安装Cypress 10.11.0,编写测试用例如下:
import * as calculator from "../../src/calculator"; describe('empty spec', () => { it('passes', () => { cy.visit('http://localhost:5173/', { onBeforeLoad() { cy.stub(calculator, 'add').returns(10) } }) }) })
测试结果:页面仍显示5,无法通过Stub让页面显示指定的10。尝试将stub放在onBeforeLoad之外,能Mockdocument.getElementById这类DOM函数,但无法对自定义脚本生效。
核心原因
你当前Stub的是测试文件中导入的calculator模块实例,而应用代码里导入的是另一个独立的模块实例,两者互不影响,所以Stub不会作用到应用代码上。
解决方案一:使用自定义命令拦截Vite模块请求
针对Vite的ES模块加载机制,我们可以通过拦截模块请求,替换为Mock版本:
- 在Cypress的
support/e2e.ts中添加自定义命令:
Cypress.Commands.add('mockModule', (modulePath: string, mockExports: Record<string, any>) => { // 转义模块路径中的特殊字符,适配正则匹配 const escapedPath = modulePath.replace(/\./g, '\\.') cy.intercept('GET', new RegExp(`${escapedPath}\\.ts`), (req) => { // 生成Mock模块的代码内容 const mockCode = Object.entries(mockExports).map(([key, value]) => { if (typeof value === 'function') { return `export const ${key} = ${value.toString()};` } return `export const ${key} = ${JSON.stringify(value)};` }).join('\n') req.reply(mockCode) }) })
- 修改测试用例,在访问页面前调用该命令:
describe('mock calculator add', () => { it('shows mocked value', () => { cy.mockModule('./calculator', { add: () => 10 }) cy.visit('http://localhost:5173/') cy.get('#app').should('have.text', '10') }) })
解决方案二:将模块挂载到window对象(更轻量化)
如果项目允许,可以在应用代码中将模块暴露到全局:
// src/main.ts import './style.css' import * as calculator from './calculator' // 仅在开发/测试环境暴露,避免生产环境污染全局 if (import.meta.env.DEV) { (window as any).calculator = calculator } document.querySelector<HTMLSpanElement>('#app')!.innerHTML = calculator.add(2, 3).toString()
然后在测试中通过window访问并Stub:
describe('mock calculator add', () => { it('shows mocked value', () => { cy.visit('http://localhost:5173/', { onBeforeLoad(win) { cy.stub(win.calculator, 'add').returns(10) } }) cy.get('#app').should('have.text', '10') }) })
内容的提问来源于stack exchange,提问作者Tomas Baranauskas
相关产品推荐
相关产品推荐

