Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fireEvent new command #130

Open
ghost opened this issue May 26, 2014 · 11 comments
Open

fireEvent new command #130

ghost opened this issue May 26, 2014 · 11 comments

Comments

@ghost
Copy link

ghost commented May 26, 2014

Since recently, there is a new command in the selenium command list : fireEvent
Here is an extract from a script :

fireEvent id=searchq blur

It is used to simulate events on some fields.
Does anyone had a look on it and how to implement it in perl ?
I had a look in selenium server the sources, it seems to be translated in a javascript that find the element and send the event on it. something like
document.getElementById('foobar').onblur();

Any idea what has to be sent to the server ?

@gempesaw
Copy link
Collaborator

I did a cursory google search and saw some results from 2009/2010 referring to selenium RC? I didn't see anything about it in the JSONWireProtocol document. It does sound quite useful though so it would be nice if it were an up and coming change...

@ghost
Copy link
Author

ghost commented May 26, 2014

I had a deeper look in the java client code and in the file
java/client/src/com/thoughworks/selenium/DefaultSelenium, there is a "fireEvent" command that is sent to the selenium server.
I'm trying that and let you know

@ghost
Copy link
Author

ghost commented May 28, 2014

Selenium package is now using some javascript libraries to execute commands like fireEvent.
When recompiling the server sources, all those libraries are built and could be imported / used to realize the job.
For example, fireEvent blur is translated in "return ('fireEvent.js').apply(null, arguments);"
The fireEvent.js is built during the server compilation process.
I did a test with execute_script and it works fine !
How could we import those scripts and enhance our perl webDriver to provide all those new possibilities ?

@gempesaw
Copy link
Collaborator

For example, fireEvent blur is translated in "return ('fireEvent.js').apply(null, arguments);"
The fireEvent.js is built during the server compilation process.
I did a test with execute_script and it works fine !

Is fireEvent.js is automatically loaded/included with the standalone server? What did your execute_script test look like?

How could we import those scripts and enhance our perl webDriver to provide all those new possibilities ?

Making an assumption or two, in WebElement.pm, a suite of event functions that look something like

sub blur {
    my ($self) = @_;

    return $self->execute_script('return ("fireEvent.js").apply(null, arguments);', $self, 'blur');
}

with usage like

my $elem = $driver->find_element('unique', 'id');
$elem->blur;

???

(oh and hmm we'd need to update WebElement's driver attribute to handle execute_script as well, nbd...

@ghost
Copy link
Author

ghost commented May 28, 2014

The file fireEvent.js is used for multiple purpose
first, to retrieve the element from its locator, then to send the event to the element.
so the code should look like

$driver->fire_event('id=unique', 'blur')

So fire_event could look like

sub fire_event {
  my ($self, @args) = @_ ;
  my $script = this->_some_function_to_retreive_js_file('fireEvent.js') ;
  return this->execute_script("return (" . $script . ").apply(null, arguments);", @args) ;
}

The fireEvent.js script is built during the compilation of the selenium-sources package (client and server side). In the java client, it is built in a library file so using some "getResource" function will find the file and load it...
Then i guess that we should import those files in the perl package

@gempesaw
Copy link
Collaborator

The fireEvent.js script is built during the compilation of the selenium-sources package (client and server side). In the java client, it is built in a library file so using some "getResource" function will find the file and load it...

Would you mind providing a few links to the references where you found this stuff? Feeling a bit lazy about digging through docs at the moment :)

On different note, do you know if there are events that we want to fire against the entire page, ie, not against a particular element? If the events are always fired against elements, I think they'd fit better in the WebElement class instead of on the Driver - it's more consistent with the rest of the 'element only' actions being on WebElement..

@ghost
Copy link
Author

ghost commented Jun 2, 2014

Sorry for the delay,

You may download the selenium-standalone version from git :
http://selenium.googlecode.com/git/
Then use the "go" shell script to generate the packages and have a look
in build/javascript/selenium-atoms/ you will find the javascript files
needed.

About implementation, I think it should be one of Driver's methods.
The first argument is the locator of the field. This locator is an argument of the javascript. The driver doesn't need to retreive the webElement to ask it to execute the fireEvent script on it. But, the driver should ask to the browser to execute the script with 2 arguments : element locator and event name.

About events that could be sent on the entire page, I'm not sure. What I have seen so far, is events like 'rotate', 'shake', 'tap or double tap', etc... all events what comes with devices like phones.

@ghost
Copy link
Author

ghost commented Jun 4, 2014

I do have a problem with the result type of _execute_command.
If a script does not return a webElement, then undef value is returned.
But undef might be a valid response.

So is it possible to change the return value of _execute_command to check if the caller wants an array :

    return $resp->{cmd_return};

should by replaced by

    return wantarray ? ($resp->{cmd_status}, $resp->{cmd_return}) : $resp->{cmd_return};

The execute_script should also be adapted :

  my $ret = $self->_execute_command( $res, $params );
  return $self->_convert_to_webelement($ret) ; 

could be replaced by

  my @ret = $self->_execute_command( $res, $params );

  return wantarray ? ($ret[0], $self->_convert_to_webelement($ret[1])) : 
                    $self->_convert_to_webelement($ret[1])  ;

here the diff :

440c440,441
<                 return $resp->{cmd_return};
---
>               return wantarray ? ($resp->{cmd_status}, $resp->{cmd_return}) : $resp->{cmd_return};
>               # return $resp->{cmd_return};
1269c1270,1274
<         my $ret = $self->_execute_command( $res, $params );
---
>         my @ret = $self->_execute_command( $res, $params );
>         # my $ret = $self->_execute_command( $res, $params );
> 
>         return wantarray ? ($ret[0], $self->_convert_to_webelement($ret[1])) : $self->_convert_to_webelement($ret[1])  ;
>         # return $self->_convert_to_webelement($ret);
1271d1275
<         return $self->_convert_to_webelement($ret);

Let me know what you think about it

@ghost
Copy link
Author

ghost commented Jun 25, 2014

Any comment on my proposal ?

@gempesaw
Copy link
Collaborator

Hm, it does seem to be directly related to #135 - the return value of _execute_command is causing problems.

I'm reluctant to change the behavior of _execute_command, as it would impact every sub. The test coverage is pretty strong but I don't think it's 100%. I'm additionally wary about wantarray. Finally, as stated in the "USAGE" section of the docs,

If no error occurred, then the subroutine called will return the value sent back from the server (if a return value was sent).

So a rule of thumb while invoking methods on the driver is if the method did not croak when called, then you can safely assume the command was successful even if nothing was returned by the method.

which would imply that getting back undef from your executed script can?/should? be interpreted as success. That being said, things get a lot more complicated, especially with execute_script, so. I'm not really sure.

@teodesian
Copy link
Owner

It sounds like this is a javascript extension to the selenium RC; as such this should probably be implemented as a convenience wrapper around execute_script(), rather than fiddling with something fundamental like execute_script.

There are actually a wide variety of JS convenience methods what should probably be added to the module (such as waiting on events to fire, which is the only real way to conquer race conditions).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants