Mink icon indicating copy to clipboard operation
Mink copied to clipboard

Implement cross-driver $element->executeJs()

Open Thinkscape opened this issue 11 years ago • 14 comments

I've found myself in a corner more than once, trying to use the built in search traversal with JS methods.

One example of that would be interacting with <select> augmenting JS scripts (selectable, select2 etc.). In order to work around issues with those, I need to be able to invoke pieces of JS on some elements.

For example:

// [...] find the field to change
$field->selectOption($option, false);
$this->getSession()->evaluateScript('$("select").trigger("change");');

Currently there's no easy method to get reference to the NodeElement node in JS. Internally, Selenium2 driver uses executeJsOnXpath() method which takes a script template and "injects" the element we want to target. I'd love to be able to do this:

// [...] find the field to change
$field->selectOption($option, false);
$field->executeJs('$({{ELEMENT}}).trigger("change");');

Thinkscape avatar Apr 23 '14 15:04 Thinkscape

I like the idea in general, but here are a few caveats:

  1. The method for running a JS code on the element is different for each driver, so most likely the {{ELEMENT}} won't do the trick with other drivers.
  2. Looking at your example I bet the "change JS event triggering" is not something that a regular website visitor can do :) Maybe you're trying to compensate for some missing Mink functionality?
  3. The {{ELEMENT}} in Selenium2 is replaced by DOM node if I'm not mistaken, no quotes are not needed.

aik099 avatar Apr 23 '14 15:04 aik099

  1. indeed
  2. not really. selectOption() will target and change a <select> field, but most of those aforementioned libs hide the real <select> and replace it with some UI <div> or something else. Whenever you change anything in the real <select> it should be caught, but some of those libs are not smart enough - that's why they need a little push - notification about external change to the underlying element (which is hidden, so it wouldn't be manipulated by the end user, but it DOES reflect what the user does with the dropdown).
  3. true, my bad. corrected

Thinkscape avatar Apr 23 '14 15:04 Thinkscape

Would you mind sending a PR for Mink and all of the drivers, that support JS (separate PR for each driver). Tests will go the Mink PR. And I guess executeJavaScript will be a better looking name.

aik099 avatar Apr 23 '14 15:04 aik099

indeed, the {{ELEMENT}} cannot be replaced cross-driver. It is replaced by a DOM element reference retrieved from Selenium. Other drivers may have their own way to get a reference to the DOM node (I know Sahi does for instance, as it is the way most actions are implemented), but this still relies on some JS scope, which means exposing a generic method for this is likely to cause issues (depending of the way your code is written aroudn it, it could break the JS code retrieving the reference. For instance, Selenium2 passes the element reference to the code being called, and the replacement is arguments[0]. this means that if you put {{ELEMENT}} inside a JS function, you will get a totally different JS object. On the other hand, in Sahi, getting the object is done as _sahi._byXPath("({$xpathEscaped})[1]");, so it will work in inner scopes as long as you don't define a local _sahi variable. In Selenium1, it would be done by calling some methods on browserbot, and I don't know how it is scoped exactly.

This means that using a {{ELEMENT}} replacement on the code will not work for a user-facing API (we can do it in Selenium2Driver because we control all JS passed to it)

stof avatar Apr 23 '14 15:04 stof

before sending a PR to all drivers, it is required to define the expected interface. This means defining what is valid to be passed to the function (for instance, DriverInterface::executeScript is not abstracted properly in 1.5 and below, as the accepted JS code is not the same in the different drivers).

stof avatar Apr 23 '14 16:04 stof

(for instance, DriverInterface::executeScript is not abstracted properly in 1.5 and below, as the accepted JS code is not the same in the different drivers).

That is one more reason to do Mink 1.6 release as soon as possible.

aik099 avatar Apr 23 '14 18:04 aik099

@Thinkscape , any PR coming in?

aik099 avatar Dec 13 '14 12:12 aik099

before doing a PR, we need to define the way the JS code would have access to the element. The proposed spec is incomplete

stof avatar Dec 19 '14 12:12 stof

Do we have an interface for that ?

Thinkscape avatar Dec 29 '14 08:12 Thinkscape

What do you mean by interface?:

  • is method present in PHP interface? no need, because it would be placed in NodeElement itself
  • representation in web interface? no, because we don't need it

aik099 avatar Dec 29 '14 09:12 aik099

@Thinkscape do you have any proposal about the way the JS code passed as argument would get access to the DOM node ?

stof avatar Jan 07 '15 13:01 stof

@Thinkscape ping

stof avatar Feb 04 '15 17:02 stof

@Thinkscape any news ?

stof avatar Mar 22 '15 21:03 stof

No, sorry. The only thing that comes to my mind is xpath generation (similar to chrome dev tools, when you right click and element and select "copy path").

Thinkscape avatar Aug 03 '15 13:08 Thinkscape