ui5-community / wdi5

official UI5 end-to-end test framework for UI5 web-apps. wdi5 = Webdriver.IO + UI5 Test API
https://ui5-community.github.io/wdi5/
Apache License 2.0
102 stars 43 forks source link

Proposal: UI5-specific extensions to expect-webdriverio #607

Open LukasHeimann opened 7 months ago

LukasHeimann commented 7 months ago

In webdriverio, the usual pattern is like this:

const link = await $('a')
await expect(link).toHaveText('WebdriverIO')
await expect(link).toHaveAttribute('href', 'https://webdriver.io')

Putting the full element into the expect function allows the library to give nice diffs, including a reference to the element that was supposed to have certain attributes. (See https://github.com/webdriverio/expect-webdriverio?tab=readme-ov-file#error-messages, which shows examples).

For wdi5, the pattern usually is different:

const input = await browser.asControl({ ... }) // sap.m.Input
const selectedItem = await input.getSelectedItem() // sap.ui.core.Item
const text = await input.getText(); // string
await expect(text).toBe('myItem')

Unfortunately, this doesn't give good error messages -- what control? which property?:

[chrome-headless-shell 124.0.6367.60 linux #0-0] expect(received).toBeTruthy()

Received: false
[chrome-headless-shell 124.0.6367.60 linux #0-0] Error: expect(received).toBeTruthy()

Additionally, the types may be an issue: you should await every step of the journey, even though the UI5 types don't expose this. wdi5 offers sophisticated chaining, that helps to avoid some of the awaits, but not all of them (and tools like eslint can't help you here, as the types are not async in any case).

Perhaps, it would be easier to deal with the issue in a more webdriverio-like way:

const selectorInput = browser.asSelector({ ... }) // sap.m.Input (but only methods that return a UI5 Element (or array of elements))
const selectorItem = selectorInput.getSelectedItem() // chaining, now sap.ui.core.Item (but no `getText` method, as that returns string not ui5 element)
await expect(selectorItem).toHaveUI5Property('text', 'myItem')

You would not need any async-traps to build the selector for these nested selects, as this is not async at all -- you can't actually retrieve anything with selectorInput or selectorItem. Only the expect would be awaited, as is common for webdriverio. Typewise, you obviously need a mapped type that filters out all the methods that return basic types, as those would still need to be async.

Not sure how that fits into the direction you want to take the project into, but having good integration with what you'd do in native webdriverio feels like a good thing :)