Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions lib/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@ var log_ = function() {
};

/**
* The plugin API for Protractor. Note that this API is extremely unstable
* and current consists of only two functions:
* <plugin>.setup - called before tests
* <plugin>.teardown - called after tests
* <plugin>.postResults - called after test results have been processed
* More information on plugins coming in the future
* The plugin API for Protractor. Note that this API is unstable. See
* plugins/README.md for more information.
*
* @constructor
* @param {Object} config parsed from the config file
*/
Expand Down Expand Up @@ -58,8 +55,12 @@ function pluginFunFactory(funName) {
var pluginConf = this.pluginConfs[name];
var pluginObj = this.pluginObjs[name];
names.push(name);
promises.push((pluginObj[funName] || noop)(pluginConf));
promises.push(
(pluginObj[funName] || noop).apply(
pluginObj[funName],
[pluginConf].concat([].slice.call(arguments))));
}

return q.all(promises).then(function(results) {
// Join the results into a single object and output any test results
var ret = {failedCount: 0};
Expand Down Expand Up @@ -131,4 +132,12 @@ Plugins.prototype.teardown = pluginFunFactory('teardown');
*/
Plugins.prototype.postResults = pluginFunFactory('postResults');

/**
* Called after each test block completes.
*
* @return {q.Promise} A promise which resolves when the plugins have all been
* torn down.
*/
Plugins.prototype.postTest = pluginFunFactory('postTest');
Copy link
Contributor

Choose a reason for hiding this comment

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

Thee word "test" seems ambiguous. Is this after each it(), assert(), or describe()?

Copy link
Member Author

Choose a reason for hiding this comment

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

each it() (in Jasmine) - another option would be spec. Preference?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also please update the comment on line 17

Copy link
Contributor

Choose a reason for hiding this comment

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

We already use spec to refer to the whole file. testcase might make sense?

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated comments.


module.exports = Plugins;
20 changes: 19 additions & 1 deletion lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,27 @@ Runner.prototype.run = function() {
self.on('testFail', restartDriver);
}

// We need to save these promises to make sure they're run, but we don't
// want to delay starting the next test (because we can't, it's just
// an event emitter).
var pluginPostTestPromises = [];

self.on('testPass', function() {
pluginPostTestPromises.push(plugins.postTest(true));
});
self.on('testFail', function() {
pluginPostTestPromises.push(plugins.postTest(false));
});

return require(frameworkPath).run(self, self.config_.specs).
then(function(testResults) {
return helper.joinTestLogs(pluginSetupResults, testResults);
return q.all(pluginPostTestPromises).then(function(postTestResultList) {
var results = helper.joinTestLogs(pluginSetupResults, testResults);
postTestResultList.forEach(function(postTestResult) {
results = helper.joinTestLogs(results, postTestResult);
});
return results;
});
});
// 5) Teardown plugins
}).then(function(testResults) {
Expand Down
16 changes: 16 additions & 0 deletions plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ exports.config = {
Writing Plugins
---------------

Plugins are designed to work with any test framework (Jasmine, Mocha, etc),
so they use generic hooks which Protractor provides. Plugins may change
the output of Protractor by returning a results object.

Plugins are node modules which export an object with the following API:

```js
Expand Down Expand Up @@ -72,6 +76,18 @@ exports.teardown = function(config) {};
* @return Return values are ignored.
*/
exports.postResults = function(config) {};

/**
* Called after each test block (in Jasmine, this means an `it` block)
* completes.
*
* @param {Object} config The plugin configuration object.
* @param {boolean} passed True if the test passed.
*
* @return Object If an object is returned, it is merged with the Protractor
* result object. May return a promise.
*/
exports.postTest = function(config, passed) {};
```

The protractor results object follows the format specified in
Expand Down
10 changes: 10 additions & 0 deletions scripts/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ executor.addCommandlineTest('node lib/cli.js spec/errorTest/mochaFailureConf.js'
stacktrace: 'mocha_failure_spec.js:11:20'
}]);

executor.addCommandlineTest('node lib/cli.js spec/errorTest/pluginsFailingConf.js')
.expectExitCode(1)
.expectErrors([
{message: 'Expected true to be false'},
{message: 'from setup'},
{message: 'from postTest passing'},
{message: 'from postTest failing'},
{message: 'from teardown'}
]);

// Check ngHint plugin

executor.addCommandlineTest(
Expand Down
30 changes: 30 additions & 0 deletions spec/errorTest/pluginsFailingConf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
var env = require('../environment.js');

// A small suite to make sure the full functionality of plugins work
exports.config = {
// seleniumAddress: env.seleniumAddress,
mockSelenium: true,

framework: 'jasmine2',

// Spec patterns are relative to this directory.
specs: [
'../plugins/fail_spec.js'
],

capabilities: env.capabilities,

baseUrl: env.baseUrl,

jasmineNodeOpts: {
isVerbose: true,
realtimeFailure: true
},

// Plugin patterns are relative to this directory.
plugins: [{
path: '../plugins/basic_plugin.js'
}, {
path: '../plugins/failing_plugin.js'
}]
};
4 changes: 4 additions & 0 deletions spec/plugins/basic_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ describe('check if plugin setup ran', function() {
it('should have set protractor.__BASIC_PLUGIN_RAN', function() {
expect(protractor.__BASIC_PLUGIN_RAN).toBe(true);
});

it('should run multiple tests', function() {
expect(true).toBe(true);
});
});
9 changes: 9 additions & 0 deletions spec/plugins/fail_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
describe('check if plugin setup ran', function() {
it('should have set protractor.__BASIC_PLUGIN_RAN', function() {
expect(protractor.__BASIC_PLUGIN_RAN).toBe(true);
});

it('should run multiple tests which fail', function() {
expect(true).toBe(false);
});
});
39 changes: 39 additions & 0 deletions spec/plugins/failing_plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
var q = require('q');

var failingResult = function(message) {
return {
failedCount: 1,
specResults: [{
description: 'plugin test which fails',
assertions: [{
passed: false,
errorMsg: message,
}],
duration: 4
}]
};
};

module.exports = {
setup: function() {
return q.delay(100).then(function() {
return failingResult('from setup');
});
},

teardown: function() {
return q.delay(100).then(function() {
return failingResult('from teardown');
});
},

postResults: function() {
// This function should cause no failures.
},

postTest: function(config, passed) {
return q.delay(100).then(function() {
return failingResult('from postTest ' + (passed ? 'passing' : 'failing'));
});
}
};
38 changes: 30 additions & 8 deletions spec/plugins/test_plugin.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
var q = require('q');

var passingResult = {
failedCount: 0,
specResults: [{
description: 'plugin test which passes',
assertions: [],
duration: 4
}]
};

module.exports = {
setup: function() {
return q.delay(100).then(function() {
return passingResult;
});
},

teardown: function() {
return {
failedCount: 0,
specResults: [{
description: 'This succeeds',
assertions: [],
duration: 1
}]
};
return q.delay(100).then(function() {
return passingResult;
});
},

postResults: function() {
// This function should cause no failures.
},

postTest: function() {
return q.delay(100).then(function() {
return passingResult;
});
}
};
2 changes: 1 addition & 1 deletion spec/pluginsBasicConf.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var env = require('./environment.js');
// A small suite to make sure the basic functionality of plugins work
// Tests the (potential) edge case of exactly one plugin being used
exports.config = {
seleniumAddress: env.seleniumAddress,
mockSelenium: true,

framework: 'jasmine2',

Expand Down
3 changes: 2 additions & 1 deletion spec/pluginsFullConf.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ var env = require('./environment.js');

// A small suite to make sure the full functionality of plugins work
exports.config = {
seleniumAddress: env.seleniumAddress,
// seleniumAddress: env.seleniumAddress,
mockSelenium: true,

framework: 'jasmine2',

Expand Down