Lệnh Tùy Chỉnh
Nếu bạn muốn mở rộng thể hiện browser với bộ lệnh riêng của mình, phương thức addCommand của trình duyệt sẽ giúp bạn. Bạn có thể viết lệnh của mình theo cách không đồng bộ, giống như trong các thông số kỹ thuật của bạn.
Tham số
Tên Lệnh
Một tên định nghĩa lệnh và sẽ được đính kèm vào phạm vi của trình duyệt hoặc phần tử.
Kiểu: String
Hàm Tùy Chỉnh
Một 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 đính kèm vào phạm vi trình duyệt hay phần tử.
Kiểu: Function
Tùy chọn
Đối tượng với các tùy chọn cấu hình sửa đổi hành vi của lệnh tùy chỉnh
Phạm vi đích
Cờ để quyết định liệu có nên gắn lệnh vào phạm vi trình duyệt hay phạm vi phần tử. Nếu được đặt thành true, lệnh sẽ là lệnh cho phần tử.
Tên Tùy Chọn: attachToElement
Kiểu: Boolean
Mặc định: false
Vô hiệu hóa implicitWait
Cờ để quyết định liệu có nên chờ ngầm định 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
Kiểu: 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 hiện tại và tiêu đề 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` đề cập đế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ể hiện phần tử với bộ lệnh riêng của mình, 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, các lệnh tùy chỉnh cho phần tử sẽ chờ 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ể bị 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 })
Lệnh tùy chỉnh cho bạn cơ hội để gộp 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. Bạn có thể định nghĩa các lệnh tùy chỉnh tại bất kỳ thời điểm nào trong bộ thử nghiệm của mình; chỉ cần đảm bảo rằng lệnh được định nghĩa trước khi 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.)
Khi đã được đị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 ra "function"
console.log(typeof elem.myCustomBrowserCommand()) // xuất ra "undefined"
browser.addCommand("myCustomElementCommand", () => { return 1 }, { attachToElement: true })
const elem2 = await $('body')
console.log(typeof browser.myCustomElementCommand) // xuất ra "undefined"
console.log(await elem2.myCustomElementCommand('foobar')) // xuất ra "1"
const elem3 = await $('body')
elem3.addCommand("myCustomElementCommand2", () => { return 2 })
console.log(typeof browser.myCustomElementCommand2) // xuất ra "undefined"
console.log(await elem3.myCustomElementCommand2('foobar')) // xuất ra "2"
Lưu ý: Nếu bạn cần liên kết 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 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 gắn với một trang cụ thể.
Multiremote
addCommand hoạt động tương tự đối với multiremote, ngoại trừ lệnh mới sẽ lan xuống các thể hiện con. B ạn phải cẩn thận khi sử dụng đối tượng this vì browser multiremote và các thể hiện con của nó có this khác nhau.
Ví dụ này cho thấy cách thêm một lệnh mới cho multiremote.
import { multiRemoteBrowser } from '@wdio/globals'
multiRemoteBrowser.addCommand('getUrlAndTitle', async function (this: WebdriverIO.MultiRemoteBrowser, customVar: any) {
// `this` đề cập đến:
// - Phạm vi MultiRemoteBrowser cho trình duyệt
// - Phạm vi Browser cho các thể hiện
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, 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 WebdriverIOtrong tệp định nghĩa kiểu), hãy đảm bảo bao gồm đường dẫn tệp trong thuộc tínhincludecủatsconfig.json.b. Nếu sử dụng các tệp định nghĩa kiểu theo kiểu môi trường xung quanh (không có import/export trong các tệp định nghĩa kiểu và
declare namespace WebdriverIOcho các lệnh tùy chỉnh), hãy đảm bảotsconfig.jsonkhông chứa bất kỳ phầnincludenà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ầnincludekhông được TypeScript nhận diện.
- Modules (using import/export)
- Ambient Type Definitions (no 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.
- Modules (using import/export)
- Ambient Type Definitions
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 các 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ợ promise, một cách tiếp cận tốt để tích hợp chúng là bao bọc 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ó sẽ 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ẽ đưa 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ố kỹ thuật 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ề phần thân phản hồi
})
Lưu ý: Kết quả của lệnh tùy chỉnh của bạn là kết quả của promise bạn trả về.
Ghi đè lệnh
Bạn cũng có thể ghi đè các lệnh có sẵn với overwriteCommand.
Không khuyến khích làm điều này, vì nó có thể dẫn đến hành vi không thể đoán trước của framework!
Cách tiếp cận tổng thể 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 sắp ghi đè. Vui lòng xem một số ví dụ dưới đây.