Security News
Maven Central Adds Sigstore Signature Validation
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.
node.js Webdriver/Selenium 2 client
npm install wd
Latest version is 0.2.8
.
Many changes have been introduced in 0.2.x versions, please check here for more details.
...
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();
...
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() {
/* jshint evil: true */
browser.eval("window.location.href", function(err, href) {
href.should.include('guinea-pig2');
browser.quit();
});
});
});
});
});
});
See example here.
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();
});
...
describe("using mocha-as-promised 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");
});
});
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")
> 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()
WD is simply implementing the Selenium JsonWireProtocol, for more details see the official docs:
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");
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',
});
var browser = wd.remote('http://localhost:4444/wd/hub');
// or
var browser = wd.remote('http://user:apiKey@ondemand.saucelabs.com/wd/hub');
var url = require('url');
var browser = wd.remote(url.parse('http://localhost:4444/wd/hub'));
// or
var browser = wd.remote(url.parse('http://user:apiKey@ondemand.saucelabs.com:80/wd/hub'));
{
protocol: 'http:'
hostname: '127.0.0.1',
port: '4444'
path: '/wd/hub'
}
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');
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();
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:
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
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.
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.
This is an alternative to adding custom methods. See example here.
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
.
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 optionalprint(prepend)
: print the previous promise result, prepend optionalNOTE: When using functions such as nth()
, first()
, second()
you must use the "plural" versions of the get
functions.
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 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/'
});
undefined
(uses the server timeout,
usually 60 seconds). Use 'default'
or undefined
for server default.3
. Pass 0
or always
to keep trying. Pass -1
or never
to disable.15
.get
method. The destination url is computed using
url.resolve
. Default is empty.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
.
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
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.
Both Android (using AndroidDriver) and ios (using ios-driver) are supported, locally or using Sauce Labs cloud.
Android and iOS work locally and on Sauce Labs.
# Install the Selenium server, Chromedriver connect
node_modules/.bin/install_selenium
node_modules/.bin/install_chromedriver
#Run the selenium server with chromedriver:
node_modules/.bin/start_selenium_with_chromedriver
cd wd
npm install
make test
# look at the results!
# Install Sauce Connect
node_modules/.bin/install_sauce_connect
# Set the following env variales: SAUCE_USERNAME and SAUCE_ACCESS_KEY
# Start Sauce Connect:
node_modules/.bin/start_sauce_connect
cd wd
npm install
make test_e2e_sauce # may be run without sauce connect
make test_midway_sauce_connect
# look at the results on Saucelabs site!
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.
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
npm version [patch|minor|major]
git push --tags origin master
npm publish
FAQs
WebDriver/Selenium 2 node.js client
We found that wd-edge demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.
Security News
CISOs are racing to adopt AI for cybersecurity, but hurdles in budgets and governance may leave some falling behind in the fight against cyber threats.
Research
Security News
Socket researchers uncovered a backdoored typosquat of BoltDB in the Go ecosystem, exploiting Go Module Proxy caching to persist undetected for years.