diff --git a/scripts/e2e-ci.sh b/scripts/e2e-ci.sh index b86edb319..a509ccee7 100755 --- a/scripts/e2e-ci.sh +++ b/scripts/e2e-ci.sh @@ -2,20 +2,26 @@ REPORTS_FOLDER=${CIRCLE_TEST_REPORTS:-./test/e2e/reports} CIRCLE_BRANCH=${CIRCLE_BRANCH:-master} +E2E_DISABLE=${E2E_DISABLE:-false} # Amount of retries before failure. E2E_MAX_RETRIES=${E2E_MAX_RETRIES:-1} +# Timeout for WaitForConditions. +E2E_WAIT_FOR_TIMEOUT=${E2E_WAIT_FOR_TIMEOUT:-10000} + # Safari >= 8 has issues connecting to browserstack-local. Safari < 8 is too old. # IE 64bit has issues with receiving keyboard input. Let's wait for them to fix it. +E2E_BROWSERS=${E2E_BROWSERS:-chrome,firefox,edge} #ie safari -# FIXME: disabled firefox,edge until fixing pass is done -# BROWSERS="chrome,firefox,edge" #ie safari -BROWSERS="chrome" +if [[ "${E2E_DISABLE}" == "true" ]]; then + echo E2E is disabled. + exit +fi if [[ "${CIRCLE_BRANCH}" == "master" && -n "$BROWSERSTACK_KEY" ]]; then echo Testing on browserstack - yarn e2e --reports-folder "$REPORTS_FOLDER" --bs-key "$BROWSERSTACK_KEY" --retries "$E2E_MAX_RETRIES" --browsers $BROWSERS + yarn e2e --reports-folder "$REPORTS_FOLDER" --bs-key "$BROWSERSTACK_KEY" --retries "$E2E_MAX_RETRIES" --timeout "$E2E_WAIT_FOR_TIMEOUT" --browsers "$E2E_BROWSERS" else # When browserstack is not available test locally using chrome headless. echo Testing locally diff --git a/scripts/e2e.js b/scripts/e2e.js index 97e321310..d1d06e99a 100755 --- a/scripts/e2e.js +++ b/scripts/e2e.js @@ -59,7 +59,7 @@ function seleniumInstall() { }); } -function nightwatch(env, config, reportsFolder, browserstack) { +function nightwatch(env, config, reportsFolder, browserstack, timeout) { return new Promise((resolve, reject) => { try { const nw = childProcess.spawn( @@ -71,6 +71,7 @@ function nightwatch(env, config, reportsFolder, browserstack) { 'BROWSERSTACK_KEY': browserstack.key, 'BROWSERSTACK_USER': browserstack.user, 'REPORTS_FOLDER': `${reportsFolder}/${env}`, + 'WAIT_FOR_TIMEOUT': timeout, }), stdio: 'inherit', }); @@ -111,13 +112,13 @@ function printSection(txt) { console.log('*****************************'.magenta); } -async function runBrowserTests(browsers, config, retries = 1, reportsFolder, browserstack) { +async function runBrowserTests(browsers, config, retries = 1, reportsFolder, browserstack, timeout) { const succeeded = {}; for (let browser of browsers) { for (let t = 0; t < retries + 1; t++) { try { printSection(`e2e test for ${browser} #${t}`); - await nightwatch(browser, config, reportsFolder, browserstack); + await nightwatch(browser, config, reportsFolder, browserstack, timeout); succeeded[browser] = t; console.log(`\n==> Succeeded e2e for ${browser} #${t}\n`.green); break; @@ -143,6 +144,7 @@ async function start(program) { const date = new Date().toISOString() .replace(/[T.]/g, '-') .replace(/:/g, ''); + const timeout = program.timeout; const reportsFolder = `${program.reportsFolder}/${date}`; let exitCode = 0; let config = 'nightwatch.conf.js'; @@ -175,6 +177,7 @@ async function start(program) { retries, reportsFolder, browserstack, + timeout, ); if (!succeeded) { exitCode = 1; @@ -202,6 +205,7 @@ program .option('-r, --retries [number]', 'Number of retries before failing', '1') .option('--headless', 'Start in headless mode for local e2e') .option('--reports-folder [folder]', 'Reports folder', './test/e2e/reports') + .option('--timeout [number]', 'Timeout for WaitForConditions', '10000') .parse(process.argv); start(program); diff --git a/test/e2e/globals.js b/test/e2e/globals.js index 4d2740404..09b297a24 100644 --- a/test/e2e/globals.js +++ b/test/e2e/globals.js @@ -11,7 +11,7 @@ module.exports = { shutdown(); done(); }, - waitForConditionTimeout: 5000, + waitForConditionTimeout: parseInt(process.env.WAIT_FOR_TIMEOUT) || 10000, testData: { admin: { email: 'admin@test.com', diff --git a/test/e2e/page_objects/embedStream.js b/test/e2e/page_objects/embedStream.js index 1cecad2a3..0a31745e4 100644 --- a/test/e2e/page_objects/embedStream.js +++ b/test/e2e/page_objects/embedStream.js @@ -62,24 +62,12 @@ module.exports = { // Focusing on the Login PopUp windowHandler.windowHandles((handles) => { this.api.switchWindow(handles[1]); - }); - const popup = this.api.page.popup().ready(); - callback(popup); + const popup = this.api.page.popup().ready(); + callback(popup); - // Give a tiny bit of time to let popup close. - this.api.pause(50); - - if (this.api.capabilities.browserName === 'MicrosoftEdge') { - - // More time for edge. - // https://www.browserstack.com/automate/builds/1ceccf4efb4683b7feb890f45a32b5922b40ed3f/sessions/7393dbfda8387e43b6d5851f359b0c07db414973 - this.api.pause(1000); - } - - // Focusing on the Embed Window - windowHandler.windowHandles((handles) => { - this.api.switchWindow(handles[0]); + // Focus on the Embed Window. + windowHandler.pop(); // For some reasons firefox does not automatically load auth after login. // https://www.browserstack.com/automate/builds/37650cb4e66c6edce0ba0800a1c1b7e7f74bf991/sessions/7a4e9da69b0f9ecdf8b7fa9150639e47b1532cb0#automate_button @@ -89,6 +77,7 @@ module.exports = { this.parent.switchToIframe(); } }); + return this; }, logout() { diff --git a/test/e2e/specs/04_userStatus.js b/test/e2e/specs/04_userStatus.js index 5a7593e53..41540db65 100644 --- a/test/e2e/specs/04_userStatus.js +++ b/test/e2e/specs/04_userStatus.js @@ -94,6 +94,14 @@ module.exports = { comments .waitForElementVisible('@restrictedMessageBox'); }, + 'user should not be able to comment': (client) => { + const embedStream = client.page.embedStream(); + const comments = embedStream.section.comments; + + comments + .waitForElementNotPresent('@commentBoxTextarea') + .waitForElementNotPresent('@commentBoxPostButton'); + }, 'user picks another username': (client) => { const embedStream = client.page.embedStream(); const comments = embedStream.section.comments; @@ -106,12 +114,12 @@ module.exports = { .click('@suspendedAccountSubmitButton') .waitForElementNotPresent('@suspendedAccountInput'); }, - 'user should not be able to comment': (client) => { + 'user should be able to comment': (client) => { const embedStream = client.page.embedStream(); const comments = embedStream.section.comments; comments - .waitForElementNotPresent('@commentBoxTextarea') - .waitForElementNotPresent('@commentBoxPostButton'); + .waitForElementVisible('@commentBoxTextarea') + .waitForElementVisible('@commentBoxPostButton'); }, }; diff --git a/test/e2e/utils/SortedWindowHandler.js b/test/e2e/utils/SortedWindowHandler.js index cb8195978..a23f71506 100644 --- a/test/e2e/utils/SortedWindowHandler.js +++ b/test/e2e/utils/SortedWindowHandler.js @@ -25,28 +25,14 @@ class SortedWindowHandler { */ windowHandles(callback) { this.client.windowHandles((result) => { - if (Array.isArray(result.value)) { - this.handles = this.handles.filter((handle) => { - for (let i = 0; i < result.value.length; i++) { - if (result.value[i] === handle) { - return true; - } - } - return false; - }); - } else { - this.handles = []; + if (result.value.message) { + throw new Error(result.value.message); } - const remaining = result.value.filter((handle) => { - for (let i = 0; i < this.handles.length; i++) { - if (this.handles[i] === handle) { - return false; - } - } - return true; - }); + this.handles = this.handles.filter((handle) => result.value.includes(handle)); + const remaining = result.value.filter((handle) => !this.handles.includes(handle)); + if (remaining.length === 1) { this.handles.push(remaining[0]); } @@ -56,6 +42,14 @@ class SortedWindowHandler { callback(this.handles); }); } + + /** + * Switch to main window handle and remove latest handle. + */ + pop() { + this.client.switchWindow(this.handles[0]); + this.handles.splice(-1, 1); + } } module.exports = SortedWindowHandler;