Coverage

88%
667
589
78

main.js

100%
19
19
0
LineHitsSource
11var __slice = Array.prototype.slice;
21var SPECIAL_KEYS = require('./special-keys');
31var webdriver = require('./webdriver');
41var promiseWebdriver = require('./promise-webdriver');
5
6// parses server parameters
71var parseRemoteWdConfig = function(args) {
839 var config;
939 if (typeof (args[0]) === 'object') {
1032 config = args[0];
11 } else {
127 config = {
13 host: args[0],
14 port: args[1],
15 username: args[2],
16 accessKey: args[3]
17 };
18 }
1939 return config;
20};
21
22// creates the webdriver object
23// server parameters can be passed in 2 ways
24// - as a list of arguments host,port, username, accessKey
25// - as an option object containing the fields above
261exports.remote = function() {
2733 var args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
2833 var rwc = parseRemoteWdConfig(args);
29
3033 return new webdriver(rwc);
31};
32
33
341exports.promiseRemote = function() {
356 var args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
366 var rwc = parseRemoteWdConfig(args);
37
386 return new promiseWebdriver(rwc);
39};
40
41
421exports.SPECIAL_KEYS = SPECIAL_KEYS;

special-keys.js

100%
2
2
0
LineHitsSource
11var SPECIAL_KEYS = {
2 'NULL': '\uE000',
3 'Cancel': '\uE001',
4 'Help': '\uE002',
5 'Back space': '\uE003',
6 'Tab': '\uE004',
7 'Clear': '\uE005',
8 'Return': '\uE006',
9 'Enter': '\uE007',
10 'Shift': '\uE008',
11 'Control': '\uE009',
12 'Alt': '\uE00A',
13 'Pause': '\uE00B',
14 'Escape': '\uE00C',
15 'Key': 'Code',
16 'Space': '\uE00D',
17 'Pageup': '\uE00E',
18 'Pagedown': '\uE00F',
19 'End': '\uE010',
20 'Home': '\uE011',
21 'Left arrow': '\uE012',
22 'Up arrow': '\uE013',
23 'Right arrow': '\uE014',
24 'Down arrow': '\uE015',
25 'Insert': '\uE016',
26 'Delete': '\uE017',
27 'Semicolon': '\uE018',
28 'Equals': '\uE019',
29 'Numpad 0': '\uE01A',
30 'Numpad 1': '\uE01B',
31 'Numpad 2': '\uE01C',
32 'Numpad 3': '\uE01D',
33 'Numpad 4': '\uE01E',
34 'Numpad 5': '\uE01F',
35 'Numpad 6': '\uE020',
36 'Numpad 7': '\uE021',
37 'Numpad 8': '\uE022',
38 'Numpad 9': '\uE023',
39 'Multiply': '\uE024',
40 'Add': '\uE025',
41 'Separator': '\uE026',
42 'Subtract': '\uE027',
43 'Decimal': '\uE028',
44 'Divide': '\uE029',
45 'F1': '\uE031',
46 'F2': '\uE032',
47 'F3': '\uE033',
48 'F4': '\uE034',
49 'F5': '\uE035',
50 'F6': '\uE036',
51 'F7': '\uE037',
52 'F8': '\uE038',
53 'F9': '\uE039',
54 'F10': '\uE03A',
55 'F11': '\uE03B',
56 'F12': '\uE03C',
57 'Command': '\uE03D',
58 'Meta': '\uE03D'
59};
60
611module.exports = SPECIAL_KEYS;

webdriver.js

86%
543
469
74
LineHitsSource
11var EventEmitter = require('events').EventEmitter;
21var async = require("async");
31var _ = require("underscore");
41var fs = require("fs");
51var element = null;
61var request = require('request');
7
81var __slice = Array.prototype.slice;
91var utils = require("./utils");
101var JSONWIRE_ERRORS = require('./jsonwire-errors.js');
111var MAX_ERROR_LENGTH = 500;
12
13// webdriver client main class
14// WdConfig is an option object containing the following fields:
15// host,port, username, accessKey
161var webdriver = module.exports = function(remoteWdConfig) {
1739 this.sessionID = null;
1839 this.username = remoteWdConfig.username || process.env.SAUCE_USERNAME;
1939 this.accessKey = remoteWdConfig.accessKey || process.env.SAUCE_ACCESS_KEY;
2039 this.basePath = (remoteWdConfig.path || '/wd/hub');
2139 this.https = (remoteWdConfig.https || false);
2239 element = remoteWdConfig.element || require('./element').element;
23 // default
2439 this.options = {
25 host: remoteWdConfig.host || '127.0.0.1'
26 , port: remoteWdConfig.port || 4444
27 , path: (this.basePath + '/session').replace('//', '/')
28 };
2939 this.defaultCapabilities = {
30 browserName: 'firefox'
31 , version: ''
32 , javascriptEnabled: true
33 , platform: 'ANY'
34 };
35 // saucelabs default
3639 if ((this.username) && (this.accessKey)) {
3713 this.defaultCapabilities.platform = 'VISTA';
38 }
39};
40
41//inherit from EventEmitter
421webdriver.prototype = new EventEmitter();
43
441webdriver.prototype._getJsonwireError = function(status) {
4565 var jsonwireError = JSONWIRE_ERRORS.filter(function(err) {
461430 return err.status === status;
47 });
4865 return ((jsonwireError.length>0) ? jsonwireError[0] : null);
49};
50
511webdriver.prototype._newError = function(opts)
52{
5365 var err = new Error();
5465 _.each(opts, function(opt, k) {
55195 err[k] = opt;
56 });
57 // nicer error output
5865 err.inspect = function() {
592 var jsonStr = JSON.stringify(err);
602 return (jsonStr.length > MAX_ERROR_LENGTH)?
61 jsonStr.substring(0,MAX_ERROR_LENGTH) + '...' : jsonStr;
62 };
6365 return err;
64};
65
661webdriver.prototype._isWebDriverException = function(res) {
671575 return res &&
68 res.class &&
69 (res.class.indexOf('WebDriverException') > 0);
70};
71
721var cbStub = function() {};
73
74// just calls the callback when there is no result
751webdriver.prototype._simpleCallback = function(cb) {
76521 cb = cb || cbStub;
77521 var _this = this;
78521 return function(err, data) {
79521 if(err) { return cb(err); }
80521 if((data === '') || (data === 'OK')) {
81 // expected behaviour when not returning JsonWire response
82509 cb(null);
83 } else {
84 // looking for JsonWire response
8512 var jsonWireRes;
8624 try{jsonWireRes = JSON.parse(data);}catch(ign){}
8712 if (jsonWireRes && (jsonWireRes.sessionId) && (jsonWireRes.status !== undefined)) {
88 // valid JsonWire response
8912 if(jsonWireRes.status === 0) {
9012 cb(null);
91 } else {
920 var error = _this._newError(
93 { message:'Error response status: ' + jsonWireRes.status + '.'
94 , status:jsonWireRes.status
95 , cause:jsonWireRes });
960 var jsonwireError = _this._getJsonwireError(jsonWireRes.status);
970 if(jsonwireError){ error['jsonwire-error'] = jsonwireError; }
980 cb(error);
99 }
100 } else {
101 // something wrong
1020 cb(_this._newError(
103 {message:'Unexpected data in simpleCallback.', data: jsonWireRes || data}) );
104 }
105 }
106 };
107};
108
109// base for all callback handling data
1101webdriver.prototype._callbackWithDataBase = function(cb) {
1111640 cb = cb || cbStub;
112
1131640 var _this = this;
1141640 return function(err, data) {
1151640 if(err) { cb(err); }
1161640 var obj;
1171640 try {
1181640 obj = JSON.parse(data);
119 } catch (e) {
1200 return cb(_this._newError({message:'Not JSON response', data:data}));
121 }
1221640 if (obj.status > 0) {
12365 var error = _this._newError(
124 { message:'Error response status: ' + obj.status + '.'
125 , status:obj.status
126 , cause:obj });
12765 var jsonwireError = _this._getJsonwireError(obj.status);
128130 if(jsonwireError){ error['jsonwire-error'] = jsonwireError; }
12965 cb(error);
130 } else {
1311575 cb(null, obj);
132 }
133 };
134};
135
136// retrieves field value from result
1371webdriver.prototype._callbackWithData = function(cb) {
138791 cb = cb || cbStub;
139791 var _this = this;
140791 return _this._callbackWithDataBase(function(err,obj) {
141809 if(err) {return cb(err);}
142773 if(_this._isWebDriverException(obj.value)) {return cb(_this._newError(
143 {message:obj.value.message,cause:obj.value}));}
144773 cb(null, obj.value);
145 });
146};
147
148// retrieves ONE element
1491webdriver.prototype._elementCallback = function(cb) {
150456 cb = cb || cbStub;
151456 var _this = this;
152456 return _this._callbackWithDataBase(function(err, obj) {
153503 if(err) {return cb(err);}
154409 if(_this._isWebDriverException(obj.value)) {return cb(_this._newError(
155 {message:obj.value.message,cause:obj.value}));}
156409 if (!obj.value.ELEMENT) {
1570 cb(_this._newError(
158 {message:"no ELEMENT in response value field.",cause:obj}));
159 } else {
160409 var el = new element(obj.value.ELEMENT, _this);
161409 cb(null, el);
162 }
163 });
164};
165
166// retrieves SEVERAL elements
1671webdriver.prototype._elementsCallback = function(cb) {
168393 cb = cb || cbStub;
169393 var _this = this;
170393 return _this._callbackWithDataBase(function(err, obj) {
171 //_this = this; TODO: not sure about this
172393 if(err) {return cb(err);}
173393 if(_this._isWebDriverException(obj.value)) {return cb(_this._newError(
174 {message:obj.value.message,cause:obj.value}));}
175393 if (!(obj.value instanceof Array)) {return cb(_this._newError(
176 {message:"Response value field is not an Array.", cause:obj.value}));}
177393 var i, elements = [];
178393 for (i = 0; i < obj.value.length; i++) {
179251 var el = new element(obj.value[i].ELEMENT, _this);
180251 elements.push(el);
181 }
182393 cb(null, elements);
183 });
184};
185
1861webdriver.prototype._newHttpOpts = function(method) {
1872191 var opts = _.extend({}, this.options);
188
1892191 opts.method = method;
1902191 opts.headers = {};
1912191 opts.https = this.https;
192
1932191 opts.headers.Connection = 'keep-alive';
1942191 if (opts.method === 'POST' || opts.method === 'GET') {
1952151 opts.headers.Accept = 'application/json'; }
1962191 if (opts.method === 'POST') {
1971605 opts.headers['Content-Type'] = 'application/json; charset=UTF-8'; }
1982191 opts.prepareToSend = function(data) {
1992191 this.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
2002191 this.url = (this.https? 'https' : 'http' ) + "://" + this.host + ":" + this.port + this.path;
2012191 this.body = data;
202 };
2032191 return opts;
204};
205
206
2071var strip = function strip(str) {
2082724 if(typeof(str) !== 'string') { return str; }
2091658 var x = [];
2101658 _(str.length).times(function(i) {
21127193463 if (str.charCodeAt(i)) {
21224722594 x.push(str.charAt(i));
213 }
214 });
2151658 return x.join('');
216};
217
218/**
219 * init(desired, cb) -> cb(err, sessionID)
220 * Initialize the browser.
221 *
222 * @jsonWire POST /session
223 */
2241webdriver.prototype.init = function() {
22530 var _this = this;
22630 var fargs = utils.varargs(arguments);
22730 var cb = fargs.callback,
228 desired = fargs.all[0] || {};
229
230 // copy containing defaults
23130 var _desired = _.clone(desired);
23230 _.defaults(_desired, this.defaultCapabilities);
233
234 // http options
23530 var httpOpts = _this._newHttpOpts('POST');
236
237 // authentication (for saucelabs)
23830 if ((_this.username) && (_this.accessKey)) {
23910 var authString = _this.username + ':' + _this.accessKey;
24010 var buf = new Buffer(authString);
24110 httpOpts.headers.Authorization = 'Basic ' + buf.toString('base64');
242 }
243
244 // building request
24530 var data = JSON.stringify({desiredCapabilities: _desired});
24630 httpOpts.timeout = this._httpInactivityTimeout;
24730 httpOpts.prepareToSend(data);
24830 request(httpOpts, function(err, res, data) {
24930 if(err) { return cb(err); }
25030 data = strip(data);
25130 if (!res.headers.location) {
2520 if (cb) {
2530 cb({ message: 'The environment you requested was unavailable.'
254 , data: data
255 });
256 } else {
2570 console.error('\x1b[31mError\x1b[0m: The environment you requested was unavailable.\n');
2580 console.error('\x1b[33mReason\x1b[0m:\n');
2590 console.error(data);
2600 console.error('\nFor the available values please consult the WebDriver JSONWireProtocol,');
2610 console.error('located at: \x1b[33mhttp://code.google.com/p/selenium/wiki/JsonWireProtocol#/session\x1b[0m');
262 }
2630 return;
264 }
26530 var locationArr = res.headers.location.split('/');
26630 _this.sessionID = locationArr[locationArr.length - 1];
26730 _this.emit('status', '\nDriving the web on session: ' + _this.sessionID + '\n');
268
26960 if (cb) { cb(null, _this.sessionID); }
270
271 });
272};
273
274// standard jsonwire call
2751webdriver.prototype._jsonWireCall = function(opts) {
2762161 var _this = this;
277
278 // http options init
2792161 var httpOpts = _this._newHttpOpts.apply(_this, [opts.method]);
280
281 // retrieving path information
2822161 var relPath = opts.relPath;
2832161 var absPath = opts.absPath;
284
285 // setting path in http options
2864318 if (this.sessionID) { httpOpts.path += '/' + this.sessionID; }
2874276 if (relPath) { httpOpts.path += relPath; }
2882167 if (absPath) { httpOpts.path = absPath;}
289
290 // building callback
2912161 var cb = opts.cb;
2922161 if (opts.emit) {
293 // wrapping cb if we need to emit a message
29428 var _cb = cb;
29528 cb = function() {
29628 var args = __slice.call(arguments, 0);
29728 _this.emit(opts.emit.event, opts.emit.message);
29856 if (_cb) { _cb.apply(_this,args); }
299 };
300 }
301
302 // logging
3032161 _this.emit('command', httpOpts.method,
304 httpOpts.path.replace(this.sessionID, ':sessionID')
305 .replace(this.basePath, ''), opts.data
306 );
307
308 // writting data
3092161 var data = opts.data || '';
3102161 if (typeof data === 'object') {
3111445 data = JSON.stringify(data);
312 }
3132161 httpOpts.timeout = this._httpInactivityTimeout;
3142161 httpOpts.prepareToSend(data);
315 // building request
3162161 request(httpOpts, function(err, res, data) {
3172161 if(err) { return cb(err); }
3182161 data = strip(data);
3192161 cb(null, data || "");
320 });
321};
322
323/**
324 * status(cb) -> cb(err, status)
325 *
326 * @jsonWire GET /status
327 */
3281webdriver.prototype.status = function(cb) {
3292 this._jsonWireCall({
330 method: 'GET'
331 , absPath: this.basePath + '/status'
332 , cb: this._callbackWithData(cb)
333 });
334};
335
336/**
337 * sessions(cb) -> cb(err, sessions)
338 *
339 * @jsonWire GET /sessions
340 */
3411webdriver.prototype.sessions = function(cb) {
3424 this._jsonWireCall({
343 method: 'GET'
344 , absPath: this.basePath + '/sessions'
345 , cb: this._callbackWithData(cb)
346 });
347};
348
349// manually stop processing of queued chained functions
3501webdriver.prototype.haltChain = function(obj){
3510 this._chainHalted = true;
3520 this._queue = null;
353};
354
3551webdriver.prototype.pauseChain = function(timeoutMs, cb){
3560 setTimeout(function() {
3570 cb();
358 }, timeoutMs);
3590 return this.chain;
360};
361
3621webdriver.prototype.chain = function(obj){
3632 var _this = this;
3644 if (!obj) { obj = {}; }
365
366 // Update the onError callback if supplied. The most recent .chain()
367 // invocation overrides previous onError handlers.
3682 if (obj.onError) {
3690 this._chainOnErrorCallback = obj.onError;
3702 } else if (!this._chainOnErrorCallback) {
3712 this._chainOnErrorCallback = function(err) {
3720 if (err) { console.error("a function in your .chain() failed:", err); }
373 };
374 }
375
376 // Add queue if not already here
3772 if(!_this._queue){
3782 _this._queue = async.queue(function (task, callback) {
37912 if(task.args.length > 0 && typeof task.args[task.args.length-1] === "function"){
380 //wrap the existing callback
3818 var func = task.args[task.args.length-1];
3828 task.args[task.args.length-1] = function(err) {
383 // if the chain user has their own callback, we will not invoke
384 // the onError handler, supplying your own callback suggests you
385 // handle the error on your own.
3868 func.apply(null, arguments);
38716 if (!_this._chainHalted) { callback(); }
388 };
389 } else {
390 // if the .chain() does not supply a callback, we assume they
391 // expect us to catch errors.
3924 task.args.push(function(err) {
393 // if there is an error, call the onError callback,
394 // and do not invoke callback() which would make the
395 // task queue continue processing
3964 if (err) { _this._chainOnErrorCallback(err); }
3974 else { callback(); }
398 });
399 }
400
401 //call the function
40212 _this[task.name].apply(_this, task.args);
403 }, 1);
404
405 // add unishift method if we need to add sth to the queue
4062 _this._queue = _.extend(_this._queue, {
407 unshift: function (data, callback) {
4080 var _this = this;
4090 if(data.constructor !== Array) {
4100 data = [data];
411 }
4120 data.forEach(function(task) {
4130 _this.tasks.unshift({
414 data: task,
415 callback: typeof callback === 'function' ? callback : null
416 });
4170 if (_this.saturated && _this.tasks.length == _this.concurrency) {
4180 _this.saturated();
419 }
4200 async.nextTick(_this.process);
421 });
422 }
423 });
424 }
425
4262 var chain = {};
427
428 //builds a placeHolder functions
4292 var buildPlaceholder = function(name){
430338 return function(){
43112 _this._queue.push({name: name, args: Array.prototype.slice.call(arguments, 0)});
43212 return chain;
433 };
434 };
435
436 //fill the chain with placeholders
4372 _.each(_.functions(_this), function(k) {
438340 if(k !== "chain"){
439338 chain[k] = buildPlaceholder(k);
440 }
441 });
442
4432 return chain;
444};
445
4461webdriver.prototype.next = function(){
4470 this._queue.unshift({name: arguments[0], args: _.rest(arguments)});
448};
449
4501webdriver.prototype.queueAdd = function(func){
4510 func();
4520 return this.chain;
453};
454
455/**
456 * Alternate strategy to get session capabilities from server session list:
457 * altSessionCapabilities(cb) -> cb(err, capabilities)
458 *
459 * @jsonWire GET /sessions
460 */
4611webdriver.prototype.altSessionCapabilities = function(cb) {
4622 var _this = this;
463 // looking for the current session
4642 _this.sessions.apply(this, [function(err, sessions) {
4652 if(err) {
4660 cb(err, sessions);
467 } else {
4682 sessions = sessions.filter(function(session) {
4692 return session.id === _this.sessionID;
470 });
4712 cb(null, sessions[0]? sessions[0].capabilities : 0);
472 }
473 }]);
474};
475
476/**
477 * sessionCapabilities(cb) -> cb(err, capabilities)
478 *
479 * @jsonWire GET /session/:sessionId
480 */
4811webdriver.prototype.sessionCapabilities = function(cb) {
48212 this._jsonWireCall({
483 method: 'GET'
484 // default url
485 , cb: this._callbackWithData(cb)
486 });
487};
488
489/**
490 * Opens a new window (using Javascript window.open):
491 * newWindow(url, name, cb) -> cb(err)
492 * newWindow(url, cb) -> cb(err)
493 * name: optional window name
494 * Window can later be accessed by name with the window method,
495 * or by getting the last handle returned by the windowHandles method.
496 */
4971webdriver.prototype.newWindow = function() {
4986 var fargs = utils.varargs(arguments);
4996 var cb = fargs.callback,
500 url = fargs.all[0],
501 name = fargs.all[1];
5026 this.execute("var url=arguments[0], name=arguments[1]; window.open(url, name);", [url,name] , cb);
503};
504
505/**
506 * close(cb) -> cb(err)
507 *
508 * @jsonWire DELETE /session/:sessionId/window
509 */
5101webdriver.prototype.close = function(cb) {
5116 this._jsonWireCall({
512 method: 'DELETE'
513 , relPath: '/window'
514 , cb: this._simpleCallback(cb)
515 });
516};
517
518/**
519 * window(name, cb) -> cb(err)
520 *
521 * @jsonWire POST /session/:sessionId/window
522 */
5231webdriver.prototype.window = function(windowRef, cb) {
52414 this._jsonWireCall({
525 method: 'POST'
526 , relPath: '/window'
527 , cb: this._simpleCallback(cb)
528 , data: { name: windowRef }
529 });
530};
531
532/**
533 * frame(frameRef, cb) -> cb(err)
534 *
535 * @jsonWire POST /session/:sessionId/frame
536 */
5371webdriver.prototype.frame = function(frameRef, cb) {
538 // avoid using this, webdriver seems very buggy
539 // doesn't work at all with chromedriver
5406 if(typeof(frameRef) === 'function'){
5412 cb = frameRef;
5422 frameRef = null;
543 }
5446 this._jsonWireCall({
545 method: 'POST'
546 , relPath: '/frame'
547 , cb: this._simpleCallback(cb)
548 , data: { id: frameRef }
549 });
550};
551
552/**
553 * windowName(cb) -> cb(err, name)
554 */
5551webdriver.prototype.windowName = function(cb) {
55614 this.safeEval("window.name", cb);
557};
558
559/**
560 * windowHandle(cb) -> cb(err, handle)
561 *
562 * @jsonWire GET /session/:sessionId/window_handle
563 */
5641webdriver.prototype.windowHandle = function(cb) {
5656 this._jsonWireCall({
566 method: 'GET'
567 , relPath: '/window_handle'
568 , cb: this._callbackWithData(cb)
569 });
570};
571
572/**
573 * windowHandles(cb) -> cb(err, arrayOfHandles)
574 *
575 * @jsonWire GET /session/:sessionId/window_handles
576 */
5771webdriver.prototype.windowHandles = function(cb) {
57810 this._jsonWireCall({
579 method: 'GET'
580 , relPath: '/window_handles'
581 , cb: this._callbackWithData(cb)
582 });
583};
584
585/**
586 * quit(cb) -> cb(err)
587 * Destroy the browser.
588 *
589 * @jsonWire DELETE /session/:sessionId
590 */
5911webdriver.prototype.quit = function(cb) {
59228 this._jsonWireCall({
593 method: 'DELETE'
594 // default url
595 , emit: {event: 'status', message: '\nEnding your web drivage..\n'}
596 , cb: this._simpleCallback(cb)
597 });
598};
599
600/**
601 * Evaluate expression (using execute):
602 * eval(code, cb) -> cb(err, value)
603 *
604 * @jsonWire POST /session/:sessionId/execute
605 */
6061webdriver.prototype.eval = function(code, cb) {
60728 code = "return " + code + ";";
60828 this.execute.apply( this, [code, function(err, res) {
60928 if(err) {return cb(err);}
61028 cb(null, res);
611 }]);
612};
613
614/**
615 * Evaluate expression (using safeExecute):
616 * safeEval(code, cb) -> cb(err, value)
617 *
618 * @jsonWire POST /session/:sessionId/execute
619 */
6201webdriver.prototype.safeEval = function(code, cb) {
62141 this.safeExecute.apply( this, [code, function(err, res) {
62245 if(err) {return cb(err);}
62337 cb(null, res);
624 }]);
625};
626
627/**
628 * execute(code, args, cb) -> cb(err, result)
629 * execute(code, cb) -> cb(err, result)
630 * args: script argument array (optional)
631 *
632 * @jsonWire POST /session/:sessionId/execute
633 * @docOrder 1
634 */
6351webdriver.prototype.execute = function() {
636166 var fargs = utils.varargs(arguments);
637166 var cb = fargs.callback,
638 code = fargs.all[0],
639 args = fargs.all[1] || [];
640
641166 this._jsonWireCall({
642 method: 'POST'
643 , relPath: '/execute'
644 , cb: this._callbackWithData(cb)
645 , data: {script: code, args: args}
646 });
647};
648
649// script to be executed in browser
6501var safeExecuteJsScript = fs.readFileSync( __dirname + "/../browser-scripts/safe-execute.js", 'utf8');
651
652/**
653 * Execute script using eval(code):
654 * safeExecute(code, args, cb) -> cb(err, result)
655 * safeExecute(code, cb) -> cb(err, result)
656 * args: script argument array (optional)
657 *
658 * @jsonWire POST /session/:sessionId/execute
659 * @docOrder 2
660 */
6611webdriver.prototype.safeExecute = function() {
66251 var fargs = utils.varargs(arguments);
66351 var cb = fargs.callback,
664 code = fargs.all[0],
665 args = fargs.all[1] || [];
666
66751 this._jsonWireCall({
668 method: 'POST'
669 , relPath: '/execute'
670 , cb: this._callbackWithData(cb)
671 , data: {script: safeExecuteJsScript, args: [code, args]}
672 });
673};
674
675/**
676 * executeAsync(code, args, cb) -> cb(err, result)
677 * executeAsync(code, cb) -> cb(err, result)
678 * args: script argument array (optional)
679 *
680 * @jsonWire POST /session/:sessionId/execute_async
681 */
6821webdriver.prototype.executeAsync = function() {
6838 var fargs = utils.varargs(arguments);
6848 var cb = fargs.callback,
685 code = fargs.all[0],
686 args = fargs.all[1] || [];
687
6888 this._jsonWireCall({
689 method: 'POST'
690 , relPath: '/execute_async'
691 , cb: this._callbackWithData(cb)
692 , data: {script: code, args: args}
693 });
694};
695
696// script to be executed in browser
6971var safeExecuteAsyncJsScript = fs.readFileSync( __dirname + "/../browser-scripts/safe-execute-async.js", 'utf8');
698
699/**
700 * Execute async script using eval(code):
701 * safeExecuteAsync(code, args, cb) -> cb(err, result)
702 * safeExecuteAsync(code, cb) -> cb(err, result)
703 * args: script argument array (optional)
704 *
705 * @jsonWire POST /session/:sessionId/execute_async
706 */
7071webdriver.prototype.safeExecuteAsync = function() {
70816 var fargs = utils.varargs(arguments);
70916 var cb = fargs.callback,
710 code = fargs.all[0],
711 args = fargs.all[1] || [];
712
71316 this._jsonWireCall({
714 method: 'POST'
715 , relPath: '/execute_async'
716 , cb: this._callbackWithData(cb)
717 , data: {script: safeExecuteAsyncJsScript , args: [code, args]}
718 });
719};
720
721/**
722 * get(url,cb) -> cb(err)
723 * Get a new url.
724 *
725 * @jsonWire POST /session/:sessionId/url
726 */
7271webdriver.prototype.get = function(url, cb) {
72833 this._jsonWireCall({
729 method: 'POST'
730 , relPath: '/url'
731 , data: {'url': url}
732 , cb: this._simpleCallback(cb)
733 });
734};
735
736/**
737 * refresh(cb) -> cb(err)
738 *
739 * @jsonWire POST /session/:sessionId/refresh
740 */
7411webdriver.prototype.refresh = function(cb) {
7428 this._jsonWireCall({
743 method: 'POST'
744 , relPath: '/refresh'
745 , cb: this._simpleCallback(cb)
746 });
747};
748
749/**
750 * maximize(handle, cb) -> cb(err)
751 *
752 * @jsonWire POST /session/:sessionId/window/:windowHandle/maximize
753 */
7541webdriver.prototype.maximize = function(win, cb) {
7550this._jsonWireCall({
756 method: 'POST'
757 , relPath: '/window/'+ win + '/maximize'
758 , cb: this._simpleCallback(cb)
759 });
760};
761
762/**
763 * windowSize(handle, width, height, cb) -> cb(err)
764 *
765 * @jsonWire POST /session/:sessionId/window/:windowHandle/size
766 */
7671webdriver.prototype.windowSize = function(win, width, height, cb) {
7680this._jsonWireCall({
769 method: 'POST'
770 , relPath: '/window/'+ win + '/size'
771 , data: {'width':width, 'height':height}
772 , cb: this._simpleCallback(cb)
773 });
774};
775
776/**
777 * getWindowSize(handle, cb) -> cb(err, size)
778 * getWindowSize(cb) -> cb(err, size)
779 * handle: window handle to get size (optional, default: 'current')
780 *
781 * @jsonWire GET /session/:sessionId/window/:windowHandle/size
782 */
7831webdriver.prototype.getWindowSize = function() {
7848 var fargs = utils.varargs(arguments);
7858 var cb = fargs.callback,
786 win = fargs.all[0] || 'current';
7878this._jsonWireCall({
788 method: 'GET'
789 , relPath: '/window/'+ win + '/size'
790 , cb: this._callbackWithData(cb)
791 });
792};
793
794/**
795 * setWindowSize(width, height, handle, cb) -> cb(err)
796 * setWindowSize(width, height, cb) -> cb(err)
797 * width: width in pixels to set size to
798 * height: height in pixels to set size to
799 * handle: window handle to set size for (optional, default: 'current')
800 * @jsonWire POST /session/:sessionId/window/:windowHandle/size
801 */
8021webdriver.prototype.setWindowSize = function() {
8034 var fargs = utils.varargs(arguments);
8044 var cb = fargs.callback,
805 width = fargs.all[0],
806 height = fargs.all[1],
807 win = fargs.all[2] || 'current';
8084this._jsonWireCall({
809 method: 'POST'
810 , relPath: '/window/'+ win + '/size'
811 , cb: this._simpleCallback(cb)
812 , data: {width: width, height: height}
813 });
814};
815
816/**
817 * forward(cb) -> cb(err)
818 *
819 * @jsonWire POST /session/:sessionId/forward
820 */
8211webdriver.prototype.forward = function(cb) {
8222 this._jsonWireCall({
823 method: 'POST'
824 , relPath: '/forward'
825 , cb: this._simpleCallback(cb)
826 });
827};
828
829/**
830 * back(cb) -> cb(err)
831 *
832 * @jsonWire POST /session/:sessionId/back
833 */
8341webdriver.prototype.back = function(cb) {
8352 this._jsonWireCall({
836 method: 'POST'
837 , relPath: '/back'
838 , cb: this._simpleCallback(cb)
839 });
840};
841
8421webdriver.prototype.setHTTPInactivityTimeout = function(ms) {
8430 this._httpInactivityTimeout = ms;
844};
845
846/**
847 * setImplicitWaitTimeout(ms, cb) -> cb(err)
848 *
849 * @jsonWire POST /session/:sessionId/timeouts/implicit_wait
850 */
8511webdriver.prototype.setImplicitWaitTimeout = function(ms, cb) {
8529 this._jsonWireCall({
853 method: 'POST'
854 , relPath: '/timeouts/implicit_wait'
855 , data: {ms: ms}
856 , cb: this._simpleCallback(cb)
857 });
858};
859
860// for backward compatibility
8611webdriver.prototype.setWaitTimeout = webdriver.prototype.setImplicitWaitTimeout;
862
863/**
864 * setAsyncScriptTimeout(ms, cb) -> cb(err)
865 *
866 * @jsonWire POST /session/:sessionId/timeouts/async_script
867 */
8681webdriver.prototype.setAsyncScriptTimeout = function(ms, cb) {
86910 this._jsonWireCall({
870 method: 'POST'
871 , relPath: '/timeouts/async_script'
872 , data: {ms: ms}
873 , cb: this._simpleCallback(cb)
874 });
875};
876
877/**
878 * setPageLoadTimeout(ms, cb) -> cb(err)
879 * (use setImplicitWaitTimeout and setAsyncScriptTimeout to set the other timeouts)
880 *
881 * @jsonWire POST /session/:sessionId/timeouts
882 */
8831webdriver.prototype.setPageLoadTimeout = function(ms, cb) {
8843 this._jsonWireCall({
885 method: 'POST'
886 , relPath: '/timeouts'
887 , data: {type: 'page load', ms: ms}
888 , cb: this._simpleCallback(cb)
889 });
890};
891
892/**
893 * element(using, value, cb) -> cb(err, element)
894 *
895 * @jsonWire POST /session/:sessionId/element
896 */
8971webdriver.prototype.element = function(using, value, cb) {
898448 this._jsonWireCall({
899 method: 'POST'
900 , relPath: '/element'
901 , data: {using: using, value: value}
902 , cb: this._elementCallback(cb)
903 });
904};
905
906/**
907 * Retrieve an element avoiding not found exception and returning null instead:
908 * elementOrNull(using, value, cb) -> cb(err, element)
909 *
910 * @jsonWire POST /session/:sessionId/elements
911 * @docOrder 3
912 */
9131webdriver.prototype.elementOrNull = function(using, value, cb) {
9144 this.elements.apply(this, [using, value,
915 function(err, elements) {
9164 if(!err) {
9178 if(elements.length>0) {cb(null,elements[0]);} else {cb(null,null);}
918 } else {
9190 cb(err); }
920 }
921 ]);
922};
923
924/**
925 * Retrieve an element avoiding not found exception and returning undefined instead:
926 * elementIfExists(using, value, cb) -> cb(err, element)
927 *
928 * @jsonWire POST /session/:sessionId/elements
929 * @docOrder 5
930 */
9311webdriver.prototype.elementIfExists = function(using, value, cb) {
932147 this.elements.apply(this, [using, value,
933 function(err, elements) {
934147 if(!err) {
935294 if(elements.length>0) {cb(null,elements[0]);} else {cb(null);}
936 } else {
9370 cb(err); }
938 }
939 ]);
940};
941
942/**
943 * elements(using, value, cb) -> cb(err, elements)
944 *
945 * @jsonWire POST /session/:sessionId/elements
946 * @docOrder 1
947 */
9481webdriver.prototype.elements = function(using, value, cb) {
949389 this._jsonWireCall({
950 method: 'POST'
951 , relPath: '/elements'
952 , data: {using: using, value: value}
953 , cb: this._elementsCallback(cb)
954 });
955};
956
957/**
958 * Check if element exists:
959 * hasElement(using, value, cb) -> cb(err, boolean)
960 *
961 * @jsonWire POST /session/:sessionId/elements
962 * @docOrder 7
963 */
9641webdriver.prototype.hasElement = function(using, value, cb){
965124 this.elements.apply( this, [using, value, function(err, elements){
966124 if(!err) {
967124 cb(null, elements.length > 0 );
968 } else {
9690 cb(err); }
970 }]);
971};
972
973/**
974 * waitForElement(using, value, timeout, cb) -> cb(err)
975 */
9761webdriver.prototype.waitForElement = function(using, value, timeout, cb){
97724 var _this = this;
97824 var endTime = Date.now() + timeout;
979
98024 var poll = function(){
98184 _this.hasElement(using, value, function(err, isHere){
98284 if(err){
9830 return cb(err);
984 }
985
98684 if(isHere){
98720 cb(null);
988 } else {
98964 if(Date.now() > endTime){
9904 cb(new Error("Element didn't appear"));
991 } else {
99260 setTimeout(poll, 200);
993 }
994 }
995 });
996 };
997
99824 poll();
999};
1000
1001/**
1002 * waitForVisible(using, value, timeout, cb) -> cb(err)
1003 */
10041webdriver.prototype.waitForVisible = function(using, value, timeout, cb) {
100524 var _this = this;
100624 var endTime = Date.now() + timeout;
1007
100824 var poll = function(){
1009139 _this.isVisible(using, value, function(err, visible) {
1010139 if (err) {
10110 return cb(err);
1012 }
1013
1014139 if (visible) {
101520 cb(null);
1016 } else {
1017119 if (Date.now() > endTime) {
10184 cb(new Error("Element didn't become visible"));
1019 } else {
1020115 setTimeout(poll, 200);
1021 }
1022 }
1023 });
1024 };
102524 poll();
1026};
1027
1028/**
1029 * takeScreenshot(cb) -> cb(err, screenshot)
1030 *
1031 * @jsonWire GET /session/:sessionId/screenshot
1032 */
10331webdriver.prototype.takeScreenshot = function(cb) {
10342 this._jsonWireCall({
1035 method: 'GET'
1036 , relPath: '/screenshot'
1037 , cb: this._callbackWithData(cb)
1038 });
1039};
1040
1041// adding all elementBy... , elementsBy... function
1042
10431_.each(utils.elementFuncTypes, function(type) {
1044
1045 /**
1046 * elementByClassName(value, cb) -> cb(err, element)
1047 * elementByCssSelector(value, cb) -> cb(err, element)
1048 * elementById(value, cb) -> cb(err, element)
1049 * elementByName(value, cb) -> cb(err, element)
1050 * elementByLinkText(value, cb) -> cb(err, element)
1051 * elementByPartialLinkText(value, cb) -> cb(err, element)
1052 * elementByTagName(value, cb) -> cb(err, element)
1053 * elementByXPath(value, cb) -> cb(err, element)
1054 * elementByCss(value, cb) -> cb(err, element)
1055 *
1056 * @jsonWire POST /session/:sessionId/element
1057 */
10589 webdriver.prototype['element' + utils.elFuncSuffix(type)] = function(value, cb) {
1059424 webdriver.prototype.element.apply(this, [utils.elFuncFullType(type), value, cb]);
1060 };
1061
1062 /**
1063 * elementByClassNameOrNull(value, cb) -> cb(err, element)
1064 * elementByCssSelectorOrNull(value, cb) -> cb(err, element)
1065 * elementByIdOrNull(value, cb) -> cb(err, element)
1066 * elementByNameOrNull(value, cb) -> cb(err, element)
1067 * elementByLinkTextOrNull(value, cb) -> cb(err, element)
1068 * elementByPartialLinkTextOrNull(value, cb) -> cb(err, element)
1069 * elementByTagNameOrNull(value, cb) -> cb(err, element)
1070 * elementByXPathOrNull(value, cb) -> cb(err, element)
1071 * elementByCssOrNull(value, cb) -> cb(err, element)
1072 *
1073 * @jsonWire POST /session/:sessionId/elements
1074 * @docOrder 4
1075 */
10769 webdriver.prototype['element' + utils.elFuncSuffix(type)+ 'OrNull'] = function(value, cb) {
107736 webdriver.prototype.elements.apply(this, [utils.elFuncFullType(type), value,
1078 function(err, elements) {
107936 if(!err) {
108072 if(elements.length>0) {cb(null,elements[0]);} else {cb(null,null);}
1081 } else {
10820 cb(err); }
1083 }
1084 ]);
1085 };
1086
1087 /**
1088 * elementByClassNameIfExists(value, cb) -> cb(err, element)
1089 * elementByCssSelectorIfExists(value, cb) -> cb(err, element)
1090 * elementByIdIfExists(value, cb) -> cb(err, element)
1091 * elementByNameIfExists(value, cb) -> cb(err, element)
1092 * elementByLinkTextIfExists(value, cb) -> cb(err, element)
1093 * elementByPartialLinkTextIfExists(value, cb) -> cb(err, element)
1094 * elementByTagNameIfExists(value, cb) -> cb(err, element)
1095 * elementByXPathIfExists(value, cb) -> cb(err, element)
1096 * elementByCssIfExists(value, cb) -> cb(err, element)
1097 *
1098 * @jsonWire POST /session/:sessionId/elements
1099 * @docOrder 6
1100 */
11019 webdriver.prototype['element' + utils.elFuncSuffix(type)+ 'IfExists'] = function(value, cb) {
110236 webdriver.prototype.elements.apply(this, [utils.elFuncFullType(type), value,
1103 function(err, elements) {
110436 if(!err) {
110572 if(elements.length>0) {cb(null,elements[0]);} else {cb(null);}
1106 } else {
11070 cb(err); }
1108 }
1109 ]);
1110 };
1111
1112 /**
1113 * hasElementByClassName(value, cb) -> cb(err, boolean)
1114 * hasElementByCssSelector(value, cb) -> cb(err, boolean)
1115 * hasElementById(value, cb) -> cb(err, boolean)
1116 * hasElementByName(value, cb) -> cb(err, boolean)
1117 * hasElementByLinkText(value, cb) -> cb(err, boolean)
1118 * hasElementByPartialLinkText(value, cb) -> cb(err, boolean)
1119 * hasElementByTagName(value, cb) -> cb(err, boolean)
1120 * hasElementByXPath(value, cb) -> cb(err, boolean)
1121 * hasElementByCss(value, cb) -> cb(err, boolean)
1122 *
1123 * @jsonWire POST /session/:sessionId/elements
1124 * @docOrder 8
1125 */
11269 webdriver.prototype['hasElement' + utils.elFuncSuffix(type)] = function(value, cb) {
112736 webdriver.prototype.hasElement.apply(this, [utils.elFuncFullType(type), value, cb]);
1128 };
1129
1130 /**
1131 * waitForElementByClassName(value, timeout, cb) -> cb(err)
1132 * waitForElementByCssSelector(value, timeout, cb) -> cb(err)
1133 * waitForElementById(value, timeout, cb) -> cb(err)
1134 * waitForElementByName(value, timeout, cb) -> cb(err)
1135 * waitForElementByLinkText(value, timeout, cb) -> cb(err)
1136 * waitForElementByPartialLinkText(value, timeout, cb) -> cb(err)
1137 * waitForElementByTagName(value, timeout, cb) -> cb(err)
1138 * waitForElementByXPath(value, timeout, cb) -> cb(err)
1139 * waitForElementByCss(value, timeout, cb) -> cb(err)
1140 */
11419 webdriver.prototype['waitForElement' + utils.elFuncSuffix(type)] = function(value, timeout, cb) {
114220 webdriver.prototype.waitForElement.apply(this, [utils.elFuncFullType(type), value, timeout, cb]);
1143 };
1144
1145 /**
1146 * waitForVisibleByClassName(value, timeout, cb) -> cb(err)
1147 * waitForVisibleByCssSelector(value, timeout, cb) -> cb(err)
1148 * waitForVisibleById(value, timeout, cb) -> cb(err)
1149 * waitForVisibleByName(value, timeout, cb) -> cb(err)
1150 * waitForVisibleByLinkText(value, timeout, cb) -> cb(err)
1151 * waitForVisibleByPartialLinkText(value, timeout, cb) -> cb(err)
1152 * waitForVisibleByTagName(value, timeout, cb) -> cb(err)
1153 * waitForVisibleByXPath(value, timeout, cb) -> cb(err)
1154 * waitForVisibleByCss(value, timeout, cb) -> cb(err)
1155 */
11569 webdriver.prototype['waitForVisible' + utils.elFuncSuffix(type)] = function(value, timeout, cb) {
115720 webdriver.prototype.waitForVisible.apply(this, [utils.elFuncFullType(type), value, timeout, cb]);
1158 };
1159
1160 /**
1161 * elementsByClassName(value, cb) -> cb(err, elements)
1162 * elementsByCssSelector(value, cb) -> cb(err, elements)
1163 * elementsById(value, cb) -> cb(err, elements)
1164 * elementsByName(value, cb) -> cb(err, elements)
1165 * elementsByLinkText(value, cb) -> cb(err, elements)
1166 * elementsByPartialLinkText(value, cb) -> cb(err, elements)
1167 * elementsByTagName(value, cb) -> cb(err, elements)
1168 * elementsByXPath(value, cb) -> cb(err, elements)
1169 * elementsByCss(value, cb) -> cb(err, elements)
1170 *
1171 * @jsonWire POST /session/:sessionId/elements
1172 * @docOrder 2
1173 */
11749 webdriver.prototype['elements' + utils.elFuncSuffix(type)] = function(value, cb) {
117538 webdriver.prototype.elements.apply(this, [utils.elFuncFullType(type), value, cb]);
1176 };
1177
1178});
1179
1180/**
1181 * getTagName(element, cb) -> cb(err, name)
1182 *
1183 * @jsonWire GET /session/:sessionId/element/:id/name
1184 */
11851webdriver.prototype.getTagName = function(element, cb) {
11868 this._jsonWireCall({
1187 method: 'GET'
1188 , relPath: '/element/' + element + '/name'
1189 , cb: this._callbackWithData(cb)
1190 });
1191};
1192
1193/**
1194 * getAttribute(element, attrName, cb) -> cb(err, value)
1195 *
1196 * @jsonWire GET /session/:sessionId/element/:id/attribute/:name
1197 * @docOrder 1
1198 */
11991webdriver.prototype.getAttribute = function(element, attrName, cb) {
1200285 this._jsonWireCall({
1201 method: 'GET'
1202 , relPath: '/element/' + element + '/attribute/' + attrName
1203 , cb: this._callbackWithData(cb)
1204 });
1205};
1206
1207/**
1208 * isDisplayed(element, cb) -> cb(err, displayed)
1209 *
1210 * @jsonWire GET /session/:sessionId/element/:id/displayed
1211 */
12121webdriver.prototype.isDisplayed = function(element, cb) {
121312 this._jsonWireCall({
1214 method: 'GET'
1215 , relPath: '/element/' + element + '/displayed'
1216 , cb: this._callbackWithData(cb)
1217 });
1218};
1219
12201webdriver.prototype.displayed = webdriver.prototype.isDisplayed;
1221
1222/**
1223 * isSelected(element, cb) -> cb(err, selected)
1224 *
1225 * @jsonWire GET /session/:sessionId/element/:id/selected
1226 */
12271webdriver.prototype.isSelected = function(element, cb) {
12280 this._jsonWireCall({
1229 method: 'GET'
1230 , relPath: '/element/' + element + '/selected'
1231 , cb: this._callbackWithData(cb)
1232 });
1233};
1234
1235// webdriver.prototype.selected = webdriver.prototype.isSelected;
1236
1237/**
1238 * Get element value (in value attribute):
1239 * getValue(element, cb) -> cb(err, value)
1240 *
1241 * @jsonWire GET /session/:sessionId/element/:id/attribute/:name
1242 * @docOrder 3
1243 */
12441webdriver.prototype.getValue = function(element, cb) {
1245262 this.getAttribute.apply(this, [element, 'value', cb]);
1246};
1247
1248/**
1249 * clickElement(element, cb) -> cb(err)
1250 *
1251 * @jsonWire POST /session/:sessionId/element/:id/click
1252 */
12531webdriver.prototype.clickElement = function(element, cb) {
125430 this._jsonWireCall({
1255 method: 'POST'
1256 , relPath: '/element/' + element + '/click'
1257 , cb: this._simpleCallback(cb)
1258 });
1259};
1260
1261/**
1262 * getComputedCss(element, cssProperty , cb) -> cb(err, value)
1263 *
1264 * @jsonWire GET /session/:sessionId/element/:id/css/:propertyName
1265 */
12661webdriver.prototype.getComputedCss = function(element, cssProperty, cb) {
126797 this._jsonWireCall({
1268 method: 'GET'
1269 , relPath: '/element/' + element + '/css/' + cssProperty
1270 , cb: this._callbackWithData(cb)
1271 });
1272};
1273
12741webdriver.prototype.getComputedCSS = webdriver.prototype.getComputedCss;
1275
1276/**
1277 * flick(xSpeed, ySpeed, swipe, cb) -> cb(err)
1278 * Flicks, starting anywhere on the screen.
1279 *
1280 * flick(element, xoffset, yoffset, speed, cb) -> cb(err)
1281 * Flicks, starting at element center.
1282 *
1283 * @jsonWire POST /session/:sessionId/touch/flick
1284 */
12851webdriver.prototype.flick = function() {
12860 var args = __slice.call(arguments, 0);
12870 if (args.length <= 4) {
12880 _flick1.apply(this, args);
1289 } else {
12900 _flick2.apply(this, args);
1291 }
1292};
1293
12941var _flick1 = function(element , cb){
12950 var fargs = utils.varargs(arguments);
12960 var cb = fargs.callback,
1297 xspeed = fargs.all[0],
1298 yspeed = fargs.all[1],
1299 swipe = fargs.all[2];
1300
13010 var data = { xspeed: xspeed, yspeed: yspeed };
13020 if (swipe) {
13030 data.swipe = swipe;
1304 }
1305
13060 this._jsonWireCall({
1307 method: 'POST'
1308 , relPath: '/touch/flick'
1309 , data: data
1310 , cb: this._simpleCallback(cb)
1311 });
1312};
1313
13141var _flick2 = function() {
13150 var fargs = utils.varargs(arguments);
13160 var cb = fargs.callback,
1317 element = fargs.all[0],
1318 xoffset = fargs.all[1],
1319 yoffset = fargs.all[2],
1320 speed = fargs.all[3];
1321
13220 this._jsonWireCall({
1323 method: 'POST'
1324 , relPath: '/touch/flick'
1325 , data: { element: element, xoffset: xoffset, yoffset: yoffset, speed: speed }
1326 , cb: this._simpleCallback(cb)
1327 });
1328};
1329
1330/**
1331 * moveTo(element, xoffset, yoffset, cb) -> cb(err)
1332 * Move to element, xoffset and y offset are optional.
1333 *
1334 * @jsonWire POST /session/:sessionId/moveto
1335 */
13361webdriver.prototype.moveTo = function() {
133790 var fargs = utils.varargs(arguments);
133890 var cb = fargs.callback,
1339 element = fargs.all[0],
1340 xoffset = fargs.all[1],
1341 yoffset = fargs.all[2];
1342
134390 this._jsonWireCall({
1344 method: 'POST'
1345 , relPath: '/moveto'
1346 , data: { element: element.toString(), xoffset: xoffset, yoffset: yoffset }
1347 , cb: this._simpleCallback(cb)
1348 });
1349};
1350
1351/**
1352 * buttonDown(cb) -> cb(err)
1353 *
1354 * @jsonWire POST /session/:sessionId/buttondown
1355 */
13561webdriver.prototype.buttonDown = function(cb) {
13572 this._jsonWireCall({
1358 method: 'POST'
1359 , relPath: '/buttondown'
1360 , cb: this._simpleCallback(cb)
1361 });
1362};
1363
1364/**
1365 * buttonUp(cb) -> cb(err)
1366 *
1367 * @jsonWire POST /session/:sessionId/buttonup
1368 */
13691webdriver.prototype.buttonUp = function(cb) {
13702 this._jsonWireCall({
1371 method: 'POST'
1372 , relPath: '/buttonup'
1373 , cb: this._simpleCallback(cb)
1374 });
1375};
1376
1377/**
1378 * click(button, cb) -> cb(err)
1379 * Click on current element.
1380 * Buttons: {left: 0, middle: 1 , right: 2}
1381 *
1382 * @jsonWire POST /session/:sessionId/click
1383 */
13841webdriver.prototype.click = function() {
1385 // parsing args, button optional
13864 var fargs = utils.varargs(arguments);
13874 var cb = fargs.callback,
1388 button = fargs.all[0];
1389
13904 this._jsonWireCall({
1391 method: 'POST'
1392 , relPath: '/click'
1393 , data: {button: button}
1394 , cb: this._simpleCallback(cb)
1395 });
1396};
1397
1398/**
1399 * doubleclick(cb) -> cb(err)
1400 *
1401 * @jsonWire POST /session/:sessionId/doubleclick
1402 */
14031webdriver.prototype.doubleclick = function(cb) {
14042 this._jsonWireCall({
1405 method: 'POST'
1406 , relPath: '/doubleclick'
1407 , cb: this._simpleCallback(cb)
1408 });
1409};
1410
1411/**
1412 * type(element, keys, cb) -> cb(err)
1413 * Type keys (all keys are up at the end of command).
1414 * special key map: wd.SPECIAL_KEYS (see lib/special-keys.js)
1415 *
1416 * @jsonWire POST /session/:sessionId/element/:id/value
1417 */
14181webdriver.prototype.type = function(element, keys, cb) {
1419134 if (!(keys instanceof Array)) {keys = [keys];}
1420 // ensure all keystrokes are strings to conform to JSONWP
142192 _.each(keys, function(key, idx) {
1422118 if (typeof key !== "string") {
14234 keys[idx] = key.toString();
1424 }
1425 });
142692 this._jsonWireCall({
1427 method: 'POST'
1428 , relPath: '/element/' + element + '/value'
1429 , data: {value: keys}
1430 , cb: this._simpleCallback(cb)
1431 });
1432};
1433
1434/**
1435 * submit(element, cb) -> cb(err)
1436 * Submit a `FORM` element.
1437 *
1438 * @jsonWire POST /session/:sessionId/element/:id/submit
1439 */
14401webdriver.prototype.submit = function(element, cb) {
14410 this._jsonWireCall({
1442 method: 'POST'
1443 , relPath: '/element/' + element + '/submit'
1444 , cb: this._simpleCallback(cb)
1445 });
1446};
1447
1448/**
1449 * keys(keys, cb) -> cb(err)
1450 * Press keys (keys may still be down at the end of command).
1451 * special key map: wd.SPECIAL_KEYS (see lib/special-keys.js)
1452 *
1453 * @jsonWire POST /session/:sessionId/keys
1454 */
14551webdriver.prototype.keys = function(keys, cb) {
1456120 if (!(keys instanceof Array)) {keys = [keys];}
1457 // ensure all keystrokes are strings to conform to JSONWP
145882 _.each(keys, function(key, idx) {
1459110 if (typeof key !== "string") {
14600 keys[idx] = key.toString();
1461 }
1462 });
146382 this._jsonWireCall({
1464 method: 'POST'
1465 , relPath: '/keys'
1466 , data: {value: keys}
1467 , cb: this._simpleCallback(cb)
1468 });
1469};
1470
1471/**
1472 * clear(element, cb) -> cb(err)
1473 *
1474 * @jsonWire POST /session/:sessionId/element/:id/clear
1475 */
14761webdriver.prototype.clear = function(element, cb) {
147776 this._jsonWireCall({
1478 method: 'POST'
1479 , relPath: '/element/' + element + '/clear'
1480 , cb: this._simpleCallback(cb)
1481 });
1482};
1483
1484/**
1485 * title(cb) -> cb(err, title)
1486 *
1487 * @jsonWire GET /session/:sessionId/title
1488 */
14891webdriver.prototype.title = function(cb) {
149014 this._jsonWireCall({
1491 method: 'GET'
1492 , relPath: '/title'
1493 , cb: this._callbackWithData(cb)
1494 });
1495};
1496
1497/**
1498 * source(cb) -> cb(err, source)
1499 *
1500 * @jsonWire GET /session/:sessionId/source
1501 */
15021webdriver.prototype.source = function(cb) {
15030 this._jsonWireCall({
1504 method: 'GET'
1505 , relPath: '/source'
1506 , cb: this._callbackWithData(cb)
1507 });
1508}
1509
1510// element must be specified
15111webdriver.prototype._rawText = function(element, cb) {
151256 this._jsonWireCall({
1513 method: 'GET'
1514 , relPath: '/element/' + element + '/text'
1515 , cb: this._callbackWithData(cb)
1516 });
1517};
1518
1519/**
1520 * text(element, cb) -> cb(err, text)
1521 * element: specific element, 'body', or undefined
1522 *
1523 * @jsonWire GET /session/:sessionId/element/:id/text
1524 * @docOrder 1
1525 */
15261webdriver.prototype.text = function(element, cb) {
152756 var _this = this;
152856 if (!element || element === 'body') {
15296 _this.element.apply(this, ['tag name', 'body', function(err, bodyEl) {
153012 if (!err) {_this._rawText.apply(_this, [bodyEl, cb]);} else {cb(err);}
1531 }]);
1532 }else {
153350 _this._rawText.apply(_this, [element, cb]);
1534 }
1535};
1536
1537/**
1538 * Check if text is present:
1539 * textPresent(searchText, element, cb) -> cb(err, boolean)
1540 * element: specific element, 'body', or undefined
1541 *
1542 * @jsonWire GET /session/:sessionId/element/:id/text
1543 * @docOrder 3
1544 */
15451webdriver.prototype.textPresent = function(searchText, element, cb) {
15466 this.text.apply(this, [element, function(err, text) {
15476 if (err) {
15480 cb(err, null);
1549 } else {
15506 cb(err, text.indexOf(searchText) >= 0);
1551 }
1552 }]);
1553};
1554
1555/**
1556 * alertText(cb) -> cb(err, text)
1557 *
1558 * @jsonWire GET /session/:sessionId/alert_text
1559 */
15601webdriver.prototype.alertText = function(cb) {
15610 this._jsonWireCall({
1562 method: 'GET'
1563 , relPath: '/alert_text'
1564 , cb: this._callbackWithData(cb)
1565 });
1566}
1567
1568/**
1569 * alertKeys(keys, cb) -> cb(err)
1570 *
1571 * @jsonWire POST /session/:sessionId/alert_text
1572 */
15731webdriver.prototype.alertKeys = function(keys, cb) {
15740 this._jsonWireCall({
1575 method: 'POST'
1576 , relPath: '/alert_text'
1577 , data: {text: keys}
1578 , cb: this._simpleCallback(cb)
1579 });
1580}
1581
1582/**
1583 * acceptAlert(cb) -> cb(err)
1584 *
1585 * @jsonWire POST /session/:sessionId/accept_alert
1586 */
15871webdriver.prototype.acceptAlert = function(cb) {
15881 this._jsonWireCall({
1589 method: 'POST'
1590 , relPath: '/accept_alert'
1591 , cb: this._simpleCallback(cb)
1592 });
1593};
1594
1595/**
1596 * dismissAlert(cb) -> cb(err)
1597 *
1598 * @jsonWire POST /session/:sessionId/dismiss_alert
1599 */
16001webdriver.prototype.dismissAlert = function(cb) {
16011 this._jsonWireCall({
1602 method: 'POST'
1603 , relPath: '/dismiss_alert'
1604 , cb: this._simpleCallback(cb)
1605 });
1606};
1607
1608/**
1609 * active(cb) -> cb(err, element)
1610 *
1611 * @jsonWire POST /session/:sessionId/element/active
1612 */
16131webdriver.prototype.active = function(cb) {
16144 var _this = this;
16154 var cbWrap = function(e, o) {
16164 var el = new element(o.ELEMENT, _this);
16174 cb(null, el);
1618 };
16194 this._jsonWireCall({
1620 method: 'POST'
1621 , relPath: '/element/active'
1622 , cb: this._callbackWithData(cbWrap)
1623 });
1624};
1625
1626/**
1627 * url(cb) -> cb(err, url)
1628 *
1629 * @jsonWire GET /session/:sessionId/url
1630 */
16311webdriver.prototype.url = function(cb) {
163210 this._jsonWireCall({
1633 method: 'GET'
1634 , relPath: '/url'
1635 , cb: this._callbackWithData(cb)
1636 });
1637};
1638
1639/**
1640 * allCookies() -> cb(err, cookies)
1641 *
1642 * @jsonWire GET /session/:sessionId/cookie
1643 */
16441webdriver.prototype.allCookies = function(cb) {
164512 this._jsonWireCall({
1646 method: 'GET'
1647 , relPath: '/cookie'
1648 , cb: this._callbackWithData(cb)
1649 });
1650};
1651
1652/**
1653 * setCookie(cookie, cb) -> cb(err)
1654 * cookie example:
1655 * {name:'fruit', value:'apple'}
1656 * Optional cookie fields:
1657 * path, domain, secure, expiry
1658 *
1659 * @jsonWire POST /session/:sessionId/cookie
1660 */
16611webdriver.prototype.setCookie = function(cookie, cb) {
1662 // setting secure otherwise selenium server throws
166316 if(cookie){ cookie.secure = cookie.secure || false; }
1664
16658 this._jsonWireCall({
1666 method: 'POST'
1667 , relPath: '/cookie'
1668 , data: { cookie: cookie }
1669 , cb: this._simpleCallback(cb)
1670 });
1671};
1672
1673/**
1674 * deleteAllCookies(cb) -> cb(err)
1675 *
1676 * @jsonWire DELETE /session/:sessionId/cookie
1677 */
16781webdriver.prototype.deleteAllCookies = function(cb) {
16794 this._jsonWireCall({
1680 method: 'DELETE'
1681 , relPath: '/cookie'
1682 , cb: this._simpleCallback(cb)
1683 });
1684};
1685
1686/**
1687 * deleteCookie(name, cb) -> cb(err)
1688 *
1689 * @jsonWire DELETE /session/:sessionId/cookie/:name
1690 */
16911webdriver.prototype.deleteCookie = function(name, cb) {
16922 this._jsonWireCall({
1693 method: 'DELETE'
1694 , relPath: '/cookie/' + encodeURIComponent(name)
1695 , cb: this._simpleCallback(cb)
1696 });
1697};
1698
1699/**
1700 * getOrientation(cb) -> cb(err, orientation)
1701 *
1702 * @jsonWire GET /session/:sessionId/orientation
1703 */
17041webdriver.prototype.getOrientation = function(cb) {
17050 this._jsonWireCall({
1706 method: 'GET'
1707 , relPath: '/orientation'
1708 , cb: this._callbackWithData(cb)
1709 });
1710};
1711
1712/**
1713 * setOrientation(cb) -> cb(err, orientation)
1714 *
1715 * @jsonWire POST /session/:sessionId/orientation
1716 */
17171webdriver.prototype.setOrientation = function(orientation, cb) {
17180 this._jsonWireCall({
1719 method: 'POST'
1720 , relPath: '/orientation'
1721 , data: { orientation: orientation }
1722 , cb: this._callbackWithData(cb)
1723 });
1724};
1725
17261var _isVisible1 = function(element , cb){
172789 this.getComputedCSS(element, "display", function(err, display){
172889 if(err){
17290 return cb(err);
1730 }
1731
173289 cb(null, display !== "none");
1733 });
1734};
1735
17361var _isVisible2 = function(queryType, querySelector, cb){
1737143 this.elementIfExists(queryType, querySelector, function(err, element){
1738143 if(err){
17390 return cb(err);
1740 }
1741
1742143 if(element){
174385 element.isVisible(cb);
1744 } else {
174558 cb(null, false); }
1746 });
1747};
1748
1749/**
1750 * isVisible(element , cb) -> cb(err, boolean)
1751 * isVisible(queryType, querySelector, cb) -> cb(err, boolean)
1752 */
17531webdriver.prototype.isVisible = function() {
1754232 var args = __slice.call(arguments, 0);
1755232 if (args.length <= 2) {
175689 _isVisible1.apply(this, args);
1757 } else {
1758143 _isVisible2.apply(this, args);
1759 }
1760};
1761
1762/**
1763 * Retrieves the pageIndex element (added for Appium):
1764 * getPageIndex(element, cb) -> cb(err, pageIndex)
1765 */
17661webdriver.prototype.getPageIndex = function(element, cb) {
17670 this._jsonWireCall({
1768 method: 'GET'
1769 , relPath: '/element/' + element + '/pageIndex'
1770 , cb: this._callbackWithData(cb)
1771 });
1772};
1773
1774/**
1775 * getLocation(element, cb) -> cb(err, location)
1776 *
1777 * @jsonWire GET /session/:sessionId/element/:id/location
1778 */
17791webdriver.prototype.getLocation = function(element, cb) {
17804 this._jsonWireCall({
1781 method: 'GET'
1782 , relPath: '/element/' + element + '/location'
1783 , cb: this._callbackWithData(cb)
1784 });
1785};
1786
1787/**
1788 * getSize(element, cb) -> cb(err, size)
1789 *
1790 * @jsonWire GET /session/:sessionId/element/:id/size
1791 */
17921webdriver.prototype.getSize = function(element, cb) {
17934 this._jsonWireCall({
1794 method: 'GET'
1795 , relPath: '/element/' + element + '/size'
1796 , cb: this._callbackWithData(cb)
1797 });
1798};
1799
1800// waitForCondition recursive implementation
18011webdriver.prototype._waitForConditionImpl = function(conditionExpr, limit, poll, cb) {
180217 var _this = this;
1803
1804 // timeout check
180517 if (Date.now() < limit) {
1806 // condition check
180717 _this.safeEval.apply( _this , [conditionExpr, function(err, res) {
180819 if(err) {return cb(err);}
180915 if (res === true) {
1810 // condition ok
18116 cb(null, true);
1812 } else {
1813 // wait for poll and try again
18149 setTimeout(function() {
18159 _this._waitForConditionImpl.apply(_this, [conditionExpr, limit, poll, cb]);
1816 }, poll);
1817 }
1818 }]);
1819 } else {
1820 // try one last time
18210 _this.safeEval.apply( _this, [conditionExpr, function(err, res) {
18220 if(err) {return cb(err);}
18230 if (res === true) {
18240 cb(null, true);
1825 } else {
1826 // condition nok within timeout
18270 cb("waitForCondition failure for: " + conditionExpr);
1828 }
1829 }]);
1830 }
1831};
1832
1833/**
1834 * Waits for JavaScript condition to be true (polling within wd client):
1835 * waitForCondition(conditionExpr, timeout, pollFreq, cb) -> cb(err, boolean)
1836 * waitForCondition(conditionExpr, timeout, cb) -> cb(err, boolean)
1837 * waitForCondition(conditionExpr, cb) -> cb(err, boolean)
1838 * conditionExpr: condition expression, should return a boolean
1839 * timeout: timeout (optional, default: 1000)
1840 * pollFreq: pooling frequency (optional, default: 100)
1841 * return true if condition satisfied, error otherwise.
1842 */
18431webdriver.prototype.waitForCondition = function() {
18448 var _this = this;
1845
1846 // parsing args
18478 var fargs = utils.varargs(arguments);
18488 var cb = fargs.callback,
1849 conditionExpr = fargs.all[0],
1850 timeout = fargs.all[1] || 1000,
1851 poll = fargs.all[2] || 100;
1852
1853 // calling implementation
18548 var limit = Date.now() + timeout;
18558 _this._waitForConditionImpl.apply(this, [conditionExpr, limit, poll, cb]);
1856};
1857
1858// script to be executed in browser
18591webdriver.prototype._waitForConditionInBrowserJsScript = fs.readFileSync( __dirname + "/../browser-scripts/wait-for-cond-in-browser.js", 'utf8');
1860
1861/**
1862 * Waits for JavaScript condition to be true (async script polling within browser):
1863 * waitForConditionInBrowser(conditionExpr, timeout, pollFreq, cb) -> cb(err, boolean)
1864 * waitForConditionInBrowser(conditionExpr, timeout, cb) -> cb(err, boolean)
1865 * waitForConditionInBrowser(conditionExpr, cb) -> cb(err, boolean)
1866 * conditionExpr: condition expression, should return a boolean
1867 * timeout: timeout (optional, default: 1000)
1868 * pollFreq: pooling frequency (optional, default: 100)
1869 * return true if condition satisfied, error otherwise.
1870 */
18711webdriver.prototype.waitForConditionInBrowser = function() {
18728 var _this = this;
1873 // parsing args
18748 var fargs = utils.varargs(arguments);
18758 var cb = fargs.callback,
1876 conditionExpr = fargs.all[0],
1877 timeout = fargs.all[1] || 1000,
1878 poll = fargs.all[2] || 100;
1879
1880 // calling script
18818 _this.safeExecuteAsync.apply( _this, [_this._waitForConditionInBrowserJsScript,
1882 [conditionExpr,timeout,poll], function(err,res) {
188310 if(err) {return cb(err);}
18846 if(res !== true) {return cb("waitForConditionInBrowser failure for: " + conditionExpr);}
18856 cb(null, res);
1886 }
1887 ]);
1888};
1889

utils.js

100%
13
13
0
LineHitsSource
11var Args = require("vargs").Constructor;
2
31exports.varargs = function(args) {
4399 var fargs = new(Args)(args);
5 // returning undefined instead of empty callback
6399 fargs.callback = fargs.callbackGiven()? fargs.callback : undefined;
7399 return fargs;
8};
9
10// convert to type to something like ById, ByCssSelector, etc...
111exports.elFuncSuffix = function(type){
1281 var res = (' by ' + type).replace(/(\s[a-z])/g,
13216 function($1){return $1.toUpperCase().replace(' ','');});
1481 return res.replace('Xpath', 'XPath');
15};
16
17// return correct jsonwire type
181exports.elFuncFullType = function(type){
19982 if(type === 'css') {return 'css selector'; } // shortcut for css
20262 return type;
21};
22
23// from JsonWire spec + shortcuts
241exports.elementFuncTypes = ['class name', 'css selector','id','name','link text',
25 'partial link text','tag name', 'xpath', 'css' ];

jsonwire-errors.js

100%
2
2
0
LineHitsSource
11var JSONWIRE_ERRORS = [
2{
3 status: 0,
4 summary:'Success',
5 detail:'The command executed successfully.'}
6, {
7 status: 7,
8 summary:'NoSuchElement',
9 detail:'An element could not be located on the page using the given search parameters.'}
10, {
11 status: 8,
12 summary:'NoSuchFrame',
13 detail:'A request to switch to a frame could not be satisfied because the frame could not be found.'}
14, {
15 status: 9,
16 summary:'UnknownCommand',
17 detail:'The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource.'}
18, {
19 status: 10,
20 summary:'StaleElementReference',
21 detail:'An element command failed because the referenced element is no longer attached to the DOM.'}
22, {
23 status: 11,
24 summary:'ElementNotVisible',
25 detail:'An element command could not be completed because the element is not visible on the page.'}
26, {
27 status: 12,
28 summary:'InvalidElementState',
29 detail:'An element command could not be completed because the element is in an invalid state (e.g. attempting to click a disabled element).'}
30, {
31 status: 13,
32 summary:'UnknownError',
33 detail:'An unknown server-side error occurred while processing the command.'}
34, {
35 status: 15,
36 summary:'ElementIsNotSelectable',
37 detail:'An attempt was made to select an element that cannot be selected.'}
38, {
39 status: 17,
40 summary:'JavaScriptError',
41 detail:'An error occurred while executing user supplied JavaScript.'}
42, {
43 status: 19,
44 summary:'XPathLookupError',
45 detail:'An error occurred while searching for an element by XPath.'}
46, {
47 status: 21,
48 summary:'Timeout',
49 detail:'An operation did not complete before its timeout expired.'}
50, {
51 status: 23,
52 summary:'NoSuchWindow',
53 detail:'A request to switch to a different window could not be satisfied because the window could not be found.'}
54, {
55 status: 24,
56 summary:'InvalidCookieDomain',
57 detail:'An illegal attempt was made to set a cookie under a different domain than the current page.'}
58, {
59 status: 25,
60 summary:'UnableToSetCookie',
61 detail:'A request to set a cookie\'s value could not be satisfied.'}
62, {
63 status: 26,
64 summary:'UnexpectedAlertOpen',
65 detail:'A modal dialog was open, blocking this operation'}
66, {
67 status: 27,
68 summary:'NoAlertOpenError',
69 detail:'An attempt was made to operate on a modal dialog when one was not open.'}
70, {
71 status: 28,
72 summary:'ScriptTimeout',
73 detail:'A script did not complete before its timeout expired.'}
74, {
75 status: 29,
76 summary:'InvalidElementCoordinates',
77 detail:'The coordinates provided to an interactions operation are invalid.'}
78, {
79 status: 30,
80 summary:'IMENotAvailable',
81 detail:'IME was not available.'}
82, {
83 status: 31,
84 summary:'IMEEngineActivationFailed',
85 detail:'An IME engine could not be started.'}
86, {
87 status: 32,
88 summary:'InvalidSelector',
89 detail:'Argument was an invalid selector (e.g. XPath/CSS).'}
90];
91
921module.exports = JSONWIRE_ERRORS;

promise-webdriver.js

96%
32
31
1
LineHitsSource
11var webdriver = require('./webdriver')
2 , Q = require('q')
3 , element = require('./element').element
4 , slice = Array.prototype.slice.call.bind(Array.prototype.slice);
5
61var copyFunctions = function(newObj, originalObj, wrapMatching) {
7 // copy all the public functions on the webdriver prototype
82 for (var prop in originalObj.prototype) {
9211 var fn = originalObj.prototype[prop];
10
11 // wrap only elements matching wrapMatching if it is provided
12211 if (wrapMatching && prop.indexOf(wrapMatching) === -1) {
1318 continue;
14 }
15 // ordered per performance on
16 // http://jsperf.com/compare-typeof-indexof-hasownproperty
17193 if (typeof fn === 'function' &&
18 prop !== 'chain' &&
19 prop !== 'toString' &&
20 prop.indexOf('_') !== 0 &&
21 originalObj.prototype.hasOwnProperty(prop)
22 ) {
23168 newObj.prototype[prop] = wrap(fn);
24 }
25 }
26};
27
28// promisify element shortcuts too
291var promiseElement = function() {
3015 return element.apply(this, arguments);
31};
321promiseElement.prototype = Object.create(element.prototype);
33
341var promiseWebdriver = module.exports = function() {
35 // inject promisified element
366 arguments[0].element = promiseElement;
376 return webdriver.apply(this, arguments);
38};
39
401promiseWebdriver.prototype = Object.create(webdriver.prototype);
41
421copyFunctions(promiseWebdriver, webdriver);
43
44// in element promisifiing only methods with element in the name
45// (other methods should already return promises)
461copyFunctions(promiseElement, element, 'element');
47
481function wrap(fn) {
49168 return function() {
5059 var callback;
5159 var deferred = Q.defer();
52
5359 var args = slice(arguments);
54
55 // Remove any undefined values from the end of the arguments array
56 // as these interfere with our callback detection below
5759 for (var i = args.length - 1; i >= 0 && args[i] === undefined; i--) {
585 args.pop();
59 }
60
61 // If the last argument is a function assume that it's a callback
62 // (Based on the API as of 2012/12/1 this assumption is always correct)
6359 if (typeof args[args.length - 1] === 'function') {
64 // Remove to replace it with our callback and then call it
65 // appropriately when the promise is resolved or rejected
665 callback = args.pop();
675 deferred.promise.then(function(value) {
685 callback(null, value);
69 }, function(error) {
700 callback(error);
71 });
72 }
73
7459 args.push(deferred.makeNodeResolver());
7559 fn.apply(this, args);
76
7759 return deferred.promise;
78 };
79}

element.js

94%
56
53
3
LineHitsSource
1//Element object
2//Wrapper around browser methods
31var _ = require("underscore")
41 , utils = require("./utils.js");;
5
61var element = function(value, browser) {
7664 this.value = value;
8664 this.browser = browser;
9
10664 if(!value){
110 throw new Error("no value passed to element constructor");
12 }
13
14664 if(!browser){
150 throw new Error("no browser passed to element constructor");
16 }
17};
18
191element.prototype.toString = function () {
20760 return String(this.value);
21};
22
23/**
24 * element.type(keys, cb) -> cb(err)
25 *
26 * @jsonWire POST /session/:sessionId/element/:id/value
27 */
281element.prototype.type = function (keys, cb) {
294 return this.browser.type(this, keys, cb);
30};
31
321element.prototype.sendKeys = element.prototype.type;
33
34
35/**
36 * element.click(cb) -> cb(err)
37 *
38 * @jsonWire POST /session/:sessionId/element/:id/click
39 */
401element.prototype.click = function (cb) {
412 return this.browser.clickElement(this, cb);
42};
43
44/**
45 * element.flick(xoffset, yoffset, speed, cb) -> cb(err)
46 *
47 * @jsonWire POST /session/:sessionId/touch/flick
48 */
491element.prototype.flick = function (xoffset, yoffset, speed, cb) {
500 this.browser.flick(this.value, xoffset, yoffset, speed, cb);
51};
52
53
54/**
55 * element.text(cb) -> cb(err, text)
56 *
57 * @jsonWire GET /session/:sessionId/element/:id/text
58 * @docOrder 2
59 */
601element.prototype.text = function (cb) {
614 return this.browser.text(this, cb);
62};
63
64/**
65 * element.textPresent(searchText, cb) -> cb(err, boolean)
66 *
67 * @jsonWire GET /session/:sessionId/element/:id/text
68 * @docOrder 4
69 */
701element.prototype.textPresent = function(searchText, cb) {
712 return this.browser.textPresent(searchText, this, cb);
72};
73
74/**
75 * element.getAttribute(attrName, cb) -> cb(err, value)
76 *
77 * @jsonWire GET /session/:sessionId/element/:id/attribute/:name
78 * @docOrder 2
79 */
801element.prototype.getAttribute = function(name, cb) {
8119 return this.browser.getAttribute(this, name, cb);
82};
83
84/**
85 * element.getTagName(cb) -> cb(err, name)
86 *
87 * @jsonWire GET /session/:sessionId/element/:id/name
88 */
891element.prototype.getTagName = function(cb) {
904 return this.browser.getTagName(this, cb);
91};
92
93/**
94 * element.isDisplayed(cb) -> cb(err, displayed)
95 *
96 * @jsonWire GET /session/:sessionId/element/:id/displayed
97 */
981element.prototype.isDisplayed = function(cb) {
996 return this.browser.isDisplayed(this, cb);
100};
101
1021element.prototype.displayed = element.prototype.isDisplayed;
103
104/**
105 * isVisible(cb) -> cb(err, boolean)
106 */
1071element.prototype.isVisible = function(cb) {
10885 return this.browser.isVisible(this, cb);
109};
110
111/**
112 * element.getLocation(cb) -> cb(err, location)
113 *
114 * @jsonWire GET /session/:sessionId/element/:id/location
115 */
1161element.prototype.getLocation = function (cb) {
1172 this.browser.getLocation(this, cb);
118};
119
120/**
121 * element.getSize(cb) -> cb(err, size)
122 *
123 * @jsonWire GET /session/:sessionId/element/:id/size
124 */
1251element.prototype.getSize = function (cb) {
1262 this.browser.getSize(this, cb);
127};
128
129/**
130 * element.getValue(cb) -> cb(err, value)
131 *
132 * @jsonWire GET /session/:sessionId/element/:id/attribute/:name
133 * @docOrder 4
134 */
1351element.prototype.getValue = function(cb) {
1368 return this.browser.getValue(this, cb);
137};
138
139/**
140 * element.getComputedCss(cssProperty , cb) -> cb(err, value)
141 *
142 * @jsonWire GET /session/:sessionId/element/:id/css/:propertyName
143 */
1441element.prototype.getComputedCss = function(styleName, cb) {
1452 return this.browser.getComputedCss(this, styleName, cb);
146};
147
1481element.prototype.getComputedCSS = element.prototype.getComputedCss;
149
150/**
151 * element.clear(cb) -> cb(err)
152 *
153 * @jsonWire POST /session/:sessionId/element/:id/clear
154 */
1551element.prototype.clear = function(cb) {
1562 return this.browser.clear(this, cb);
157};
158
159/**
160 * element.getComputedCss(cssProperty , cb) -> cb(err, value)
161 *
162 * @jsonWire GET /session/:sessionId/element/:id/css/:propertyName
163 */
1641element.prototype.getComputedCss = function(styleName, cb) {
1652 this.browser.getComputedCss(this, styleName, cb);
166};
167
1681_.each(utils.elementFuncTypes, function(type) {
169 /**
170 * element.elementByClassName(value, cb) -> cb(err, element)
171 * element.elementByCssSelector(value, cb) -> cb(err, element)
172 * element.elementById(value, cb) -> cb(err, element)
173 * element.elementByName(value, cb) -> cb(err, element)
174 * element.elementByLinkText(value, cb) -> cb(err, element)
175 * element.elementByPartialLinkText(value, cb) -> cb(err, element)
176 * element.elementByTagName(value, cb) -> cb(err, element)
177 * element.elementByXPath(value, cb) -> cb(err, element)
178 * element.elementByCss(value, cb) -> cb(err, element)
179 *
180 * @jsonWire POST /session/:sessionId/element/:id/element
181 * @docOrder 2
182 */
1839 element.prototype['element' + utils.elFuncSuffix(type)] = function(value, cb) {
1848 element.prototype.element.apply(this, [utils.elFuncFullType(type), value, cb]);
185 };
186
187 /**
188 * element.elementsByClassName(value, cb) -> cb(err, elements)
189 * element.elementsByCssSelector(value, cb) -> cb(err, elements)
190 * element.elementsById(value, cb) -> cb(err, elements)
191 * element.elementsByName(value, cb) -> cb(err, elements)
192 * element.elementsByLinkText(value, cb) -> cb(err, elements)
193 * element.elementsByPartialLinkText(value, cb) -> cb(err, elements)
194 * element.elementsByTagName(value, cb) -> cb(err, elements)
195 * element.elementsByXPath(value, cb) -> cb(err, elements)
196 * element.elementsByCss(value, cb) -> cb(err, elements)
197 *
198 * @jsonWire POST /session/:sessionId/element/:id/elements
199 * @docOrder 2
200 */
2019 element.prototype['elements' + utils.elFuncSuffix(type)] = function(value, cb) {
2024 element.prototype.elements.apply(this, [utils.elFuncFullType(type), value, cb]);
203 };
204});
205
206/**
207 * element.element(using, value, cb) -> cb(err, element)
208 *
209 * @jsonWire POST /session/:sessionId/element/:id/element
210 * @docOrder 1
211 */
2121element.prototype.element = function(using, value, cb) {
2138 var _this = this;
2148 this.browser._jsonWireCall({
215 method: 'POST'
216 , relPath: '/element/' + _this.value + '/element'
217 , data: {using: using, value: value}
218 , cb: this.browser._elementCallback(cb)
219 });
220};
221
222/**
223 * element.elements(using, value, cb) -> cb(err, elements)
224 *
225 * @jsonWire POST /session/:sessionId/element/:id/elements
226 * @docOrder 1
227 */
2281element.prototype.elements = function(using, value, cb) {
2294 var _this = this;
2304 this.browser._jsonWireCall({
231 method: 'POST'
232 , relPath: '/element/' + _this.value + '/elements'
233 , data: {using: using, value: value}
234 , cb: this.browser._elementsCallback(cb)
235 });
236};
237
2381exports.element = element;