Cypress系列(69)- route() 命令详解

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Cypress系列(69)- route() 命令详解

如果想从头学起Cypress,可以看下面的系列文章哦

https://www.cnblogs.com/poloyy/category/1768839.html

 

前言


  • Cypress 6.0.0 开始不推荐使用 cy.server()cy.route()
  • 在将来的版本中,对 cy.server()cy.route() 的支持将移至插件
  • 现在优先考虑使用 cy.intercept()

 

作用


管理控制整个网络请求

 

重要注意事项


Cypress 目前仅支持拦截 XMLHttpRequest(XHR)

可在开发者工具(network 一栏)看到请求的 type 是 xhr,或者直接点击 xhr 进行筛选

image.png

同样是 login 请求,有些是 xhr,有些却是 document,对于 type=document 的请求, .route() 默认是不会拦截到的

 

非 XHR 请求

使用 Fetch API 的请求以及其他类型的网络请求(例如页面加载和 <script> 标记)将不会在命令日志中被拦截或看到

 

语法格式


cy.route(url)
cy.route(url, response)
cy.route(method, url)
cy.route(method, url, response)
cy.route(callbackFn)
cy.route(options)

参数说明

url

需要监听的 URL,遵循 minimatch 模式

 

response

为匹配上的 URL 提供自定义响应体

 

method

待匹配监听 URL 的请求方法

 

callbackFn

回调函数

 

options

image.png

通俗理解的总结

  • 当发出请求的 url + method 匹配上路由的 url + method,就会被该路由监听到
  • 简单理解:response 是自定义响应体,status 是自定义响应状态码,headers 是自定义响应头
  • 如果设置了 response、status、headers 参数,则被监听到的请求会获取到这三个参数

 

 

命令执行结果

  • 执行结果是 null
  • 且后续不能再链接其他命令

 

URL minimatch 的栗子


前言

可以通过 *、** 来匹配动态的路由,咱们直接看栗子就好了

 

栗子一

cy.server()
cy.route('**/users/*/comments')
// https://localhost:7777/users/123/comments     <-- 匹配
// https://localhost:7777/users/123/comments/465 <-- 不匹配

栗子二

cy.server()
cy.route('**/posts/**')
// https://localhost:7777/posts/1            <-- 匹配
// https://localhost:7777/posts/foo/bar/baz  <-- 匹配
// https://localhost:7777/posts/quuz?a=b&1=2 <-- 匹配
// https://localhost:7777/posts <-- 不匹配

栗子三

cy.route('**/users/*')
// 下面的都匹配
/users/1
http://localhost:2020/users/2
https://google.com/users/3
// 下面的都不匹配
/users/4/foo
http://localhost:2020/users/5/foo


实际栗子


进入演示项目目录下

注:演示项目是 cypress 提供的,如何下载可看 Cypress 系列文章的一开始几篇都有写

cd C:\Users\user\Desktop\py\cypress-example-recipes\examples\logging-in__xhr-web-forms

 

启动演示项目

npm start

 

浏览器访问项目

http://localhost:7079/

 

测试代码

    const username = 'jane.lane'
    const password = 'password123'
    before(function () {
        cy.visit('http://localhost:7079/')
    })
    it('正常登录,修改登录请求的status、response', function () {
        cy.server()
        cy.route({
            url: '**/login',
            method: 'POST',
            status: 503,
            delay: 1000,
            response: {
                success: false,
                data: 'Not success'
            },
        }).as("login")
        cy.get("input[name=username]").type(username)
        cy.get("input[name=password]").type(`${password}{enter}`)
        cy.wait('@login').then((res) => {
            cy.log(res)
            expect(res.status).to.eq(503)
            expect(res.responseBody.data).to.eq('Not success')
        })
    });


image.png

查看 route 路由的日志

  • 每当启动服务器( cy.server() )并添加路由( cy.route() )时,Cypress 都会显示一个名为 ROUTES(n)的新模块日志
  • 它将在日志中列出路由表,包括方法,URL,是否Stubbed,别名和成功匹配请求的数量

image.png

可以看到成功匹配一个请求

 

查看 XHR 命令日志

image.png

  • 当发出 XHR 请求后,Cypress 会记录此请求是否匹配到某个路由的别名
  • 这里的 /login 请求就匹配到了 @login

 

console 查看响应结果

image.png

如果要对响应体做断言,可以从这对象里面拿到对应的值

 

重点一

Cypress 通过 cy.route().as()cy.wait() ,可以自动等到接口返回以后再执行后续操作,增强了测试用例的健壮性

// 简单的代码结构(仅演示)
// 启动 Mock 服务器
cy.server({
    // 添加 options...        
})
// 添加多个 route 路由
cy.route({
    // 添加 options...       
}).as("route1")
cy.route({
    // 添加 options...       
}).as("route2")
....
// UI 界面的操作...
// 某些操作发出请求
// 等待请求的完成
cy.wait('route1').then((res)=>{
    // 对接口的响应做后续操作或断言
    expect(res.status).to.eq(200)
})


重点二

指定了 status 参数之后,也必须指定 response 参数

 

强制返回 404 的栗子


不匹配路由的请求,强制返回 404 状态和空 response

测试代码

 cy.server({ force404: true })
        cy.route({
            url: '**/logins',
            method: 'POST',
            status: 503,
            delay: 1000,
            response: {
                success: false,
                data: 'Not success'
            },
        }).as("login")
// 伪代码
// 发出 /login 请求的操作


image.png

官方的栗子


    it('cy.route() - route responses to matching requests', () => {
        // https://on.cypress.io/route
        // 访问
        cy.visit('https://example.cypress.io/commands/network-requests')
        // 预置变量
        let message = 'whoa, this comment does not exist'
        // 启动 Mock 服务器
        cy.server()
        // 路由1:监听 url 是 comments/* 且 请求方法是 GET 的请求
        cy.route('GET', 'comments/*').as('getComment')
        // 点击按钮触发请求
        cy.get('.network-btn').click()
        // 等待请求响应成功后获取 status 进行断言
        cy.wait('@getComment').its('status').should('eq', 200)
        // 路由2:监听 url 是 /commets 且 请求方法是 POST 的请求
        cy.route('POST', '/comments').as('postComment')
        // 点击按钮触发请求
        cy.get('.network-post').click()
        // 等待请求响应成功后进行断言
        cy.wait('@postComment').should((xhr) => {
            expect(xhr.requestBody).to.include('email')
            expect(xhr.requestHeaders).to.have.property('Content-Type')
            expect(xhr.responseBody).to.have.property('name', 'Using POST in cy.route()')
        })
        /*
        路由3:监听 url 是 comments/* 且 请求方法是 POST 的请求
        自定义 status、response、delay 并返回给监听到的请求
         */
        cy.route({
            method: 'PUT',
            url: 'comments/*',
            status: 503,
            response: {error: message},
            delay: 500,
        }).as('putComment')
        // // 等待请求响应成功后进行断言
        cy.get('.network-put').click()
        cy.wait('@putComment')
        // 出现 404 之后断言文案
        cy.get('.network-put-comment').should('contain', message)
    })


注意事项


了解存根与常规XHR

Cypress 会在命令日志中显示 XHR 是发送给服务器还是 stub

image.png

  • 单击命令日志中的命令时,在开发者工具 Console 中 Cypress 还会显示 XHR是 否存根到控制台、匹配到的 URL
  • Initiator 是启动器,里面是发送 XHR 的堆栈跟踪

 

无法使用  cy.request() 调试 cy.route()

image.png

  • cy.request() 会将请求直接发送到服务器,直接绕开 .route() 路由
  • cy.request() 目的是用于检查实际云心的服务器,而无须启动前端应用程序

 

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
JavaScript
Cypress系列(91)- Cypress.config 命令详解
Cypress系列(91)- Cypress.config 命令详解
449 0
Cypress系列(91)- Cypress.config 命令详解
Cypress系列(78)- getCookie() 命令详解
Cypress系列(78)- getCookie() 命令详解
305 0
Cypress系列(78)- getCookie() 命令详解
Cypress系列(73)- within() 命令详解
Cypress系列(73)- within() 命令详解
271 0
Cypress系列(73)- within() 命令详解
Cypress系列(80)- setCookie() 命令详解
Cypress系列(80)- setCookie() 命令详解
140 0
Cypress系列(80)- setCookie() 命令详解
|
JSON 数据格式
Cypress系列(95)- writeFile() 命令详解
Cypress系列(95)- writeFile() 命令详解
234 0
Cypress系列(95)- writeFile() 命令详解
|
测试技术
Cypress系列(82)- clearCookies() 命令详解
Cypress系列(82)- clearCookies() 命令详解
154 0
Cypress系列(82)- clearCookies() 命令详解
|
JavaScript
Cypress系列(76)- cloest() 命令详解
Cypress系列(76)- cloest() 命令详解
320 0
Cypress系列(76)- cloest() 命令详解
|
测试技术
Cypress系列(81)- clearCookie() 命令详解
Cypress系列(81)- clearCookie() 命令详解
171 0
Cypress系列(81)- clearCookie() 命令详解
|
索引
Cypress系列(74)- each() 命令详解
Cypress系列(74)- each() 命令详解
313 0
Cypress系列(74)- each() 命令详解
Cypress系列(79)- getCookies() 命令详解
Cypress系列(79)- getCookies() 命令详解
228 0
Cypress系列(79)- getCookies() 命令详解