Alex-Programer

Alex-Programer

随缘博客,不定期更新不确定的内容~
github
twitter

Cypress 使用手冊

版本號 ^11.2.0#

前提準備與說明#

{
	"e2e": "cypress open", // 打開客戶端手動選擇性執行
	"test": "cypress run && cypress run --component" // 在命令行裡,執行所有的測試用例
}

Tip

cypress 的 api ,都是以同步的寫法,來異步執行的。比如 async await 那樣,它不需要顯示聲明,直接調用。比如在獲取元素的時候,它會有相應的等待時間來異步處理。

使用場景#

前往某個頁面#

cy.visit(url);

獲取元素#

選擇器匹配#

// 這種匹配方式,可以參考 querySelector 的行為
cy.get(selector);

內容匹配#

// 內容匹配,下列語句將會匹配包含了 hello 文本的元素
cy.contain('hello');

事件調用#

基本事件#

// 以調用點擊事件為例,其它事件也可以同樣如此
cy.get(selector).click();

複雜事件#

// 這種方式,除了觸發基本事件,還可以觸發 mousedown、mouseup 這類的事件,來模擬複雜的用戶操作
cy.get(selector).trigger(eventName);

內容校驗#

// 該語法是在判斷選中的元素,應該有 hello 的內容
cy.get(selector).should('have.value', 'hello');

// 判斷元素的 top 值,是否為 10 px;
cy.get(selector).should('have.css', 'top').and('eq', '10px');

結合 ts 的語法提示,should 的第一個參數,還有很多其它的行為來進行校驗

模擬按鍵#

// 按住 ctrl
cy.get('body').type('{ctrl}', { release: false });

// 抬起 ctrl
cy.get('body').type('{ctrl}', { release: true });

接口請求#

獲取接口的調用結果#

// 開始監聽某個接口
 cy.intercept({
    method: 'GET',
    // 比如監聽 /api/login?account=xxx,寫法為:/api/login*
    url: `接口的path部分`, 
  }).as('test');

// 此處注意。在監聽的代碼開始執行時,後面的請求行為如果不是該接口,就會報錯。也就是說,在開始監聽後,需要確保接下來的請求一定是這個監聽的請求。所以不能一開始就去監聽。推薦做法就是在監聽後,確定後續行為馬上可以監聽到該接口來處理,比如在這裡觸發某個按鈕的點擊行為,來調用接口

// 獲取接口的請求結果
cy.wait('@test')
	.its('response.body')
	.then(data => {
		cy.log(JSON.stringify(data));
	});

根據上述描述,可以封裝如下方法使用

export const watchRequest = <T>(url: string, trigger: () => void, callback: (data: T) => void) => {
	cy.intercept({
		method: 'GET',
		url: `${url}*`,
	}).as(url);

	trigger();

	cy.wait(`@${url}`)
	.its('response.body')
	.then(data) => {
		callback(data);
	});
};
是否正常訪問某個頁面#

在上述場景情況下,做如下調整,即可大致確認某個頁面是否屬於正常訪問。

/**
* 某個頁面可以正常訪問
* @param url 頁面地址
* @param requestCount 判定頁面發起了多少個請求都是正常的
*/
export const normalVisit = (url: string, requestCount = 30) => {
	cy.intercept({
		url: '*',
	}).as('apiCheck')

	cy.visit(url);

	Array(requestCount).fill('').forEach(() => {
		cy.wait('@apiCheck').then((interception) => {
			expect(Boolean(interception.response)).equal(true);
			assert.isNotNull(interception.response!.body);
			expect(interception.response!.statusCode).to.be.oneOf([200, 304])
		});
	});
}

修改請求參數#

// 修改 get 請求的參數
 cy.intercept('/api/test*', (req) => {
	const request = JSON.parse(req.query as string);
	req.query.account = 2;
});

注意:修改的請求參數,在控制台裡面看請求時,參數沒有發生顯示變化,實際上已經改變了。

強制等待#

cy.wait(1000); // 等待1s

自定義指令#

元素是否存在#

声明类型#

/// <reference types="cypress" />
/// <reference types="cypress-wait-until" />

declare namespace Cypress {
	interface Chainable<Subject> {
		/**
		* 檢查元素是否存在
		*
		* @param selector 選擇器
		* @return Chainable<Subject>
		*/
		isElementExist(selector: string): Chainable<Subject>;
	}
}

定義指令#

/// <reference types="cypress" />
/// <reference types="cypress-wait-until" />

require("cypress-wait-until");

export function isElementExist(selector: string) {
	return cy
		.window()
		.then(($window) => $window.document.querySelector(selector));
}

Cypress.Commands.add("isElementExist", isElementExist);

使用指令#

cy.isElementExist(".shoe-id").then((value) => {
	if (value) {
		// ...
	} else {
		// ...
	}
}

測試數據#

cypress/fixtures 目錄下的 json 文件可以當作測試數據來用,例如: user.json:

{
	"username": "hello world"
}

那麼在使用的時候就可以這麼獲取

cy.fixture('user').then(res => {
	console.log(res.username);
})
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。