Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

Commit

Permalink
chore(exitCodes): adding exit code for browser connect errors
Browse files Browse the repository at this point in the history
  • Loading branch information
cnishina committed Apr 22, 2016
1 parent 47f54ad commit df2cb56
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 18 deletions.
16 changes: 9 additions & 7 deletions lib/driverProviders/direct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as fs from 'fs';
import * as path from 'path';
import * as util from 'util';

import {BrowserError} from '../exitCodes';
import {Config} from '../configParser';
import {DriverProvider} from './driverProvider';
import {Logger} from '../logger2';
Expand Down Expand Up @@ -35,9 +36,9 @@ export class Direct extends DriverProvider {
logger.info('Using FirefoxDriver directly...');
break;
default:
throw new Error(
'browserName (' + this.config_.capabilities.browserName +
') is not supported with directConnect.');
throw new BrowserError(
logger, 'browserName ' + this.config_.capabilities.browserName +
' is not supported with directConnect.');
}
return q.fcall(function() {});
}
Expand Down Expand Up @@ -65,7 +66,8 @@ export class Direct extends DriverProvider {
this.config_.chromeDriver || defaultChromeDriverPath;

if (!fs.existsSync(chromeDriverFile)) {
throw new Error('Could not find chromedriver at ' + chromeDriverFile);
throw new BrowserError(
logger, 'Could not find chromedriver at ' + chromeDriverFile);
}

let service = new chrome.ServiceBuilder(chromeDriverFile).build();
Expand All @@ -79,9 +81,9 @@ export class Direct extends DriverProvider {
driver = new firefox.Driver(this.config_.capabilities);
break;
default:
throw new Error(
'browserName ' + this.config_.capabilities.browserName +
'is not supported with directConnect.');
throw new BrowserError(
logger, 'browserName ' + this.config_.capabilities.browserName +
' is not supported with directConnect.');
}
this.drivers_.push(driver);
return driver;
Expand Down
12 changes: 7 additions & 5 deletions lib/driverProviders/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as path from 'path';
import * as q from 'q';
import * as util from 'util';

import {BrowserError} from '../exitCodes';
import {Config} from '../configParser';
import {DriverProvider} from './driverProvider';
import {Logger} from '../logger2';
Expand Down Expand Up @@ -39,10 +40,10 @@ export class Local extends DriverProvider {
require('../../config.json').webdriverVersions.selenium + '.jar');
}
if (!fs.existsSync(this.config_.seleniumServerJar)) {
throw new Error(
'No selenium server jar found at the specified ' +
'location (' + this.config_.seleniumServerJar +
'). Check that the version number is up to date.');
throw new BrowserError(
logger, 'No selenium server jar found at the specified ' +
'location (' + this.config_.seleniumServerJar +
'). Check that the version number is up to date.');
}
if (this.config_.capabilities.browserName === 'chrome') {
if (!this.config_.chromeDriver) {
Expand All @@ -59,7 +60,8 @@ export class Local extends DriverProvider {
if (fs.existsSync(this.config_.chromeDriver + '.exe')) {
this.config_.chromeDriver += '.exe';
} else {
throw new Error(
throw new BrowserError(
logger,
'Could not find chromedriver at ' + this.config_.chromeDriver);
}
}
Expand Down
59 changes: 53 additions & 6 deletions lib/exitCodes.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,75 @@
import {Logger} from './logger2';

const CONFIG_ERROR_CODE = 105;
const BROWSER_ERROR_CODE = 135;

export class ProtractorError extends Error {
static ERR_MSGS: string[];
static DEFAULT_MSG = 'protractor encountered an error';

export class ProtractorError {
error: Error;
description: string;
code: number;
stack: string;
constructor(logger: Logger, description: string, code: number) {
super();
this.error = new Error();
this.description = description;
this.code = code;
this.description = description;
this.stack = this.error.stack;
this.logError(logger);
}

logError(logger: Logger) {
logger.error('error code: ' + this.code);
logger.error('description: ' + this.description);
this.stack = this.error.stack;
logger.error(this.stack);
}
}

/**
* Configuration file error
*/
export class ConfigError extends ProtractorError {
static DEFAULT_MSG = 'configuration error';
static CODE = CONFIG_ERROR_CODE;
constructor(logger: Logger, description: string) {
super(logger, description, ConfigError.CODE);
constructor(logger: Logger, opt_msg?: string) {
super(logger, opt_msg || ConfigError.DEFAULT_MSG, ConfigError.CODE);
}
}

/**
* Browser errors including getting a driver session, direct connect, etc.
*/
export class BrowserError extends ProtractorError {
static DEFAULT_MSG = 'browser error';
static CODE = BROWSER_ERROR_CODE;
static ERR_MSGS =
['ECONNREFUSED connect ECONNREFUSED', 'Sauce Labs Authentication Error'];
constructor(logger: Logger, opt_msg?: string) {
super(logger, opt_msg || BrowserError.DEFAULT_MSG, BrowserError.CODE);
}
}

export class ErrorHandler {
static isError(errMsgs: string[], e: Error): boolean {
if (errMsgs && errMsgs.length > 0) {
for (let errPos in errMsgs) {
let errMsg = errMsgs[errPos];
if (e.message.indexOf(errMsg) !== -1) {
return true;
}
}
}
return false;
}

static parseError(e: Error): number {
if (ErrorHandler.isError(ConfigError.ERR_MSGS, e)) {
return ConfigError.CODE;
}
if (ErrorHandler.isError(BrowserError.ERR_MSGS, e)) {
return BrowserError.CODE;
}
return null;
}
}
9 changes: 9 additions & 0 deletions lib/launcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
import * as q from 'q';
import {Config, ConfigParser} from './configParser';
import {ErrorHandler} from './exitCodes';
import {Logger} from './logger2';
import {Runner} from './runner';
import {TaskRunner} from './taskRunner';
Expand Down Expand Up @@ -176,6 +177,14 @@ let initFn = function(configFile: string, additionalConfig: Config) {
// 4) Run tests.
let scheduler = new TaskScheduler(config);

process.on('uncaughtException', (e: Error) => {
let errorCode = ErrorHandler.parseError(e);
if (errorCode) {
logger.error(e.stack);
process.exit(errorCode);
}
});

process.on('exit', (code: number) => {
if (code) {
logger.error('Process exited with error code ' + code);
Expand Down
26 changes: 26 additions & 0 deletions scripts/exitCodes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env node

'use strict';

var spawn = require('child_process').spawnSync;
var runProtractor, output, messages;
var checkLogs = function(output, messages) {
for (var pos in messages) {
var message = messages[pos];
if (output.indexOf(message) === -1) {
throw new Error('does not exist in logs: ' + message);
}
}
};

/******************************
*Below are exit failure tests*
******************************/

// assert authentication error for sauce labs
runProtractor = spawn('node',
['bin/protractor', 'spec/errorTest/sauceLabNotAvailable.js']);
output = runProtractor.stdout.toString();
messages = ['WebDriverError: Sauce Labs Authentication Error.',
'Process exited with error code 135'];
checkLogs(output, messages);
1 change: 1 addition & 0 deletions scripts/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var passingTests = [
'node built/cli.js spec/noGlobalsConf.js',
'node built/cli.js spec/angular2Conf.js',
'node scripts/attachSession.js',
'node scripts/exitCodes.js',
'node scripts/interactive_tests/interactive_test.js',
'node scripts/interactive_tests/with_base_url.js',
// Unit tests
Expand Down
23 changes: 23 additions & 0 deletions spec/errorTest/sauceLabNotAvailable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var env = require('../environment.js');

exports.config = {
sauceUser: 'foobar',
sauceKey: process.env.SAUCE_ACCESS_KEY,

framework: 'jasmine',

specs: [
'../../example/example_spec.js'
],

capabilities: {
'browserName': 'chrome'
},

baseUrl: env.baseUrl + '/ng1/',

jasmineNodeOpts: {
defaultTimeoutInterval: 90000
}

};
68 changes: 68 additions & 0 deletions spec/unit/driverProviders/direct_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
var fs = require('fs'),
os = require('os'),
path = require('path');
var BrowserError = require('../../../built/exitCodes').BrowserError,
Logger = require('../../../built/logger2').Logger,
WriteTo = require('../../../built/logger2').WriteTo;

describe('direct connect', function() {
beforeEach(function() {
Logger.setWrite(WriteTo.NONE);
});

afterEach(function() {
Logger.setWrite(WriteTo.CONSOLE);
});

describe('without the chrome driver', function() {
it('should throw an error if no drivers are present', function() {
var config = {
directConnect: true,
capabilities: { browserName: 'chrome' },
chromeDriver: '/foo/bar/chromedriver'
};
var errorFound = false;
try {
webdriver = require('../../../built/driverProviders/direct')(config);
webdriver.getNewDriver();
} catch(e) {
errorFound = true;
expect(e.code).toBe(BrowserError.CODE);
}
expect(errorFound).toBe(true);
});
});

describe('with chromedriver drivers', function() {
var chromedriver = '';
beforeEach(function() {
// add files to selenium folder
file = 'chromedriver';
chromedriver = path.resolve(os.tmpdir(), file);
fs.openSync(chromedriver, 'w');
});

afterEach(function() {
try {
fs.unlinkSync(chromedriver);
} catch(e) {
}
});
it('should throw an error if the driver cannot be used', function() {
var config = {
directConnect: true,
capabilities: { browserName: 'foobar explorer' },
chromeDriver: chromedriver
};
var errorFound = false;
try {
webdriver = require('../../../built/driverProviders/direct')(config);
webdriver.getNewDriver();
} catch(e) {
errorFound = true;
expect(e.code).toBe(BrowserError.CODE);
}
expect(errorFound).toBe(true);
});
});
});
71 changes: 71 additions & 0 deletions spec/unit/driverProviders/local_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
var fs = require('fs'),
os = require('os'),
path = require('path');
var BrowserError = require('../../../built/exitCodes').BrowserError,
Logger = require('../../../built/logger2').Logger,
WriteTo = require('../../../built/logger2').WriteTo;

describe('local connect', function() {
beforeEach(function() {
Logger.setWrite(WriteTo.NONE);
});

afterEach(function() {
Logger.setWrite(WriteTo.CONSOLE);
});

describe('without the selenium standalone jar', function() {
it('should throw an error jar file is not present', function() {
var config = {
directConnect: true,
capabilities: { browserName: 'chrome' },
seleniumServerJar: '/foo/bar/selenium.jar'
};
var errorFound = false;
try {
webdriver = require('../../../built/driverProviders/local')(config);
webdriver.setupEnv();
} catch(e) {
errorFound = true;
expect(e.code).toBe(BrowserError.CODE);
}
expect(errorFound).toBe(true);
});
});

describe('with the selenium standalone jar', function() {
it('should throw an error if the jar file does not work', function() {
var jarFile = '';
beforeEach(function() {
// add files to selenium folder
file = 'selenium.jar';
jarFile = path.resolve(os.tmpdir(), file);
fs.openSync(jarFile, 'w');
});

afterEach(function() {
try {
fs.unlinkSync(jarFile);
} catch(e) {
}
});

it('should throw an error if the selenium sever jar cannot be used', function() {
var config = {
directConnect: true,
capabilities: { browserName: 'foobar explorer' },
seleniumServerJar: jarFile
};
var errorFound = false;
try {
webdriver = require('../../../built/driverProviders/local')(config);
webdriver.getNewDriver();
} catch(e) {
errorFound = true;
expect(e.code).toBe(BrowserError.CODE);
}
expect(errorFound).toBe(true);
});
});
});
});

0 comments on commit df2cb56

Please sign in to comment.