ember-cli-page-object icon indicating copy to clipboard operation
ember-cli-page-object copied to clipboard

Add ability to look up items in a collection via properties other than index

Open lsthornt opened this issue 7 years ago • 6 comments

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.

lsthornt avatar Mar 06 '17 00:03 lsthornt

https://github.com/san650/ember-cli-page-object/issues/198 related.

ro0gr avatar Mar 06 '17 05:03 ro0gr

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();

dadleyy avatar Aug 18 '17 18:08 dadleyy

@lsthornt Interesting. How does this work with component integration tests?

dodeja avatar Nov 01 '17 02:11 dodeja

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

pzuraq avatar Nov 18 '17 17:11 pzuraq

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;

ro0gr avatar Jul 24 '18 22:07 ro0gr

@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');

san650 avatar Jul 24 '18 22:07 san650

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');

ro0gr avatar Nov 25 '22 22:11 ro0gr