Các Lệnh Tùy Chỉnh
Nếu bạn muốn mở rộng thực thể browser
với bộ lệnh riêng của bạn, phương thức addCommand
của trình duyệt có sẵn cho bạn. Bạn có thể viết lệnh của mình theo cách bất đồng bộ, giống như trong các đặc tả của bạn.
Tham số
Tên Lệnh
Tên định nghĩa lệnh và sẽ được gắn vào phạm vi trình duyệt hoặc phần tử.
Loại: String
Hàm Tùy Chỉnh
Hàm được thực thi khi lệnh được gọi. Phạm vi this
là WebdriverIO.Browser
hoặc WebdriverIO.Element
tùy thuộc vào việc lệnh được gắn vào phạm vi trình duyệt hay phần tử.
Loại: Function
Tùy chọn
Đối tượng với các tùy chọn cấu hình điều chỉnh hành vi lệnh tùy chỉnh
Phạm vi Mục tiêu
Cờ để quyết định liệu gắn lệnh vào phạm vi trình duyệt hay phần tử. Nếu đặt là true
, lệnh sẽ là lệnh của phần tử.
Tên Tùy chọn: attachToElement
Loại: Boolean
M ặc định: false
Vô hiệu hóa implicitWait
Cờ để quyết định liệu có đợi ngầm cho phần tử tồn tại trước khi gọi lệnh tùy chỉnh hay không.
Tên Tùy chọn: disableElementImplicitWait
Loại: Boolean
Mặc định: false
Ví dụ
Ví dụ này cho thấy cách thêm một lệnh mới trả về URL và tiêu đề hiện tại dưới dạng một kết quả. Phạm vi (this
) là một đối tượng WebdriverIO.Browser
.
browser.addCommand('getUrlAndTitle', async function (customVar) {
// `this` ám chỉ đến phạm vi `browser`
return {
url: await this.getUrl(),
title: await this.getTitle(),
customVar: customVar
}
})
Ngoài ra, bạn có thể mở rộng thực thể phần tử với bộ lệnh riêng của bạn, bằng cách truyền true
làm đối số cuối cùng. Phạm vi (this
) trong trường hợp này là một đối tượng WebdriverIO.Element
.
browser.addCommand("waitAndClick", async function () {
// `this` là giá trị trả về của $(selector)
await this.waitForDisplayed()
await this.click()
}, { attachToElement: true })
Theo mặc định, lệnh tùy chỉnh của phần tử sẽ đợi phần tử tồn tại trước khi gọi lệnh tùy chỉnh. Mặc dù hầu hết thời gian điều này là mong muốn, nếu không, nó có thể được vô hiệu hóa với disableImplicitWait
:
browser.addCommand("waitAndClick", async function () {
// `this` là giá trị trả về của $(selector)
await this.waitForExists()
await this.click()
}, { attachToElement: true, disableElementImplicitWait: true })
Các lệnh tùy chỉnh cho phép bạn gom một chuỗi lệnh cụ thể mà bạn thường xuyên sử dụng thành một lần gọi duy nhất. Bạn có thể định nghĩa lệnh tùy chỉnh tại bất kỳ thời điểm nào trong bộ kiểm thử của bạn; chỉ cần đảm bảo rằng lệnh được định nghĩa trước khi nó được sử dụng lần đầu tiên. (Hook before
trong tệp wdio.conf.js
của bạn là một nơi tốt để tạo chúng.)
Sau khi đã định nghĩa, bạn có thể sử dụng chúng như sau:
it('should use my custom command', async () => {
await browser.url('http://www.github.com')
const result = await browser.getUrlAndTitle('foobar')
assert.strictEqual(result.url, 'https://github.com/')
assert.strictEqual(result.title, 'GitHub · Where software is built')
assert.strictEqual(result.customVar, 'foobar')
})
Lưu ý: Nếu bạn đăng ký một lệnh tùy chỉnh cho phạm vi browser
, lệnh đó sẽ không thể truy cập được cho các phần tử. Tương tự, nếu bạn đăng ký một lệnh cho phạm vi phần tử, nó sẽ không thể truy cập được trong phạm vi browser
:
browser.addCommand("myCustomBrowserCommand", () => { return 1 })
const elem = await $('body')
console.log(typeof browser.myCustomBrowserCommand) // xuất "function"
console.log(typeof elem.myCustomBrowserCommand()) // xuất "undefined"
browser.addCommand("myCustomElementCommand", () => { return 1 }, { attachToElement: true })
const elem2 = await $('body')
console.log(typeof browser.myCustomElementCommand) // xuất "undefined"
console.log(await elem2.myCustomElementCommand('foobar')) // xuất "1"
const elem3 = await $('body')
elem3.addCommand("myCustomElementCommand2", () => { return 2 })
console.log(typeof browser.myCustomElementCommand2) // xuất "undefined"
console.log(await elem3.myCustomElementCommand2('foobar')) // xuất "2"
Lưu ý: Nếu bạn cần chuỗi một lệnh tùy chỉnh, lệnh nên kết thúc bằng $
,
browser.addCommand("user$", (locator) => { return ele })
browser.addCommand("user$", (locator) => { return ele }, { attachToElement: true })
await browser.user$('foo').user$('bar').click()
Hãy cẩn thận để không làm quá tải phạm vi browser
với quá nhiều lệnh tùy chỉnh.
Chúng tôi khuyên bạn nên định nghĩa logic tùy chỉnh trong page objects, để chúng được gắn với một trang cụ thể.
Multiremote
addCommand
hoạt động tương tự cho multiremote, ngoại trừ việc lệnh mới sẽ được lan truyền xuống các thực thể con. Bạn phải ch ú ý khi sử dụng đối tượng this
vì browser
multiremote và các thực thể con của nó có this
khác nhau.
Ví dụ này cho thấy cách thêm lệnh mới cho multiremote.
import { multiremotebrowser } from '@wdio/globals'
multiremotebrowser.addCommand('getUrlAndTitle', async function (this: WebdriverIO.MultiRemoteBrowser, customVar: any) {
// `this` ám chỉ đến:
// - Phạm vi MultiRemoteBrowser cho browser
// - Phạm vi Browser cho các thực thể
return {
url: await this.getUrl(),
title: await this.getTitle(),
customVar: customVar
}
})
multiremotebrowser.getUrlAndTitle()
/*
{
url: [ 'https://webdriver.io/', 'https://webdriver.io/' ],
title: [
'WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO',
'WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO'
],
customVar: undefined
}
*/
multiremotebrowser.getInstance('browserA').getUrlAndTitle()
/*
{
url: 'https://webdriver.io/',
title: 'WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO',
customVar: undefined
}
*/
Mở rộng định nghĩa kiểu
Với TypeScript, bạn có thể dễ dàng mở rộng các giao diện WebdriverIO. Thêm kiểu cho các lệnh tùy chỉnh của bạn như sau:
-
Tạo một tệp định nghĩa kiểu (ví dụ:
./src/types/wdio.d.ts
) -
a. Nếu sử dụng tệp định nghĩa kiểu theo kiểu module (sử dụng import/export và
declare global WebdriverIO
trong tệp định nghĩa kiểu), hãy đảm bảo đường dẫn tệp được đưa vào thuộc tínhinclude
trongtsconfig.json
.b. Nếu sử dụng tệp định nghĩa kiểu theo kiểu môi trường (không có import/export trong tệp định nghĩa kiểu và
declare namespace WebdriverIO
cho các lệnh tùy chỉnh), hãy đảm bảotsconfig.json
không chứa bất kỳ phầninclude
nào, vì điều này sẽ khiến tất cả các tệp định nghĩa kiểu không được liệt kê trong phầninclude
không được TypeScript nhận diện.
- Modules (sử dụng import/export)
- Định nghĩa kiểu môi trường (không có tsconfig include)
{
"compilerOptions": { ... },
"include": [
"./test/**/*.ts",
"./src/types/**/*.ts"
]
}
{
"compilerOptions": { ... }
}
- Thêm định nghĩa cho các lệnh của bạn theo chế độ thực thi của bạn.
- Modules (sử dụng import/export)
- Định nghĩa kiểu môi trường
declare global {
namespace WebdriverIO {
interface Browser {
browserCustomCommand: (arg: any) => Promise<void>
}
interface MultiRemoteBrowser {
browserCustomCommand: (arg: any) => Promise<void>
}
interface Element {
elementCustomCommand: (arg: any) => Promise<number>
}
}
}
declare namespace WebdriverIO {
interface Browser {
browserCustomCommand: (arg: any) => Promise<void>
}
interface MultiRemoteBrowser {
browserCustomCommand: (arg: any) => Promise<void>
}
interface Element {
elementCustomCommand: (arg: any) => Promise<number>
}
}
Tích hợp thư viện bên thứ 3
Nếu bạn sử dụng thư viện bên ngoài (ví dụ, để thực hiện các cuộc gọi cơ sở dữ liệu) hỗ trợ promises, một cách tiếp cận tốt để tích hợp chúng là gói gọn các phương thức API nhất định bằng một lệnh tùy chỉnh.
Khi trả về promise, WebdriverIO đảm bảo rằng nó không tiếp tục với lệnh tiếp theo cho đến khi promise được giải quyết. Nếu promise bị từ chối, lệnh sẽ ném ra lỗi.
browser.addCommand('makeRequest', async (url) => {
const response = await fetch(url)
return await response.json()
})
Sau đó, chỉ cần sử dụng nó trong các thông số kiểm tra WDIO của bạn:
it('execute external library in a sync way', async () => {
await browser.url('...')
const body = await browser.makeRequest('http://...')
console.log(body) // trả về nội dung phản hồi
})
Lưu ý: Kết quả của lệnh tùy chỉnh của bạn chính là kết quả của promise mà bạn trả về.
Ghi đè lệnh
Bạn cũng có thể ghi đè các lệnh gốc bằng overwriteCommand
.
Không khuyến nghị làm điều này, vì nó có thể dẫn đến hành vi không thể dự đoán của framework!
Cách tiếp cận chung tương tự như addCommand
, sự khác biệt duy nhất là đối số đầu tiên trong hàm lệnh là hàm gốc mà bạn đang ghi đè. Vui lòng xem một số ví dụ dưới đây.