webdriverio-boneyard / wdio-sync

A WebdriverIO v4 plugin. Helper module to run WebdriverIO commands synchronously.
http://v4.webdriver.io
MIT License
17 stars 31 forks source link

[Feature Request] Support wrapping of elements in the value array with prototype methods #40

Closed christian-bromann closed 7 years ago

christian-bromann commented 7 years ago

From @gregorskii on October 26, 2016 21:48

The problem

When querying for elements via client.elements() in sync mode the response includes a WebDriver JSON object that contains a field values as an array. Each element of this array does not have the prototype methods .click .isVisible etc. There is also no way to query the DOM for the original WebDriver JSON element via the ID returned by the elements call.

Environment

When querying the DOM for elements through a selector the Webdriver JSON Object returned includes an array in its values field:

{ sessionId: '4a8763ec-9c6e-42c1-90a9-e64a2508c0d6',
  state: 'success',
  value: [ { ELEMENT: '204' } ],
  class: 'org.openqa.selenium.remote.Response',
  hCode: 886205991,
  selector: 'SELECTOR',
  _status: 0 }

There is not currently a way to use the prototype methods .click(), .element(), .elements() etc directly with a single item in the array. The docs state that these prototype methods will apply to the first element in the array, an example of which is click:

element to click on. If it matches with more than one DOM-element it automatically clicks on the first element

There are convenience methods to do these actions against an ELEMENT ID in the DOM via the elementIDMETHOD functions ex click.

However under certain use cases it would be helpful to have the ability to have the prototype methods applied to each element in the array, or to be able to query the DOM by ID and get the prototype methods.

An example use case of this would be in a map method after a elements query:

Direct form:

const items = this.instance.elements('SELECTOR');

return items.value.each((element) => {
   element.elements('a').isVisible();
  // ... any other actions against this element
});

Function form:

const items = this.instance.elements('SELECTOR');

return items.value.map((webJSONElement) => {
  return webJSONElement.ELEMENT;
}).each((id) => {
  const element = client.elementID(id);
  element.elements('a').isVisible();
  // ... any other actions against this element
});

This functionality is being used primarily with ChimpJS which uses a sync form of Webdriverio, or forces it to be sync.

Copied from original issue: webdriverio/webdriverio#1672

christian-bromann commented 7 years ago

This functionality is being used primarily with ChimpJS which uses a sync form of Webdriverio, or forces it to be sync.

Even though Chimpjs uses some functions from wdio-sync I can't promise that it will be supported there as well.

christian-bromann commented 7 years ago

From @gregorskii on November 2, 2016 15:32

Will the feature be available in wd-sync? I can work with the developers of chimp to pull it in.

christian-bromann commented 7 years ago

From @gregorskii on November 2, 2016 15:34

Also let me know if there is anything I can do to work on this. Happy to work on a PR if I know where to look and tips on implementing it.

Thanks!

christian-bromann commented 7 years ago

Will the feature be available in wd-sync?

Yes, in fact it will affect the method that is consumed by chimp.

All magic happen when the result object gets overloaded by applyPrototype in wdio-sync.

Actually let's move this into the wdio-sync project since most of the implementation has to been made there.

christian-bromann commented 7 years ago

@gregorskii holy 💩 .. I got this implemented. I will roll it out to the framework adapters and then you should be able to do something like this:

<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>

test:

it('should get text of all span elements', () => {
    browser.elements('span').value.forEach((span) => {
        console.log(span.getText());
    });
});

output:

1
2
3
4

That looks like super magic given that the test code does 5 async requests to a selenium server. I hope that won't bite my a\ at some point. 😆

gregorskii commented 7 years ago

😃 awesome! 🙏