diff --git a/.babelrc b/.babelrc index 9224ca318..eafcfa0d6 100644 --- a/.babelrc +++ b/.babelrc @@ -7,11 +7,6 @@ "transform-react-display-name" ], "env": { - "test": { - "plugins": [ - "rewire" - ] - }, "development": { "plugins": [ "typecheck" diff --git a/.eslintrc b/.eslintrc index a8d2f2fb3..a277bf4a8 100644 --- a/.eslintrc +++ b/.eslintrc @@ -50,6 +50,8 @@ "webpackIsomorphicTools": true, ga: true, Raven: true, - mixpanel: true + mixpanel: true, + "expect": true, + "browser": true } } diff --git a/nightwatch.js b/nightwatch.js deleted file mode 100644 index eddf548a7..000000000 --- a/nightwatch.js +++ /dev/null @@ -1,11 +0,0 @@ -require('dotenv').load(); -require('app-module-path').addPath(__dirname); -require('app-module-path').addPath('./src/scripts'); - -require("babel-register"); - -global.__CLIENT__ = false; -global.__SERVER__ = true; - - -require('nightwatch/bin/runner.js'); diff --git a/nightwatch.json b/nightwatch.json deleted file mode 100644 index 09b59063f..000000000 --- a/nightwatch.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "src_folders": ["tests/functional/specs"], - "output_folder": "tests/functional/output", - "custom_commands_path": "tests/functional/commands", - "custom_assertions_path": "tests/functional/assertions", - "page_objects_path": "tests/functional/pages", - "globals_path": "tests/functional/globals.js", - "selenium" : { - "start_process" : true, - "server_path" : "node_modules/selenium-server/lib/runner/selenium-server-standalone-2.52.0.jar", - "log_path" : "", - "host" : "127.0.0.1", - "port" : 5555, - "cli_args" : { - "webdriver.chrome.driver" : "node_modules/chromedriver/lib/chromedriver/chromedriver" - } - }, - "test_settings" : { - "default" : { - "exclude": ["./pages", "./commands"], - "filter": "*.spec.js", - "launch_url" : "http://localhost", - "selenium_port" : 5555, - "selenium_host" : "localhost", - "silent": true, - "screenshots" : { - "enabled" : true, - "path" : "tests/functional/screenshots" - }, - "desiredCapabilities": { - "browserName": "chrome", - "javascriptEnabled": true, - "acceptSslCerts": true - } - }, - "production" : { - "exclude": ["./pages", "./commands"], - "filter": "*.spec.js", - "launch_url" : "http://localhost", - "selenium_port" : 5555, - "selenium_host" : "localhost", - "silent": true, - "screenshots" : { - "enabled" : true, - "path" : "tests/functional/screenshots" - }, - "desiredCapabilities": { - "browserName" : "phantomjs", - "javascriptEnabled" : true, - "acceptSslCerts" : true, - "phantomjs.binary.path" : "/usr/local/phantomjs/bin/phantomjs" - } - }, - "mobile": { - "exclude": ["./pages", "./commands"], - "filter": "**/*.spec.js", - "launch_url" : "http://localhost", - "selenium_port" : 5555, - "selenium_host" : "localhost", - "silent": true, - "screenshots" : { - "enabled" : true, - "path" : "tests/functional/screenshots" - }, - "desiredCapabilities": { - "browserName": "chrome", - "javascriptEnabled": true, - "acceptSslCerts": true, - "chromeOptions": { - "args": [ - "--user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_2 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A4449d Safari/9537.53", - "--window-size=320,568" - ] - } - } - } - } -} diff --git a/package.json b/package.json index e9c50dd77..120cdff41 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,15 @@ "private": false, "scripts": { "test": "npm run test:dev:unit", + "test:ci:unit": "./node_modules/karma/bin/karma start --browsers PhantomJS --single-run; npm run test:ci:lint", + "test:ci:functional": "BROWSER=phantomjs bash tests/functional/test.sh start-ci", + "posttest:ci:functional": "bash tests/functional/test.sh stop", "test:ci:unit": "karma start --browsers PhantomJS --single-run; npm run test:ci:lint", - "test:ci:functional": "node ./nightwatch.js -c ./nightwatch.json -e production", "test:dev:unit": "karma start", - "test:dev:functional": "node ./nightwatch.js -c ./nightwatch.json", "test:ci:lint": "eslint ./src/**/*.js", + "test:dev:unit": "./node_modules/karma/bin/karma start", + "test:dev:functional": "BROWSER=chrome bash tests/functional/test.sh start", + "posttest:dev:functional": "bash tests/functional/test.sh stop", "test:dev:lint": "eslint ./src/scripts/**/*.js", "test:stylelint": "stylelint './src/**/*.scss' --config webpack/.stylelintrc", "dev": "node webpack/dev-server.js & PORT=8000 node start.js", @@ -135,9 +139,9 @@ "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^1.6.0", "mocha": "^2.2.5", - "nightwatch": "^0.8.6", "nodemon": "^1.7.1", "path": "^0.11.14", + "phantomjs": "^1.9.20", "phantomjs-polyfill": "0.0.1", "piping": "^0.3.0", "pre-commit": "^1.1.3", @@ -152,6 +156,9 @@ "sinon": "^1.15.3", "sinon-chai": "^2.8.0", "stylelint-webpack-plugin": "^0.2.0", + "wdio-mocha-framework": "^0.3.7", + "wdio-spec-reporter": "0.0.3", + "webdriverio": "4.2.1", "webpack-dev-server": "^1.6.5" }, "pre-commit": [ diff --git a/tests/functional/assertions/default.js b/tests/functional/assertions/default.js deleted file mode 100644 index f053ebf79..000000000 --- a/tests/functional/assertions/default.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {}; diff --git a/tests/functional/commands/default.js b/tests/functional/commands/default.js deleted file mode 100644 index f053ebf79..000000000 --- a/tests/functional/commands/default.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {}; diff --git a/tests/functional/pageobjects/BasePage.js b/tests/functional/pageobjects/BasePage.js new file mode 100644 index 000000000..788b2c0d0 --- /dev/null +++ b/tests/functional/pageobjects/BasePage.js @@ -0,0 +1,16 @@ +export default class BasePage { + constructor(selectors) { + this.selectors = Object.assign(selectors, { + SURAH_PAGE_SURAH_NAME: '.surah-body .navbar-text.surah-name' + }); + } + + getSurahName() { + return browser.getText(this.selectors.SURAH_PAGE_SURAH_NAME); + } + + goHome() { + browser.url('http://quran.com'); + } + +}; diff --git a/tests/functional/pageobjects/HomePage.js b/tests/functional/pageobjects/HomePage.js new file mode 100644 index 000000000..f0d282122 --- /dev/null +++ b/tests/functional/pageobjects/HomePage.js @@ -0,0 +1,33 @@ +import BasePage from './BasePage'; +import selectors from './selectors'; + +export default class HomePage extends BasePage { + constructor() { + super(selectors); + this.selectors = selectors; + } + + getLandingText() { + const landingText = browser.getText(this.selectors.LANDING_TEXT); + return landingText; + } + + getNumberOfSurahs() { + const surahs = browser.elements(this.selectors.SURAH_LIST); + return surahs.value.length; + } + + searchForSurahAndGoToSurahPage(searchQuery) { + browser.setValue(this.selectors.SEARCH_FORM, searchQuery); + browser.waitForVisible(this.selectors.SEARCH_RESULT_LIST); + browser.click(this.selectors.SEARCH_RESULT_LIST); + return this.getSurahName(); + } + + clickOntheSurahByNumber(number) { + const surahs = browser.elements('.row .col-xs-7 span'); + const surahID = surahs.value[number].ELEMENT; + browser.elementIdClick(surahID); + return browser.getUrl(); + } +} diff --git a/tests/functional/pageobjects/selectors.js b/tests/functional/pageobjects/selectors.js new file mode 100644 index 000000000..1a8d66fb8 --- /dev/null +++ b/tests/functional/pageobjects/selectors.js @@ -0,0 +1,10 @@ +export default { + LANDING_TEXT: 'h4.title', + NEXT: 'a[data-direction="next"]', + PREVIOUS: 'a[data-direction="previous"]', + SURAH_LIST: '.row .col-md-4 li', + SEARCH_FORM: '.searchinput input', + SEARCH_RESULT_LIST: '.searchinput a', + SURAH_PAGE: '.surah-body .surah-title', + SURAH_NAME: '.navbar-text.surah-name' +}; diff --git a/tests/functional/pages/index.js b/tests/functional/pages/index.js deleted file mode 100644 index 498efda57..000000000 --- a/tests/functional/pages/index.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - url: 'http://localhost:8000', - elements: { - surahList: { - selector: '.surah-list', - }, - searchInput: { - selector: '.searchinput' - }, - indexHeader: { - selector: '.index-header' - }, - firstSurah: { - selector: '.surah-list a[href="/1"]' - }, - lastSurah: { - selector: '.surah-list a[href="/114"]' - } - } -}; diff --git a/tests/functional/specs/HomePageTests.js b/tests/functional/specs/HomePageTests.js new file mode 100644 index 000000000..e860bde0b --- /dev/null +++ b/tests/functional/specs/HomePageTests.js @@ -0,0 +1,27 @@ +import Homepage from '../pageobjects/HomePage'; +const homePage = new Homepage(browser); + +describe('Home Page', () => { + + it('Should Have English Heading', () => { + homePage.goHome(); + const text = homePage.getLandingText(); + expect(text).to.equal('THE NOBLE QUR\'AN'); + }); + + it('Should have 114 surahs', () => { + const numberSurahs = homePage.getNumberOfSurahs(); + expect(numberSurahs).to.equal(114); + }); + + it('Should search for surah, click the first result item and land on the surah page', () => { + const surahName = homePage.searchForSurahAndGoToSurahPage('ya-sin'); + expect(surahName).to.equal('YA-SIN (YA SIN) - سورة يس'); + }); + + it('Should click a surah from the list of surahs and land on the surah page', () => { + homePage.goHome(); + const url = homePage.clickOntheSurahByNumber(1); + expect(url).to.contain('/1'); + }); +}); diff --git a/tests/functional/specs/Index.spec.js b/tests/functional/specs/Index.spec.js deleted file mode 100644 index 29bec56a8..000000000 --- a/tests/functional/specs/Index.spec.js +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = { - 'can view index page': function(client) { - var index = client.page.index(); - - index.navigate() - .waitForElementVisible('body', 2000) - .assert.title("The Noble Qur'an - القرآن الكريم"); - - index.expect.element('@indexHeader').to.be.present; - index.expect.element('@surahList').to.be.present; - index.expect.element('@indexHeader').to.be.present; - - client.end(); - }, - - 'can view surah list': function(client) { - var index = client.page.index(); - - index.navigate(); - - index.expect.element('@surahList').to.be.present; - index.expect.element('@firstSurah').to.be.present; - index.expect.element('@lastSurah').to.be.present; - - index.expect.element('@firstSurah').text.to.contain('The Opener'); - index.expect.element('@firstSurah').text.to.contain('Al-Fatihah'); - index.expect.element('@lastSurah').text.to.contain('The Mankind'); - index.expect.element('@lastSurah').text.to.contain('An-Nas'); - - client.end(); - } -} diff --git a/tests/functional/test.sh b/tests/functional/test.sh new file mode 100755 index 000000000..16b55a933 --- /dev/null +++ b/tests/functional/test.sh @@ -0,0 +1,26 @@ + +#!/bin/bash +if [ "$1" == 'stop' ]; then + echo "Stopping selenium server..." + pid=`ps -eo pid,args | grep selenium-server-standalone | grep -v grep | cut -c1-6` + echo $pid + kill $pid +elif [ "$1" == 'start' ]; then + echo "Starting selenium server..." + PATH="./node_modules/phantomjs/bin:$PATH" java -jar ./node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.0.jar &> /dev/null & + sleep 2 + BROWSERNAME=$BROWSER ./node_modules/.bin/wdio ./tests/functional/wdio.conf.js +elif [ "$1" == 'start-ci' ]; then + echo "[CI] Starting selenium server..." + + if [ ! -f selenium-server-standalone-2.53.1.jar ]; then + echo "selenium jar File not found!" + wget https://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.1.jar + fi + + PATH="./node_modules/phantomjs/bin:$PATH" java -jar selenium-server-standalone-2.53.1.jar &> /dev/null & + sleep 5 + BROWSERNAME=$BROWSER ./node_modules/.bin/wdio ./tests/functional/wdio.conf.js +else + echo "Nothing to do!" +fi diff --git a/tests/functional/wdio.conf.js b/tests/functional/wdio.conf.js new file mode 100644 index 000000000..b02f41928 --- /dev/null +++ b/tests/functional/wdio.conf.js @@ -0,0 +1,44 @@ +const browser = process.env.BROWSERNAME || 'phantomjs'; + +exports.config = { + + maxInstances: 4, + sync: true, + specs: [ + './tests/functional/specs/**/*.js' + ], + exclude: [ + ], + + capabilities: [ + { + browserName: browser + } + ], + + logLevel: 'error', + coloredLogs: true, + screenshotPath: './errorShots/', + + waitforTimeout: 10000, + framework: 'mocha', + reporters: ['dot', 'spec'], + onPrepare: () => { + }, + before: () => { + + const chai = require('chai'); // eslint-disable-line global-require + global.chai = chai; + global.expect = chai.expect; + + process.on('unhandledRejection', (e) => { + console.error(e); + if (e.stack) { + console.error(e.stack); + } + }); + + require('babel-core/register'); // eslint-disable-line global-require + require('babel-polyfill'); // eslint-disable-line global-require + } +};