From a7fac9b5a1ce7852afe7591cbe77c87dee11c8a4 Mon Sep 17 00:00:00 2001 From: Odei Maiz <33152403+odeimaiz@users.noreply.github.com> Date: Fri, 3 Apr 2020 10:30:04 +0200 Subject: [PATCH] Fix e2e false positives (#1428) * Added mechanisms for waiting for services to start * extract New Study Data from "open" response --- tests/e2e/tutorials/mattward.js | 8 ++-- tests/e2e/tutorials/tutorialBase.js | 28 +++++++++++++ tests/e2e/utils/responsesQueue.js | 64 +++++++++++++++++++++++++---- tests/e2e/utils/utils.js | 13 ++++++ 4 files changed, 102 insertions(+), 11 deletions(-) diff --git a/tests/e2e/tutorials/mattward.js b/tests/e2e/tutorials/mattward.js index 6f431642013..f2d7182f28b 100644 --- a/tests/e2e/tutorials/mattward.js +++ b/tests/e2e/tutorials/mattward.js @@ -26,10 +26,12 @@ async function runTutorial () { await tutorial.registerIfNeeded(); await tutorial.login(); - await tutorial.openTemplate(1000); + const studyData = await tutorial.openTemplate(1000); + const workbenchData = utils.extractWorkbenchData(studyData["data"]); + await tutorial.waitForService(workbenchData["studyId"], workbenchData["nodeIds"][0]); - // Wait service to start and output files to be pushed - await tutorial.waitFor(60000); + // Wait for the output files to be pushed + await tutorial.waitFor(30000); // This study opens in fullscreen mode await tutorial.restoreIFrame(); diff --git a/tests/e2e/tutorials/tutorialBase.js b/tests/e2e/tutorials/tutorialBase.js index f6c6c199967..e872f5e8537 100644 --- a/tests/e2e/tutorials/tutorialBase.js +++ b/tests/e2e/tutorials/tutorialBase.js @@ -90,18 +90,46 @@ class TutorialBase { } } + async waitForOpen() { + this.__responsesQueue.addResponseListener("open"); + let resp = null; + try { + resp = await this.__responsesQueue.waitUntilResponse("open"); + } + catch(err) { + console.error(this.__templateName, "could not be started", err); + } + return resp; + } + async openTemplate(waitFor = 1000) { await utils.takeScreenshot(this.__page, this.__templateName + "_dashboardOpenFirstTemplate_before"); this.__responsesQueue.addResponseListener("projects?from_template="); + this.__responsesQueue.addResponseListener("open"); + let resp = null; try { await auto.dashboardOpenFirstTemplate(this.__page, this.__templateName); await this.__responsesQueue.waitUntilResponse("projects?from_template="); + resp = await this.__responsesQueue.waitUntilResponse("open"); } catch(err) { console.error(this.__templateName, "could not be started", err); } await this.__page.waitFor(waitFor); await utils.takeScreenshot(this.__page, this.__templateName + "_dashboardOpenFirstTemplate_after"); + return resp; + } + + async waitForService(studyId, nodeId) { + this.__responsesQueue.addResponseServiceListener(studyId, nodeId); + let resp = null; + try { + resp = await this.__responsesQueue.waitUntilServiceReady(studyId, nodeId); + } + catch(err) { + console.error(this.__templateName, "could not be started", err); + } + return resp; } async restoreIFrame() { diff --git a/tests/e2e/utils/responsesQueue.js b/tests/e2e/utils/responsesQueue.js index c2b4c1a5b27..9eaf2bbad8e 100644 --- a/tests/e2e/utils/responsesQueue.js +++ b/tests/e2e/utils/responsesQueue.js @@ -8,12 +8,18 @@ class ResponsesQueue { this.__respReceivedQueue = {}; } - addResponseListener(url) { + isRequestInQueue(url) { + return this.__reqQueue.includes(url); + } + + isResponseInQueue(url) { + return this.__respPendingQueue.includes(url); + } + + __addRequestListener(url) { const page = this.__page; const reqQueue = this.__reqQueue; - const respPendingQueue = this.__respPendingQueue; reqQueue.push(url); - respPendingQueue.push(url); console.log("-- Expected response added to queue", url); page.on("request", function callback(req) { if (req.url().includes(url)) { @@ -25,6 +31,14 @@ class ResponsesQueue { } } }); + } + + addResponseListener(url) { + this.__addRequestListener(url); + + const page = this.__page; + const respPendingQueue = this.__respPendingQueue; + respPendingQueue.push(url); const that = this; page.on("response", function callback(resp) { if (resp.url().includes(url)) { @@ -52,12 +66,36 @@ class ResponsesQueue { }); } - isRequestInQueue(url) { - return this.__reqQueue.includes(url); - } + addResponseServiceListener(studyId, nodeId) { + const url = "projects/" + studyId +"/nodes/" + nodeId; + this.__addRequestListener(url); - isResponseInQueue(url) { - return this.__respPendingQueue.includes(url); + const page = this.__page; + const respPendingQueue = this.__respPendingQueue; + respPendingQueue.push(url); + const that = this; + page.on("response", function callback(resp) { + if (resp.url().includes(url) && resp.status() === 200) { + resp.json().then(data => { + console.log((new Date).toUTCString(), "-- Queued services status response received", resp.url(), ":"); + const status = data["data"]["service_state"]; + console.log("Status:", status); + const stopListening = [ + "running", + "complete", + "failed" + ]; + if (stopListening.includes(status)) { + that.__respReceivedQueue[url] = data; + page.removeListener("response", callback); + const index = respPendingQueue.indexOf(url); + if (index > -1) { + respPendingQueue.splice(index, 1); + } + } + }); + } + }); } async waitUntilResponse(url, timeout = 10000) { @@ -80,6 +118,16 @@ class ResponsesQueue { return resp; } } + + async waitUntilServiceReady(studyId, nodeId, timeout = 30000) { + const url = "projects/" + studyId +"/nodes/" + nodeId; + const resp = await this.waitUntilResponse(url, timeout); + const status = resp["data"]["service_state"]; + if (status !== "running") { + throw("-- Failed starting service" + nodeId + ":" + status); + } + return resp; + } } module.exports = { diff --git a/tests/e2e/utils/utils.js b/tests/e2e/utils/utils.js index 40d2fa87a4f..27018ae02b6 100644 --- a/tests/e2e/utils/utils.js +++ b/tests/e2e/utils/utils.js @@ -168,6 +168,18 @@ async function takeScreenshot(page, captureName) { }) } +function extractWorkbenchData(data) { + const workbenchData = { + studyId: null, + nodeIds: [] + }; + workbenchData.studyId = data["uuid"]; + if ("workbench" in data) { + workbenchData.nodeIds = Object.keys(data["workbench"]); + } + return workbenchData; +} + module.exports = { getUserAndPass, getDomain, @@ -182,4 +194,5 @@ module.exports = { waitAndClick, sleep, takeScreenshot, + extractWorkbenchData, }