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(...);
I'm a big fan of most of the listed suggestions.
Yes. Adapters seems to be the most reasonable strategy to achieve this. I've made an attempt to extract Adapters in ember-cli-page-object. I like simpliefied API and possibilities it unlocks. However, in ec-page-object, it's currently possible to perform action against the
multiple
DOM elements, which makes it pretty hard to integrate adapters in V1 of ec-page-object.I'm afraid that can lead to an extra layer of indirection and learnability issues. Cause adapters detection can be order dependant.
I think
setAdapter
is good and clear enough. So in case, if you have a test suite mixed from, let's say,setupTest
andmoduleFor
, you can set your mode explicitly before each test. And if you have a "clean" test suite, you can just do it once in thetest-helper.js
.String as a scope
I've explored this area a bit. I think it's a good idea.
But, in ec-page-object, we also have
testContainer
, which is also a string. Also we might want to add some string configuration in the future, which would not be a forward compatible feature..I believe, in order to make it safe, we should change API to isolate all the query options like:
I think, with an ability to pass all the query options to the
scope
object we can safely treat all thestring
options as ascope
.