Goals:
- page objects should be cross-ecosystem, cross-technology
- simple API
- interop with Ember, and WebDriver (via adapters, which means testing-library would be supported, if anyone wanted to use that).
- all async/awaitable
- componentizable -- encourage separation of structure from the actual page object creation.
- all properties lazily evaluated
Nomenclature:
- Adapter: Converts meaning in to behavior -- "click" means different things to ember and webdriver
- Page Object: a literal object that represents how one would interact with the page
Proposed API:
import { setAdapter, create } from 'unknown package';
import { EmberAdapter } from 'unknown package/ember';
setAdapter(EmberAdapter);
const definition = {
login: {
username: '[data-test-username]',
password: '[data-test-password]',
submit: '[data-test-submit]',
},
list: {
scope: '[data-test-list]',
rows: collection('[data-test-row]', {
click: '[data-test-row-clicker]'
});
}
};
const page = create(definition);
// Usage
await page.login.username.click();
page.login.username.isFocussed; // true
await page.login.username.fillIn('text'); // username is now "text"
page.login.username.dom // <input type='text' data-test-username ... >
page.login.submit.fillIn('text'); // Error!: buttons are not fillable
await page.login.submit.click();
// for typescript, types are optional
// by default, all methods and properties will be available, and will throw runtime errors
// but the type of the interactable will still auto-complete for all methods and properties.
interface Definition {
login: {
submit: ButtonInteractor;
}
};
const typedPage = create<Definition>(definition);
// by default, every entry in the page object would be of type "OmniInteractor"
Usage with qunit-dom
assert.dom(page.login.username.dom).hasClass(...);
The web isn't in a place where we are allowed to ignore the DOM. (and page objects don't grant you this either). (unfortunately)
I majorly disagree with this statement.
Page objects are still great for abstracting interaction!
The main issue that I want to solve, is that when using ember-cli-page-object, for everything, your assertions suck. You can only do equality or boolean logic checks.
qunit-dom
, specifically, has very nice assertions for giving your more context, and more debugging.Let's say you're integrating with some 3rd party javascript that changes the
classList
on some element.assert.dom(thing.dom).hasClass('3rd-party-class');
, will say:hey, I couldn't find this class, but here are the ones I did see
.qunit-dom has tons of helpers for helping developers with context, so that you don't need to manually specify the context yourself as the assertion or test name.
I don't think it's possible for a page object library to provide this context. at least.. not as separate libraries.
however, something that
qunit-dom
could to to improve support for the above would be to implicitly call.dom
if a page object is passed.and it doesn't even need to be have class, it could be (from the readme):
All of these give contextual error messages that speed up debugging :D