From 0b65292e4b52c527bbccd70e8d07da5c2dad4ed0 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sat, 12 Mar 2016 21:03:05 -0600 Subject: [PATCH 1/6] test: Update protractor to v3 and use mocha --- package.json | 2 +- protractor.conf.js | 42 ++++++++++++------------- tasks/gulp-tests.js | 9 +++--- test/.eslintrc | 1 + test/e2e/.eslintrc | 8 +---- test/e2e/e2e.js | 62 ------------------------------------- test/e2e/front-page.test.js | 62 +++++++++++++++++++++++++++++++++++++ 7 files changed, 91 insertions(+), 95 deletions(-) delete mode 100644 test/e2e/e2e.js create mode 100644 test/e2e/front-page.test.js diff --git a/package.json b/package.json index cf42cba0e3..e3f368752c 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "mongodb": "^2.0.46", "mongoskin": "~0.6.1", "phantomjs": "^1.9", - "protractor": "~2.5.1", + "protractor": "^3.1.1", "rewire": "^2.3.3", "rimraf": "^2.4.3", "run-sequence": "^1.1.4", diff --git a/protractor.conf.js b/protractor.conf.js index 0f810a8915..41f2a699cc 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -1,26 +1,26 @@ -// An example configuration file. +'use strict' + +require('babel-register'); +require('babel-polyfill'); + exports.config = { - // The address of a running selenium server. + specs: 'test/e2e/**/*.js', + baseUrl: 'http://localhost:3003/', + directConnect: true, seleniumAddress: 'http://localhost:4444/wd/hub', - - // Capabilities to be passed to the webdriver instance. - capabilities: { - 'browserName': 'firefox' + framework: 'mocha', + mochaOpts: { + reporter: 'spec', + slow: 6000, + timeout: 10000, + compilers: 'js:babel-register' }, + onPrepare: () => { + browser.ignoreSynchronization = true; + let chai = require('chai'); + let chaiAsPromised = require('chai-as-promised'); - // Spec patterns are relative to the current working directly when - // protractor is called. - specs: ['test/e2e/e2e.js'], - - // A base URL for your application under test. Calls to protractor.get() - // with relative paths will be prepended with this. - baseUrl: 'http://localhost:3003', - - // Options to be passed to Jasmine-node. - jasmineNodeOpts: { - showColors: true, - defaultTimeoutInterval: 90000, - isVerbose: true, - displayPendingSpec: true - } + chai.use(chaiAsPromised); + global.expect = chai.expect; + }, }; diff --git a/tasks/gulp-tests.js b/tasks/gulp-tests.js index e505b92d9c..9922522fd4 100644 --- a/tasks/gulp-tests.js +++ b/tasks/gulp-tests.js @@ -297,11 +297,12 @@ gulp.task('test:e2e:safe', ['test:prepare', 'test:prepare:server'], (cb) => { * Note: As it stands, protractor wont report pending specs */ let match = stdout.match(/(\d+) tests?.*(\d) failures?/); + testResults.push({ - suite: 'End-to-End Specs', - pass: parseInt(match[1]) - parseInt(match[2]), - fail: parseInt(match[2]), - pend: 0 + suite: 'End-to-End Specs\t', + pass: testCount(stdout, /(\d+) passing/), + fail: testCount(stdout, /(\d+) failing/), + pend: testCount(stdout, /(\d+) pending/) }); support.forEach(kill); cb(); diff --git a/test/.eslintrc b/test/.eslintrc index 7b5868eca9..9ee7ce9e28 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -1,6 +1,7 @@ { "rules": { "one-var": 0, + "func-names": 0, "max-nested-callbacks": 0, "no-unused-expressions": 0, "mocha/no-exclusive-tests": 2, diff --git a/test/e2e/.eslintrc b/test/e2e/.eslintrc index ecf3d02e9f..252188793a 100644 --- a/test/e2e/.eslintrc +++ b/test/e2e/.eslintrc @@ -1,13 +1,7 @@ { - "rules": { - "func-names": 0, - "no-var": 0, - "prefer-template": 0 - }, "globals": { "browser": true, "by": true, - "element": true, - "jasmine": true + "element": true } } diff --git a/test/e2e/e2e.js b/test/e2e/e2e.js deleted file mode 100644 index 90a3a742f3..0000000000 --- a/test/e2e/e2e.js +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; - -var fs = require('fs'); - -describe('front page', function () { - beforeEach(function () { - browser.ignoreSynchronization = true; - browser.get('/'); - browser.sleep(1000); - }); - - // based on https://github.com/angular/protractor/issues/114#issuecomment-29046939 - afterEach(function () { - var currentSpec = jasmine.getEnv().currentSpec; - var passed = currentSpec.results().passed(); - if (!passed) { - var filename = 'exception_' + currentSpec.description + '.png'; - browser.takeScreenshot().then(function (png) { - var buffer = new Buffer(png, 'base64'); - var stream = fs.createWriteStream(filename); - stream.write(buffer); - stream.end(); - }); - } - }); - - it('shows the front page', function () { - var button = element(by.id('play-btn')); - expect(button.getText()).toEqual('Join for free'); - }); - - it('does not login when using wrong credentials', function () { - var button = element(by.id('play-btn')); - button.click(); - browser.sleep(1000); - element(by.model('loginUsername')).sendKeys('username'); - element(by.model('loginPassword')).sendKeys('pass'); - var login = element(by.css('#loginForm input[value="Login"]')); - login.click(); - var alertDialog = browser.switchTo().alert(); - expect(alertDialog.getText()).toMatch('Uh-oh - your username or password is incorrect.\n- Make sure your username or email is typed correctly.\n- You may have signed up with Facebook, not email. Double-check by trying Facebook login.\n- If you forgot your password, click "Forgot Password" on the habitica.com website\'s login form.'); - alertDialog.accept(); - }); - - xit('registers a new user', function () { - var button = element(by.id('play-btn')); - button.click(); - browser.sleep(1000); - var registerTab = element(by.linkText('Register')); - registerTab.click(); - element(by.model('registerVals.username')).sendKeys('user'); - element(by.model('registerVals.email')).sendKeys('user@example.com'); - element(by.model('registerVals.password')).sendKeys('pass'); - element(by.model('registerVals.confirmPassword')).sendKeys('pass'); - var register = element(by.css('#registrationForm input[value="Register"]')); - register.click(); - browser.sleep(1000); - browser.getCurrentUrl().then(function (url) { - expect(url).not.toMatch(/static\/front/); - }); - }); -}); diff --git a/test/e2e/front-page.test.js b/test/e2e/front-page.test.js new file mode 100644 index 0000000000..d0504259fe --- /dev/null +++ b/test/e2e/front-page.test.js @@ -0,0 +1,62 @@ +import fs from 'fs'; + +describe('Static Front Page', () => { + beforeEach(() => { + browser.get('/'); + browser.sleep(1000); + }); + + // based on https://github.com/angular/protractor/issues/114#issuecomment-29046939 + afterEach(async function () { + let lastTest = this.currentTest; + + if (lastTest.state === 'failed') { + let filename = `exception_${lastTest.title}.png`; + let png = await browser.takeScreenshot(); + let buffer = new Buffer(png, 'base64'); + let stream = fs.createWriteStream(filename); + + stream.write(buffer); + stream.end(); + } + }); + + it('shows the front page', async () => { + let button = element(by.id('play-btn')); + await expect(button.getText()).to.eventually.eql('Join for free'); + }); + + it('does not login when using wrong credentials', async () => { + let button = element(by.id('play-btn')); + button.click(); + browser.sleep(1000); + element(by.model('loginUsername')).sendKeys('username'); + element(by.model('loginPassword')).sendKeys('pass'); + let login = element(by.css('#loginForm input[value="Login"]')); + login.click(); + browser.sleep(1000); + let alertDialog = browser.switchTo().alert(); + + await expect(alertDialog.getText()).to.eventually.match(/username or password is incorrect./); + + alertDialog.accept(); + }); + + xit('registers a new user', function () { + let button = element(by.id('play-btn')); + button.click(); + browser.sleep(1000); + let registerTab = element(by.linkText('Register')); + registerTab.click(); + element(by.model('registerVals.username')).sendKeys('user'); + element(by.model('registerVals.email')).sendKeys('user@example.com'); + element(by.model('registerVals.password')).sendKeys('pass'); + element(by.model('registerVals.confirmPassword')).sendKeys('pass'); + let register = element(by.css('#registrationForm input[value="Register"]')); + register.click(); + browser.sleep(1000); + browser.getCurrentUrl().then(function (url) { + expect(url).not.toMatch(/static\/front/); + }); + }); +}); From 17d2efb822b89c596fff92926f2c48969549881d Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 13 Mar 2016 16:41:17 -0500 Subject: [PATCH 2/6] refactor: Organize protractor setup --- package.json | 2 +- tasks/gulp-tests.js | 6 ------ test/e2e/helper.js | 17 +++++++++++++++++ .../e2e/protractor.conf.js | 11 ++++++----- test/e2e/{ => static-pages}/front-page.test.js | 17 ----------------- 5 files changed, 24 insertions(+), 29 deletions(-) create mode 100644 test/e2e/helper.js rename protractor.conf.js => test/e2e/protractor.conf.js (70%) rename test/e2e/{ => static-pages}/front-page.test.js (76%) diff --git a/package.json b/package.json index e3f368752c..2cb617e733 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "test:karma:watch": "karma start", "test:prepare:webdriver": "webdriver-manager update", "test:e2e:webdriver": "webdriver-manager start", - "test:e2e": "protractor protractor.conf.js", + "test:e2e": "protractor test/e2e/protractor.conf.js", "test:nodemon": "gulp test:nodemon", "start": "gulp run:dev", "sprites": "gulp sprites:compile", diff --git a/tasks/gulp-tests.js b/tasks/gulp-tests.js index 9922522fd4..bada857d36 100644 --- a/tasks/gulp-tests.js +++ b/tasks/gulp-tests.js @@ -269,9 +269,6 @@ gulp.task('test:e2e', ['test:prepare', 'test:prepare:server'], (cb) => { let runner = exec( 'npm run test:e2e', (err, stdout, stderr) => { - /* - * Note: As it stands, protractor wont report pending specs - */ support.forEach(kill); cb(err); } @@ -293,9 +290,6 @@ gulp.task('test:e2e:safe', ['test:prepare', 'test:prepare:server'], (cb) => { let runner = exec( 'npm run test:e2e', (err, stdout, stderr) => { - /* - * Note: As it stands, protractor wont report pending specs - */ let match = stdout.match(/(\d+) tests?.*(\d) failures?/); testResults.push({ diff --git a/test/e2e/helper.js b/test/e2e/helper.js new file mode 100644 index 0000000000..0f0a9cf44a --- /dev/null +++ b/test/e2e/helper.js @@ -0,0 +1,17 @@ +import fs from 'fs'; + +// based on https://github.com/angular/protractor/issues/114#issuecomment-29046939 +afterEach(async function () { + let lastTest = this.currentTest; + + if (lastTest.state === 'failed') { + let filename = `exception_${lastTest.title}.png`; + let png = await browser.takeScreenshot(); + let buffer = new Buffer(png, 'base64'); + let stream = fs.createWriteStream(filename); + + stream.write(buffer); + stream.end(); + } +}); + diff --git a/protractor.conf.js b/test/e2e/protractor.conf.js similarity index 70% rename from protractor.conf.js rename to test/e2e/protractor.conf.js index 41f2a699cc..630733c4f2 100644 --- a/protractor.conf.js +++ b/test/e2e/protractor.conf.js @@ -1,10 +1,13 @@ -'use strict' +'use strict'; + +let chai = require('chai'); +let chaiAsPromised = require('chai-as-promised'); require('babel-register'); require('babel-polyfill'); exports.config = { - specs: 'test/e2e/**/*.js', + specs: ['./helper.js', './**/*.test.js'], baseUrl: 'http://localhost:3003/', directConnect: true, seleniumAddress: 'http://localhost:4444/wd/hub', @@ -13,12 +16,10 @@ exports.config = { reporter: 'spec', slow: 6000, timeout: 10000, - compilers: 'js:babel-register' + compilers: 'js:babel-register', }, onPrepare: () => { browser.ignoreSynchronization = true; - let chai = require('chai'); - let chaiAsPromised = require('chai-as-promised'); chai.use(chaiAsPromised); global.expect = chai.expect; diff --git a/test/e2e/front-page.test.js b/test/e2e/static-pages/front-page.test.js similarity index 76% rename from test/e2e/front-page.test.js rename to test/e2e/static-pages/front-page.test.js index d0504259fe..9d107389f6 100644 --- a/test/e2e/front-page.test.js +++ b/test/e2e/static-pages/front-page.test.js @@ -1,26 +1,9 @@ -import fs from 'fs'; - describe('Static Front Page', () => { beforeEach(() => { browser.get('/'); browser.sleep(1000); }); - // based on https://github.com/angular/protractor/issues/114#issuecomment-29046939 - afterEach(async function () { - let lastTest = this.currentTest; - - if (lastTest.state === 'failed') { - let filename = `exception_${lastTest.title}.png`; - let png = await browser.takeScreenshot(); - let buffer = new Buffer(png, 'base64'); - let stream = fs.createWriteStream(filename); - - stream.write(buffer); - stream.end(); - } - }); - it('shows the front page', async () => { let button = element(by.id('play-btn')); await expect(button.getText()).to.eventually.eql('Join for free'); From 88ef920a2fa4526066c7298ec7beb75b1174bf5a Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 13 Mar 2016 21:05:06 -0500 Subject: [PATCH 3/6] fix: Update travis yaml to run protractor 3 --- test/e2e/protractor.conf.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/e2e/protractor.conf.js b/test/e2e/protractor.conf.js index 630733c4f2..4aea36e0dc 100644 --- a/test/e2e/protractor.conf.js +++ b/test/e2e/protractor.conf.js @@ -9,6 +9,9 @@ require('babel-polyfill'); exports.config = { specs: ['./helper.js', './**/*.test.js'], baseUrl: 'http://localhost:3003/', + capabilities: { + browserName: 'firefox', + }, directConnect: true, seleniumAddress: 'http://localhost:4444/wd/hub', framework: 'mocha', From 3ffb84d890a8ca89a5c405e854178853f16e03ea Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 13 Mar 2016 21:56:12 -0500 Subject: [PATCH 4/6] test: Reset db before running e2e tests --- test/e2e/helper.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/e2e/helper.js b/test/e2e/helper.js index 0f0a9cf44a..6d9fd7cab0 100644 --- a/test/e2e/helper.js +++ b/test/e2e/helper.js @@ -1,4 +1,9 @@ import fs from 'fs'; +import { resetHabiticaDB } from '../helpers/api-integration/mongo'; + +before(async () => { + await resetHabiticaDB(); +}) // based on https://github.com/angular/protractor/issues/114#issuecomment-29046939 afterEach(async function () { From 6ce0893edca73e6a2fb792d62868de0ba226dcfe Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 13 Mar 2016 21:56:42 -0500 Subject: [PATCH 5/6] test: unpend registration test --- test/e2e/static-pages/front-page.test.js | 37 ++++++++++++++++++------ 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/test/e2e/static-pages/front-page.test.js b/test/e2e/static-pages/front-page.test.js index 9d107389f6..9f1475d455 100644 --- a/test/e2e/static-pages/front-page.test.js +++ b/test/e2e/static-pages/front-page.test.js @@ -1,3 +1,5 @@ +import { v4 as generateUniqueId } from 'uuid'; + describe('Static Front Page', () => { beforeEach(() => { browser.get('/'); @@ -6,18 +8,25 @@ describe('Static Front Page', () => { it('shows the front page', async () => { let button = element(by.id('play-btn')); + await expect(button.getText()).to.eventually.eql('Join for free'); }); it('does not login when using wrong credentials', async () => { let button = element(by.id('play-btn')); + let randomName = generateUniqueId(); + button.click(); browser.sleep(1000); - element(by.model('loginUsername')).sendKeys('username'); + + element(by.model('loginUsername')).sendKeys(randomName); element(by.model('loginPassword')).sendKeys('pass'); + let login = element(by.css('#loginForm input[value="Login"]')); + login.click(); browser.sleep(1000); + let alertDialog = browser.switchTo().alert(); await expect(alertDialog.getText()).to.eventually.match(/username or password is incorrect./); @@ -25,21 +34,31 @@ describe('Static Front Page', () => { alertDialog.accept(); }); - xit('registers a new user', function () { + it('registers a new user', async function () { + this.timeout(30000); // TODO: Speed up registration action. Takes way too long and times out unless you extend the timeout + let button = element(by.id('play-btn')); + let randomName = generateUniqueId(); + button.click(); browser.sleep(1000); + let registerTab = element(by.linkText('Register')); registerTab.click(); - element(by.model('registerVals.username')).sendKeys('user'); - element(by.model('registerVals.email')).sendKeys('user@example.com'); + element(by.model('registerVals.username')).sendKeys(randomName); + element(by.model('registerVals.email')).sendKeys(`${randomName}@example.com`); element(by.model('registerVals.password')).sendKeys('pass'); element(by.model('registerVals.confirmPassword')).sendKeys('pass'); - let register = element(by.css('#registrationForm input[value="Register"]')); + + let register = element(by.css('#registrationForm input[type="submit"]')); + register.click(); - browser.sleep(1000); - browser.getCurrentUrl().then(function (url) { - expect(url).not.toMatch(/static\/front/); - }); + browser.sleep(3000); + + let url = await browser.getCurrentUrl(); + + expect(url).to.not.match(/static\/front/); }); + + it('logs in an existing user'); }); From 278b972c61d2fa26ee9127e701dab806a48d4d1c Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Sun, 13 Mar 2016 22:06:09 -0500 Subject: [PATCH 6/6] lint: Add missing semicolon to test helper --- test/e2e/helper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/helper.js b/test/e2e/helper.js index 6d9fd7cab0..dda430085c 100644 --- a/test/e2e/helper.js +++ b/test/e2e/helper.js @@ -3,7 +3,7 @@ import { resetHabiticaDB } from '../helpers/api-integration/mongo'; before(async () => { await resetHabiticaDB(); -}) +}); // based on https://github.com/angular/protractor/issues/114#issuecomment-29046939 afterEach(async function () {