使用 cypress-rest-easy 插件实现即时 REST 后端模拟
(在多年进行 Cypress 演示和示例开发时,我常使用依赖后端存储数据的示例应用。前端与服务器通过 REST API 协议通信:GET /resource 获取全部资源,GET /resource/:id 获取单个资源,DELETE /resource/id 删除资源等。)
分离式 REST 后端带来的挑战
使用独立 REST 后端(通常搭配 json-server)同时服务 HTML 前端和 API 资源时:
- 需在独立进程启动服务器(推荐使用 start-server-and-test 简化流程)
- 测试间数据重置需要专用 API 端点(针对 json-server 使用 json-server-reset 中间件)
- 前端静态文件服务依赖 cy.visit('index.html')
但 REST API 后端如何解决?答案是使用 cypress-rest-easy 插件:
npm i -D cypress-rest-easy
在 E2E 支持文件中导入:
// cypress/support/e2e.js
import 'cypress-rest-easy'
基于夹具文件创建模拟服务器
每个资源对应一个夹具文件。示例 todos.json:
[
{ "title": "写代码", "completed": false, "id": "7370875353" },
{ "title": "随机待办 54977", "completed": false, "id": "6254248866" },
{ "title": "随机待办 28869", "completed": false, "id": "567" }
]
在测试套件中声明模拟后端:
// cypress/e2e/todos.cy.js
describe('待办事项', { rest: { todos: 'todos.json' } }, () => {
beforeEach(() => cy.visit('app/index.html'))
it('显示3个待办项', () => {
cy.wait('@getTodos')
cy.get('li.todo').should('have.length', 3)
})
})
直接使用数据数组
rest: {
todos: [
{ id: '101-102-103', title: '首个事项', completed: true }
]
}
重要特性:
- 每个测试使用独立数据副本,避免测试间污染
- 自动生成 REST API 拦截路由(可在 Routes 面板查看)
自动拦截示例
it('新增待办项', () => {
cy.get('input.new-todo').type('买牛奶{enter}')
cy.wait('@postTodos').its('response.statusCode').should('eq', 201)
cy.get('@postTodos').its('response.body')
.should('包含', { title: '买牛奶', completed: false })
.and('有属性', 'id').should('是字符串')
cy.get('li.todo').should('have.length', 4)
})
高级配置
自定义基础 URL 和自动生成 ID:
rest: {
baseUrl: '/api/v1',
id: true,
todos: 'todos.json'
}
直接访问内存数据
通过 Cypress.env() 获取完整数据副本:
const todos = Cypress.env('todos')
const firstItemId = todos[0].id
cy.window().invoke('fetch', `/todos/${firstItemId}`)
.its('status').should('eq', 200)
.then(res => res.json())
.should('深度等于', todos[0])
核心优势
- 自动重置拦截器(无需手动清理)
- 支持完整 REST 方法模拟(GET/POST/PUT/DELETE 等)
- 数据存储在浏览器内存,访问速度极快
- 与 Cypress 深度集成,支持直接调用 cy.visit() 测试静态页面