From 5ecf8c83db90f9022ec02c2b64aa26200bdcac4e Mon Sep 17 00:00:00 2001 From: Kazuhito Yokoi Date: Tue, 25 Feb 2020 18:46:02 +0900 Subject: [PATCH 1/4] Support to input JSON path in debug node property --- test/editor/pageobjects/nodes/core/common/21-debug_page.js | 2 ++ test/editor/specs/scenario/cookbook_httprequests_uispec.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/editor/pageobjects/nodes/core/common/21-debug_page.js b/test/editor/pageobjects/nodes/core/common/21-debug_page.js index 602d4d542..56854b195 100644 --- a/test/editor/pageobjects/nodes/core/common/21-debug_page.js +++ b/test/editor/pageobjects/nodes/core/common/21-debug_page.js @@ -33,6 +33,8 @@ debugNode.prototype.setOutput = function (complete) { // Select the "msg" type. browser.clickWithWait('//div[contains(@class, "red-ui-typedInput-options")][1]/a[1]'); // Input the path in msg. + browser.clickWithWait('//*[contains(@class, "red-ui-typedInput-input")]/input'); + browser.keys(Array('payload'.length).fill('Backspace')); browser.setValue('//*[contains(@class, "red-ui-typedInput-input")]/input', complete); } else { // Select the "complete msg object" type. diff --git a/test/editor/specs/scenario/cookbook_httprequests_uispec.js b/test/editor/specs/scenario/cookbook_httprequests_uispec.js index 785451429..797b06041 100644 --- a/test/editor/specs/scenario/cookbook_httprequests_uispec.js +++ b/test/editor/specs/scenario/cookbook_httprequests_uispec.js @@ -190,7 +190,7 @@ describe('cookbook', function () { httpRequestNode.clickOk(); debugNode.edit(); - debugNode.setOutput('.title'); + debugNode.setOutput('payload.title'); debugNode.clickOk(); injectNode.connect(changeNodeSetPost); From f7d2314d64eb0af5fa0db9f9af942da462531fb5 Mon Sep 17 00:00:00 2001 From: Kazuhito Yokoi Date: Tue, 25 Feb 2020 19:01:17 +0900 Subject: [PATCH 2/4] Add page object code for split node and remove duplicated code --- .../editor/pageobjects/nodes/core/sequence/17-split_page.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/editor/pageobjects/nodes/core/sequence/17-split_page.js b/test/editor/pageobjects/nodes/core/sequence/17-split_page.js index 6029e4d90..3c8c70aa5 100644 --- a/test/editor/pageobjects/nodes/core/sequence/17-split_page.js +++ b/test/editor/pageobjects/nodes/core/sequence/17-split_page.js @@ -18,13 +18,13 @@ var util = require('util'); var nodePage = require('../../node_page'); -function joinNode(id) { +function splitNode(id) { nodePage.call(this, id); } -util.inherits(joinNode, nodePage); +util.inherits(splitNode, nodePage); -module.exports = joinNode; +module.exports = splitNode; function joinNode(id) { nodePage.call(this, id); From 21c57f968a0f92e696dbc532a6669995645e24b6 Mon Sep 17 00:00:00 2001 From: Kazuhito Yokoi Date: Tue, 25 Feb 2020 19:02:46 +0900 Subject: [PATCH 3/4] Add page object code for nodes --- .../editor/pageobjects/editor/palette_page.js | 8 +++- .../nodes/core/common/24-complete_page.js | 47 ++++++++++++++++++ .../nodes/core/common/25-catch_page.js | 48 +++++++++++++++++++ .../nodes/core/common/25-status_page.js | 48 +++++++++++++++++++ .../nodes/core/common/90-comment_page.js | 27 +++++++++++ .../nodes/core/function/89-delay_page.js | 33 +++++++++++++ .../nodes/core/sequence/19-batch_page.js | 39 +++++++++++++++ .../pageobjects/nodes/nodefactory_page.js | 12 +++++ 8 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 test/editor/pageobjects/nodes/core/common/24-complete_page.js create mode 100644 test/editor/pageobjects/nodes/core/common/25-catch_page.js create mode 100644 test/editor/pageobjects/nodes/core/common/25-status_page.js create mode 100644 test/editor/pageobjects/nodes/core/common/90-comment_page.js create mode 100644 test/editor/pageobjects/nodes/core/function/89-delay_page.js create mode 100644 test/editor/pageobjects/nodes/core/sequence/19-batch_page.js diff --git a/test/editor/pageobjects/editor/palette_page.js b/test/editor/pageobjects/editor/palette_page.js index 97077059b..6af0b5271 100644 --- a/test/editor/pageobjects/editor/palette_page.js +++ b/test/editor/pageobjects/editor/palette_page.js @@ -18,11 +18,16 @@ var idMap = { // common "inject": ".red-ui-palette-node[data-palette-type='inject']", "debug": ".red-ui-palette-node[data-palette-type='debug']", + "complete": ".red-ui-palette-node[data-palette-type='complete']", + "catch": ".red-ui-palette-node[data-palette-type='catch']", + "status": ".red-ui-palette-node[data-palette-type='status']", + "comment": ".red-ui-palette-node[data-palette-type='comment']", // function "function": ".red-ui-palette-node[data-palette-type='function']", "change": ".red-ui-palette-node[data-palette-type='change']", "range": ".red-ui-palette-node[data-palette-type='range']", "template": ".red-ui-palette-node[data-palette-type='template']", + "delay": ".red-ui-palette-node[data-palette-type='delay']", // network "mqttIn": ".red-ui-palette-node[data-palette-type='mqtt in']", "mqttOut": ".red-ui-palette-node[data-palette-type='mqtt out']", @@ -30,8 +35,9 @@ var idMap = { "httpResponse": ".red-ui-palette-node[data-palette-type='http response']", "httpRequest": ".red-ui-palette-node[data-palette-type='http request']", // sequence - "join": ".red-ui-palette-node[data-palette-type='join']", "split": ".red-ui-palette-node[data-palette-type='split']", + "join": ".red-ui-palette-node[data-palette-type='join']", + "batch": ".red-ui-palette-node[data-palette-type='batch']", // parser "csv": ".red-ui-palette-node[data-palette-type='csv']", "html": ".red-ui-palette-node[data-palette-type='html']", diff --git a/test/editor/pageobjects/nodes/core/common/24-complete_page.js b/test/editor/pageobjects/nodes/core/common/24-complete_page.js new file mode 100644 index 000000000..558ee709a --- /dev/null +++ b/test/editor/pageobjects/nodes/core/common/24-complete_page.js @@ -0,0 +1,47 @@ +/** + * Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +var util = require('util'); + +var nodePage = require('../../node_page'); + +function completeNode(id) { + nodePage.call(this, id); +} + +util.inherits(completeNode, nodePage); + +completeNode.prototype.setScope = function (scope) { + if (scope) { + browser.clickWithWait('//*[@id="node-input-complete-target-select"]'); + browser.pause(1000); + if (Array.isArray(scope)) { + for (var i = 0; i < scope.length; i++) { + browser.moveToObject(scope[i].id); + browser.buttonDown(); + browser.buttonUp(); + } + } else { + browser.moveToObject(scope.id); + browser.buttonDown(); + browser.buttonUp(); + } + browser.clickWithWait('//*[contains(@class, "red-ui-notification")]/div/button[2]'); + browser.pause(1000); + } +} + +module.exports = completeNode; diff --git a/test/editor/pageobjects/nodes/core/common/25-catch_page.js b/test/editor/pageobjects/nodes/core/common/25-catch_page.js new file mode 100644 index 000000000..89bcb7f1e --- /dev/null +++ b/test/editor/pageobjects/nodes/core/common/25-catch_page.js @@ -0,0 +1,48 @@ +/** + * Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +var util = require('util'); + +var nodePage = require('../../node_page'); + +function catchNode(id) { + nodePage.call(this, id); +} + +util.inherits(catchNode, nodePage); + +catchNode.prototype.setScope = function (scope) { + if (scope) { + browser.selectWithWait('#node-input-scope-select', 'target'); + browser.clickWithWait('//*[@id="node-input-catch-target-select"]'); + browser.pause(1000); + if (Array.isArray(scope)) { + for (var i = 0; i < scope.length; i++) { + browser.moveToObject(scope[i].id); + browser.buttonDown(); + browser.buttonUp(); + } + } else { + browser.moveToObject(scope.id); + browser.buttonDown(); + browser.buttonUp(); + } + browser.clickWithWait('//*[contains(@class, "red-ui-notification")]/div/button[2]'); + browser.pause(1000); + } +} + +module.exports = catchNode; diff --git a/test/editor/pageobjects/nodes/core/common/25-status_page.js b/test/editor/pageobjects/nodes/core/common/25-status_page.js new file mode 100644 index 000000000..6de0fcde7 --- /dev/null +++ b/test/editor/pageobjects/nodes/core/common/25-status_page.js @@ -0,0 +1,48 @@ +/** + * Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +var util = require('util'); + +var nodePage = require('../../node_page'); + +function statusNode(id) { + nodePage.call(this, id); +} + +util.inherits(statusNode, nodePage); + +statusNode.prototype.setScope = function (scope) { + if (scope) { + browser.selectWithWait('#node-input-scope-select', 'target'); + browser.clickWithWait('//*[@id="node-input-status-target-select"]'); + browser.pause(1000); + if (Array.isArray(scope)) { + for (var i = 0; i < scope.length; i++) { + browser.moveToObject(scope[i].id); + browser.buttonDown(); + browser.buttonUp(); + } + } else { + browser.moveToObject(scope.id); + browser.buttonDown(); + browser.buttonUp(); + } + browser.clickWithWait('//*[contains(@class, "red-ui-notification")]/div/button[2]'); + browser.pause(1000); + } +} + +module.exports = statusNode; diff --git a/test/editor/pageobjects/nodes/core/common/90-comment_page.js b/test/editor/pageobjects/nodes/core/common/90-comment_page.js new file mode 100644 index 000000000..2687dacfe --- /dev/null +++ b/test/editor/pageobjects/nodes/core/common/90-comment_page.js @@ -0,0 +1,27 @@ +/** + * Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +var util = require('util'); + +var nodePage = require('../../node_page'); + +function commentNode(id) { + nodePage.call(this, id); +} + +util.inherits(commentNode, nodePage); + +module.exports = commentNode; diff --git a/test/editor/pageobjects/nodes/core/function/89-delay_page.js b/test/editor/pageobjects/nodes/core/function/89-delay_page.js new file mode 100644 index 000000000..a4e2197e4 --- /dev/null +++ b/test/editor/pageobjects/nodes/core/function/89-delay_page.js @@ -0,0 +1,33 @@ +/** + * Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +var util = require("util"); + +var nodePage = require("../../node_page"); + +var keyPage = require("../../../util/key_page"); + +function delayNode(id) { + nodePage.call(this, id); +} + +util.inherits(delayNode, nodePage); + +delayNode.prototype.setTimeout = function (timeout) { + browser.setValue('//*[@id="node-input-timeout"]', timeout); +} + +module.exports = delayNode; diff --git a/test/editor/pageobjects/nodes/core/sequence/19-batch_page.js b/test/editor/pageobjects/nodes/core/sequence/19-batch_page.js new file mode 100644 index 000000000..0d7b13028 --- /dev/null +++ b/test/editor/pageobjects/nodes/core/sequence/19-batch_page.js @@ -0,0 +1,39 @@ +/** + * Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +var util = require('util'); + +var nodePage = require('../../node_page'); + +function batchNode(id) { + nodePage.call(this, id); +} + +batchNode.prototype.setMode = function (mode) { + browser.selectWithWait('#node-input-mode', mode); +} + +batchNode.prototype.setCount = function (count) { + browser.setValue('#node-input-count', count); +} + +batchNode.prototype.setOverlap = function (overlap) { + browser.setValue('#node-input-overlap', overlap); +} + +util.inherits(batchNode, nodePage); + +module.exports = batchNode; diff --git a/test/editor/pageobjects/nodes/nodefactory_page.js b/test/editor/pageobjects/nodes/nodefactory_page.js index 33193e112..17949e313 100644 --- a/test/editor/pageobjects/nodes/nodefactory_page.js +++ b/test/editor/pageobjects/nodes/nodefactory_page.js @@ -16,10 +16,15 @@ var injectNode = require('./core/common/20-inject_page'); var debugNode = require('./core/common/21-debug_page'); +var completeNode = require('./core/common/24-complete_page'); +var catchNode = require('./core/common/25-catch_page'); +var statusNode = require('./core/common/25-status_page'); +var commentNode = require('./core/common/90-comment_page'); var functionNode = require('./core/function/10-function_page'); var changeNode = require('./core/function/15-change_page'); var rangeNode = require('./core/function/16-range_page'); var templateNode = require('./core/function/80-template_page'); +var delayNode = require('./core/function/89-delay_page'); var mqttInNode = require('./core/network/10-mqttin_page'); var mqttOutNode = require('./core/network/10-mqttout_page'); var httpInNode = require('./core/network/21-httpin_page'); @@ -27,6 +32,7 @@ var httpResponseNode = require('./core/network/21-httpresponse_page'); var httpRequestNode = require('./core/network/21-httprequest_page'); var splitNode = require('./core/sequence/17-split_page'); var joinNode = require('./core/sequence/17-split_page'); +var batchNode = require('./core/sequence/19-batch_page'); var csvNode = require('./core/parsers/70-CSV_page'); var htmlNode = require('./core/parsers/70-HTML_page'); var jsonNode = require('./core/parsers/70-JSON_page'); @@ -38,11 +44,16 @@ var nodeCatalog = { // common "inject": injectNode, "debug": debugNode, + "complete": completeNode, + "catch": catchNode, + "status": statusNode, + "comment": commentNode, // function "function": functionNode, "change": changeNode, "range": rangeNode, "template": templateNode, + "delay": delayNode, // network "mqttIn": mqttInNode, "mqttOut": mqttOutNode, @@ -52,6 +63,7 @@ var nodeCatalog = { // sequence "split": splitNode, "join": joinNode, + "batch": batchNode, // parser "csv": csvNode, "html": htmlNode, From 00477fd67a159faf3fb26cefea503fbd483a2b6a Mon Sep 17 00:00:00 2001 From: Kazuhito Yokoi Date: Tue, 25 Feb 2020 19:56:48 +0900 Subject: [PATCH 4/4] Add UI test case for error handling --- .../scenario/cookbook_errorhandling_uispec.js | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 test/editor/specs/scenario/cookbook_errorhandling_uispec.js diff --git a/test/editor/specs/scenario/cookbook_errorhandling_uispec.js b/test/editor/specs/scenario/cookbook_errorhandling_uispec.js new file mode 100644 index 000000000..5285c5c0f --- /dev/null +++ b/test/editor/specs/scenario/cookbook_errorhandling_uispec.js @@ -0,0 +1,74 @@ +/** + * Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +var when = require('when'); +var should = require('should'); +var fs = require('fs-extra'); + +var helper = require('../../editor_helper'); +var debugTab = require('../../pageobjects/editor/debugTab_page'); +var workspace = require('../../pageobjects/editor/workspace_page'); +var specUtil = require('../../pageobjects/util/spec_util_page'); + +var httpNodeRoot = '/api'; + +// https://cookbook.nodered.org/ +describe('cookbook', function () { + beforeEach(function () { + workspace.init(); + }); + + before(function () { + helper.startServer(); + }); + + after(function () { + helper.stopServer(); + }); + + describe('messages', function () { + it('trigger a flow when a node throws an error', function () { + var injectNode = workspace.addNode('inject'); + var functionNode = workspace.addNode('function'); + var catchNode = workspace.addNode('catch', 0 , 80); + var debugNode = workspace.addNode('debug'); + + functionNode.edit(); + functionNode.setFunction('node.error("an example error", msg);'); + functionNode.clickOk(); + + catchNode.edit(); + catchNode.setScope(functionNode); + catchNode.clickOk(); + + debugNode.edit(); + debugNode.setOutput('error'); + debugNode.clickOk(); + + injectNode.connect(functionNode); + catchNode.connect(debugNode); + + workspace.deploy(); + + debugTab.open(); + injectNode.clickLeftButton(); + debugTab.getMessage().should.eql(['"an example error"', 'function']); + }); + + // skip this case since the flow outputs random results. + it.skip('automatically retry an action after an error'); + }); +});