wix-incubator / unidriver

UniDriver - Universal Component Drivers 🚀
MIT License
53 stars 15 forks source link

Feature Request: `children` API #12

Open hepiyellow opened 5 years ago

hepiyellow commented 5 years ago

I have a base unidriver, and I want to get the first child. I can do it by getting the native element

it ('should have first child text', ()=> {
  const firstChildText: HTMLElement = driver.root().getNative().children[0].textContent;
}

But I want the driver to have a getFirstChildText function, I don't need to expose the root UniDriver.

It is not possible to use querySelectAll to get direct children. A quote from a Stackoverflow answer:

Instead of the unsupported myDiv.querySelectorAll("> *") you can just write myDiv.children

So I expect UniDriver would provide a children API.

GabiGrin commented 5 years ago

@hepiyellow sorry for the delay how is it different than yourDriver.$$('.rows').get(0).text()?

hepiyellow commented 5 years ago

@GabiGrin

Is there any technical reason why a children API would be problematic? Did you try it, and realized something I haven't thought of? Or just didn't try to implement it?

GabiGrin commented 5 years ago

@hepiyellow I understand the need better now, but still not sure it fits

.children works well for DOM, but what about other environments? how would you implement it in:

Can you share your exact use case? your test example is not a good use case for unidriver, as you are not using it's abstraction and accessing the dom element again.

hepiyellow commented 5 years ago

In both protractor and puppeteer, you run a custom script in the browser environment and receive the return value.

Protractor

browser.executeScript

If the return value includes HTMLElements, they are wrapped with WebDrivers (ElementFinders), so we can wrap them with a UniDriver.

Puppeterr

page.eval()

Selenium

I think selenium is same as protractor (actually protractor uses the selenium's executeScript.

My example is not a valid use of unidriver to create a component driver), because unidriver does not provide a children API (-: (so I have to use getNative())

GabiGrin commented 5 years ago

@hepiyellow regarding the use case, can you share a real world feature test you need this API for?

GabiGrin commented 5 years ago

as mentioned in #35 and #34, it's not aligned to the libraries principles

hepiyellow commented 5 years ago

@GabiGrin @borisd9 Consider this component which renders:

<div>
  <div class="sizeMedium">Item 1</div>
  <a href="...">
    <div class="sizeSmall">
      Link Item 2
    </div>
  </a>
  <div>
    <div>Item 3</div>
    <div>Item 3 - subtitle</div>
  </div>
</div>

As I mentioned in this comment above, the element, who's children we want to fetch, may not have a common class or data-hook on all children.

Say I need to provide my consumers a driver that can count the number of items. How do I do that?

Seems that NOT having a children API, means that UniDriver is forcing me to ADD a data-hook only for test purposes.

hepiyellow commented 5 years ago

@GabiGrin @borisd9

Your Principles Against You 🔫

Oh, and, by your principles of having in the API only methods representing things that an end User (Browser user) would do... Then you also shouldn't have $ and $$ in the API, since Users don't do queries by selectors.

If you do allow querying for nodes (elements) using selectors, then you might as well allow querying nodes by other means (like children , childNodes).

GabiGrin commented 5 years ago

@hepiyellow well, you can say that a manual tester will not write code and end that there 😛 Ideally, the api would be $('main submit button in the page').click() but there's a long way till it gets there

For now, I think it's sane to leave the challenge of locating elements revolving css selectors. The actions (click/etc) should stay "manual tester only" though

With that in mind, my main concern regarding this is that it couples the implementation to DOM selectors, not that it defies philosophy.

In your case, you can add a class name, or use (.root-component-class div > *) PS: I think data-hook is an anti pattern, and each component should have an unique class name (in the example above, root-component-class is it)

hepiyellow commented 5 years ago

I can not use your suggested selector in my example case, since my components root element is that outer div, and i need it’s direct children. So if i have an instance of a unidriver over my component’s root div, call it ‘root’, i can’t do: root.$$(“> *”)

There is no “self” in css: root.$$(“self > *)