diff --git a/package.json b/package.json index 00cfb53d2..a299c2442 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,9 @@ "start": "make start", "stop": "make stop", "test": "make test", - "smoke": "make smoke", + "smoke": "tap ./test/integration/smoke-testing/*.js --timeout=3600", "smoke-verbose": "make smoke-verbose", + "smoke-sauce": "tap ./test/integration/smoke-testing/*.js --timeout=60000", "watch": "make watch", "build": "make build", "dev": "make watch && make start &" diff --git a/test/integration/selenium-helpers.js b/test/integration/selenium-helpers.js index 3097ba75c..dcd96476f 100644 --- a/test/integration/selenium-helpers.js +++ b/test/integration/selenium-helpers.js @@ -1,91 +1,127 @@ -var webdriver = require('selenium-webdriver'); +const webdriver = require('selenium-webdriver'); +const bindAll = require('lodash.bindall'); const headless = process.env.SMOKE_HEADLESS || false; - -const getDriver = function () { - const chromeCapabilities = webdriver.Capabilities.chrome(); - let args = []; - if (headless) { - args.push('--headless'); - args.push('window-size=1024,1680'); - args.push('--no-sandbox'); - } - chromeCapabilities.set('chromeOptions', {args}); - const newDriver = new webdriver.Builder() - .forBrowser('chrome') - .withCapabilities(chromeCapabilities) - .build(); - return newDriver; -}; - -const driver = getDriver(); - +const remote = process.env.SMOKE_REMOTE || false; +const {SAUCE_USERNAME, SAUCE_ACCESS_KEY} = process.env; const {By, until} = webdriver; -const findByXpath = (xpath) => { - return driver.wait(until.elementLocated(By.xpath(xpath), 5 * 1000)); -}; +class SeleniumHelper { + constructor () { + bindAll(this, [ + 'getDriver', + 'getSauceDriver', + 'buildDriver', + 'clickXpath', + 'findByXpath', + 'clickText', + 'findText', + 'clickButton', + 'findByCss', + 'clickCss', + 'getLogs' + ]); + } + buildDriver (name) { + if (remote === 'true'){ + this.driver = this.getSauceDriver(SAUCE_USERNAME, SAUCE_ACCESS_KEY, name); + } else { + this.driver = this.getDriver(); + } + return this.driver; + } -const clickXpath = (xpath) => { - return findByXpath(xpath).then(el => el.click()); -}; + getDriver () { + const chromeCapabilities = webdriver.Capabilities.chrome(); + let args = []; + if (headless) { + args.push('--headless'); + args.push('window-size=1024,1680'); + args.push('--no-sandbox'); + } + chromeCapabilities.set('chromeOptions', {args}); + let driver = new webdriver.Builder() + .forBrowser('chrome') + .withCapabilities(chromeCapabilities) + .build(); + return driver; + } -const clickText = (text) => { - return clickXpath(`//*[contains(text(), '${text}')]`); -}; + getSauceDriver (username, accessKey, name) { + // Driver configs can be generated with the Sauce Platform Configurator + // https://wiki.saucelabs.com/display/DOCS/Platform+Configurator + let driverConfig = { + browserName: 'chrome', + platform: 'macOS 10.13', + version: '67.0' + }; + var driver = new webdriver.Builder() + .withCapabilities({ + browserName: driverConfig.browserName, + platform: driverConfig.platform, + version: driverConfig.version, + username: username, + accessKey: accessKey, + name: name + }) + .usingServer(`http://${username}:${accessKey + }@ondemand.saucelabs.com:80/wd/hub`) + .build(); + return driver; + } -const findText = (text) => { - return driver.wait(until.elementLocated(By.xpath(`//*[contains(text(), '${text}')]`), 5 * 1000)); -}; + findByXpath (xpath) { + return this.driver.wait(until.elementLocated(By.xpath(xpath), 5 * 1000)); + } -const clickButton = (text) => { - return clickXpath(`//button[contains(text(), '${text}')]`); -}; + clickXpath (xpath) { + return this.findByXpath(xpath).then(el => el.click()); + } -const findByCss = (css) => { - return driver.wait(until.elementLocated(By.css(css), 1000 * 5)); -}; + clickText (text) { + return this.clickXpath(`//*[contains(text(), '${text}')]`); + } -const clickCss = (css) => { - return findByCss(css).then(el => el.click()); -}; + findText (text) { + return this.driver.wait(until.elementLocated(By.xpath(`//*[contains(text(), '${text}')]`), 5 * 1000)); + } -const getLogs = (whitelist) => { - return driver.manage() - .logs() - .get('browser') - .then((entries) => { - return entries.filter((entry) => { - const message = entry.message; - for (let i = 0; i < whitelist.length; i++) { - if (message.indexOf(whitelist[i]) !== -1) { - // eslint-disable-next-line no-console - // console.warn('Ignoring whitelisted error: ' + whitelist[i]); - return false; - } else if (entry.level !== 'SEVERE') { - // eslint-disable-next-line no-console - // console.warn('Ignoring non-SEVERE entry: ' + message); - return false; + clickButton (text) { + return this.clickXpath(`//button[contains(text(), '${text}')]`); + } + + findByCss (css) { + return this.driver.wait(until.elementLocated(By.css(css), 1000 * 5)); + } + + clickCss (css) { + return this.findByCss(css).then(el => el.click()); + } + + getLogs (whitelist) { + return this.driver.manage() + .logs() + .get('browser') + .then((entries) => { + return entries.filter((entry) => { + const message = entry.message; + for (let i = 0; i < whitelist.length; i++) { + if (message.indexOf(whitelist[i]) !== -1) { + // eslint-disable-next-line no-console + // console.warn('Ignoring whitelisted error: ' + whitelist[i]); + return false; + } else if (entry.level !== 'SEVERE') { + // eslint-disable-next-line no-console + // console.warn('Ignoring non-SEVERE entry: ' + message); + return false; + } + return true; } return true; - } - return true; + }); }); - }); -}; + } -module.exports = { - webdriver, - By, - until, - driver, - clickXpath, - findByXpath, - clickText, - findText, - clickButton, - findByCss, - clickCss, - getLogs, - getDriver -}; +} + +module.exports = SeleniumHelper; diff --git a/test/integration/smoke-testing/test-login-failures.js b/test/integration/smoke-testing/test-login-failures.js index fca6c9c01..a629bb5fd 100644 --- a/test/integration/smoke-testing/test-login-failures.js +++ b/test/integration/smoke-testing/test-login-failures.js @@ -1,17 +1,22 @@ -const { - driver, - findByCss, - clickCss, - until -} = require('../selenium-helpers.js'); - -var username = process.env.SMOKE_USERNAME; -var password = process.env.SMOKE_PASSWORD; - +const SeleniumHelper = require('../selenium-helpers.js'); +const helper = new SeleniumHelper(); var tap = require('tap'); const test = tap.test; +const webdriver = require('selenium-webdriver'); +const driver = helper.buildDriver('www-smoke test-login-failures'); + +const { + findByCss, + clickCss +} = helper; + +var until = webdriver.until; + +var username = process.env.SMOKE_USERNAME; +var password = process.env.SMOKE_PASSWORD; + var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; var url = rootUrl + '/users/' + username; diff --git a/test/integration/smoke-testing/test-my-stuff.js b/test/integration/smoke-testing/test-my-stuff.js index d6ea50285..b16aee85e 100644 --- a/test/integration/smoke-testing/test-my-stuff.js +++ b/test/integration/smoke-testing/test-my-stuff.js @@ -5,21 +5,24 @@ * */ +const SeleniumHelper = require('../selenium-helpers.js'); +const helper = new SeleniumHelper(); + +var tap = require('tap'); +const test = tap.test; + +const driver = helper.buildDriver('www-smoke test-my-stuff'); + const { clickText, findByXpath, clickXpath, - clickButton, - driver -} = require('../selenium-helpers.js'); + clickButton +} = helper; var username = process.env.SMOKE_USERNAME; var password = process.env.SMOKE_PASSWORD; - -var tap = require('tap'); -const test = tap.test; - var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; var url = rootUrl + '/users/' + username; diff --git a/test/integration/smoke-testing/test_footer_links.js b/test/integration/smoke-testing/test_footer_links.js index 8cf84909a..3bdf54416 100644 --- a/test/integration/smoke-testing/test_footer_links.js +++ b/test/integration/smoke-testing/test_footer_links.js @@ -4,15 +4,13 @@ * Test cases: https://github.com/LLK/scratch-www/wiki/Most-Important-Workflows */ +const SeleniumHelper = require('../selenium-helpers.js'); +const helper = new SeleniumHelper(); + const tap = require('tap'); -const { - driver, - webdriver -} = require('../selenium-helpers.js'); - -// Selenium's promise driver will be deprecated, so we should not rely on it -webdriver.SELENIUM_PROMISE_MANAGER = 0; +const webdriver = require('selenium-webdriver'); +const driver = helper.buildDriver('www-smoke test_footer_links'); const rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; diff --git a/test/integration/smoke-testing/test_navbar_links.js b/test/integration/smoke-testing/test_navbar_links.js index fbfd72291..3f1eac308 100644 --- a/test/integration/smoke-testing/test_navbar_links.js +++ b/test/integration/smoke-testing/test_navbar_links.js @@ -4,16 +4,13 @@ * Test cases: https://github.com/LLK/scratch-www/wiki/Most-Important-Workflows */ -require('chromedriver'); +const SeleniumHelper = require('../selenium-helpers.js'); +const helper = new SeleniumHelper(); -const { - driver, - webdriver -} = require('../selenium-helpers.js'); var tap = require('tap'); -// Selenium's promise driver will be deprecated, so we should not rely on it -webdriver.SELENIUM_PROMISE_MANAGER = 0; +const webdriver = require('selenium-webdriver'); +const driver = helper.buildDriver('www-smoke test_navbar_links'); // Set test url through environment variable var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; diff --git a/test/integration/smoke-testing/test_project_rows.js b/test/integration/smoke-testing/test_project_rows.js index a84bc4c61..7d6c327b1 100644 --- a/test/integration/smoke-testing/test_project_rows.js +++ b/test/integration/smoke-testing/test_project_rows.js @@ -5,16 +5,13 @@ * Test cases: https://github.com/LLK/scratch-www/wiki/Most-Important-Workflows */ -require('chromedriver'); +const SeleniumHelper = require('../selenium-helpers.js'); +const helper = new SeleniumHelper(); + var tap = require('tap'); -var seleniumWebdriver = require('selenium-webdriver'); -// Selenium's promise driver will be deprecated, so we should not rely on it -seleniumWebdriver.SELENIUM_PROMISE_MANAGER = 0; - -const { - driver -} = require('../selenium-helpers.js'); +const webdriver = require('selenium-webdriver'); +const driver = helper.buildDriver('www-smoke test_project_rows'); var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; @@ -34,7 +31,7 @@ tap.beforeEach(function () { // checks that the title of the first row is Featured Projects tap.test('checkFeaturedProjectsRowTitleWhenSignedOut', function (t) { var xPathLink = '//div[@class="box"]/div[@class="box-header"]/h4'; - driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) + driver.findElement(webdriver.By.xpath(xPathLink)) .then(function (element) { element.getText('h4') .then(function (text) { @@ -51,8 +48,8 @@ tap.test('checkFeaturedProjectsRowLinkWhenSignedOut', function (t) { var xPathLink = '//div[contains(@class, "thumbnail") ' + 'and contains(@class, "project") and contains(@class, "slick-slide") ' + 'and contains(@class, "slick-active")]/a[@class="thumbnail-image"]'; - driver.wait(seleniumWebdriver.until - .elementLocated(seleniumWebdriver.By.xpath(xPathLink))) + driver.wait(webdriver.until + .elementLocated(webdriver.By.xpath(xPathLink))) .then(function (element) { element.getAttribute('href') .then(function (url) { @@ -68,7 +65,7 @@ tap.test('checkFeaturedProjectsRowLinkWhenSignedOut', function (t) { // checks that the title of the 2nd row is Featured Studios tap.test('checkFeaturedStudiosRowWhenSignedOut', function (t) { var xPathLink = '//div[@class="box"][2]/div[@class="box-header"]/h4'; - driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) + driver.findElement(webdriver.By.xpath(xPathLink)) .then(function (element) { element.getText('h4') .then(function (text) { @@ -83,7 +80,7 @@ tap.test('checkFeaturedStudiosRowWhenSignedOut', function (t) { tap.test('checkFeaturedStudiosRowLinkWhenSignedOut', function (t) { var xPathLink = '//div[contains(@class, "thumbnail") and contains(@class, "gallery") ' + 'and contains(@class, "slick-slide") and contains(@class, "slick-active")]/a[@class="thumbnail-image"]'; - driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) + driver.findElement(webdriver.By.xpath(xPathLink)) .then(function (element) { element.getAttribute('href') .then(function (url) { diff --git a/test/integration/smoke-testing/test_signing_in_and_out_discuss.js b/test/integration/smoke-testing/test_signing_in_and_out_discuss.js index 47abb9ea6..018521537 100644 --- a/test/integration/smoke-testing/test_signing_in_and_out_discuss.js +++ b/test/integration/smoke-testing/test_signing_in_and_out_discuss.js @@ -5,22 +5,25 @@ * */ +const SeleniumHelper = require('../selenium-helpers.js'); +const helper = new SeleniumHelper(); + +var tap = require('tap'); +const test = tap.test; + +const driver = helper.buildDriver('www-smoke test_sign_in_out_discuss'); + const { clickText, findByXpath, findText, clickXpath, - clickButton, - driver -} = require('../selenium-helpers.js'); + clickButton +} = helper; var username = process.env.SMOKE_USERNAME; var password = process.env.SMOKE_PASSWORD; - -var tap = require('tap'); -const test = tap.test; - var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; var url = rootUrl + '/discuss'; diff --git a/test/integration/smoke-testing/test_signing_in_and_out_homepage.js b/test/integration/smoke-testing/test_signing_in_and_out_homepage.js index e21fbc91e..40ab21f79 100644 --- a/test/integration/smoke-testing/test_signing_in_and_out_homepage.js +++ b/test/integration/smoke-testing/test_signing_in_and_out_homepage.js @@ -5,20 +5,24 @@ * */ +const SeleniumHelper = require('../selenium-helpers.js'); +const helper = new SeleniumHelper(); + +var tap = require('tap'); +const test = tap.test; + +const driver = helper.buildDriver('www-smoke test_sign_in_out_homepage'); + const { clickText, findText, findByXpath, - clickXpath, - driver -} = require('../selenium-helpers.js'); + clickXpath +} = helper; var username = process.env.SMOKE_USERNAME; var password = process.env.SMOKE_PASSWORD; -var tap = require('tap'); -const test = tap.test; - var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; tap.plan(2); diff --git a/test/integration/smoke-testing/test_statistics_page.js b/test/integration/smoke-testing/test_statistics_page.js index 223184b7e..9a8f9596c 100644 --- a/test/integration/smoke-testing/test_statistics_page.js +++ b/test/integration/smoke-testing/test_statistics_page.js @@ -5,16 +5,20 @@ * */ -const { - clickText, - findByXpath, - findByCss, - driver -} = require('../selenium-helpers.js'); +const SeleniumHelper = require('../selenium-helpers.js'); +const helper = new SeleniumHelper(); var tap = require('tap'); const test = tap.test; +const driver = helper.buildDriver('www-smoke test_statistics_page'); + +const { + clickText, + findByXpath, + findByCss +} = helper; + tap.plan(2); tap.tearDown(function () {