Cypress系列(101)- intercept() 命令詳解

若是想從頭學起Cypress,能夠看下面的系列文章哦html

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

 

做用

使用該命令在網絡層管理 HTTP 請求的行爲github

 

包含如下功能

  • 對任何類型的 HTTP 請求進行 stub 或 spy
  • 在 HTTP 請求發送到目標服務器前,能夠修改 HTTP 請求 body、headers、URL(相似抓包工具對請求進行打斷點而後修改)
  • 動態或靜態地對 HTTP 請求的響應進行 stub
  • 接收 HTTP 響應後可對 HTTP 響應 body、headers、status、code 進行修改(相似抓包工具對響應進行打斷點而後修改)
  • 在全部階段均可以徹底訪問全部 HTTP 請求

 

相較於 cy.route() 的不一樣

 cy.route() 命令詳解:http://www.javashuo.com/article/p-bcbrptkn-nx.html正則表達式

  • 能夠攔截全部類型的網絡請求,包括 Fetch API,頁面加載,XMLHttpRequest,資源加載等
  • 不須要在使用前調用 cy.server() ,實際上 cy.server() 根本不影響 cy.intercept() 
  • 默認狀況下沒有將請求方法設置爲 GET

 

語法格式

cy.intercept(url, routeHandler?)
cy.intercept(method, url, routeHandler?)
cy.intercept(routeMatcher, routeHandler?)

 

url

要匹配的請求 URL ,能夠是字符串也能夠是正則表達式npm

cy.intercept('http://example.com/widgets')
cy.intercept('http://example.com/widgets', { fixture: 'widgets.json' })

沒有指定請求方法的話,能夠匹配任意類型的請求方法json

 

method

請求方法數組

cy.intercept('POST', 'http://example.com/widgets', {
  statusCode: 200,
  body: 'it worked!'
})

 

routeMatcher 

  • 它是一個對象
  • 用於匹配此路由將處理哪些傳入的 HTTP 請求
  • 全部對象屬性都是可選的,不是必填的
  • 設置的全部屬性必須與路由匹配才能處理請求
  • 若是將字符串傳遞給任何屬性,則將使用 minimatch 將與請求進行全局匹配

它有如下屬性

{
  /**
   * 與 HTTP Basic身份驗證中使用的用戶名和密碼匹配
   */
  auth?: { username: string | RegExp, password: string | RegExp }

  /**
   * 與請求上的 HTTP Headers 匹配
   */
  headers?: {
    [name: string]: string | RegExp
  }

  /**
   * 與請求上的 hostname 匹配
   */
  hostname?: string | RegExp

  /**
   * If 'true', 只有 https 的請求會被匹配
   * If 'false', 只有 http 的請求會被匹配
   */
  https?: boolean

  /**
   * 與請求上的 method 請求方法匹配
   * 默認 '*', 匹配所有類型的 method
   */
  method?: string | RegExp

  /**
   * 主機名後的路徑, 包括了 ? 後面的查詢參數
   * www.baidu.com/s?wd=2
   */
  path?: string | RegExp

  /**
   * 和 path 同樣, 不過無論 ? 後面的查詢參數
   * www.baidu.com/s
   */
  pathname?: string | RegExp

  /**
   * 與指定的端口匹配, 或者傳遞多個端口組成的數組, 其中一個匹配上就好了
   */
  port?: number | number[]

  /**
   * 與請求路徑 ? 後面跟的查詢參數匹配上
   * wd=2
   */
  query?: {
    [key: string]: string | RegExp
  }

  /**
   * 完整的請求 url
   * http://www.baidu.com/s?wd=2
   */
  url?: string | RegExp
}

   

routeHandler 

  • routeHandler 定義了若是請求和 routeMatcher 匹配將對請求進行的指定的處理
  • 可接受的數據類型:string、object、Function、StaticResponse

 

StaticResponse

  • 至關於一個自定義響應體對象
  • 能夠自定義 Response headers、HTTP 狀態碼、Response body 等
  • 詳細栗子將在後面展開講解

 

StaticResponse 對象的屬性

{
  /**
   * 將 fixture 文件做爲響應主體, 以 cypress/fixtures 爲根目錄
   */
  fixture?: string
  /**
   * 將字符串或 JSON 對象做爲響應主體
   */
  body?: string | object | object[]
  /**
   * 響應 headers
   * @default {}
   */
  headers?: { [key: string]: string }
  /**
   * 響應狀態碼
   * @default 200
   */
  statusCode?: number
  /**
   * 若是 true, Cypress 將破壞網絡鏈接, 而且不發送任何響應
   * 主要用於模擬沒法訪問的服務器
   * 請勿與其餘選項結合使用
   */
  forceNetworkError?: boolean
  /**
   * 發送響應前要延遲的毫秒數
   */
  delayMs?: number
  /**
   * 以多少 kbps 發送響應體
   */
  throttleKbps?: number
}

 

string

  • 若是傳遞一個字符串,這個值至關於響應 body 的值
  • 等價於 StaticResponse 對象 { body: "foo" } 

 

object

  • 若是傳遞了沒有 StaticResponse 密鑰的對象,則它將做爲 JSON 響應 Body 發送
  • 例如, {foo:'bar'} 等價於 StaticResponse 對象 {body:{foo:'bar'}} 

 

function

  • 若是傳遞了一個回調函數,當一個請求匹配上了該路由將會自動調用這個函數
  • 函數第一個參數是請求對象
  • 在回調函數內部,能夠修改外發請求、發送響應、訪問實際響應
  • 詳細栗子將在後面展開講解

 

命令返回結果

  • 返回 null
  • 能夠連接 as() 進行別名,但不可連接其餘命令
  • 可使用 cy.wait() 等待 cy.intercept() 路由匹配上請求,這將會產生一個對象,包含匹配上的請求/響應相關信息

 

實際栗子的前置準備

Cypress 官方項目的下載地址:https://github.com/cypress-io/cypress-example-kitchensinkpromise

 

下載好後進入下圖項目文件夾

 

啓動項目

npm start

 

經過 URL 路由匹配請求的栗子

測試代碼

 

等價於 route() 的測試代碼

注:  route()  將來將會被棄用瀏覽器

 

運行結果

登陸請求匹配上了路由服務器

 

Console 查看 cy.wait() 返回的對象

最重要的固然是 request 和 response 兩個屬性

 

經過 RouteMatcher 路由匹配請求的栗子

測試代碼

斷言請求體和響應狀態碼

 

運行結果

 

Console 查看 cy.wait() 返回的對象

 

另外一種斷言方式

// 斷言匹配此路由的請求接收到包含【username】的請求 body
cy.wait('@login3').its('request.body').should('have.property', 'username')

// 斷言匹配此路由的請求接收到 HTTP 狀態碼爲 500
cy.wait('@login3').its('response.statusCode').should('eq', 200)

// 斷言匹配此路由的請求接收到包含【redirect】的請求 body
cy.wait('@login3').its('response.body').should('have.property', 'redirect')

不過這樣的話只能每次寫一條不能同時三條都寫,因此仍是建議像代碼圖同樣,先 .then() 再進行斷言

 

自定義不一樣類型的響應體的各類栗子

自定義一個純字符串的響應體

測試代碼

 

運行結果

 

接口響應

 

自定義一個 JSON 的響應體

測試代碼

會從cypress安裝目錄/fixtures 下讀取對應的數據文件,它會變成響應 body 的數據

 

test.json 數據文件

 

運行結果

 

接口響應

 

自定義一個 StaticResponse 的響應體

測試代碼

自定義了響應body、statusCode,還有返回響應的延時時間

 

運行結果

延時生效了

 

body 和 statusCode 變成自定義的數據了

 

攔截請求的栗子

前置操做

beforeEach(() => {
    cy.visit('http://localhost:7079/login')
})

 

斷言請求的栗子

測試代碼

 

運行結果

 

Console 查看打印結果

能夠看到回調函數只有一個參數,就是 request 參數

 

重點

回調函數內不能包含 cy.**() 的命令,若是包含會報錯

簡單來講就是

 cy.type() 命令執行完後會返回一個 promise 對象,同時又會調用回調函數,而回調函數內又調用了 cy.get() 返回了一個 promise 對象,Cypress 會將這種狀況當作測試失敗處理

 

將請求傳遞給下一個路由處理程序

前言

意思就是一個請求能夠同時匹配上多個路由

 

測試代碼

 

運行結果

一個登陸請求匹配成功了兩個路由,且回調函數會按匹配的順序執行

 

總結

回調函數的參數就是一個請求對象,它其實能夠調用如下方法

{
  /**
   * 銷燬該請求並返回網絡錯誤的響應
   */
  destroy(): void

  /**
   * 控制請求的響應
   * 若是傳入的是一個函數, 則它是回調函數, 當響應時會調用
   * 若是傳入的是一個 StaticResponse 對象, 將不會發出請求, 而是直接將這個對象當作響應返回
   */
  reply(interceptor?: StaticResponse | HttpResponseInterceptor): void

  /**
   * 使用 response body(必填) 和 response header(可選) 響應請求
   */
  reply(body: string | object, headers?: { [key: string]: string }): void

  /**
   * 使用 HTTP 狀態碼(必填)、 response body(可選)、response header(可選) 響應請求
   */
  reply(status: number, body?: string | object, headers?: { [key: string]: string }): void

  /**
   * 重定向到新的 location 來響應請求,
   * @param statusCode 用來重定向的 HTTP 狀態代碼, Default: 302
   */
  redirect(location: string, statusCode?: number): void
}

 

攔截響應的栗子

req.reply() 函數詳解

前言

可使用 req.reply() 函數來動態控制對請求的響應

 

使用講解

cy.intercept('/login', (req) => {
    // functions on 'req' can be used to dynamically respond to a request here

    // 將請求發送到目標服務器
    req.reply()

    // 將這個 JSON 對象響應請求
    req.reply({plan: 'starter'})

    // 將請求發送到目標服務器, 而且攔截服務器返回的實際響應, 而後進行後續操做(相似抓包工具對響應打斷點)
    req.reply((res) => {
        // res 就是實際的響應對象
    })
})

 

.reply() 直接修改響應的栗子

測試代碼

 

接口響應內容

 

攔截響應的小栗子

測試代碼

 

運行結果

 

Console 查看打印結果

一個是 request 對象,一個是 response 對象

 

自定義響應內容

前言

  • 可使用 resp.send() 函數動態控制傳入的響應
  • 另外,當響應發送到瀏覽器時,對 resp 的任何修改都將保留
  • 若是還沒有調用 resp.send() ,則它會在 req.reply() 回調函數完成後隱式調用

 

使用講解

cy.intercept('/notification', (req) => {
    req.reply((resp) => {
        // Success 將做爲 response body 返回到瀏覽器
        resp.send('Success')

        // 將 success.json 裏面的數據做爲 response body 返回到瀏覽器
        resp.send({fixture: 'success.json'})

        // 將響應延遲 1000ms
        resp.delay(1000)

        // 將響應限制爲 64kbps
        resp.throttle(64)
    })
})

 

傳遞字符串做爲響應內容

測試代碼

 

接口響應內容

 

傳遞 JSON 對象做爲響應內容

測試代碼

 

接口響應內容

 

傳遞 StaticResponse 對象做爲響應內容

測試代碼

 

接口響應內容

 

resp 可調用的函數總結

{
/**
* 能夠自定義 response statusCode、response body、response header
* 也能夠直接傳 StaticResponse 對象
*/
send(status: number, body?: string | number | object, headers?: { [key: string]: string }): void
send(body: string | object, headers?: { [key: string]: string }): void
send(staticResponse: StaticResponse): void
/**
* 繼續返回響應
*/
send(): void
/**
* 等待 delayMs 毫秒,而後再將響應發送給客戶端
*/
delay: (delayMs: number) => IncomingHttpResponse
/**
* 以多少 kbps 的速度發送響應
*/
throttle: (throttleKbps: number) => IncomingHttpResponse
}
相關文章
相關標籤/搜索