diff --git a/.gitignore b/.gitignore index 38c2e2616d3..acfedeb10ac 100644 --- a/.gitignore +++ b/.gitignore @@ -126,6 +126,7 @@ services/docker-compose.stack.*.yml *secret* *ignore* !.dockerignore +!.gitignore # Any generated output folder (e.g. codegen, build, ...) out/ diff --git a/.vscode-template/launch.json b/.vscode-template/launch.json index 14186ec35ec..28d4310274e 100644 --- a/.vscode-template/launch.json +++ b/.vscode-template/launch.json @@ -68,6 +68,22 @@ "remoteRoot": "/devel" } ] + }, + { + "type": "node", + "request": "launch", + "name": "Debug e2e tests", + "runtimeArgs": [ + "--inspect-brk", + "${workspaceRoot}/tests/e2e/node_modules/.bin/jest", + "--runInBand", + "--colors" + ], + "cwd": "${workspaceFolder}/tests/e2e", + "restart": true, + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "port": 9229 } ] } \ No newline at end of file diff --git a/services/web/client/.eslintrc.json b/services/web/client/.eslintrc.json index 97eb4a63580..4d1bc01ce35 100644 --- a/services/web/client/.eslintrc.json +++ b/services/web/client/.eslintrc.json @@ -33,7 +33,8 @@ { "ignoreChainWithDepth": 3 } - ] + ], + "no-eq-null": 0 }, "env": { "browser": true diff --git a/services/web/client/source/class/osparc/auth/LoginPage.js b/services/web/client/source/class/osparc/auth/LoginPage.js index 6172e0f5aeb..d1ccc782140 100644 --- a/services/web/client/source/class/osparc/auth/LoginPage.js +++ b/services/web/client/source/class/osparc/auth/LoginPage.js @@ -92,7 +92,12 @@ qx.Class.define("osparc.auth.LoginPage", { login.resetValues(); }, this); - [register, resetRequest, reset].forEach(srcPage => { + register.addListener("done", msg => { + osparc.utils.Utils.cookie.deleteCookie("user"); + this.fireDataEvent("done", msg); + }); + + [resetRequest, reset].forEach(srcPage => { srcPage.addListener("done", msg => { pages.setSelection([login]); srcPage.resetValues(); diff --git a/services/web/client/source/class/osparc/auth/Manager.js b/services/web/client/source/class/osparc/auth/Manager.js index 7312e467c0c..13ccc0d7a68 100644 --- a/services/web/client/source/class/osparc/auth/Manager.js +++ b/services/web/client/source/class/osparc/auth/Manager.js @@ -108,20 +108,14 @@ qx.Class.define("osparc.auth.Manager", { .finally(this.__logoutUser()); }, - register: function(userData, successCbk, failCbk, context) { - console.debug("Registering user ..."); + register: function(userData) { const params = { data: userData }; - osparc.data.Resources.fetch("auth", "postRegister", params) - .then(data => { - successCbk.call(context, data); - }) - .catch(err => failCbk.call(context, err.message)); + return osparc.data.Resources.fetch("auth", "postRegister", params); }, resetPasswordRequest: function(email, successCbk, failCbk, context) { - console.debug("Requesting reset password ..."); const params = { data: { email @@ -135,7 +129,6 @@ qx.Class.define("osparc.auth.Manager", { }, resetPassword: function(newPassword, confirmation, code, successCbk, failCbk, context) { - console.debug("Reseting password ..."); const params = { url: { code diff --git a/services/web/client/source/class/osparc/auth/ui/RegistrationView.js b/services/web/client/source/class/osparc/auth/ui/RegistrationView.js index e8cbc39f6a0..a0f0df3fa6d 100644 --- a/services/web/client/source/class/osparc/auth/ui/RegistrationView.js +++ b/services/web/client/source/class/osparc/auth/ui/RegistrationView.js @@ -54,12 +54,6 @@ qx.Class.define("osparc.auth.ui.RegistrationView", { email.activate(); }); - // const uname = new qx.ui.form.TextField().set({ - // required: true, - // placeholder: this.tr("Introduce a user name") - // }); - // this.add(uname); - const pass1 = new qx.ui.form.PasswordField().set({ required: true, placeholder: this.tr("Introduce a password") @@ -88,7 +82,6 @@ qx.Class.define("osparc.auth.ui.RegistrationView", { return osparc.auth.core.Utils.checkSamePasswords(pass1, pass2); }); - // submit & cancel buttons const grp = new qx.ui.container.Composite(new qx.ui.layout.HBox(10)); @@ -123,21 +116,15 @@ qx.Class.define("osparc.auth.ui.RegistrationView", { }, __submit: function(userData) { - console.debug("Registering new user"); - - let manager = osparc.auth.Manager.getInstance(); - - let successFun = function(log) { - this.fireDataEvent("done", log.message); - osparc.component.message.FlashMessenger.getInstance().log(log); - }; - - let failFun = function(msg) { - msg = msg || this.tr("Cannot register user"); - osparc.component.message.FlashMessenger.getInstance().logAs(msg, "ERROR"); - }; - - manager.register(userData, successFun, failFun, this); + osparc.auth.Manager.getInstance().register(userData) + .then(log => { + this.fireDataEvent("done", log.message); + osparc.component.message.FlashMessenger.getInstance().log(log); + }) + .catch(err => { + const msg = err.message || this.tr("Cannot register user"); + osparc.component.message.FlashMessenger.getInstance().logAs(msg, "ERROR"); + }); }, _onAppear: function() { diff --git a/services/web/client/source/class/osparc/component/form/tag/TagToggleButton.js b/services/web/client/source/class/osparc/component/form/tag/TagToggleButton.js index 25b5225c6e0..29ffbedef40 100644 --- a/services/web/client/source/class/osparc/component/form/tag/TagToggleButton.js +++ b/services/web/client/source/class/osparc/component/form/tag/TagToggleButton.js @@ -50,7 +50,7 @@ qx.Class.define("osparc.component.form.tag.TagToggleButton", { this._add(control, { flex: 1 }); - if (this.getLabel() == null || this.getShow() === "icon") { // eslint-disable-line no-eq-null + if (this.getLabel() == null || this.getShow() === "icon") { control.exclude(); } break; diff --git a/services/web/client/source/class/osparc/component/service/NodeStatus.js b/services/web/client/source/class/osparc/component/service/NodeStatus.js index 8b67fac95fb..3f85b79b734 100644 --- a/services/web/client/source/class/osparc/component/service/NodeStatus.js +++ b/services/web/client/source/class/osparc/component/service/NodeStatus.js @@ -90,7 +90,9 @@ qx.Class.define("osparc.component.service.NodeStatus", { return "@FontAwesome5Solid/check/12"; }, onUpdate: (source, target) => { - if (source.getInteractiveStatus() === "ready") { + if (source.getInteractiveStatus() == null) { + this.__removeClass(this.__icon.getContentElement(), "rotate"); + } else if (source.getInteractiveStatus() === "ready") { this.__removeClass(this.__icon.getContentElement(), "rotate"); target.setTextColor("ready-green"); } else if (source.getInteractiveStatus() === "failed") { diff --git a/services/web/client/source/class/osparc/component/service/ServiceJumbo.js b/services/web/client/source/class/osparc/component/service/ServiceJumbo.js index 3fe501f640c..283d9a7624c 100644 --- a/services/web/client/source/class/osparc/component/service/ServiceJumbo.js +++ b/services/web/client/source/class/osparc/component/service/ServiceJumbo.js @@ -32,7 +32,7 @@ qx.Class.define("osparc.component.service.ServiceJumbo", { const text = serviceModel.getDescription ? serviceModel.getDescription() : ""; const footer = serviceModel.getContact ? serviceModel.getContact() : ""; this.base(arguments, label, text, icon, footer); - if (serviceModel != null) { // eslint-disable-line no-eq-null + if (serviceModel != null) { this.setServiceModel(serviceModel); } }, diff --git a/services/web/client/source/class/osparc/component/service/ServiceList.js b/services/web/client/source/class/osparc/component/service/ServiceList.js index 1c63c38dafc..85e74bcbcf6 100644 --- a/services/web/client/source/class/osparc/component/service/ServiceList.js +++ b/services/web/client/source/class/osparc/component/service/ServiceList.js @@ -100,7 +100,7 @@ qx.Class.define("osparc.component.service.ServiceList", { * @return True if no item is selected, false if there one or more item selected. */ isSelectionEmpty: function() { - if (this.__buttonGroup == null) { // eslint-disable-line no-eq-null + if (this.__buttonGroup == null) { return true; } return this.__buttonGroup.getSelection().length === 0; diff --git a/services/web/client/source/class/osparc/component/service/manager/ActivityTree.js b/services/web/client/source/class/osparc/component/service/manager/ActivityTree.js index b67b51df539..69a0b2f1518 100644 --- a/services/web/client/source/class/osparc/component/service/manager/ActivityTree.js +++ b/services/web/client/source/class/osparc/component/service/manager/ActivityTree.js @@ -215,8 +215,8 @@ qx.Class.define("osparc.component.service.manager.ActivityTree", { const queued = activity[key].queued; const limits = activity[key].limits; if (stats) { - row[4] = stats.cpuUsage == null ? null : (Math.round(stats.cpuUsage * 10) / 10) + (limits && limits.cpus ? `/${limits.cpus * 100}` : ""); // eslint-disable-line no-eq-null - row[5] = stats.memUsage == null ? null : (Math.round(stats.memUsage * 10) / 10) + (limits && limits.mem ? `/${limits.mem}` : ""); // eslint-disable-line no-eq-null + row[4] = stats.cpuUsage == null ? null : (Math.round(stats.cpuUsage * 10) / 10) + (limits && limits.cpus ? `/${limits.cpus * 100}` : ""); + row[5] = stats.memUsage == null ? null : (Math.round(stats.memUsage * 10) / 10) + (limits && limits.mem ? `/${limits.mem}` : ""); row[3] = this.tr("Running"); } if (queued) { diff --git a/services/web/client/source/class/osparc/component/widget/inputs/NodeOutputTree.js b/services/web/client/source/class/osparc/component/widget/inputs/NodeOutputTree.js index c6c4d64fd18..a9bbb1f4aaa 100644 --- a/services/web/client/source/class/osparc/component/widget/inputs/NodeOutputTree.js +++ b/services/web/client/source/class/osparc/component/widget/inputs/NodeOutputTree.js @@ -151,7 +151,7 @@ qx.Class.define("osparc.component.widget.inputs.NodeOutputTree", { portData.open = true; } else { portData.icon = osparc.data.Converters.fromTypeToIcon(ports[portKey].type); - portData.value = ports[portKey].value == null ? this.tr("no value") : ports[portKey].value; // eslint-disable-line no-eq-null + portData.value = ports[portKey].value == null ? this.tr("no value") : ports[portKey].value; } data.children.push(portData); } diff --git a/services/web/client/source/class/osparc/component/workbench/ServiceCatalog.js b/services/web/client/source/class/osparc/component/workbench/ServiceCatalog.js index a35ef6e8979..12d2413ac37 100644 --- a/services/web/client/source/class/osparc/component/workbench/ServiceCatalog.js +++ b/services/web/client/source/class/osparc/component/workbench/ServiceCatalog.js @@ -261,7 +261,7 @@ qx.Class.define("osparc.component.workbench.ServiceCatalog", { }, __onAddService: function(model) { - if (model == null && this.__serviceBrowser.isSelectionEmpty()) { // eslint-disable-line no-eq-null + if (model == null && this.__serviceBrowser.isSelectionEmpty()) { return; } diff --git a/services/web/client/source/class/osparc/data/Resources.js b/services/web/client/source/class/osparc/data/Resources.js index 40e08ea43f8..0417e9d5ebc 100644 --- a/services/web/client/source/class/osparc/data/Resources.js +++ b/services/web/client/source/class/osparc/data/Resources.js @@ -460,14 +460,14 @@ qx.Class.define("osparc.data.Resources", { */ fetch: function(resource, endpoint, params = {}, deleteId) { return new Promise((resolve, reject) => { - if (this.self().resources[resource] == null) { // eslint-disable-line no-eq-null + if (this.self().resources[resource] == null) { reject(Error(`Error while fetching ${resource}: the resource is not defined`)); } const resourceDefinition = this.self().resources[resource]; const res = new osparc.io.rest.Resource(resourceDefinition.endpoints); - if (!res.includesRoute(endpoint)) { // eslint-disable-line no-eq-null + if (!res.includesRoute(endpoint)) { reject(Error(`Error while fetching ${resource}: the endpoint is not defined`)); } diff --git a/services/web/client/source/class/osparc/desktop/NavigationBar.js b/services/web/client/source/class/osparc/desktop/NavigationBar.js index f13a788a2ae..9388f7b3438 100644 --- a/services/web/client/source/class/osparc/desktop/NavigationBar.js +++ b/services/web/client/source/class/osparc/desktop/NavigationBar.js @@ -327,7 +327,10 @@ qx.Class.define("osparc.desktop.NavigationBar", { this.tr("To create an issue in GitHub, you must have an account in GitHub and be already logged-in.") ); const contBtn = new qx.ui.toolbar.Button(this.tr("Continue"), "@FontAwesome5Solid/external-link-alt/12"); - contBtn.addListener("execute", () => window.open(osparc.component.widget.NewGHIssue.getNewIssueUrl()), this); + contBtn.addListener("execute", () => { + window.open(osparc.component.widget.NewGHIssue.getNewIssueUrl()); + issueConfirmationWindow.close(); + }, this); const loginBtn = new qx.ui.toolbar.Button(this.tr("Log in in GitHub"), "@FontAwesome5Solid/external-link-alt/12"); loginBtn.addListener("execute", () => window.open("https://github.com/login"), this); issueConfirmationWindow.addButton(contBtn); diff --git a/services/web/client/source/class/osparc/desktop/SidePanel.js b/services/web/client/source/class/osparc/desktop/SidePanel.js index 98059ef7fda..eaaf80802b0 100644 --- a/services/web/client/source/class/osparc/desktop/SidePanel.js +++ b/services/web/client/source/class/osparc/desktop/SidePanel.js @@ -141,7 +141,7 @@ qx.Class.define("osparc.desktop.SidePanel", { __getSplitpaneContainer: function() { const splitpane = this.__getParentSplitpane(); - if (splitpane == null) { // eslint-disable-line no-eq-null + if (splitpane == null) { return this; } let container = this; diff --git a/services/web/client/source/class/osparc/file/FilesTree.js b/services/web/client/source/class/osparc/file/FilesTree.js index f4a113c7674..0a53432c6a1 100644 --- a/services/web/client/source/class/osparc/file/FilesTree.js +++ b/services/web/client/source/class/osparc/file/FilesTree.js @@ -466,7 +466,7 @@ qx.Class.define("osparc.file.FilesTree", { }, __getFilesInTree: function(item, leaves) { - if (item.getChildren == null) { // eslint-disable-line no-eq-null + if (item.getChildren == null) { leaves.push(item); } else { for (let i=0; i this.setElement(element), this); } else { this.setElement(element); diff --git a/services/web/client/source/class/osparc/ui/table/cellrenderer/Percentage.js b/services/web/client/source/class/osparc/ui/table/cellrenderer/Percentage.js index ea33b0af32b..0570cbae974 100644 --- a/services/web/client/source/class/osparc/ui/table/cellrenderer/Percentage.js +++ b/services/web/client/source/class/osparc/ui/table/cellrenderer/Percentage.js @@ -28,7 +28,7 @@ qx.Class.define("osparc.ui.table.cellrenderer.Percentage", { members: { // overridden _getContentHtml: function(cellInfo) { - if (cellInfo.value == null || cellInfo.value < 0) { // eslint-disable-line no-eq-null + if (cellInfo.value == null || cellInfo.value < 0) { return ""; } const splitted = cellInfo.value.split("/"); diff --git a/services/web/client/source/class/osparc/ui/table/cellrenderer/Unit.js b/services/web/client/source/class/osparc/ui/table/cellrenderer/Unit.js index a47a71540c5..9cd4dd114d2 100644 --- a/services/web/client/source/class/osparc/ui/table/cellrenderer/Unit.js +++ b/services/web/client/source/class/osparc/ui/table/cellrenderer/Unit.js @@ -23,7 +23,7 @@ qx.Class.define("osparc.ui.table.cellrenderer.Unit", { members: { // overridden _getContentHtml: function(cellInfo) { - if (cellInfo.value == null || cellInfo.value < 0) { // eslint-disable-line no-eq-null + if (cellInfo.value == null || cellInfo.value < 0) { return ""; } return `${cellInfo.value} ${this.getUnit()}`; diff --git a/tests/e2e/.gitignore b/tests/e2e/.gitignore new file mode 100644 index 00000000000..ab05ba52bff --- /dev/null +++ b/tests/e2e/.gitignore @@ -0,0 +1,3 @@ +# coverage and screenshots for e2e testing +coverage/ +screenshots/ diff --git a/tests/e2e/README.md b/tests/e2e/README.md new file mode 100644 index 00000000000..f122ecd3233 --- /dev/null +++ b/tests/e2e/README.md @@ -0,0 +1,32 @@ +## To run the tests locally +```bash +cd tests/e2e +npm install +npm test +``` +## To debug the tests locally with VSCode +Add the following configuration to your local ``launch.json``: +```json +{ + "type": "node", + "request": "launch", + "name": "Debug e2e tests", + "runtimeArgs": [ + "--inspect-brk", + "${workspaceRoot}/tests/e2e/node_modules/.bin/jest", + "--runInBand", + "--colors" + ], + "cwd": "${workspaceFolder}/tests/e2e", + "restart": true, + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "port": 9229 +} +``` +Now you can run the tests by clicking on the Play button, using that configuration. It should allow you to insert breakpoints and inspect variables. +## To run the tutorials +```bash +cd tests/e2e +node tutorials/.js [ ] +``` diff --git a/tests/e2e/tests/register.test.js b/tests/e2e/tests/register.test.js index 67ac0e5c72e..8da728962f5 100644 --- a/tests/e2e/tests/register.test.js +++ b/tests/e2e/tests/register.test.js @@ -10,7 +10,7 @@ beforeAll(async () => { await page.goto(url); }, ourTimeout); -test('Register, Log In and Log Out', async () => { +test('Register and Log Out', async () => { page.on('response', async response => { if (response.url().endsWith("/config")) { try { @@ -55,6 +55,6 @@ test('Register, Log In and Log Out', async () => { } } }); - await auto.logIn(page, user, pass); + await auto.logOut(page); }, 30000); diff --git a/tests/e2e/tests/startupCalls.test.js b/tests/e2e/tests/startupCalls.test.js index 4f840f173d0..9982f12f0f4 100644 --- a/tests/e2e/tests/startupCalls.test.js +++ b/tests/e2e/tests/startupCalls.test.js @@ -8,9 +8,8 @@ const { beforeAll(async () => { await page.goto(url); - await auto.register(page, user, pass); - await auto.logIn(page, user, pass); + await page.waitFor(1000); }, ourTimeout); afterAll(async () => { @@ -18,8 +17,6 @@ afterAll(async () => { }, ourTimeout); describe('Calls after logging in', () => { - page.waitFor(1000); - test('Profile', async () => { const responseEnv = await utils.fetch('me'); expect(responseEnv.data["login"]).toBe(user); diff --git a/tests/e2e/tutorials/sleepers.js b/tests/e2e/tutorials/sleepers.js index 7892aaba0e8..401ca2ac421 100644 --- a/tests/e2e/tutorials/sleepers.js +++ b/tests/e2e/tutorials/sleepers.js @@ -6,7 +6,7 @@ const tutorialBase = require('./tutorialBase'); const args = process.argv.slice(2); if (args.length < 1) { - console.log('More arguments expented'); + console.log('More arguments expected'); process.exit(1); } const url = args[0]; @@ -24,8 +24,10 @@ async function runTutorial () { await tutorial.beforeScript(); await tutorial.goTo(); - await tutorial.registerIfNeeded(); - await tutorial.login(); + const needsRegister = await tutorial.registerIfNeeded(); + if (!needsRegister) { + await tutorial.login(); + } await tutorial.openTemplate(1000); // Some time for loading the workbench diff --git a/tests/e2e/tutorials/tutorialBase.js b/tests/e2e/tutorials/tutorialBase.js index 96c0ca648a4..6ec57677ceb 100644 --- a/tests/e2e/tutorials/tutorialBase.js +++ b/tests/e2e/tutorials/tutorialBase.js @@ -65,7 +65,9 @@ class TutorialBase { async registerIfNeeded() { if (this.__newUser) { await auto.register(this.__page, this.__user, this.__pass); + return true; } + return false; } async login() {