diff --git a/bin/start_selenium_standalone b/bin/start_selenium_standalone new file mode 100755 index 000000000..4cf5eac2b --- /dev/null +++ b/bin/start_selenium_standalone @@ -0,0 +1,3 @@ +#!/bin/bash +java -jar selenium/selenium-server-standalone-2.34.0.jar -Dwebdriver.chrome.driver=./selenium/chromedriver + diff --git a/mochachaiwd/bootstrap.js b/mochachaiwd/bootstrap.js new file mode 100644 index 000000000..01d868ed4 --- /dev/null +++ b/mochachaiwd/bootstrap.js @@ -0,0 +1,8 @@ +global.chai = require('chai'); +global.expect = chai.expect; + +var promiseTesting = require('promise-testing'); +global.promiseEngine = new promiseTesting(); +promiseEngine.scanChai(chai); + +require('./index.js'); \ No newline at end of file diff --git a/mochachaiwd/index.js b/mochachaiwd/index.js new file mode 100644 index 000000000..5eeddf4f3 --- /dev/null +++ b/mochachaiwd/index.js @@ -0,0 +1,102 @@ +/** + * Adapts Mocha tests to work better with WebDriverJS. Borrows + * heavily from the mocha WebDriverJS adapter at + * https://code.google.com/p/selenium/source/browse/javascript/node/selenium-webdriver/testing/index.js + */ + +var webdriver = require('selenium-webdriver'); + +var flow = webdriver.promise.controlFlow(); + +/** + * Wraps a function so that all passed arguments are ignored. + * @param {!Function} fn The function to wrap. + * @return {!Function} The wrapped function. + */ +function seal(fn) { + return function() { + fn(); + }; +}; + + +/** + * Wraps a function so it runs inside a webdriver.promise.ControlFlow and + * waits for the flow to complete before continuing. + * @param {!Function} globalFn The function to wrap. + * @return {!Function} The new function. + */ +function wrapInControlFlow(globalFn) { + return function() { + switch (arguments.length) { + case 1: + globalFn(asyncTestFn(arguments[0])); + break; + + case 2: + // The first variable is a description. + globalFn(arguments[0], asyncTestFn(arguments[1])); + break; + + default: + throw Error('Invalid # arguments: ' + arguments.length); + } + }; + + function asyncTestFn(fn) { + return function(done) { + var that = this; + flow.execute(function() { + fn.call(that); + }).then(seal(done), done); + }; + }; +}; + +global.it = wrapInControlFlow(global.it); +global.beforeEach = wrapInControlFlow(global.beforeEach); +global.afterEach = wrapInControlFlow(global.afterEach); +global.after = wrapInControlFlow(global.after); +global.before = wrapInControlFlow(global.before); + + + +/** + * Wrap a Jasmine matcher function so that it can take webdriverJS promises. + * @param {!Function} matcher The matcher function to wrap. + * @param {webdriver.promise.Promise} actualPromise The promise which will + * resolve to the actual value being tested. + */ +function wrapMatcher(matcher, actualPromise) { + return function(expected) { + actualPromise.then(function(actual) { + if (expected instanceof webdriver.promise.Promise) { + expected.then(function(exp) { + expect(actual)[matcher](exp); + }); + } else { + expect(actual)[matcher](expected); + } + }); + }; +}; + +/** + * Return a chained set of matcher functions which will be evaluated + * after actualPromise is resolved. + * @param {webdriver.promise.Promise} actualPromise The promise which will + * resolve to the acutal value being tested. + */ +function promiseMatchers(actualPromise) { + return promiseEngine.wrap(actualPromise).then.expect.result; +}; + +originalExpect = global.expect; + +global.expect = function(actual) { + if (actual instanceof webdriver.promise.Promise) { + return promiseMatchers(actual); + } else { + return originalExpect(actual); + } +}; diff --git a/mochachaiwd/onMocha.js b/mochachaiwd/onMocha.js new file mode 100644 index 000000000..1823c6765 --- /dev/null +++ b/mochachaiwd/onMocha.js @@ -0,0 +1,63 @@ +/** + * This example shows how to use the protractor library in a Mocha test. + * It assumes that a selenium server is running at localhost:4444. + * Run this test with: + * mocha onMocha.js + */ + +var util = require('util'); +var webdriver = require('selenium-webdriver'); +var protractor = require('../lib/protractor.js'); + +describe('angularjs.org homepage', function() { + this.timeout(80000); + + var driver, ptor; + + before(function() { + driver = new webdriver.Builder(). + usingServer('http://localhost:4444/wd/hub'). + withCapabilities(webdriver.Capabilities.chrome()).build(); + + driver.manage().timeouts().setScriptTimeout(10000); + ptor = protractor.wrapDriver(driver); + }); + + after(function(done) { + driver.quit().then(function() {done()}); + }) + + it('should greet using binding', function() { + ptor.get('http://www.angularjs.org'); + + ptor.findElement(protractor.By.input('yourName')).sendKeys('Julie'); + + var hello = ptor.findElement(protractor.By.binding('{{yourName}}')); + + expect(hello.getText()).to.eql('Hello Julie!'); + }); + + it('should list todos', function() { + ptor.get('http://www.angularjs.org'); + + var todo = ptor.findElement( + protractor.By.repeater('todo in todos').row(2)); + + expect(todo.getText()).to.eql('build an angular app'); + }); + + // Uncomment to see failures. + + // it('should greet using binding - this one fails', function(done) { + // ptor.get('http://www.angularjs.org'); + + // ptor.findElement(protractor.By.input("yourName")).sendKeys("Julie"); + + // ptor.findElement(protractor.By.binding("Hello {{yourName}}!")). + // getText().then(function(text) { + // expect(text).to.eql('Hello Jack'); + // done(); + // }); + // }); + +}); diff --git a/package.json b/package.json index 10412d153..9e3c1a3e9 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "expect.js": "~0.2.0", "jasmine-node": "~1.9.0", "mocha": "~1.10.0", - "express": "~3.3.4" + "express": "~3.3.4", + "chai": "~1.7.2", + "promise-testing": "0.0.1" }, "repository": { "type": "git", @@ -31,7 +33,8 @@ "bin": "bin/protractor", "main": "lib/protractor.js", "scripts": { - "test": "node lib/cli.js conf.js" + "test": "node lib/cli.js conf.js", + "testMocha": "node ./node_modules/.bin/mocha -r ./mochachaiwd/bootstrap.js ./mochachaiwd/onMocha.js" }, "version": "0.7.0" }