如果想從頭學起Cypress,可以看下面的系列文章哦
https://www.cnblogs.com/poloyy/category/1768839.html
PO 模式
PageObject(頁面物件)模式是自動化測試中的一個最佳實踐,相信很多小夥伴都知道的
PO 模式特徵
- 將每個頁面(或者待測試物件)封裝成一個(class),類裡面包含了頁面上所有元素及它們的操作方法(單步操作或功能集合)
- 測試程式碼和被測頁面程式碼解耦,使用 PO 模式後,當頁面發生改變,無須改變測試程式碼,僅改頁面程式碼
接下來就講解下 Cypress 下如何使用 PO 模式
前期準備
啟動 Cypress 提供的演示專案
cmd 視窗進入下面的資料夾
執行下面的命令
npm start
PO 模式程式碼
簡單的 PageObject 模型栗子
待測試頁面程式碼
在 C:\Users\user\Desktop\py\cypress-example-recipes\examples\logging-in__html-web-forms\cypress 資料夾下新建 pages 資料夾,並建立一個 login.js 待測試頁面檔案,程式碼如下
// login.js export default class LoginPage { constructor() { this.userName = 'input[name=username]' this.password = 'input[name=password]' this.form = 'form' this.url = 'http://localhost:7077/login' } isTargetPage() { cy.visit('/login') cy.url().should('eq', this.url) } login(username, pwd) { cy.get(this.userName).type(username) cy.get(this.password).type(pwd) cy.get(this.form).submit() } }
測試用例檔案
在 C:\Users\user\Desktop\py\cypress-example-recipes\examples\logging-in__html-web-forms\cypress\integration 資料夾下,建立一個 testLogin.js 測試用例檔案,程式碼如下
import LoginPage from "../pages/login" context('登入測試,PO 模式', function () { const username = 'jane.lane' const pwd = 'password123' it('登入成功', function () { // 建立 po 例項 const loginInstance = new LoginPage() loginInstance.isTargetPage() loginInstance.login(username, pwd) cy.url().should('include', '/dashboard') }); })
測試結果
總結下
這樣的 PageObject 模式程式碼只是把定位元素的元素定位表示式給剝離出來,並沒有針對元素本身進行封裝
針對元素本身進行封裝的栗子
待測試頁面程式碼
// login.js export default class LoginPage { constructor() { this.userNameLocator = 'input[name=username]' this.passwordLocator = 'input[name=password]' this.formLocator = 'form' this.url = 'http://localhost:7077/login' } get username() { return cy.get(this.userNameLocator) } get password() { return cy.get(this.passwordLocator) } get form() { return cy.get(this.formLocator) } isTargetPage() { cy.visit('/login') cy.url().should('eq', this.url) } login(username, pwd) { this.username.type(username) this.password.type(pwd) this.form.submit() } }
跳轉頁面程式碼
當登入成功後,頁面將跳轉至 mainPage 頁面,上面只寫了 login 頁面,這裡寫下跳轉後的頁面
// login.js export default class mainPage{ constructor() { this.h1Locator = 'h1' this.url = 'http://localhost:7077/dashboard' } get welComeText() { return cy.get(this.h1Locator) } isTargetPage() { cy.url().should('eq', this.url) } }
測試用例程式碼
測試用例程式碼和上面的栗子一樣哦!不需要變!
測試結果
總結下
- login.js 和 mainPage.js 兩個頁面物件都有一個 isTargetPage() 函式來判斷當前頁面 URL 是否正確
- 那這裡就將每個 page 都共用的部分再次剝離,放到一個新的 common page
- 然後每個 page 都繼承自 common page(類似 selenium po 模式的 BasePage)
使用 common page 的栗子
commonPage.js 的程式碼
它也在 pages 資料夾下建立
export default class commanPage { constructor() { // 建構函式可以為空 // 如果不為空 應該是所有 page 都會用到的變數 } isTargetPage() { cy.url().should('eq', this.url1) } }
login.js 的程式碼
// login.js import commanPage from "./commonPage"; // 繼承 commonPage export default class LoginPage extends commanPage{ constructor() { // 呼叫父類的構造方法 super() this.userNameLocator = 'input[name=username]' this.passwordLocator = 'input[name=password]' this.formLocator = 'form' this.url = 'http://localhost:7077/login' } get username() { return cy.get(this.userNameLocator) } get password() { return cy.get(this.passwordLocator) } get form() { return cy.get(this.formLocator) } visitPage(){ cy.visit('/login') } login(username, pwd) { this.username.type(username) this.password.type(pwd) this.form.submit() } }
mainPage.js 的程式碼
// login.js import commonPage from "./commonPage"; // 繼承 commonPage export default class mainPage extends commonPage { constructor() { super() this.h1Locator = 'h1' this.url = 'http://localhost:7077/dashboard' } get welComeText() { return cy.get(this.h1Locator) } }
測試結果
測試結果和上面的栗子一樣
Cypress 使用 PO 模式的總結
- Cypress 完全支援 PageObject 模式
- 但存在一個問題,如果一個測試需要訪問多個頁面物件,就意味著測試中要初始化多個頁面物件例項(new Page())
- 如果一個頁面物件需要登入才能訪問(大部分場景都是這樣),則每次初始化都需要先登入再訪問(只有登入後才能重用 cookie),這無形增加了測試執行的時間
- Cypress 不認為 PO 模式是一個好模式,它認為跨頁面共享邏輯是一個反邏輯,因為 Cypress 的實現原理與其他工具完全不同
- 那 Cypress 用什麼方式來替代 PO 模式呢?答案就是下一篇要講到的 Custom Commands