ember-cli-page-object
ember-cli-page-object copied to clipboard
Add ability to look up items in a collection via properties other than index
Use case:
<ul>
<li data-test-id='UUID1'>Object 1</li>
<li data-test-id='UUID2'>Object 2</li>
</ul>
PageObject.create({
objects: collection({
scope: 'ul',
itemScope: 'li'
})
});
page.objects("[data-test-id='UUID1']");
This can currently be solved by using nested PageObjects, a la:
PageObject.create({
objects(uuid) {
return PageObject.create({
scope: `[data-test-id='${uuid}']`
});
}
});
page.objects('UUID1');
However there are some drawbacks to this, including the fact that the outer PageObject's scope will not be inherited.
https://github.com/san650/ember-cli-page-object/issues/198 related.
I didn't want to make a completely separate issue for this, but I was wondering if it would be niceto have collections be able to receive a list of indices to return:
const [a,b,c] = page.objects([1,2,3])
vs.
const [a,b,c] = page.objects().toArray();
@lsthornt Interesting. How does this work with component integration tests?
I think this could actually more safely be accomplished by allowing collections to query the page objects of the items in the collections themselves, rather than directly querying the items:
<ul>
<li data-test-id='UUID1'>Object 1</li>
<li data-test-id='UUID2'>Object 2</li>
</ul>
PageObject.create({
objects: collection({
scope: 'ul',
itemScope: 'li',
item: {
id: attribute('data-test-id')
}
})
});
page.objects('id', 'UUID1');
This way you aren't breaking encapsulation, the item in the collection gets to define it's own content and values you can search. It could be a completely separate component definition, and you would essentially be searching its public API
I think we should have a way to describe where an element id can be found. So id
field sounds like a good candidate for a default collection DSL to me. If we have an id
we then also need something like getById
.
const form = create({
fields: collection({
scope: 'input',
id: attribute('name')
})
});
const login = form.fields.byId('login')
const password = form.fields.byId('password')
Hopefully it should be also possible to proxy it like we do for positional elements:
const { login, password } = form.fields;
@lsthornt have you tried doing something like this?
<ul>
<li data-test-id='UUID1'>Object 1</li>
<li data-test-id='UUID2'>Object 2</li>
</ul>
// I'm using the new API for collections here but it should work the same with
// old API
PageObject.create({
objects: collection('ul li', {
id: attribute('data-test-id')
})
});
let li = page.objects().filterBy('id', 'UUID1')[0];
assert.equal(li.text, 'Object 1');
----
// And going a bit further
PageObject.create({
objects: collection('ul li', {
id: attribute('data-test-id')
}),
objectById(id) {
return this.objects().filterBy('id', id)[0];
}
});
assert.equal(page.objectById('UUID2').text, 'Object 2');
Assuming the original markup:
<ul>
<li data-test-id='UUID1'>Object 1</li>
<li data-test-id='UUID2'>Object 2</li>
</ul>
I believe, today we can do it like:
const { objects } = create({
scope: 'ul',
objects: collection('li', {
id: attribute('data-test-id'),
})
});
objects.findOneBy('id', 'UUID1');