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

Console errors and warning plugin #1916

Closed
wants to merge 15 commits into from
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ changes.sh
xmloutput*
npm-debug.log

*.swp
*.swp
118 changes: 118 additions & 0 deletions plugins/console/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
var q = require('q');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should use protractor.promise instead of q. The webdriver code has its own promise implementation and you probably want to use the same infrastructure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's super confusing, but Protractor actually uses both q and the webdriver promises. I think it's OK to use q in this situation, because it has no need to sync up with the webdriver promises - and it's actually probably safer, because it can't accidentally interfere with the webdriver control flow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will use q for now as per Julies comment


var testOut = {
failedCount: 0, specResults: [{
description: "Console output",
assertions: [],
duration: 0
}]
};

/**
* This plugin checks the browser log after each test for warnings and errors. It can be configured to fail a test if either is detected.
* There is also an optional exclude parameter which accepts both regex and strings,
* Any log matching the exclude parameter will not fail the test or be logged to the console
*
* exports.config = {
* plugins: [{
* path: 'node_modules/protractor/plugins/console',
* failOnWarning: {Boolean} (Default - false),
* failOnError: {Boolean} (Default - true)
* exclude: {Array of strings and regex} (Default - [])
* }]
* };
*/
var ConsolePlugin = function() {
};

/**
* Gets the browser log
*
* @returns {!webdriver.promise.Promise.<!Array.<!webdriver.logging.Entry>>}
*/
ConsolePlugin.getBrowserLog = function() {
return browser.manage().logs().get('browser');
};

/**
* Logs messages to the test output
*
* @param warnings
* The list of warnings detected by the browser log
* @param errors
* The list of errors detected by the browser log
*/
ConsolePlugin.logMessages = function(warnings, errors) {
var passed = (testOut.failedCount === 0);
warnings.map(function(warning) {
testOut.specResults[0].assertions.push(
{passed: passed, errorMsg: warning.level.name + ': ' + warning.message}
);
});

errors.map(function(error) {
testOut.specResults[0].assertions.push(
{passed: passed, errorMsg: error.level.name + ': ' + error.message}
);
});
};

/**
* Determines if a log message is filtered out or not. This can be set at the config stage using the exclude parameter.
* The parameter accepts both strings and regex
*
* @param logMessage
* Current log message
* @returns {boolean}
*/
ConsolePlugin.includeLog = function(logMessage) {
return this.exclude.filter(function(e) {
return (e instanceof RegExp) ? logMessage.match(e) : logMessage.indexOf(e) > -1;
}).length === 0;
};

/**
* Parses the log and decides whether to throw an error or not
*
* @param config
* The config of the plugin defined in the protractor config file
* @returns {!webdriver.promise.Promise.<R>}
*/
ConsolePlugin.parseLog = function(config) {
var self = this;
var failOnWarning = (config.failOnWarning === undefined) ? false : config.failOnWarning;
var failOnError = (config.failOnError == undefined) ? true : config.failOnError;
this.exclude = config.exclude || [];

return this.getBrowserLog().then(function(log) {

var warnings = log.filter(function(node) {
return (node.level || {}).name === 'WARNING' && self.includeLog(node.message);
});

var errors = log.filter(function(node) {
return (node.level || {}).name === 'SEVERE' && self.includeLog(node.message);
});

testOut.failedCount += (warnings.length > 0 && failOnWarning) ? warnings.length : 0;
testOut.failedCount += (errors.length > 0 && failOnError) ? errors.length : 0;

self.logMessages(warnings, errors);
});

};

/**
* Tear-down function used by protractor
*
* @param config
*/
ConsolePlugin.prototype.teardown = function(config) {
return ConsolePlugin.parseLog(config).then(function() {
return testOut;
});
};

var consolePlugin = new ConsolePlugin();

exports.teardown = consolePlugin.teardown.bind(consolePlugin);
13 changes: 13 additions & 0 deletions plugins/console/spec/consoleFailConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
var env = require('../../../spec/environment.js');

exports.config = {
seleniumAddress: env.seleniumAddress,
framework: 'jasmine2',
specs: ['fail_spec.js'],
baseUrl: env.baseUrl,
plugins: [{
path: '../index.js',
failOnWarning: true,
failOnError: true
}]
};
13 changes: 13 additions & 0 deletions plugins/console/spec/consoleFailErrorConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
var env = require('../../../spec/environment.js');

exports.config = {
seleniumAddress: env.seleniumAddress,
framework: 'jasmine2',
specs: ['fail_error_spec.js'],
baseUrl: env.baseUrl,
plugins: [{
path: '../index.js',
failOnWarning: false,
failOnError: true
}]
};
17 changes: 17 additions & 0 deletions plugins/console/spec/consoleFailFilterConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
var env = require('../../../spec/environment.js');

exports.config = {
seleniumAddress: env.seleniumAddress,
framework: 'jasmine2',
specs: ['fail_error_spec.js'],
baseUrl: env.baseUrl,
plugins: [{
path: '../index.js',
failOnWarning: true,
failOnError: true,
exclude: [
'string',
/regex/
]
}]
};
13 changes: 13 additions & 0 deletions plugins/console/spec/consoleFailWarningConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
var env = require('../../../spec/environment.js');

exports.config = {
seleniumAddress: env.seleniumAddress,
framework: 'jasmine2',
specs: ['fail_warning_spec.js'],
baseUrl: env.baseUrl,
plugins: [{
path: '../index.js',
failOnWarning: true,
failOnError: false
}]
};
13 changes: 13 additions & 0 deletions plugins/console/spec/consolePassConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
var env = require('../../../spec/environment.js');

exports.config = {
seleniumAddress: env.seleniumAddress,
framework: 'jasmine2',
specs: ['pass_spec.js'],
baseUrl: env.baseUrl,
plugins: [{
path: '../index.js',
failOnWarning: false,
failOnError: false
}]
};
15 changes: 15 additions & 0 deletions plugins/console/spec/fail_error_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
describe('console plugin', function() {

var logMessageButton = element(by.id('log-message'));
var deleteMessageButton = element(by.id('simulate-error'));

it('should not fail on log and debug messages', function() {
browser.get('console/index.html');
logMessageButton.click();
});

it('should fail on error message', function() {
browser.get('console/index.html');
deleteMessageButton.click();
});
});
21 changes: 21 additions & 0 deletions plugins/console/spec/fail_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
describe('console plugin', function() {

var logMessageButton = element(by.id('log-message'));
var warningMessageButton = element(by.id('simulate-warning'));
var deleteMessageButton = element(by.id('simulate-error'));

it('should not fail on log and debug messages', function() {
browser.get('console/index.html');
logMessageButton.click();
});

it('should fail on warning message', function() {
browser.get('console/index.html');
warningMessageButton.click();
});

it('should fail on error message', function() {
browser.get('console/index.html');
deleteMessageButton.click();
});
});
15 changes: 15 additions & 0 deletions plugins/console/spec/fail_warning_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
describe('console plugin', function() {

var logMessageButton = element(by.id('log-message'));
var warningMessageButton = element(by.id('simulate-warning'));

it('should not fail on log and debug messages', function() {
browser.get('console/index.html');
logMessageButton.click();
});

it('should fail on warning message', function() {
browser.get('console/index.html');
warningMessageButton.click();
});
});
21 changes: 21 additions & 0 deletions plugins/console/spec/pass_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
describe('console plugin', function() {

var logMessageButton = element(by.id('log-message'));
var warningMessageButton = element(by.id('simulate-warning'));
var deleteMessageButton = element(by.id('simulate-error'));

it('should not fail on log and debug messages', function() {
browser.get('console/index.html');
logMessageButton.click();
});

it('should not fail on warning message', function() {
browser.get('console/index.html');
warningMessageButton.click();
});

it('should not fail on error message', function() {
browser.get('console/index.html');
deleteMessageButton.click();
});
});
39 changes: 38 additions & 1 deletion scripts/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ passingTests.push('node node_modules/minijasminenode/bin/minijn ' +
passingTests.push(
'node lib/cli.js plugins/timeline/spec/conf.js',
'node lib/cli.js plugins/ngHint/spec/successConfig.js',
'node lib/cli.js plugins/accessibility/spec/successConfig.js');
'node lib/cli.js plugins/accessibility/spec/successConfig.js',
'node lib/cli.js plugins/console/spec/consolePassConfig.js'
);

var executor = new Executor();

Expand Down Expand Up @@ -135,4 +137,39 @@ executor.addCommandlineTest(
message: '1 element failed:'
}]);

// Check console plugin

executor.addCommandlineTest(
'node lib/cli.js plugins/console/spec/consoleFailConfig.js')
.expectExitCode(1)
.expectErrors([
{message: 'This is a test warning'},
{message: 'This is a test error'},
{message: 'This should be filtered out by string'},
{message: 'This should be filtered out by regex'}
]);

executor.addCommandlineTest(
'node lib/cli.js plugins/console/spec/consoleFailErrorConfig.js')
.expectExitCode(1)
.expectErrors([
{message: 'This is a test error'},
{message: 'This should be filtered out by string'},
{message: 'This should be filtered out by regex'}
]);

executor.addCommandlineTest(
'node lib/cli.js plugins/console/spec/consoleFailWarningConfig.js')
.expectExitCode(1)
.expectErrors([
{message: 'This is a test warning'}
]);

executor.addCommandlineTest(
'node lib/cli.js plugins/console/spec/consoleFailFilterConfig.js')
.expectExitCode(1)
.expectErrors([
{message: 'This is a test error'}
]);

executor.execute();
2 changes: 1 addition & 1 deletion spec/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ module.exports = {
'http://' + (process.env.HTTP_HOST || 'localhost') +
':' + (process.env.HTTP_PORT || webServerDefaultPort)

};
};
35 changes: 35 additions & 0 deletions testapp/console/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>

<html ng-app="consolePlugin" lang="en">
<head>
<meta charset="utf-8">
<title>Angular.js Example</title>
<script src="../../lib/angular/angular.min.js"></script>
<script src="../../lib/angular/angular-aria.min.js"></script>
<script type="text/javascript">
angular.module('consolePlugin', [])
.controller('TestCtrl', ['$scope', function($scope) {

$scope.logMessage = function() {
console.log('This is a test log');
console.debug('This is a test debug');
};

$scope.simulateWarning = function() {
console.warn('This is a test warning');
};

$scope.simulateError = function() {
console.error('This is a test error');
console.error('This should be filtered out by string');
console.error('This should be filtered out by regex');
}
}]);
</script>
</head>
<body ng-controller="TestCtrl">
<button id="log-message" ng-click="logMessage()">Log Message</button>
<button id="simulate-warning" ng-click="simulateWarning()">Simulate Warning</button>
<button id="simulate-error" ng-click="simulateError()">Simulate Error</button>
</body>
</html>