# Coverage

12%
83
10
73

## /Users/asciidisco/Github/dalekjs/dalek-browser-ie/index.js

8%
80
7
73

Line | Hits | Source
--- | --- | ---
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 |  |
25 | 1 | 'use strict';
26 |  |
27 |  | // ext. libs
28 | 1 | var Q = require('q');
29 | 1 | var cp = require('child_process');
30 | 1 | var portscanner = require('portscanner');
31 |  |
32 |  | // int. libs
33 | 1 | var iedriver = require('./lib/iedriver');
34 |  |
35 |  | /**
36 |  | * This module is a browser plugin for [DalekJS](//github.com/dalekjs/dalek).
37 |  | * It provides all a WebDriverServer & browser launcher for Internet Explorer.
38 |  | *
39 |  | * The browser plugin can be installed with the following command:
40 |  | *
41 |  | * ```bash
42 |  | * $ npm install dalek-browser-ie --save-dev
43 |  | * ```
44 |  | *
45 |  | * You can use the browser plugin by adding a config option to the your Dalekfile
46 |  | *
47 |  | * ```javascript
48 |  | * "browsers": ["IE"]
49 |  | * ```
50 |  | *
51 |  | * Or you can tell Dalek that it should test in this browser via the command line:
52 |  | *
53 |  | * ```bash
54 |  | * $ dalek mytest.js -b IE
55 |  | * ```
56 |  | *
57 |  | * The Webdriver Server tries to open Port 5555 by default,
58 |  | * if this port is blocked, it tries to use a port between 5555 & 5564
59 |  | * You can specifiy a different port from within your [Dalekfile](/pages/config.html) like so:
60 |  | *
61 |  | * ```javascript
62 |  | * "browsers": {
63 |  | * "ie": {
64 |  | * "port": 6555
65 |  | * }
66 |  | * }
67 |  | * ```
68 |  | *
69 |  | * It is also possible to specify a range of ports:
70 |  | *
71 |  | * ```javascript
72 |  | * "browsers": {
73 |  | * "ie": {
74 |  | * "portRange": [6100, 6120]
75 |  | * }
76 |  | * }
77 |  | * ```
78 |  | *
79 |  | * @module DalekJS
80 |  | * @class InternetExplorer
81 |  | * @namespace Browser
82 |  | * @part InternetExplorer
83 |  | * @api
84 |  | */
85 |  |
86 | 1 | var InternetExplorer = {
87 |  |
88 |  | /**
89 |  | * Verbose version of the browser name
90 |  | *
91 |  | * @property longName
92 |  | * @type string
93 |  | * @default Internet Explorer
94 |  | * @api
95 |  | */
96 |  |
97 |  | longName: 'Internet Explorer',
98 |  |
99 |  | /**
100 |  | * Default port of the IEDriverServer
101 |  | * The port may change, cause the port conflict resultion
102 |  | * tool might pick another one, if the default one is blocked
103 |  | *
104 |  | * @property port
105 |  | * @type integer
106 |  | * @default 5555
107 |  | */
108 |  |
109 |  | port: 5555,
110 |  |
111 |  | /**
112 |  | * Default maximum port of the IEDriverServer
113 |  | * The port is the highest port in the range that can be allocated
114 |  | * by the IEDriverServer
115 |  | *
116 |  | * @property maxPort
117 |  | * @type integer
118 |  | * @default 5654
119 |  | */
120 |  |
121 |  | maxPort: 5654,
122 |  |
123 |  | /**
124 |  | * Default host of the IEDriverServer
125 |  | * The host may be overridden with
126 |  | * a user configured value
127 |  | *
128 |  | * @property host
129 |  | * @type string
130 |  | * @default localhost
131 |  | */
132 |  |
133 |  | host: 'localhost',
134 |  |
135 |  | /**
136 |  | * Default desired capabilities that should be
137 |  | * transferred when the browser session gets requested
138 |  | *
139 |  | * @property desiredCapabilities
140 |  | * @type object
141 |  | */
142 |  |
143 |  | desiredCapabilities: {
144 |  | browserName: 'InternetExplorer',
145 |  | initialBrowserUrl: ''
146 |  | },
147 |  |
148 |  | /**
149 |  | * Driver defaults, what should the driver be able to access.
150 |  | *
151 |  | * @property driverDefaults
152 |  | * @type object
153 |  | */
154 |  |
155 |  | driverDefaults: {
156 |  | viewport: true,
157 |  | status: true,
158 |  | sessionInfo: true
159 |  | },
160 |  |
161 |  | /**
162 |  | * Path to the IEDriverServer.exe file
163 |  | *
164 |  | * @property path
165 |  | * @type string
166 |  | * @default /
167 |  | */
168 |  |
169 |  | path: '/',
170 |  |
171 |  | /**
172 |  | * Child process instance of the IEDriverServer
173 |  | *
174 |  | * @property spawned
175 |  | * @type null|Object
176 |  | */
177 |  |
178 |  | spawned: null,
179 |  |
180 |  | /**
181 |  | * IE processes that are running on startup,
182 |  | * and therefor shouldn`t be closed
183 |  | *
184 |  | * @property openProcesses
185 |  | * @type array
186 |  | * @default []
187 |  | */
188 |  |
189 |  | openProcesses: [],
190 |  |
191 |  | /**
192 |  | * Resolves the driver port
193 |  | *
194 |  | * @method getPort
195 |  | * @return {integer} port WebDriver server port
196 |  | */
197 |  |
198 |  | getPort: function () {
199 | 0 | return this.port;
200 |  | },
201 |  |
202 |  | /**
203 |  | * Returns the driver host
204 |  | *
205 |  | * @method getHost
206 |  | * @return {string} host WebDriver server hostname
207 |  | */
208 |  |
209 |  | getHost: function () {
210 | 0 | return this.host;
211 |  | },
212 |  |
213 |  | /**
214 |  | * Resolves the maximum range for the driver port
215 |  | *
216 |  | * @method getMaxPort
217 |  | * @return {integer} port Max WebDriver server port range
218 |  | */
219 |  |
220 |  | getMaxPort: function () {
221 | 0 | return this.maxPort;
222 |  | },
223 |  |
224 |  | /**
225 |  | * Launches the driver
226 |  | * (the driver takes care of launching the browser)
227 |  | *
228 |  | * @method launch
229 |  | * @return {object} promise Browser promise
230 |  | */
231 |  |
232 |  | launch: function (configuration, events, config) {
233 | 0 | var deferred = Q.defer();
234 |  |
235 |  | // store injected configuration/log event handlers
236 | 0 | this.reporterEvents = events;
237 | 0 | this.configuration = configuration;
238 | 0 | this.config = config;
239 |  |
240 |  | // check for a user set port
241 | 0 | var browsers = this.config.get('browsers');
242 | 0 | if (browsers && Array.isArray(browsers)) {
243 | 0 | browsers.forEach(this._checkUserDefinedPorts.bind(this));
244 |  | }
245 |  |
246 |  | // check if the current port is in use, if so, scan for free ports
247 | 0 | portscanner.findAPortNotInUse(this.getPort(), this.getMaxPort(), this.getHost(), this._checkPorts.bind(this, deferred));
248 | 0 | return deferred.promise;
249 |  | },
250 |  |
251 |  | /**
252 |  | * Kills the driver & browser processes
253 |  | *
254 |  | * @method kill
255 |  | * @chainable
256 |  | */
257 |  |
258 |  | kill: function () {
259 |  | // get a list of all running processes
260 | 0 | this._list(function(svc){
261 |  | // filter out the browser process
262 | 0 | svc.forEach(function (item, idx) {
263 | 0 | Object.keys(item).forEach(function (key) {
264 | 0 | if(svc[idx][key] === 'iexplore.exe') {
265 |  | // kill the browser process
266 | 0 | this._kill(svc[idx].PID, true);
267 |  | }
268 |  | }.bind(this));
269 |  | }.bind(this));
270 |  | }.bind(this),true);
271 |  |
272 |  | // kill the driver process
273 | 0 | this.spawned.kill('SIGTERM');
274 | 0 | return this;
275 |  | },
276 |  |
277 |  | _checkPorts: function (deferred, err, port) {
278 |  | // check if the port was blocked & if we need to switch to another port
279 | 0 | if (this.port !== port) {
280 | 0 | this.reporterEvents.emit('report:log:system', 'dalek-browser-ie: Switching to port: ' + port);
281 | 0 | this.port = port;
282 |  | }
283 |  |
284 |  | // invoke the ie driver afterwards
285 | 0 | this._startIEdriver(deferred);
286 | 0 | return this;
287 |  | },
288 |  |
289 |  | _startIEdriver: function (deferred) {
290 | 0 | var stream = '';
291 | 0 | this.spawned = cp.spawn(iedriver.path, ['--port=' + this.getPort()]);
292 |  |
293 | 0 | this.spawned.stdout.on('data', function (data) {
294 | 0 | var dataStr = data + '';
295 | 0 | stream += dataStr;
296 | 0 | if (stream.search('Listening on port') !== -1) {
297 | 0 | deferred.resolve();
298 |  | }
299 |  | });
300 | 0 | return this;
301 |  | },
302 |  |
303 |  | /**
304 |  | * Process user defined ports
305 |  | *
306 |  | * @method _checkUserDefinedPorts
307 |  | * @param {object} browser Browser configuration
308 |  | * @chainable
309 |  | * @private
310 |  | */
311 |  |
312 |  | _checkUserDefinedPorts: function (browser) {
313 |  | // check for a single defined port
314 | 0 | if (browser.ie && browser.ie.port) {
315 | 0 | this.port = parseInt(browser.ie.port, 10);
316 | 0 | this.maxPort = this.port + 90;
317 | 0 | this.reporterEvents.emit('report:log:system', 'dalek-browser-ie: Switching to user defined port: ' + this.port);
318 |  | }
319 |  |
320 |  | // check for a port range
321 | 0 | if (browser.ie && browser.ie.portRange && browser.ie.portRange.length === 2) {
322 | 0 | this.port = parseInt(browser.ie.portRange[0], 10);
323 | 0 | this.maxPort = parseInt(browser.ie.portRange[1], 10);
324 | 0 | this.reporterEvents.emit('report:log:system', 'dalek-browser-ie: Switching to user defined port(s): ' + this.port + ' -> ' + this.maxPort);
325 |  | }
326 |  |
327 | 0 | return this;
328 |  | },
329 |  |
330 |  | /**
331 |  | * Lists all running processes (win only)
332 |  | *
333 |  | * @method _list
334 |  | * @param {Function} callback Receives the process object as the only callback argument
335 |  | * @param {Boolean} [verbose=false] Verbose output
336 |  | * @chainable
337 |  | * @private
338 |  | */
339 |  |
340 |  | _list: function(callback, verbose) {
341 | 0 | verbose = typeof verbose === 'boolean' ? verbose : false;
342 | 0 | cp.exec('tasklist /FO CSV' + (verbose === true ? ' /V' : ''), function (err, stdout) {
343 | 0 | var pi = stdout.split('\r\n');
344 | 0 | var p = [];
345 |  |
346 | 0 | pi.forEach(function (line) {
347 | 0 | if (line.trim().length !== 0) {
348 | 0 | p.push(line);
349 |  | }
350 |  | });
351 |  |
352 | 0 | var proc = [];
353 | 0 | var head = null;
354 | 0 | while (p.length > 1) {
355 | 0 | var rec = p.shift();
356 | 0 | rec = rec.replace(/\"\,/gi,'";').replace(/\"|\'/gi,'').split(';');
357 | 0 | if (head === null){
358 | 0 | head = rec;
359 | 0 | for (var i=0;i<head.length;i++){
360 | 0 | head[i] = head[i].replace(/ /gi,'');
361 |  | }
362 |  |
363 | 0 | if (head.indexOf('PID')<0){
364 | 0 | head[1] = 'PID';
365 |  | }
366 |  | } else {
367 | 0 | var tmp = {};
368 | 0 | for (var j=0;j<rec.length;j++){
369 | 0 | tmp[head[j]] = rec[j].replace(/\"|\'/gi,'');
370 |  | }
371 | 0 | proc.push(tmp);
372 |  | }
373 |  | }
374 | 0 | callback(proc);
375 |  | });
376 |  |
377 | 0 | return this;
378 |  | },
379 |  |
380 |  | /**
381 |  | * Kill a specific process (win only)
382 |  | *
383 |  | * @method _kill
384 |  | * @param {Number} PID Process ID
385 |  | * @param {Boolean} [force=false] Force close the process.
386 |  | * @param {Function} [callback] Callback after process has been killed
387 |  | * @chainable
388 |  | * @private
389 |  | */
390 |  |
391 |  | _kill: function(pid, force, callback) {
392 | 0 | if (!pid || isNaN(parseInt(pid))){
393 | 0 | throw new Error('PID is required for the kill operation.');
394 |  | }
395 | 0 | callback = callback || function(){};
396 | 0 | if (typeof force === 'function'){
397 | 0 | callback = force;
398 | 0 | force = false;
399 |  | }
400 | 0 | cp.exec('taskkill /PID ' + pid + (force === true ? ' /f' : ''),callback);
401 | 0 | return this;
402 |  | }
403 |  |
404 |  | };
405 |  |
406 |  | // expose the module
407 | 1 | module.exports = InternetExplorer;
408 |  |

## /Users/asciidisco/Github/dalekjs/dalek-browser-ie/lib/iedriver.js

100%
3
3
0

Line | Hits | Source
--- | --- | ---
1 |  | // Copyright 2013 The Obvious Corporation.
2 |  |
3 |  | /**
4 |  | * @fileoverview Helpers made available via require('dalek-browser-ie') once package is
5 |  | * installed.
6 |  | */
7 |  |
8 | 1 | var path = require('path');
9 |  |
10 |  |
11 |  | /**
12 |  | * Where the iedriverserver binary can be found.
13 |  | * @type {string}
14 |  | */
15 | 1 | exports.path = path.join(__dirname, 'bin', 'IEDriverServer.exe');
16 |  |
17 |  |
18 |  | /**
19 |  | * The version of iedriverserver installed by this package.
20 |  | * @type {number}
21 |  | */
22 | 1 | exports.version = '23.0.0';
23 |  |