Coverage

7%
80
6
74

/home/ubuntu/src/github.com/dalekjs/dalek-internal-driver/index.js

7%
80
6
74
LineHitsSource
1/*!
2 *
3 * Copyright (c) 2013 Sebastian Golasch
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 */
24
251'use strict';
26
27// ext. libs
281var async = require('async');
29
30// int. libs
311var Testsuite = require('dalek-internal-testsuite');
32
33/**
34 * Configures the driver instance
35 *
36 * @constructor
37 */
38
391var Driver = function (options) {
40 // add configuration data to the driver instance
410 this.config = options.config;
420 this.browser = this.config.get('browser');
430 this.files = this.config.get('tests');
440 this.drivers = this.config.get('driver');
45
46 // flag if we use the canary driver builds
470 this.driverIsCanary = false;
48
49 // link driver events
500 this.driverEmitter = options.driverEmitter;
510 this.reporterEvents = options.reporterEvents;
52};
53
54/**
55 * Generates & starts drivers & browsers
56 * the tests will be run in
57 *
58 * @module DalekJS
59 * @class Driver
60 * @namespace Dalek
61 * @part Driver
62 * @api
63 */
64
651Driver.prototype = {
66
67 /**
68 * Checks if the requested driver is available
69 *
70 * @method isDriver
71 * @param {string} driver Name of the requested driver
72 * @return {bool} isDriver Driver is availavle
73 */
74
75 isDriver: function (driver) {
760 try {
770 require.resolve('dalek-driver-' + driver);
78 } catch (e) {
790 try {
800 require.resolve('dalek-driver-' + driver + '-canary');
81 } catch (e) {
820 return false;
83 }
840 this.driverIsCanary = true;
850 return true;
86 }
870 return true;
88 },
89
90 /**
91 * Loads the requested driver
92 * Emits an event to the reporter
93 *
94 * @method loadDriver
95 * @param {string} driver Name of the requested driver
96 * @return {object} driverModule Instance of the driver module
97 */
98
99 loadDriver: function (driver) {
1000 this.reporterEvents.emit('report:log:system', 'dalek-internal-driver: Loading driver: "' + driver + '"');
1010 return require('dalek-driver-' + driver + (this.driverIsCanary ? '-canary' : ''));
102 },
103
104 /**
105 * Returns a list with browser driver instances
106 *
107 * @method getDrivers
108 * @return {array} verifiedDrivers
109 */
110
111 getDrivers: function () {
1120 return this.drivers.map(this.getVerifiedBrowser, this)[0];
113 },
114
115 /**
116 * Returns a list with browser driver instances
117 *
118 * @method getVerifiedBrowser
119 * @param {string} driver Name of the requested driver
120 * @return {array} verifiedDrivers Array of dribver 'run' functions
121 */
122
123 getVerifiedBrowser: function (driver) {
1240 return this.browser.map(this.getVerifiedDriver.bind(this, this.loadDriver(driver), driver));
125 },
126
127 /**
128 * Returns a scoped version of the driver run function
129 *
130 * @method getVerifiedDriver
131 * @param {object} driverModule Instance of the used driver
132 * @param {string} driver Name of ther used driver
133 * @param {string} browser Name of the used browser
134 * @return {function} run Function that kicks off execution of a testsuite chain in a browser
135 */
136
137 getVerifiedDriver: function (driverModule, driver, browser) {
1380 return this.run.bind(this, driver, driverModule, browser);
139 },
140
141 /**
142 * Loads a browser driver
143 *
144 * @method loadBrowserConfiguration
145 * @param {string} browser Name of the requested browser driver
146 * @param {object} browsers Configuration options for the requested browser
147 * @return {object} browserConfiguration Browser driver isntance and configuration meta data
148 */
149
150 loadBrowserConfiguration: function (browser, browsers, driver) {
1510 var browserConfiguration;
152
1530 if (driver.dummyBrowser && driver.dummyBrowser()) {
1540 return driver.getBrowser(driver);
155 }
156
1570 try {
1580 browserConfiguration = this.getDefaultBrowserConfiguration(browser, browsers);
159 } catch (e) {
1600 browserConfiguration = this.getUserBrowserConfiguration(browser, browsers);
161 }
162
1630 return browserConfiguration;
164 },
165
166 /**
167 * Loads the default browser driver
168 *
169 * @method getDefaultBrowserConfiguration
170 * @param {string} browser Name of the requested browser driver
171 * @param {object} browsers Configuration options for the requested browser
172 * @return {object} browserConfiguration Browser driver isntance and configuration meta data
173 */
174
175 getDefaultBrowserConfiguration: function (browser, browsers) {
1760 var browserConfiguration = {configuration: null, module: null};
177
1780 try {
1790 browserConfiguration.module = require('dalek-browser-' + browser);
180 } catch (e) {
1810 browserConfiguration.module = require('dalek-browser-' + browser + '-canary');
182 }
1830 if (browsers[browser]) {
1840 browserConfiguration.configuration = browsers[browser];
185 }
186
1870 return browserConfiguration;
188 },
189
190 /**
191 * Loads a user configured browser driver
192 *
193 * @method getUserBrowserConfiguration
194 * @param {string} browser Name of the requested browser driver
195 * @param {object} browsers Configuration options for the requested browser
196 * @return {object} browserConfiguration Browser driver isntance and configuration meta data
197 */
198
199 getUserBrowserConfiguration: function (browser, browsers) {
2000 var browserConfiguration = {configuration: null, module: null};
201
2020 if (browsers && browsers[browser] && browsers[browser].actAs) {
2030 browserConfiguration.module = require('dalek-browser-' + browsers[browser].actAs);
2040 browserConfiguration.configuration = browsers[browser];
205 }
206
2070 if (!browserConfiguration.module && browser.search(':') !== -1) {
2080 var args = browser.split(':');
2090 var extractedBrowser = args[0].trim();
2100 var browserType = args[1].trim().toLowerCase();
2110 browserConfiguration.module = require('dalek-browser-' + extractedBrowser);
212
2130 if (browserConfiguration.module && browserConfiguration.module.browserTypes && browserConfiguration.module.browserTypes[browserType]) {
2140 var binary = (process.platform === 'win32' ? browserConfiguration.module.browserTypes[browserType].win32 : browserConfiguration.module.browserTypes[browserType].darwin);
2150 browserConfiguration.configuration = {
216 binary: binary,
217 type: browserType
218 };
219 }
220 }
221
2220 return browserConfiguration;
223 },
224
225 /**
226 * Couple driver & session status events for the reporter
227 *
228 * @method coupleReporterEvents
229 * @param {string} driverName Name of the requested driver
230 * @param {string} browser Name of the requested browser
231 * @chainable
232 */
233
234 coupleReporterEvents: function (driverName, browser) {
2350 this.driverEmitter.on('driver:sessionStatus:' + driverName + ':' + browser, this.reporterEvents.emit.bind(this.reporterEvents, 'report:driver:session'));
2360 this.driverEmitter.on('driver:status:' + driverName + ':' + browser, this.reporterEvents.emit.bind(this.reporterEvents, 'report:driver:status'));
2370 return this;
238 },
239
240 /**
241 * Returns a list of testsuite runner functions
242 *
243 * @method getTestsuiteInstances
244 * @param {object} driverInstance Instance of the requested driver
245 * @return {array} testsuiteRunners List of testsuites that should be run
246 */
247
248 getTestsuiteInstances: function (driverInstance) {
2490 return this.files.map(this.createTestsuiteInstance.bind(this, driverInstance));
250 },
251
252 /**
253 * Creates a testsuite runner function
254 *
255 * @method createTestsuiteInstance
256 * @param {object} driverInstance Instance of the requested driver
257 * @param {string} file Filename of the testsuite
258 * @return {function} testsuiteRunner Runner function from the testsuite
259 */
260
261 createTestsuiteInstance: function (driverInstance, file) {
2620 var suite = new Testsuite({numberOfSuites: this.files.length, file: file, driver: driverInstance, driverEmitter: this.driverEmitter, reporterEmitter: this.reporterEvents});
2630 return suite.run.bind(suite);
264 },
265
266 /**
267 * Generates a testsuite instance, emits the
268 * browser running event & starts a new async() sesries execution
269 * Will be called when the driver is ready
270 *
271 * @method _onDriverReadyclear
272 * @param {string} browser Name of the requested browser
273 * @param {string} driverName Name of the requested driver
274 * @param {function} callback Asyncs next() callback function
275 * @param {object} driverInstance Instance of the requested driver
276 * @chainable
277 * @private
278 */
279
280 _onDriverReady: function (browser, driverName, callback, driverInstance) {
281 // generate testsuite instance from test files
2820 var testsuites = this.getTestsuiteInstances(driverInstance);
2830 this.reporterEvents.emit('report:run:browser', driverInstance.webdriverClient.opts.longName);
2840 async.series(testsuites, this._onTestsuiteComplete.bind(this, callback, driverName, browser));
2850 return this;
286 },
287
288 /**
289 * Emits a 'tests complete' event & calls asyncs next() callback
290 *
291 * @method _onTestsuiteComplete
292 * @param {function} callback Asyncs next() callback function
293 * @param {string} driverName Name of the requested driver
294 * @param {string} browser Name of the requested browser
295 * @chainable
296 * @private
297 */
298
299 _onTestsuiteComplete: function (callback, driverName, browser) {
3000 this.driverEmitter.emit('tests:complete:' + driverName + ':' + browser);
3010 callback();
3020 return this;
303 },
304
305 /**
306 * Driver runner function.
307 * Registers event handlers for this run,
308 * loads browser & driver configuration & instances,
309 * emits the 'driver ready' event for the browser/driver combination
310 *
311 * @method run
312 * @param {string} driverName Name of the requested driver
313 * @param {object} driverModule Instance of the used driver module
314 * @param {string} browser Name of the requested browser
315 * @param {function} callback Asyncs next() callback function
316 * @chainable
317 */
318
319 run: function (driverName, driverModule, browser, callback) {
320 // load browser configuration
3210 var browsersRaw = this.config.get('browsers');
3220 var browsers = [];
323
324 // Check if we have a valid browser conf, then get the data out
3250 if (browsersRaw !== null) {
3260 browsers = browsersRaw[0];
327 }
328
3290 var browserConfiguration = this.loadBrowserConfiguration(browser, browsers, driverModule);
3300 var driverInstance = driverModule.create({events: this.driverEmitter, reporter: this.reporterEvents, browser: browser, config: this.config, browserMo: browserConfiguration.module, browserConf: browserConfiguration.configuration});
331 // couple driver & session status events for the reporter
3320 this.coupleReporterEvents(driverName, browser);
333
334 // register shutdown handler
3350 if (driverInstance.webdriverClient.opts.kill) {
3360 this.driverEmitter.on('killAll', driverInstance.webdriverClient.opts.kill.bind(driverInstance.webdriverClient.opts));
337 }
338
339 // dispatch some (web)driver events to the reporter
3400 this.driverEmitter.on('driver:webdriver:response', function (res) {
3410 this.reporterEvents.emit('report:log:system:webdriver', 'webdriver: ' + res.statusCode + ' ' + res.method + ' ' + res.path);
3420 this.reporterEvents.emit('report:log:system:webdriver', 'webdriver: ' + res.data);
343 }.bind(this));
344
345 // run the tests in the browser, when the driver is ready
346 // emit the tests:complete event, when all tests have been run
3470 this.driverEmitter.on('driver:ready:' + driverName + ':' + browser, this._onDriverReady.bind(this, browser, driverName, callback, driverInstance));
3480 return this;
349 }
350};
351
352// export driver module
3531module.exports = Driver;
354