GithubHelp home page GithubHelp logo

admc / wd Goto Github PK

View Code? Open in Web Editor NEW
1.5K 53.0 403.0 3.9 MB

A node.js client for webdriver/selenium 2.

License: Other

Makefile 0.23% JavaScript 98.51% Shell 0.02% HTML 0.41% CSS 0.62% Handlebars 0.21%

wd's Introduction

WD.js

NPM version Downloads Dependency Status devDependency Status Build Status Selenium Test Status

Selenium Test Status

node.js Webdriver/Selenium 2 client

This library is designed to be a maleable implementation of the webdriver protocol in Node, exposing functionality via a number of programming paradigms. If you are looking for a more polished, opinionated and active library - I would suggest webdriver.io.

Release Notes

here

Install

npm install wd

Note: WD.js does not start the selenium server. You may use the selenium-standalone package to install and start a selenium server.

Authors

License

Usage

Q promises + chaining

...

browser
  .init({browserName:'chrome'})
  .get("http://admc.io/wd/test-pages/guinea-pig.html")
  .title()
    .should.become('WD Tests')
  .elementById('i am a link')
  .click()
  .eval("window.location.href")
    .should.eventually.include('guinea-pig2')
  .back()
  .elementByCss('#comments').type('Bonjour!')
  .getValue().should.become('Bonjour!')
  .fin(function() { return browser.quit(); })
  .done();

full code here

Pure async

...

browser.init({browserName:'chrome'}, function() {
  browser.get("http://admc.io/wd/test-pages/guinea-pig.html", function() {
    browser.title(function(err, title) {
      title.should.include('WD');
      browser.elementById('i am a link', function(err, el) {
        browser.clickElement(el, function() {
          browser.eval("window.location.href", function(err, href) {
            href.should.include('guinea-pig2');
            browser.quit();
          });
        });
      });
    });
  });
});

full code here

Q promises without chaining

See example here.

Generators api

Yiewd

Yiewd is a wrapper around Wd.js that uses generators in order to avoid nested callbacks, like so:

wd.remote(function*() {
  yield this.init(desiredCaps);
  yield this.get("http://mysite.com");
  el = yield this.elementById("someId");
  yield el.click();
  el2 = yield this.elementById("anotherThing")
  text = yield el2.text();
  text.should.equal("What the text should be");
  yield this.quit();
});

Mocha integration

...

describe("using promises and chai-as-promised", function() {
  var browser;

  before(function() {
    browser = wd.promiseChainRemote();
    ...

    return browser.init({browserName:'chrome'});
  });

  beforeEach(function() {
    return browser.get("http://admc.io/wd/test-pages/guinea-pig.html");
  });

  after(function() {
    return browser.quit();
  });

  it("should retrieve the page title", function() {
    return browser.title().should.become("WD Tests");
  });

  it("submit element should be clicked", function() {
    return browser.elementById("submit").click().eval("window.location.href")
      .should.eventually.include("&submit");
  });
});

example here

Repl

If wd was installed via npm run:

./node_modules/.bin/wd shell

Or for local install run:

node lib/bin.js shell

Then within the shell:

): wd shell
> x = wd.remote() or wd.remote("ondemand.saucelabs.com", 80, "username", "apikey") or wd.remote("hub.browserstack.com", 80, "username", "apikey") or wd.remote("hub.testingbot.com", 80, "key", "secret")

> x.init() or x.init({desired capabilities override})
> x.get("http://www.url.com")
> x.eval("window.location.href", function(e, o) { console.log(o) })
> x.quit()

Doc

Api

jsonwire mapping + api doc

full jsonwire mapping

JsonWireProtocol

WD is simply implementing the Selenium JsonWireProtocol, for more details see the official docs:

WD is incrementally implementing the Mobile JsonWireProtocol draft, see proposal docs:

Check which Mobile JsonWire Protocol methods are supported in /doc/jsonwire-mobile.md

Browser initialization

Indexed parameters

var browser = wd.remote();
// or
var browser = wd.remote('localhost');
// or
var browser = wd.remote('localhost', 8888);
// or
var browser = wd.remote("ondemand.saucelabs.com", 80, "username", "apikey");
// or
var browser = wd.remote("hub.browserstack.com", 80, "username", "apikey");
// or
var browser = wd.remote("hub.testingbot.com", 80, "key", "secret");

Named parameters

The parameters used are similar to those in the url module.

var browser = wd.remote()
// or
var browser = wd.remote({
  hostname: '127.0.0.1',
  port: 4444,
  user: 'username',
  pwd: 'password',
});
// or
var browser = wd.remote({
  hostname: '127.0.0.1',
  port: 4444,
  auth: 'username:password',
});

The following parameters may also be used (as in earlier versions):

var browser = wd.remote({
  host: '127.0.0.1',
  port: 4444,
  username: 'username',
  accessKey: 'password',
});

Url string

var browser = wd.remote('http://localhost:4444/wd/hub');
// or
var browser = wd.remote('http://user:[email protected]/wd/hub');
// or
var browser = wd.remote('http://user:[email protected]/wd/hub');
// or
var browser = wd.remote('http://key:[email protected]/wd/hub');
// or
var browser = wd.remote('https://user:[email protected]/wd/hub');

Url object created via url.parse

URL module documentation

var url = require('url');
var browser = wd.remote(url.parse('http://localhost:4444/wd/hub'));
// or
var browser = wd.remote(url.parse('http://user:[email protected]:80/wd/hub'));
// or
var browser = wd.remote(url.parse('http://user:[email protected]:80/wd/hub'));
// or
var browser = wd.remote(url.parse('http://key:[email protected]:80/wd/hub'));
// or
var browser = wd.remote(url.parse('https://user:[email protected]/wd/hub'));

Defaults

{
    protocol: 'http:'
    hostname: '127.0.0.1',
    port: '4444'
    path: '/wd/hub'
}

Specifying driver type in remote

You may pass async,promise or promiseChain to remote to specify the driver type instead of calling the driver specific method.

var browser = wd.remote('promiseChain')
// or
var browser = wd.remote('localhost', 8888, 'promise');
// or
var browser = wd.remote('localhost', 'promiseChain');
// or
var browser = wd.remote({
  hostname: '127.0.0.1',
  port: 4444,
  user: 'username',
  pwd: 'password',
}, 'promise');
// or
var browser = wd.remote({
  hostname: '127.0.0.1',
  port: 4444,
  auth: 'username:password',
}, 'promiseChain');

Attach to an already-existing session

Instead of calling 'init' use 'attach' using the WebDriver session ID. Use detach to detach from the session (callbacks are optional).

var browser = wd.remote('http://localhost:4444/wd/hub');
browser.attach('df606fdd-f4b7-4651-aaba-fe37a39c86e3', function(err, capabilities) {
  // The 'capabilities' object as returned by sessionCapabilities
  if (err) { /* that session doesn't exist */ }
  else {
    browser.elementByCss("button.groovy-button", function(err, el) {
      ...
    });
  }
});
...
browser.detach();

Capabilities

doc here.

Element function chaining (using promise chains)

With the promise chain api the method from the browser prototype and the element prototype are all available within the browser instance, so it might be confusing at first. However we tried to keep the logic as simple as possible using the principles below:

  • There is no state passed between calls, except for what the method returns.
  • If the method returns an element the element scope is propagated.
  • If the method returns nothing (click, type etc...) we make the method return the current element, so the element scope is propagated.
  • If the method returns something (text, getAttribute...), the element scope is lost.
  • You may use "<" as the first parameter to get out of the element scope.
  • You may use ">" as the first parameter to force the call to be done within the current context (mainly used to retrieve subelements).
  • By default element(s) methods are always executed in the global context, because this is the most common use case, but you may use ">" to retrieve subelements. If you want to change the default use browser.defaultChainingScope = 'element';.

If you need to do something more complicated, like reusing an element for 2 calls, then can either Q promise functionality (like then, Q.all or Q sequences), or retrieve your element twice (since the promise chain api is very terse, this is usually acceptable).

Element function chaining example here

Waiting for something

Below are the methods to use to wait for a condition:

  • browser.waitFor(asserter, timeout, pollFreq, cb) -> cb(err, value): generic wait method, the return value is provided by the asserter when the condition is satisfied.
  • browser.waitForElementBy???(value ,asserter, timeout, pollFreq, cb) -> cb(err, el): waits for a element then a condition, then returns the element.
  • browser.waitForConditionInBrowser(conditionExpr, timeout, pollFreq, cb) -> cb(err, boolean): waits for a js condition within a browser, then returns a boolean.

NOTE: When using waitForConditionInBrowser you must first set the async script timeout using setAsyncScriptTimeout(). For instance:

// init phase
browser
  .init()
  .setAsyncScriptTimeout(30000);
// test
browser
  .waitForConditionInBrowser("document.querySelectorAll('.foo').length > 0", 10000);

You should be able to use ready to use asserters, in most cases. Here is a simple example. Please refer to the asserter category in the api doc here.

Custom asserters should be written using either models below . target may be browser and/or element depending on the context.

// async
var asyncAsserter = new Asserter(
  function(target,cb) {
    ...
    cb(err, satisfied, value);
  }
);

// promise
var promiseAsserter = new Asserter(
  function(target) {
    ...
    return promise; // promise resolved with the wait_for return value.

    // Promise asserter should throw errors marked with `err.retriable=true`
    // when the condition is not satisfied.
  }
);

Here is a custom asserter example.

Adding custom methods

  • wd.addAsyncMethod(name, method): This is for regular async methods with callback as the last argument. This will not only add the method to the async browser prototype, but also wrap the method and add it to the promise and promiseChain prototypes.
  • wd.addPromiseMethod(name, method): This is for promise returning methods NOT USING CHAIN internally. This will not only add the method to the promise browser prototype, but also wrap the method and add it to the promiseChain prototype (but not to the async prototype).
  • wd.addPromiseChainMethod(name, method): This is for promise returning methods USING CHAIN internally. This will only add the method to the promiseChain browser prototype (but neither to async nor to promise browser prototypes).

If you are only using the promise chain api, you should probably stick with wd.addPromiseChainMethod.

Custom methods may be removed with wd.removeMethod(name). That will remove the method from the 3 prototypes.

Please refer to the following examples:

Note: No need to call rewrap anymore.

Promise helpers

This is an alternative to adding custom methods. See example here.

Starting the promise chain

The browser and element object are not themselves promises (cause that would lead to chaos), so you cannot call Q core methods on them. However you may call one of the method below to initiate the promise chain:

  • browser.chain()
  • browser.noop()
  • browser.resolve(promise)
  • element.chain()
  • element.noop()
  • element.resolve(promise)

The resolve methods work like Q thenResolve.

Extra promise methods:

  • at(i): get element from list (starting at 0).
  • nth(i): get element from list (starting at 1).
  • first(): get the first element.
  • second(): get the second element.
  • third(): get the third element.
  • last(): get the last element.
  • printError(prepend): print the previous error, prepend optional
  • print(prepend): print the previous promise result, prepend optional

NOTE: When using functions such as nth(), first(), second() you must use the "plural" versions of the get functions.

Working with external promise libraries

wd uses Q internally, but you may use promises from other libraries with the following methods:

  • browser.resolve(externalPromise)
  • wd.addPromiseChainMethod(name, externalPromise)
  • wd.addPromiseMethod(name, externalPromise)

The external promise will be automatically wrapped within a Q promise using new Q(externalPromise).

See example here.

Http configuration / base url

Http behaviour and base url may be configured via the configureHttp method as in the code below:

// global config
wd.configureHttp({
  timeout: 60000,
  retries: 3,
  retryDelay: 100,
  baseUrl: 'http://example.com/'
});
// per browser config
browser.configureHttp({
  timeout: 60000,
  retries: 3,
  retryDelay: 100,
  baseUrl: 'http://example.com/'
});
  • timeout: http timeout in ms, default is undefined (uses the server timeout, usually 60 seconds). Use 'default' or undefined for server default.
  • retries: Number of reconnection attempts in case the connection is dropped. Default is 3. Pass 0 or always to keep trying. Pass -1 or never to disable.
  • retryDelay: the number of ms to wait before reconnecting. Default is 15.
  • baseUrl: the base url use by the get method. The destination url is computed using url.resolve. Default is empty.
  • proxy: proxy configuration, as used in request. Default is empty.
  • If a field is not specified, the current configuration for this field is unchanged.

Environment variables for Saucelabs

When connecting to Saucelabs, the user and pwd fields can also be set through the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables.

The following helper are also available to update sauce jobs: sauceJobUpdate and sauceJobStatus.

Safe Methods

The safeExecute and safeEval methods are equivalent to execute and eval but the code is executed within a eval block. They are safe in the sense that eventual code syntax issues are tackled earlier returning as syntax error and avoiding browser hanging in some cases.

An example below of expression hanging Chrome:

browser.eval("wrong!!!", function(err, res) { // hangs
browser.safeEval("wrong!!!", function(err, res) { // returns
browser.execute("wrong!!!", function(err, res) { //hangs
browser.safeExecute("wrong!!!", function(err, res) { //returns

Working with mobile device emulators

It is possible to use wd to test mobile devices using either Selenium or Appium. However in either case the full JsonWire protocol is not supported (or is buggy).

Examples here.

Selenium

Both Android (using AndroidDriver) and ios (using ios-driver) are supported, locally or using Sauce Labs cloud.

Appium

Android and iOS work locally and on Sauce Labs or BrowserStack.

Run the tests!

# Install the Selenium server, Chromedriver connect
node_modules/.bin/install_selenium
node_modules/.bin/install_chromedriver
# NOTE: You may need to upgrade /tmp/sv-selenium/chromedriver to match your Chrome version!

#Run the selenium server with chromedriver:
node_modules/.bin/start_selenium_with_chromedriver

#Run the test
gulp test

//TODO: better doc + sauce test doc

Adding new method / Contributing

If the method you want to use is not yet implemented, that should be easy to add it to lib/webdriver.js. You can use the doubleclick method as a template for methods not returning data, and getOrientation for methods which returns data. No need to modify README as the doc generation is automated. Other contributions are welcomed.

Generating doc

The JsonWire mappings in the README and mapping files are generated from code comments using dox.

To update the mappings run the following commands:

make mapping > doc/api.md
make full_mapping > doc/jsonwire-full-mapping.md
make unsupported_mapping > doc/jsonwire-unsupported-mapping.md

Publishing

npm version [patch|minor|major]
git push origin master
git push --tags
npm publish

Test Coverage

test coverage

wd's People

Contributors

admc avatar arikon avatar austenke avatar avaly avatar bernii avatar dmlemeshko avatar dpgraham avatar geekdave avatar imurchie avatar jlipps avatar joeyparrish avatar jonahss avatar kazucocoa avatar khanhdodang avatar lloyd avatar mattisg avatar mattrayner avatar maudineormsby avatar onioni avatar peterbraden avatar pita avatar pwnall avatar ralphtheninja avatar santiycr avatar sebv avatar sourishkrout avatar stuk avatar theojepsen avatar vrunoa avatar whoaa512 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wd's Issues

selenium and event delegation

This question should probably go directly to selenium, but I've never used selenium other then with WD module. Does event delegation work in selenium? I'm listening for events on parent node and clicking on child element do not fire it. Do you have any experiences with this problem?

Extending WD with own methods is difficult

When attempting to extend WD with our own methods we ran into many difficulties, and it can't be easily done without many hacks.

We're using the chain()ing api, which architecturally is unsound, as it doesn't allow sub-chaining, meaning we have to manually push methods into the queue. Take a look at this method for example:

// Submit the login form details:
wdproto.login = function (username, password) {
    this.chain()
        .elementByCss('#username', function (err, el) {
            el.type(username);
        })
        .elementByCss('#password', function (err, el) {
            el.type(password);
        })
        .elementByCss('#login_submit', function (err, el) {
            el.click();
        })
};

// Later on...

wd.chain().init().get(url).login().waitForElementByCss('body', 10000);

What happens here is that our waitForElementByCss() call is added to the chain, and then everything inside login() is appended to said chain, because chain() returns a singleton.

If chain() were a factory method that returns a new instance of async.queue() attached to _this._queue, it would allow this level of design. Allow me to explain this with some ascii, to make the picture clearer:

// Current chain() impl
_this._queue ->
    singletonChain ->
        get(url)
        waitForElementByCss('body', 1000)
        elementByCss('#username')
        elementByCss('#password')
        elementByCss('#login_submit')
// Proposed chain() impl

_this._queue ->
    subChain ->
        get(url)
    subChain ->
        elementByCss('#username')
        elementByCss('#password')
        elementByCss('#login_submit')
    subChain ->
        waitForElementByCss('body', 10000)

Windows support: use named pipe in bin.js

The repl was crashing on me on WinXP. Adding a named pipe solved the problem...

.listen(process.platform === "win32" ? "\\\\.\\pipe\\node-repl-sock" :"/tmp/node-repl-sock");

Adding support for promises

I would love to add support for promises using Q. If I coded it up and created a pull request would you be willing to accept it?

I've had a look and it might require touching all the webdriver.js _callback functions, but the external callback api would remain the same.

error return is inconsistent, sometimes `null`, sometimes `undefined`

A total nitpick, but the error value passed to callbacks is inconsistent. For writing tests it would be great if a non-error was always represented with null.

Here is a sample test I wrote where I switch between assert.isNull() and assert.isUndefined:
https://github.com/lloyd/meh/blob/5d47fd820e62/factor_out_libraries/new_user_secondary.js

Again, this is a total nit and the test author could work around it simply by testing for falsey values, so fwiw.

make test fails

clean pull
npm install .

make test

WD output

per-method-test.coffee
✔ wd - per method test - starting express
....
✔ wd - per method test - chrome - type

POST: /session/:sessionID/element
GET: /session/:sessionID/element/49/attribute/value
POST: /session/:sessionID/element/49/click
POST: /session/:sessionID/keys

/Users/adam/Projects/wd/node_modules/should/lib/should.js:66
throw new AssertionError({
^
AssertionError: expected [Error: [object Object]] to not exist
make: *** [test] Error 1

Selenium server output

23:16:57.276 INFO - Executing: [send keys to active: Hello] at URL: /session/1337062481459/keys)
23:16:57.280 WARN - Exception thrown
org.openqa.selenium.UnsupportedCommandException: [GET, HEAD, DELETE]
Command duration or timeout: 2 milliseconds
Build info: version: '2.21.0', revision: '16552', time: '2012-04-11 19:08:38'
System info: os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.7.3', java.version: '1.6.0_31'
Driver info: driver.version: RemoteWebDriver
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:175)
at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:128)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:459)
at org.openqa.selenium.remote.ExecuteMethod.execute(ExecuteMethod.java:47)
at org.openqa.selenium.remote.RemoteKeyboard.sendKeys(RemoteKeyboard.java:35)
at org.openqa.selenium.support.events.internal.EventFiringKeyboard.sendKeys(EventFiringKeyboard.java:26)
at org.openqa.selenium.remote.server.handler.interactions.SendKeyToActiveElement.call(SendKeyToActiveElement.java:54)
at org.openqa.selenium.remote.server.handler.interactions.SendKeyToActiveElement.call(SendKeyToActiveElement.java:1)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at org.openqa.selenium.remote.server.DefaultSession$1.run(DefaultSession.java:151)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)

gh-pages branch mess up/restore/update

FYI I've had overwritten gh-pages with master by mistake, and when I tried to revert the commit the whole branch got corrupted. So I took the party to restore the gh-pages branch from my fork which was a few months old. Should not matter since this branch is seldom updated except for test and coverage files.

After that I updated the wd site using github generator, updated test coverage, and verified that test suite was still working.

Should be fine now, but if you notice some weird behaviour, let me know.

Error with OnDemand on browser.quit()

When executing the example code from /test/test.ondemand.js against SauceLabs, the last step (browser.quit()), fails on Sauce with "Connection refused: connect".

Possible to re-use browser across multiple tests?

This was an issue opened in wd-sync, but I think it need to be resolved here first.

I'm wondering if it's possible to re-use the browser across multiple tests, so that I don't have to wait for a browser to open for every test. I'm using the Mocha BDD style for tests right now, but if there is a testing framework better suited to wd-sync, I'm happy to change frameworks. Here is a gist showing what I'm doing now: https://gist.github.com/3490535

Ideally, I could browser.init() just once, before the tests run, but I run into errors like "needs a fiber". Do you have any suggestions? Thank you!

Bug with webdriver's inheritance

The way that the webdriver class/module/whatever inherits from EventEmitter is wrong:

webdriver.prototype = new EventEmitter();

This way each instance of webdriver you create is sharing the same EventEmitter variables.
This is not a problem if you have one webdriver, but if you have more, even not at the same time, it causes problems because when you call webdriver.on( 'status'|'command' ), the listeners of all instances (even ones that are not active) will be called whenever there is event. If one is trying to run several drivers in parallel it becomes a mess. In other words if you have two webdrivers each event in each webdriver will trigger two event callbacks.

The correct way to inherit from EventEmitter:

var util = require( 'util' );
function webdriver ( args ) {
  EventEmitter.call( this );
  //the rest of the webdriver constructor
}
util.inherits( webdriver, EventEmitter );
//now each webdriver instance has its own private event listeners

Version 8 on npm, only 7 on github?

Hi,
WD is looking great - thanks for publishing! I'm trying to make it run against SauceLabs and ran into some issues. If I run the basic ondemand example (from /test/test.ondemand.js) from current github version (0.0.7), then I get errors around browser.eval).

I looked at version 0.0.8, which is published on npm, and the statement is browser.exec. This version seems to work.

I was wondering which version I should be using and if the example in 0.0.7 is known to not work.

Thanks!

browser.setWindowSize

My Code:

browser.setWindowSize(vidWidth, vidHeight, function(err){
});

I am receiving an error saying:

Object # has no method 'setWindowSize'

Any help would be appreciated. Thanks.

enhancement

Just wondering admc and other view on this possible enhancements:

  • catching err status 7 on element function and returning null or undefined.
  • defaulting position arguments in moveTo method.
  • defaulting button to left in click.

Exposing options in "command" emit.

It's helpful to have the selector available for debugging purposes (such as a waitFor being unable to find an element).

I now do this in webdriver.js

    _this.emit('command', httpOpts.method,
        httpOpts.path.replace(this.sessionID, ':sessionID')
            .replace(this.basePath, ''),
        opts
    );

And then I can check for:

  data: 
   { using: 'class name',
     value: 'child_waitForElementByClassName' },

allow switching between active sessions

While it looks like you can start additional sessions by doing wd.init() repeatedly, but I don't see how you could toggle between sessions.

Is this in the API somewhere and I'm simply missing it?

I'm happy to hack something together and submit a pull request if it's missing and not high priority right now (if that's the case, let me know if you're picky about how I implement it).

Thanks!

Not working with grid2 hub yet?

I passed grid2 hub server host and port to the remote method.
A simple test(just getting a page) failed with

Error: The environment you requested was unavailable.

Reason:

{"status":13,"value":{"message":"Error forwarding the new session cannot find : {platform=ANY, javascriptEnabled=true, browserName=firefox, version=}","class":"org.openqa.grid.internal.GridException","stackTrace":[{"fileName":"RequestHandler.java","lineNumber":143,"className":"org.openqa.grid.web.servlet.handler.RequestHandler","methodName":"process"},{"fileName":"DriverServlet.java","lineNumber":79,"className":"org.openqa.grid.web.servlet.DriverServlet","methodName":"process"},{"fileName":"DriverServlet.java","lineNumber":65,"className":"org.openqa.grid.web.servlet.DriverServlet","methodName":"doPost"},{"fileName":"HttpServlet.java","lineNumber":727,"className":"javax.servlet.http.HttpServlet","methodName":"service"},{"fileName":"HttpServlet.java","lineNumber":820,"className":"javax.servlet.http.HttpServlet","methodName":"service"},{"fileName":"ServletHolder.java","lineNumber":428,"className":"org.openqa.jetty.jetty.servlet.ServletHolder","methodName":"handle"},{"fileName":"WebApplicationHandler.java","lineNumber":473,"className":"org.openqa.jetty.jetty.servlet.WebApplicationHandler","methodName":"dispatch"},{"fileName":"ServletHandler.java","lineNumber":568,"className":"org.openqa.jetty.jetty.servlet.ServletHandler","methodName":"handle"},{"fileName":"HttpContext.java","lineNumber":1530,"className":"org.openqa.jetty.http.HttpContext","methodName":"handle"},{"fileName":"WebApplicationContext.java","lineNumber":633,"className":"org.openqa.jetty.jetty.servlet.WebApplicationContext","methodName":"handle"},{"fileName":"HttpContext.java","lineNumber":1482,"className":"org.openqa.jetty.http.HttpContext","methodName":"handle"},{"fileName":"HttpServer.java","lineNumber":909,"className":"org.openqa.jetty.http.HttpServer","methodName":"service"},{"fileName":"HttpConnection.java","lineNumber":820,"className":"org.openqa.jetty.http.HttpConnection","methodName":"service"},{"fileName":"HttpConnection.java","lineNumber":986,"className":"org.openqa.jetty.http.HttpConnection","methodName":"handleNext"},{"fileName":"HttpConnection.java","lineNumber":837,"className":"org.openqa.jetty.http.HttpConnection","methodName":"handle"},{"fileName":"SocketListener.java","lineNumber":243,"className":"org.openqa.jetty.http.SocketListener","methodName":"handleConnection"},{"fileName":"ThreadedServer.java","lineNumber":357,"className":"org.openqa.jetty.util.ThreadedServer","methodName":"handle"},{"fileName":"ThreadPool.java","lineNumber":534,"className":"org.openqa.jetty.util.ThreadPool$PoolThread","methodName":"run"}]}}

“Not JSON response” on wrong selector type

Hi there,

When trying to call element(using, elm, callback), if using is incorrect, the Selenium server returns an HTML error page. This triggers, in turn, a Not JSON response error in wd, which makes it quite hard to debug.

(shortened) example data received when using css as using:

<html>
<head>
<title>Error 500 org.openqa.selenium.WebDriverException: org.openqa.selenium.WebDriverException: Cannot find matching element locator to: css
Build info: version: '2.24.1', revision: '17205', time: '2012-06-19 17:28:14'
System info: os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.6.8', java.version: '1.6.0_33'
Driver info: driver.version: unknown
[…]
<h2>HTTP ERROR: 500</h2><pre>org.openqa.selenium.WebDriverException: org.openqa.selenium.WebDriverException: Cannot find matching element locator to: css

Problem running tests

I am new to this project - I am trying to run the example tests and the usage instructions are not working for me. Specifically, I typed in the "make test" command and I get "no such file or directory". I have installed selenium jar file as instructed and it starts the server. Any info would be great - this is an awesome project !

FF session hangs when trying to get els on a dismissed window

Summary:

In some of our tests, we try to click an element in a dialog that has (sometimes) dismissed itself. Only when using FF, this test hangs, possibly because FF is throwing an error that wd is not catching.

Repro steps:

  1. open a dialog
  2. interact with it
  3. dialog closes itself
  4. try to find an element in the dialog

More details:

Spoke with this on mozilla irc with @AutomatedTester and his guess is it's a bug in wd:

AutomatedTester _6a68: I know if a window isnt around FirefoxDriver will error saying the window doesnt exist
AutomatedTester _6a68: so my gut feel is there there either a missing callback in wd or its unhandled

Here's an example on sauce labs of a test that hung: https://saucelabs.com/tests/5fd58b93e1a4481cb2e9708e90e7e6f0

And here's the relevant test, though we have a bunch of wd extensions that might make it a little opaque to see what we're doing: https://github.com/mozilla/browserid/blob/kapow/automation-tests/tests/remove-email.js#L172 If you're curious about how that test works, I'm happy to add explanation.

IE9: check for error message before trying to match() on it

I've seen a few IE9 errors of the form:

cancel-account | vista_ie_9 | var messageMatch = value.match(/([^\n]+)\nCommand duration/);
                                     ^
cancel-account | vista_ie_9 | TypeError: Cannot call method 'match' of null
    at Object.<anonymous> (/var/lib/jenkins/jobs/identity.browserid.dev.windows.7.ie.9/workspace/automation-tests/node_modules/wd/lib/webdriver.js:70:42)
    at Object.stringify (native)
    at /var/lib/jenkins/jobs/identity.browserid.dev.windows.7.ie.9/workspace/automation-tests/node_modules/wd/lib/webdriver.js:65:31
    at Error.inspect (/var/lib/jenkins/jobs/identity.browserid.dev.windows.7.ie.9/workspace/automation-tests/node_modules/wd/lib/webdriver.js:92:8)
    at /var/lib/jenkins/jobs/identity.browserid.dev.windows.7.ie.9/workspace/automation-tests/lib/wd-extensions.js:43:29
    at /var/lib/jenkins/jobs/identity.browserid.dev.windows.7.ie.9/workspace/automation-tests/node_modules/wd/lib/webdriver.js:207:29
    at IncomingMessage.<anonymous> (/var/lib/jenkins/jobs/identity.browserid.dev.windows.7.ie.9/workspace/automation-tests/node_modules/wd/lib/webdriver.js:184:9)
    at IncomingMessage.<anonymous> (events.js:88:20)
    at IncomingMessage.emit (/var/lib/jenkins/jobs/identity.browserid.dev.windows.7.ie.9/workspace/automation-tests/node_modules/vows/lib/vows.js:237:24)
    at HTTPParser.onMessageComplete (http.js:137:23)

(that snippet pulled from here)

The fix seems pretty clear: check that value isn't falsy before trying to do value.match.

Pull request coming in 2 seconds.

Add file upload support

Please make element.sendKeys() to automatically upload the file when it is used to set the value of a file input field.

This is not documented in JsonWriteProtocol, but nevertheless it is in the original selenium implementation for Java and Python.

References:
Original selenium python implementation:
http://code.google.com/p/selenium/source/browse/py/selenium/webdriver/remote/webelement.py

Some guy on stackoverflow shedding light on the issue:
http://stackoverflow.com/questions/10559728/uploading-files-remotely-on-selenium-webdriver-via-php

saucelabs jobs issues

Most jobs are not marked as passed, one job is unnamed.

For basic test, we notify the saucelabs server 3 times, but 2 messages seems to have no effect. Could someone check the saucelabs server log, we must be doing something wrong.

For browser-init it is also implemented, but messages disapear.

I'll track down the unnamed job later, it's probably in the browser-init test file.

I've disabled all tests but saucelabs on travis so that we track this down more easily.

Should wd.js return errors for unexpected responses?

Hi,

I noticed that the _simpleCallback in webdriver.js response handler will return a non-null error if it gets content from responses that are not specified in the protocol. This seems to be unnecessarily strict, and forces me to handle responses when a server has implemented them as in the case of GhostDriver.

https://github.com/admc/wd/blob/master/lib/webdriver.js#L113

I also filed an issue with GhostDriver because I do not think they should return a response when the standard doesn't say to:

https://github.com/detro/ghostdriver/issues/78

I don't know what the best approach is here, but I'm not sure that there is a good reason for returning this error and I'm simply forced to ignore it whenever I see it while using GhostDriver. Maybe there is a reason I am not aware of that makes this an error I should not ignore? (In which case I'd have to patch GhostDriver or stop using phantom.js I guess).

Correct Way to Test jQuery ready?

Hi,

I am not sure if this is the right place to post this question. Here we go anyway...

The application I'm trying to test generates a part of its user interface using jQuery. Is there some nice way to take this in count? I tried fiddling with the timeouts without success.

I know this must be very simple given jQuery is popular. Just missing something very obvious. :)

Advantages over selenium-webdriver?

What are some immediate difference from selenium-webdriver?

Do you support setting the screen dimension or view port so when I take a screenshot it will always be 800, 600 ?

chaining dsl

we ran into a problem with the chaining DSL. it seems like you cant chain on the browser object inside of a callback. note, we are calling browser.init and browser.quit etc from a different file, this just illustrates the example.

module.exports = function(browser, assert) {
  return browser
    .elementByCss('.something', function(error, element) {
      if (error) throw error;

      // DOESNT WORK
      // browser.moveto(element, function(error) {
      //   if (error) throw error;
      // })

      // WORKS BUT UGLY
      element.browser.moveTo(element, function() {
        if (error) throw error;
      })
    })
};

npm publish for appium functionality

Can we get someone to publish so that appium users can make use of the functionality we've added in the last bit? Maybe after merging bernii's request? Thanks!

frame method returns error code 13 - unknown error

I see there is a warning against using the frame method in the comments ....

  // avoid using this, webdriver seems very buggy  
  // doesn't work at all with chromedriver

Can anything be done about this problem or can you suggest a workaround?

Launching too much remotes() results in error

Hello

Using selenium grid + browsers, locally.
I'm trying to spread my tests accross multiple browser instances.

Here's a test file:

var wd = require('wd');
var async = require('async');
var assert = require('assert');

var desired = {
  browserName: 'firefox'
}

function launchTest() {
  var browser = wd.remote();
  async.series([
    browser.init.bind(browser, desired),
    browser.get.bind(browser, 'http://192.168.56.1:8080/tests/minified.html'),
    // wait for the test to execute before polling
    wait.bind(null, 5000),
    ], function(err, results) {
      console.log(arguments)
      browser.quit();
  });
}

launchTest();
launchTest();
launchTest();
launchTest();
launchTest();

function wait(ms, cb) {
  setTimeout(cb, ms);
}

When used I get this error:

{ '0': {"message":"Unexpected data in simpleCallback.","data":{"status":13,"value":{"message":"Session [94a62ef1-948d-4f00-827d-e019bf402cfd] not available and is not among the last 1000 terminated sessions.\nActive sessions are[ext. key 792a5d71-9a0f-4bc1-b426-19634b726aad, ext. key 507a5174-b868-4a55-b260-70bc6d86c62f]","class":"org.openqa.grid.common.exception.GridException","stackTrace":[{"fileName":"ActiveTestSessions.java","lineNumber":109,"className":"org.openqa.grid.internal.ActiveTestSessions"...,

If I launch the tests in series and not in parallel, everything is ok.

It seems that the number of instances for a particular browser is limiting us. If you launch more tests than available instances for the desired browser then it will fail badly.

I just upped the number of browser instances from 3 to 5 and everything worked. (5 instances, 5 tests)

What should we do? I can limit the number of parallel tests with async.queue but I guess we could handle this in wd ?

PS: I tried saucelabs and got same result, launching multiple remote in parallel results in fail in simpleCallback. I guess I'm limited to the number of instances of my saucelabs account.

Version inconsistency (0.0.25 / 0.0.26)?

The current version in the GitHub package.json is 0.0.25.
However using 'npm update', it installs 0.0.26.
Are versions out of sync?

btw: thanks a lot for creating and maintaining wd, it works great.

json mapping generation from docs broken?

See the README: we have a bunch of EXTRA cell values that look like they shouldn't be there. I followed the instructions to generate the mapping and made my docstrings look like the surrounding code. Anything else to know?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.