Skip to content

Commit d8e7bcc

Browse files
authored
wait for notebook to complete (#2190)
* waiting for notebook/lab to complete * page.waitFor is deprecated * wait enough before getting results * add healthcheck for postgres/redis
1 parent 50240e5 commit d8e7bcc

File tree

5 files changed

+62
-39
lines changed

5 files changed

+62
-39
lines changed

services/docker-compose.yml

+9
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@ services:
272272
- default
273273
- interactive_services_subnet
274274
- computational_services_subnet
275+
healthcheck:
276+
test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}"]
277+
interval: 15s
278+
retries: 5
275279
# NOTES: this is not yet compatible with portainer deployment but could work also for other containers
276280
# works with Docker 19.03 and not yet with Portainer 1.23.0 (see https://github.com/portainer/portainer/issues/3551)
277281
# in the meantime postgres allows to set a configuration through CLI.
@@ -299,6 +303,11 @@ services:
299303
networks:
300304
- default
301305
- computational_services_subnet
306+
healthcheck:
307+
test: ["CMD", "redis-cli", "ping"]
308+
interval: 5s
309+
timeout: 30s
310+
retries: 50
302311

303312
traefik:
304313
image: traefik:v2.2.1

tests/e2e/tutorials/jupyters.js

+44-30
Original file line numberDiff line numberDiff line change
@@ -27,43 +27,55 @@ async function runTutorial() {
2727

2828
const workbenchData = utils.extractWorkbenchData(studyData["data"]);
2929
await tutorial.waitForServices(workbenchData["studyId"], [workbenchData["nodeIds"][1], workbenchData["nodeIds"][2]]);
30+
await tutorial.waitFor(2000);
3031

3132
// open jupyterNB
3233
await tutorial.openNode(1);
3334

3435
const iframeHandles = await tutorial.getIframe();
3536
const iframes = [];
36-
for (let i=0; i<iframeHandles.length; i++) {
37+
for (let i = 0; i < iframeHandles.length; i++) {
3738
const frame = await iframeHandles[i].contentFrame();
3839
iframes.push(frame);
3940
}
4041
const nbIframe = iframes.find(iframe => iframe._url.endsWith("tree?"));
4142

4243
// inside the iFrame, open the first notebook
4344
const notebookCBSelector = '#notebook_list > div:nth-child(2) > div > input[type=checkbox]';
44-
await nbIframe.waitForSelector(notebookCBSelector);
45-
await nbIframe.click(notebookCBSelector);
46-
await tutorial.waitFor(2000);
45+
await utils.waitAndClick(nbIframe, notebookCBSelector)
4746
const notebookViewSelector = "#notebook_toolbar > div.col-sm-8.no-padding > div.dynamic-buttons > button.view-button.btn.btn-default.btn-xs"
48-
await nbIframe.waitForSelector(notebookViewSelector);
49-
await nbIframe.click(notebookViewSelector);
50-
await tutorial.waitFor(2000);
51-
await tutorial.takeScreenshot("openNotebook");
52-
53-
// inside the first notebook, click Run button 5 times
54-
const runNBBtnSelector = '#run_int > button:nth-child(1)';
55-
const runNotebookTimes = 5;
56-
for (let i = 0; i < runNotebookTimes; i++) {
57-
await nbIframe.waitForSelector(runNBBtnSelector);
58-
await nbIframe.click(runNBBtnSelector);
59-
await tutorial.waitFor(3000);
60-
await tutorial.takeScreenshot("pressRunNB_" + (i + 1));
47+
await utils.waitAndClick(nbIframe, notebookViewSelector)
48+
49+
50+
// inside the first notebook, click Run all button
51+
const runAllButtonSelector = '#run_int > button:nth-child(4)';
52+
await utils.waitAndClick(nbIframe, runAllButtonSelector);
53+
await tutorial.takeScreenshot("pressRunAllButtonNotebook");
54+
55+
// inside the first notebook, click confirm run all (NOTE: this dialog does not appear in headless mode)
56+
try {
57+
const confirmRunAllButtonSelector = 'body > div.modal.fade.in > div > div > div.modal-footer > button.btn.btn-default.btn-sm.btn-danger';
58+
await utils.waitAndClick(nbIframe, confirmRunAllButtonSelector, 10000);
59+
await tutorial.takeScreenshot("pressRunNotebookAfterConfirmation");
60+
} catch (err) {
61+
console.log("The confirmation dialog appears only in --demo mode.");
6162
}
6263

63-
// TODO: Better check that the kernel is finished
64-
await tutorial.waitFor(3000);
6564

66-
console.log('Checking results for the notebook:');
65+
// now check that the input contains [4]
66+
console.log('Waiting for notebook results...');
67+
const finishedRunningCheckboxSelector = '#notebook-container > div:nth-child(5) > div.input > div.prompt_container > div.prompt.input_prompt';
68+
// the page scrolls down, so first wait so that it becomes visible
69+
await nbIframe.waitForSelector(finishedRunningCheckboxSelector);
70+
await nbIframe.waitForFunction('document.querySelector("' + finishedRunningCheckboxSelector + '").innerText.match(/\[[0-9]+\]/)');
71+
await tutorial.takeScreenshot("notebookWaitingForNotebookCompleted");
72+
console.log('...waiting completed');
73+
const element = await nbIframe.$(finishedRunningCheckboxSelector);
74+
const value = await nbIframe.evaluate(el => el.textContent, element);
75+
console.log('Results for the notebook cell is:', value);
76+
// NOTE: we need to wait here to get the results.
77+
await tutorial.waitFor(10000);
78+
6779
await tutorial.openNodeFiles(1);
6880
const outFiles = [
6981
"TheNumberNumber.txt",
@@ -77,7 +89,7 @@ async function runTutorial() {
7789

7890
const iframeHandles2 = await tutorial.getIframe();
7991
const iframes2 = [];
80-
for (let i=0; i<iframeHandles2.length; i++) {
92+
for (let i = 0; i < iframeHandles2.length; i++) {
8193
const frame = await iframeHandles2[i].contentFrame();
8294
iframes2.push(frame);
8395
}
@@ -89,21 +101,23 @@ async function runTutorial() {
89101
await jLabIframe.click(input2outputFileSelector, {
90102
clickCount: 2
91103
});
92-
await tutorial.waitFor(2000);
93-
94104
// click Run Menu
95105
const mainRunMenuBtnSelector = '#jp-MainMenu > ul > li:nth-child(4)';
96-
await jLabIframe.waitForSelector(mainRunMenuBtnSelector);
97-
await jLabIframe.click(mainRunMenuBtnSelector);
98-
await tutorial.waitFor(1000);
106+
await utils.waitAndClick(jLabIframe, mainRunMenuBtnSelector)
99107

100108
// click Run All Cells
101109
const mainRunAllBtnSelector = ' body > div.lm-Widget.p-Widget.lm-Menu.p-Menu.lm-MenuBar-menu.p-MenuBar-menu > ul > li:nth-child(17)';
102-
await jLabIframe.waitForSelector(mainRunAllBtnSelector);
103-
await jLabIframe.click(mainRunAllBtnSelector);
104-
await tutorial.waitFor(6000);
110+
await utils.waitAndClick(jLabIframe, mainRunAllBtnSelector)
111+
112+
console.log('Waiting for jupyter lab results...');
113+
const labCompletedInputSelector = 'div.lm-Widget.p-Widget.jp-MainAreaWidget.jp-NotebookPanel.jp-Document.jp-Activity > div:nth-child(2) > div:nth-child(3) > div.lm-Widget.p-Widget.lm-Panel.p-Panel.jp-Cell-inputWrapper > div.lm-Widget.p-Widget.jp-InputArea.jp-Cell-inputArea > div.lm-Widget.p-Widget.jp-InputPrompt.jp-InputArea-prompt';
114+
await jLabIframe.waitForFunction('document.querySelector("' + labCompletedInputSelector + '").innerText.match(/\[[0-9]+\]/)');
115+
const jLabElement = await jLabIframe.$(labCompletedInputSelector);
116+
const jLabVvalue = await jLabIframe.evaluate(el => el.textContent, jLabElement);
117+
console.log('Checking results for the jupyter lab cell:', jLabVvalue);
105118
await tutorial.takeScreenshot("pressRunJLab");
106-
119+
// wait sufficiently before getting the results
120+
await tutorial.waitFor(10000);
107121
console.log('Checking results for the jupyter lab:');
108122
await tutorial.openNodeFiles(2);
109123
const outFiles2 = [

tests/e2e/tutorials/tutorialBase.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ class TutorialBase {
179179
console.error(`"${this.__templateName}" template could not be started:\n`, err);
180180
throw (err);
181181
}
182-
await this.__page.waitFor(waitFor);
182+
await this.__page.waitForTimeout(waitFor);
183183
await this.takeScreenshot("dashboardOpenFirstTemplate_after");
184184
return resp;
185185
}
@@ -197,7 +197,7 @@ class TutorialBase {
197197
console.error(`"${this.__templateName}" service could not be started:\n`, err);
198198
throw (err);
199199
}
200-
await this.__page.waitFor(waitFor);
200+
await this.__page.waitForTimeout(waitFor);
201201
await this.takeScreenshot("dashboardOpenFirstService_after");
202202
return resp;
203203
}
@@ -296,7 +296,7 @@ class TutorialBase {
296296

297297
async retrieve(waitAfterRetrieve = 5000) {
298298
await auto.clickRetrieve(this.__page);
299-
await this.__page.waitFor(waitAfterRetrieve);
299+
await this.__page.waitForTimeout(waitAfterRetrieve);
300300
}
301301

302302
async openNodeRetrieveAndRestart(nodePosInTree = 0) {
@@ -380,7 +380,7 @@ class TutorialBase {
380380
}
381381

382382
async waitFor(waitFor) {
383-
await this.__page.waitFor(waitFor);
383+
await this.__page.waitForTimeout(waitFor);
384384
}
385385

386386
async takeScreenshot(screenshotTitle) {

tests/e2e/utils/auto.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ async function checkDataProducedByNode(page, nFiles = 1) {
314314
let children = [];
315315
const minTime = 1000; // wait a bit longer for fetching the files
316316
for (let i = 0; i < tries && children.length === 0; i++) {
317-
await page.waitFor(minTime * (i + 1));
317+
await page.waitForTimeout(minTime * (i + 1));
318318
await page.waitForSelector('[osparc-test-id="fileTreeItem_NodeFiles"]');
319319
children = await utils.getFileTreeItemIDs(page, "NodeFiles");
320320
console.log(i + 1, 'try: ', children);

tests/e2e/utils/utils.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ async function isServiceConnected(page, studyId, nodeId) {
246246
console.log("-- Is Service Connected", nodeId);
247247
const serviceUrl = await getServiceUrl(page, studyId, nodeId);
248248
const connected = await makePingRequest(page, serviceUrl);
249-
console.log(connected, "--")
249+
console.log(connected ? ("service " + nodeId + " connected") : ("service" + nodeId + " connecting..."), "--")
250250
return connected;
251251
}
252252

@@ -300,10 +300,10 @@ async function waitForValidOutputFile(page) {
300300
})
301301
}
302302

303-
async function waitAndClick(page, id) {
303+
async function waitAndClick(page, id, timeout) {
304304
await page.waitForSelector(id, {
305-
timeout: 30000 // default 30s
306-
})
305+
timeout: (timeout ? timeout : 30000) // default 30s
306+
});
307307
await page.click(id);
308308
}
309309

0 commit comments

Comments
 (0)