protractor
Version:
Webdriver E2E test wrapper for Angular.
200 lines (186 loc) • 5.82 kB
JavaScript
var q = require('q'),
fs = require('fs'),
_ = require('lodash'),
ngHintNames = {
ngHintControllers: 'Controllers',
ngHintDirectives: 'Directives',
ngHintDom: 'DOM',
ngHintEvents: 'Events',
ngHintInterpolation: 'Interpolation',
ngHintModules: 'Modules',
ngHintScopes: 'Scopes',
ngHintGeneral: 'General'
};
/**
* You enable this plugin in your config file:
*
* exports.config = {
* plugins: [{
* path: 'node_modules/protractor/plugins/ngHint',
*
* asTests: {Boolean},
* excludeURLs: {(String|RegExp)[]}
* }]
* };
*
* asTests specifies if the plugin should generate passed/failed test results
* based on the ngHint output or instead log the results to the console.
* Defaults to true.
*
* excludeURLs specifies a list of URLs for which ngHint results should be
* ignored. Defaults to []
*/
/*
* The strategy for this plugin is as follows:
*
* During setup, install the ngHint code and listeners to capture its output.
* Store the output in the following format:
* {page URL} -> {module} -> {message} -> {message type}
*
* So, for instance, you might have:
* {
* 'google.com': {
* 'Controllers': {
* {'It is against Angular best practices to...': warning}
* },
* 'Modules: {
* {'Module "Search" was loaded but does not exist': error}
* }
* }
* }
*
* We store the messages as keys in objects in order to avoid duplicates.
*/
/**
* Configures the plugin to grab the output of ngHint
*
* @see docs/plugins.md
* @public
*/
function setup() {
// Intercept ngHint output
browser.addMockModule('protractorNgHintCaptureModule_', function() {
angular.module('protractorNgHintCaptureModule_', []);
var hintInstalled = true;
if (!angular.hint) {
hintInstalled = false;
angular.hint = {};
}
/** override */
angular.hint.onMessage = function(module, message, type) {
var ngHintLog = JSON.parse(localStorage.getItem(
'ngHintLog_protractor') || '{}');
var pageLog = ngHintLog[location] || {};
var moduleLog = pageLog[module] || {};
moduleLog[message] = type;
pageLog[module] = moduleLog;
ngHintLog[location] = pageLog;
localStorage.setItem('ngHintLog_protractor',
JSON.stringify(ngHintLog));
};
if (!hintInstalled) {
angular.hint.onMessage('General', 'ngHint plugin cannot be run as ' +
'ngHint code was never included into the page', 'warning');
}
});
}
/**
* Checks if a URL should not be examined by the ngHint plugin
*
* @param {String} url The URL to check for exclusion
* @param {Object} config The configuration file for the ngHint plugin
* @return {Boolean} true if the URL should not be examined by the ngHint plugin
* @private
*/
function isExcluded(url, config) {
var excludeURLs = config.excludeURLs || [];
for (var i = 0; i < excludeURLs.length; i++) {
if (typeof excludeURLs[i] == typeof '') {
if (url == excludeURLs[i]) {
return true;
}
} else {
if (excludeURLs[i].test(url)) {
return true;
}
}
}
return false;
}
/**
* Checks if a warning message should be ignored by the ngHint plugin
*
* @param {String} message The message to check
* @return {Boolean} true if the message should be ignored
* @private
*/
function isMessageToIgnore(message) {
if (message == 'It is against Angular best practices to instantiate a ' +
'controller on the window. This behavior is deprecated in Angular ' +
'1.3.0') {
return true; // An ngHint bug, see http://git.io/S3yySQ
}
var module = /^Module "(\w*)" was created but never loaded\.$/.exec(
message);
if (module != null) {
module = module[1];
if (ngHintNames[module] != null) {
return true; // An ngHint module
}
if ((module == 'protractorBaseModule_') || (module ==
'protractorNgHintCaptureModule_')) {
return true; // A protractor module
}
}
return false;
}
/**
* Checks the information which has been stored by the ngHint plugin and
* generates passed/failed tests and/or console output
*
* @see docs/plugins.md
* @return {q.Promise} A promise which resolves to the results of any passed or
* failed tests
* @public
*/
function teardown() {
var self = this;
// Get logged data
return browser.executeScript_(function() {
return localStorage.getItem('ngHintLog_protractor') || '{}';
}, 'get ngHintLog').then(function(ngHintLog) {
ngHintLog = JSON.parse(ngHintLog);
// Get a list of all the modules we tested against
var modulesUsed = _.union.apply(_, [_.values(ngHintNames)].concat(
_.values(ngHintLog).map(Object.keys)));
// Check log
var testOut = {failedCount: 0, specResults: []};
for (url in ngHintLog) {
if (!isExcluded(url, self.config)) {
for (var i = 0; i < modulesUsed.length; i++) {
var resultInfo = {specName: 'Angular Hint Test: ' + modulesUsed[i] +
' (' + url + ')'};
var passed = true;
// Fill in the test details
var messages = ngHintLog[url][modulesUsed[i]];
if (messages) {
for (var message in messages) {
if (!isMessageToIgnore(message)) {
(self.config.asTests !== false ? self.addFailure :
self.addWarning)(messages[message] + ' -- ' + message,
resultInfo);
passed = false;
}
}
}
if (passed) {
self.addSuccess(resultInfo);
}
}
}
}
});
}
// Export
exports.setup = setup;
exports.teardown = teardown;