Skip to content

Commit

Permalink
feat(runner): add beta support for using mocha as your test framework
Browse files Browse the repository at this point in the history
This change adds limited support for using mocha as the test framework instead
of jasmine. Make the switch by using `--framework=mocha` on the command line
or adding `framework: 'mocha'` to the config. Tests will be run using the
BDD interface. The interface is adapted so that tests run asynchronously
without needing to call `done()`.

Note that there is currently no support for an assertion framework, so you will
need to require whichever assertion framework you prefer. This means there
is no adapter to make the assertions unwrap promises, so you will need to
resolve promises yourself and run the assertions afterwards.
  • Loading branch information
juliemr committed Dec 27, 2013
1 parent 8d7c948 commit 478c00a
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 79 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -31,7 +31,7 @@ The Protractor runner is a binary which accepts a config file. Install protracto
# Run the line below to see command line options
protractor

You will need a *configuration file* containing setup info and *test files* containing the actual test scripts. The config file specifies how the runner should start webdriver, where your test files are, and global setup options. The test files use Jasmine framework, but other adapters may be added in the future.
You will need a *configuration file* containing setup info and *test files* containing the actual test scripts. The config file specifies how the runner should start webdriver, where your test files are, and global setup options. The test files use Jasmine framework by default (Mocha is supported in beta).

Create a configuration file - an example with detailed comments is shown in `node_modules/protractor/referenceConf.js`. Edit the configuration file to point to your test files.

Expand Down
35 changes: 35 additions & 0 deletions example/mocha/example_spec.js
@@ -0,0 +1,35 @@
/**
* This example shows how to use the protractor library in a Mocha test.
*
* Run this test with:
* protractor example/mocha/mochaConf.js
*/

// Note that there is nothing adapting expect.js to understand promises,
// so we may only use it once promises have been resolved.
var expect = require('expect.js');

describe('angularjs.org homepage', function() {
this.timeout(80000);

it('should greet using binding', function() {
browser.get('http://www.angularjs.org');

element(by.input('yourName')).sendKeys('Julie');

element(by.binding('{{yourName}}')).
getText().then(function(text) {
expect(text).to.eql('Hello Julie!');
});
});

it('should list todos', function() {
browser.get('http://www.angularjs.org');

var todo = element(by.repeater('todo in todos').row(1));

todo.getText().then(function(text) {
expect(text).to.eql('build an angular app');
});
});
});
17 changes: 17 additions & 0 deletions example/mocha/mochaConf.js
@@ -0,0 +1,17 @@
// An example configuration file.
exports.config = {
// Do not start a Selenium Standalone sever - only run this using chrome.
chromeOnly: true,
chromeDriver: '../../selenium/chromedriver',

framework: 'mocha',

// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},

// Spec patterns are relative to the current working directly when
// protractor is called.
specs: ['example_spec.js'],
};
69 changes: 0 additions & 69 deletions example/mocha/onMocha.js

This file was deleted.

1 change: 1 addition & 0 deletions lib/cli.js
Expand Up @@ -24,6 +24,7 @@ var argv = require('optimist').
describe('verbose', 'Print full spec names').
describe('stackTrace', 'Print stack trace on error').
describe('params', 'Param object to be passed to the tests').
describe('framework', 'Test framework to use. jasmine or mocha.').
alias('browser', 'capabilities.browserName').
alias('name', 'capabilities.name').
alias('platform', 'capabilities.platform').
Expand Down
69 changes: 62 additions & 7 deletions lib/runner.js
Expand Up @@ -4,11 +4,9 @@ var fs = require('fs');
var webdriver = require('selenium-webdriver');
var remote = require('selenium-webdriver/remote');
var chrome = require('selenium-webdriver/chrome');
var minijn = require('minijasminenode');
var protractor = require('./protractor.js');
var SauceLabs = require('saucelabs');
var glob = require('glob');
require('../jasminewd')

var server;
var driver;
Expand All @@ -28,6 +26,7 @@ var config = {
},
rootElement: 'body',
params: {},
framework: 'jasmine',
jasmineNodeOpts: {
isVerbose: false,
showColors: true,
Expand Down Expand Up @@ -210,7 +209,7 @@ var setUpSelenium = function() {
* @return {webdriver.promise.Promise} A promise that will resolve
* when the test run is finished.
*/
var runJasmineTests = function() {
var runTests = function() {
if (config.jasmineNodeOpts.specFolders) {
throw new Error('Using config.jasmineNodeOpts.specFolders is deprecated ' +
'since Protractor 0.6.0. Please switch to config.specs.');
Expand All @@ -233,7 +232,6 @@ var runJasmineTests = function() {
throw new Error('Spec patterns did not match any files.');
}

minijn.addSpecs(resolvedSpecs);
// TODO: This should not be tied to the webdriver promise loop, it should use
// another promise system instead.
var runDeferred = webdriver.promise.defer();
Expand Down Expand Up @@ -269,6 +267,45 @@ var runJasmineTests = function() {
global.element = browser.element;
global.by = protractor.By;

// Do the framework setup here so that jasmine and mocha globals are
// available to the onPrepare function.
var minijn, mocha;
if (config.framework == 'jasmine') {
minijn = require('minijasminenode');
require('../jasminewd');
minijn.addSpecs(resolvedSpecs);
} else if (config.framework == 'mocha') {
var Mocha = require('mocha');

mocha = new Mocha({
ui: 'bdd',
reporter: 'list'
});

resolvedSpecs.forEach(function(file) {
mocha.addFile(file);
});

// Mocha doesn't set up the ui until the pre-require event, so
// wait until then to load mocha-webdriver adapters as well.
mocha.suite.on('pre-require', function() {
var mochaAdapters = require('selenium-webdriver/testing');
global.after = mochaAdapters.after;
global.afterEach = mochaAdapters.afterEach;
global.before = mochaAdapters.before;
global.beforeEach = mochaAdapters.beforeEach;

global.it = mochaAdapters.it;
global.it.only = global.iit = mochaAdapters.it.only;
global.it.skip = global.xit = mochaAdapters.xit;
});

mocha.loadFiles();
} else {
throw 'config.framework ' + config.framework +
' is not a valid framework.';
}

// Let the configuration configure the protractor instance before running
// the tests.
webdriver.promise.controlFlow().execute(function() {
Expand All @@ -293,7 +330,25 @@ var runJasmineTests = function() {
});
};

minijn.executeSpecs(options);
if (config.framework == 'jasmine') {
minijn.executeSpecs(options);
} else if (config.framework == 'mocha') {
mocha.run(function(failures) {
// Warning: hack to make it have the same signature as Jasmine 1.3.1.
if (originalOnComplete) {
originalOnComplete();
}
driver.quit().then(function() {
runDeferred.fulfill({
results: function() {
return {
failedCount: failures
};
}
});
});
});
}
});
});

Expand All @@ -306,11 +361,11 @@ var runJasmineTests = function() {
*/
var runOnce = function() {
return setUpSelenium().then(function() {
// cleanUp must be registered directly onto runJasmineTests, not onto
// cleanUp must be registered directly onto runTests, not onto
// the chained promise, so that cleanUp is still called in case of a
// timeout error. Timeout errors need to clear the control flow, which
// would mess up chaining promises.
return runJasmineTests().then(cleanUp);
return runTests().then(cleanUp);
});
};

Expand Down
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -22,7 +22,7 @@
"devDependencies": {
"expect.js": "~0.2.0",
"jasmine-node": "~1.9.0",
"mocha": "~1.10.0",
"mocha": "~1.16.0",
"express": "~3.3.4",
"mustache": "~0.7.2"
},
Expand All @@ -36,7 +36,7 @@
},
"main": "lib/protractor.js",
"scripts": {
"test": "node lib/cli.js spec/basicConf.js; node lib/cli.js spec/altRootConf.js; node lib/cli.js spec/onPrepareConf.js; node_modules/.bin/minijasminenode jasminewd/spec/adapterSpec.js"
"test": "node lib/cli.js spec/basicConf.js; node lib/cli.js spec/altRootConf.js; node lib/cli.js spec/onPrepareConf.js; node lib/cli.js spec/mochaConf.js; node_modules/.bin/minijasminenode jasminewd/spec/adapterSpec.js"
},
"license" : "MIT",
"version": "0.15.0",
Expand Down
7 changes: 7 additions & 0 deletions referenceConf.js
Expand Up @@ -98,6 +98,13 @@ exports.config = {
password: '1234'
}
},

// ----- The test framework -----
//
// Jasmine is fully supported as a test and assertion framework.
// Mocha has limited beta support. You will need to include your own
// assertion framework if working with mocha.
framework: 'jasmine',

// ----- Options to be passed to minijasminenode -----
//
Expand Down
24 changes: 24 additions & 0 deletions spec/mocha/lib_spec.js
@@ -0,0 +1,24 @@
var expect = require('expect.js');

describe('no protractor at all', function() {
it('should still do normal tests', function() {
expect(true).to.eql(true);
});
});

describe('protractor library', function() {
it('should expose the correct global variables', function() {
expect(protractor).not.to.be(undefined);
expect(browser).not.to.be(undefined);
expect(by).not.to.be(undefined);
expect(element).not.to.be(undefined);
expect($).not.to.be(undefined);
});

it('should wrap webdriver', function() {
browser.get('index.html');
browser.getTitle().then(function(text) {
expect(text).to.eql('My AngularJS App');
});
});
});
24 changes: 24 additions & 0 deletions spec/mochaConf.js
@@ -0,0 +1,24 @@
// A small suite to make sure the mocha frameowork works.
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',

framework: 'mocha',

// Spec patterns are relative to this directory.
specs: [
'mocha/*_spec.js'
],

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

baseUrl: 'http://localhost:8000',

params: {
login: {
user: 'Jane',
password: '1234'
}
}
};

0 comments on commit 478c00a

Please sign in to comment.