mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Merge pull request #2426 from kazuhitoyokoi/master-fixuitest
Improvements of UI testing
This commit is contained in:
		| @@ -28,7 +28,7 @@ module.exports = function(grunt) { | ||||
|  | ||||
|     var nonHeadless = grunt.option('non-headless'); | ||||
|     if (nonHeadless) { | ||||
|         process.env.NODE_RED_NON_HEADLESS = 'true'; | ||||
|         process.env.NODE_RED_NON_HEADLESS = true; | ||||
|     } | ||||
|     grunt.initConfig({ | ||||
|         pkg: grunt.file.readJSON('package.json'), | ||||
|   | ||||
| @@ -57,6 +57,9 @@ function cleanup(flowFile) { | ||||
|     deleteFile(homeDir + "/." + flowFile + ".backup"); | ||||
|     deleteFile(homeDir + "/" + credentialFile); | ||||
|     deleteFile(homeDir + "/." + credentialFile + ".backup"); | ||||
|     deleteFile(homeDir + "/package.json"); | ||||
|     deleteFile(homeDir + "/lib/flows"); | ||||
|     deleteFile(homeDir + "/lib"); | ||||
| } | ||||
|  | ||||
| function deleteFile(flowFile) { | ||||
| @@ -66,7 +69,7 @@ function deleteFile(flowFile) { | ||||
|             fs.unlinkSync(flowFile); | ||||
|         } | ||||
|     } catch (e) {} | ||||
| }; | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|     startServer: function() { | ||||
| @@ -104,7 +107,7 @@ module.exports = { | ||||
|                 }); | ||||
|             }); | ||||
|             browser.url(url); | ||||
|             browser.waitForExist(".red-ui-palette-node[data-palette-type='inject']") | ||||
|             browser.waitForExist(".red-ui-palette-node[data-palette-type='inject']"); | ||||
|         } catch (err) { | ||||
|             console.log(err); | ||||
|             throw err; | ||||
|   | ||||
| @@ -15,18 +15,15 @@ | ||||
|  **/ | ||||
|  | ||||
| var when = require("when"); | ||||
|  | ||||
| var events = require("nr-test-utils").require("@node-red/runtime/lib/events.js"); | ||||
|  | ||||
| var palette = require("./palette_page"); | ||||
| var nodeFactory = require("../nodes/nodefactory_page"); | ||||
|  | ||||
| var keyPage = require("../util/key_page"); | ||||
| var flowLayout = { | ||||
|     flowRightEnd : 600, | ||||
|     widthInterval : 300, | ||||
|     heightInterval : 80 | ||||
| }; | ||||
|  | ||||
| var previousX = -flowLayout.widthInterval; | ||||
| var previousY = 0; | ||||
|  | ||||
| @@ -44,6 +41,9 @@ function addNode(type, x, y) { | ||||
|             previousY = previousY + flowLayout.heightInterval; | ||||
|         } | ||||
|     } | ||||
|     browser.waitForVisible('#red-ui-palette-search'); | ||||
|     browser.setValue('//*[@id="red-ui-palette-search"]/div/input', type.replace(/([A-Z])/g,' $1').toLowerCase()); | ||||
|     browser.pause(300); | ||||
|     browser.waitForVisible(palette.getId(type)); | ||||
|     browser.moveToObject(palette.getId(type)); | ||||
|     browser.buttonDown(); | ||||
| @@ -57,13 +57,10 @@ function addNode(type, x, y) { | ||||
| } | ||||
|  | ||||
| function deleteAllNodes() { | ||||
|     browser.waitForVisible('.red-ui-workspace-chart-event-layer'); | ||||
|     try { | ||||
|         browser.click('.red-ui-workspace-chart-event-layer'); | ||||
|     } catch (e) { | ||||
|         console.log(e); | ||||
|     } | ||||
|     browser.keys(['Control', 'a', 'a', 'Control']); // call twice to release the keys. | ||||
|     browser.waitForVisible('//*[contains(@class, "active")]/a[@class="red-ui-tab-label"]'); | ||||
|     browser.click('//*[contains(@class, "active")]/a[@class="red-ui-tab-label"]'); | ||||
|     browser.pause(1000); | ||||
|     browser.keys(keyPage.selectAll()); | ||||
|     browser.keys(['Delete']); | ||||
| } | ||||
|  | ||||
| @@ -78,7 +75,7 @@ function deploy() { | ||||
|             browser.clickWithWait('#red-ui-header-button-deploy'); | ||||
|         }); | ||||
|     }); | ||||
|     browser.waitForText('#red-ui-header-button-deploy', 2000); | ||||
|     browser.waitForText('#red-ui-header-button-deploy', 10000); | ||||
|     // Need additional wait until buttons becomes clickable. | ||||
|     browser.pause(50); | ||||
| } | ||||
|   | ||||
| @@ -26,16 +26,13 @@ function debugNode(id) { | ||||
| 
 | ||||
| util.inherits(debugNode, nodePage); | ||||
| 
 | ||||
| debugNode.prototype.setOutput = function(complete) { | ||||
| debugNode.prototype.setOutput = function (complete) { | ||||
|     // Open a payload type list.
 | ||||
|     browser.clickWithWait('//*[contains(@class, "red-ui-typedInput-container")]/button'); | ||||
|     if (complete !== 'true') { | ||||
|         // 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(keyPage.selectAll()); | ||||
|         browser.keys(['Delete']); | ||||
|         browser.setValue('//*[contains(@class, "red-ui-typedInput-input")]/input', complete); | ||||
|     } else { | ||||
|         // Select the "complete msg object" type.
 | ||||
| @@ -26,12 +26,11 @@ function functionNode(id) { | ||||
| 
 | ||||
| util.inherits(functionNode, nodePage); | ||||
| 
 | ||||
| functionNode.prototype.setFunction = function(func) { | ||||
| functionNode.prototype.setFunction = function (func) { | ||||
|     browser.clickWithWait('#node-input-func-editor'); | ||||
|     browser.keys(keyPage.selectAll()); | ||||
|     for (var i = 0; i < func.length; i++) { | ||||
|         browser.keys([func.charAt(i)]); | ||||
|     } | ||||
|     browser.keys(['Delete']); | ||||
|     browser.keys(func); | ||||
|     // Delete the unnecessary code that ace editor does the autocompletion.
 | ||||
|     browser.keys(keyPage.selectToEnd()); | ||||
|     browser.keys(['Delete']); | ||||
| @@ -49,8 +49,8 @@ function setT(t, index) { | ||||
| } | ||||
| 
 | ||||
| // It is better to create a function whose input value is the object type in the future,
 | ||||
| changeNode.prototype.ruleSet = function(p, pt, to, tot, index) { | ||||
|     index = index ? index : 1; | ||||
| changeNode.prototype.ruleSet = function (p, pt, to, tot, index) { | ||||
|     index = index || 1; | ||||
|     setT("set", index); | ||||
|     if (pt) { | ||||
|         browser.clickWithWait('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[1]/div/button[1]'); | ||||
| @@ -68,23 +68,23 @@ changeNode.prototype.ruleSet = function(p, pt, to, tot, index) { | ||||
|         browser.clickWithWait(totXPath); | ||||
|     } | ||||
|     if (to) { | ||||
|         browser.setValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[2]/div[2]/div/input' , to); | ||||
|         browser.setValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[2]/div[2]/div/input', to); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| changeNode.prototype.ruleDelete = function(index) { | ||||
|     index = index ? index : 1; | ||||
| changeNode.prototype.ruleDelete = function (index) { | ||||
|     index = index || 1; | ||||
|     setT("delete", index); | ||||
| } | ||||
| 
 | ||||
| changeNode.prototype.ruleMove = function(p, to, index) { | ||||
|     index = index ? index : 1; | ||||
| changeNode.prototype.ruleMove = function (p, to, index) { | ||||
|     index = index || 1; | ||||
|     setT("move", index); | ||||
|     browser.setValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[1]/div/div/input', p); | ||||
|     browser.setValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[4]/div[2]/div/input', to); | ||||
| } | ||||
| 
 | ||||
| changeNode.prototype.addRule = function() { | ||||
| changeNode.prototype.addRule = function () { | ||||
|     browser.clickWithWait('//*[@id="dialog-form"]/div[3]/div/a'); | ||||
| } | ||||
| 
 | ||||
| @@ -26,21 +26,19 @@ function templateNode(id) { | ||||
| 
 | ||||
| util.inherits(templateNode, nodePage); | ||||
| 
 | ||||
| templateNode.prototype.setSyntax = function(syntax) { | ||||
| templateNode.prototype.setSyntax = function (syntax) { | ||||
|     browser.selectWithWait('#node-input-syntax', syntax); | ||||
| } | ||||
| 
 | ||||
| templateNode.prototype.setFormat = function(format) { | ||||
| templateNode.prototype.setFormat = function (format) { | ||||
|     browser.selectWithWait('#node-input-format', format); | ||||
| } | ||||
| 
 | ||||
| templateNode.prototype.setTemplate = function(template) { | ||||
| templateNode.prototype.setTemplate = function (template) { | ||||
|     browser.clickWithWait('#node-input-template-editor'); | ||||
|     browser.keys(keyPage.selectAll()); | ||||
|     // Need to add a character one by one since some words such as 'Control' are treated as a special word.
 | ||||
|     for (var i = 0; i < template.length; i++) { | ||||
|         browser.keys([template.charAt(i)]); | ||||
|     } | ||||
|     browser.keys(['Delete']); | ||||
|     browser.keys(template); | ||||
|     browser.keys(keyPage.selectToEnd()); | ||||
|     browser.keys(['Delete']); | ||||
|     // Need to wait until ace editor correctly checks the syntax.
 | ||||
| @@ -23,14 +23,14 @@ function setServer(broker, port) { | ||||
| function clickOk() { | ||||
|     browser.clickWithWait('#node-config-dialog-ok'); | ||||
|     // Wait until an config dialog closes.
 | ||||
|     browser.waitForVisible('#node-config-dialog-ok', 4000, true); | ||||
|     browser.waitForVisible('#node-config-dialog-ok', 10000, true); | ||||
| } | ||||
| 
 | ||||
| function edit() { | ||||
|     browser.waitForVisible('#node-input-lookup-broker'); | ||||
|     browser.click('#node-input-lookup-broker'); | ||||
|     // Wait until a config dialog opens.
 | ||||
|     browser.waitForVisible('#node-config-dialog-ok', 4000); | ||||
|     browser.waitForVisible('#node-config-dialog-ok', 10000); | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| @@ -18,21 +18,24 @@ function Node(id) { | ||||
|     this.id = '//*[@id="' + id + '"]'; | ||||
| } | ||||
|  | ||||
| Node.prototype.edit = function() { | ||||
|     browser.clickWithWait(this.id); | ||||
|     browser.clickWithWait(this.id); | ||||
| Node.prototype.edit = function () { | ||||
|     browser.waitForVisible(this.id); | ||||
|     browser.moveToObject(this.id); | ||||
|     browser.buttonDown(); | ||||
|     browser.buttonUp(); | ||||
|     browser.keys(['Enter']); | ||||
|     // Wait until an edit dialog opens. | ||||
|     browser.waitForVisible('#node-dialog-ok', 4000); | ||||
|     browser.waitForVisible('#node-dialog-ok', 10000); | ||||
| } | ||||
|  | ||||
| Node.prototype.clickOk = function() { | ||||
| Node.prototype.clickOk = function () { | ||||
|     browser.clickWithWait('#node-dialog-ok'); | ||||
|     // Wait untile an edit dialog closes. | ||||
|     browser.waitForVisible('#node-dialog-ok', 4000, true); | ||||
|     browser.waitForVisible('#node-dialog-ok', 10000, true); | ||||
|     browser.pause(50); | ||||
| } | ||||
|  | ||||
| Node.prototype.connect = function(targetNode) { | ||||
| Node.prototype.connect = function (targetNode) { | ||||
|     var outputPort = this.id + '/*[@class="red-ui-flow-port-output"]'; | ||||
|     var inputPort = targetNode.id + '/*[@class="red-ui-flow-port-input"]'; | ||||
|     browser.dragAndDrop(outputPort, inputPort) | ||||
|   | ||||
| @@ -14,46 +14,46 @@ | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
|  | ||||
| var injectNode = require('./core/core/20-inject_page'); | ||||
| var debugNode = require('./core/core/58-debug_page'); | ||||
| var templateNode = require('./core/core/80-template_page'); | ||||
| var functionNode = require('./core/core/80-function_page'); | ||||
| var mqttInNode = require('./core/io/10-mqttin_page'); | ||||
| var mqttOutNode = require('./core/io/10-mqttout_page'); | ||||
| var httpInNode = require('./core/io/21-httpin_page'); | ||||
| var httpResponseNode = require('./core/io/21-httpresponse_page'); | ||||
| var changeNode = require('./core/logic/15-change_page'); | ||||
| var rangeNode = require('./core/logic/16-range_page'); | ||||
| var httpRequestNode = require('./core/io/21-httprequest_page'); | ||||
| var injectNode = require('./core/common/20-inject_page'); | ||||
| var debugNode = require('./core/common/21-debug_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 mqttInNode = require('./core/network/10-mqttin_page'); | ||||
| var mqttOutNode = require('./core/network/10-mqttout_page'); | ||||
| var httpInNode = require('./core/network/21-httpin_page'); | ||||
| var httpResponseNode = require('./core/network/21-httpresponse_page'); | ||||
| var httpRequestNode = require('./core/network/21-httprequest_page'); | ||||
| var htmlNode = require('./core/parsers/70-HTML_page'); | ||||
| var jsonNode = require('./core/parsers/70-JSON_page'); | ||||
| var fileInNode = require('./core/storage/50-filein_page'); | ||||
|  | ||||
| var fileInNode = require('./core/storage/10-filein_page'); | ||||
|  | ||||
| var nodeCatalog = { | ||||
|     // input | ||||
|     // common | ||||
|     "inject": injectNode, | ||||
|     "httpIn": httpInNode, | ||||
|     "mqttIn":mqttInNode, | ||||
|     // output | ||||
|     "debug": debugNode, | ||||
|     "httpResponse": httpResponseNode, | ||||
|     "mqttOut": mqttOutNode, | ||||
|     // function | ||||
|     "function": functionNode, | ||||
|     "template": templateNode, | ||||
|     "change": changeNode, | ||||
|     "range": rangeNode, | ||||
|     "template": templateNode, | ||||
|     // network | ||||
|     "mqttIn": mqttInNode, | ||||
|     "mqttOut": mqttOutNode, | ||||
|     "httpIn": httpInNode, | ||||
|     "httpResponse": httpResponseNode, | ||||
|     "httpRequest": httpRequestNode, | ||||
|     // parser | ||||
|     "html": htmlNode, | ||||
|     "json":jsonNode, | ||||
|     "json": jsonNode, | ||||
|     // storage | ||||
|     "fileIn": fileInNode, | ||||
| } | ||||
|     "fileIn": fileInNode | ||||
| }; | ||||
|  | ||||
| function create(type, id) { | ||||
|     var node = nodeCatalog[type]; | ||||
|     return new node(id); | ||||
|     var Node = nodeCatalog[type]; | ||||
|     return new Node(id); | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|   | ||||
| @@ -17,21 +17,20 @@ | ||||
| var os = require("os"); | ||||
|  | ||||
| var shortCutKeyMap = { | ||||
|     "selectAll": ['Control', 'a', 'Control'], | ||||
|     "selectAll": ['Control', 'a', 'a', 'Control'], | ||||
|     "selectToEnd": ['Control', 'Shift', 'End', 'Shift', 'Control'], | ||||
| }; | ||||
|  | ||||
| var shortCutKeyMapForMac = { | ||||
|     "selectAll": ['Command', 'a', 'Command'], | ||||
|     "selectAll": ['Command', 'a', 'a', 'Command'], | ||||
|     "selectToEnd": ['Command', 'Shift', 'ArrowDown', 'Shift', 'Command'], | ||||
| }; | ||||
|  | ||||
| function getShortCutKey(type) { | ||||
|     if (os.type() === "Darwin") { | ||||
|     if (os.type() === 'Darwin') { | ||||
|         return shortCutKeyMapForMac[type]; | ||||
|     } else { | ||||
|         return shortCutKeyMap[type]; | ||||
|     } | ||||
|     return shortCutKeyMap[type]; | ||||
| } | ||||
|  | ||||
| function selectAll() { | ||||
|   | ||||
| @@ -22,42 +22,45 @@ 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 mqttConfig = require('../../pageobjects/nodes/core/io/10-mqttconfig_page.js'); | ||||
| var mqttConfig = require('../../pageobjects/nodes/core/network/10-mqttconfig_page.js'); | ||||
|  | ||||
| var httpNodeRoot = "/api"; | ||||
|  | ||||
| var mqttServer; | ||||
| var mosca = require('mosca'); | ||||
| var moscaSettings = { | ||||
|     port: 1883, | ||||
|     port: parseInt(Math.random() * 16383 + 49152), | ||||
|     persistence: { | ||||
|         // Needs for retaining messages. | ||||
|         factory: mosca.persistence.Memory | ||||
|     } | ||||
| }; | ||||
|  | ||||
|  | ||||
| // https://cookbook.nodered.org/ | ||||
| describe('cookbook', function() { | ||||
|     beforeEach(function() { | ||||
| describe('cookbook', function () { | ||||
|     beforeEach(function () { | ||||
|         workspace.init(); | ||||
|     }); | ||||
|  | ||||
|     before(function() { | ||||
|         browser.call(function() { | ||||
|             return new Promise(function(resolve, reject) { | ||||
|                 mqttServer = new mosca.Server(moscaSettings, function() { | ||||
|                     resolve(); | ||||
|     before(function () { | ||||
|         browser.call(function () { | ||||
|             return new Promise(function (resolve, reject) { | ||||
|                 mqttServer = new mosca.Server(moscaSettings, function (err) { | ||||
|                     if (err) { | ||||
|                         reject(err); | ||||
|                     } else { | ||||
|                         resolve(); | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
|         helper.startServer(); | ||||
|     }); | ||||
|  | ||||
|     after(function() { | ||||
|         browser.call(function() { | ||||
|             return new Promise(function(resolve, reject) { | ||||
|                 mqttServer.close(function() { | ||||
|     after(function () { | ||||
|         browser.call(function () { | ||||
|             return new Promise(function (resolve, reject) { | ||||
|                 mqttServer.close(function () { | ||||
|                     resolve(); | ||||
|                 }); | ||||
|             }); | ||||
| @@ -65,20 +68,20 @@ describe('cookbook', function() { | ||||
|         helper.stopServer(); | ||||
|     }); | ||||
|  | ||||
|     describe('MQTT', function() { | ||||
|         it('Add an MQTT broker to prepare for UI test', function() { | ||||
|     describe('MQTT', function () { | ||||
|         it('Add an MQTT broker to prepare for UI test', function () { | ||||
|             var mqttOutNode = workspace.addNode("mqttOut"); | ||||
|  | ||||
|             mqttOutNode.edit(); | ||||
|             mqttConfig.edit(); | ||||
|             mqttConfig.setServer("localhost"); | ||||
|             mqttConfig.setServer("localhost", moscaSettings.port); | ||||
|             mqttConfig.clickOk(); | ||||
|             mqttOutNode.clickOk(); | ||||
|  | ||||
|             workspace.deploy(); | ||||
|         }); | ||||
|  | ||||
|         it('Connect to an MQTT broker', function() { | ||||
|         it('Connect to an MQTT broker', function () { | ||||
|             var injectNode = workspace.addNode("inject"); | ||||
|             var mqttOutNode = workspace.addNode("mqttOut"); | ||||
|  | ||||
| @@ -112,7 +115,7 @@ describe('cookbook', function() { | ||||
|         // skip this case since it is same as other cases. | ||||
|         it.skip('Publish messages to a topic'); | ||||
|  | ||||
|         it('Set the topic of a published message', function() { | ||||
|         it('Set the topic of a published message', function () { | ||||
|             var injectNode = workspace.addNode("inject"); | ||||
|             var mqttOutNode = workspace.addNode("mqttOut"); | ||||
|  | ||||
| @@ -144,7 +147,7 @@ describe('cookbook', function() { | ||||
|             debugTab.getMessage().should.eql('"22"'); | ||||
|         }); | ||||
|  | ||||
|         it('Publish a retained message to a topic', function() { | ||||
|         it('Publish a retained message to a topic', function () { | ||||
|             var injectNode = workspace.addNode("inject"); | ||||
|             var mqttOutNode = workspace.addNode("mqttOut"); | ||||
|  | ||||
| @@ -182,7 +185,7 @@ describe('cookbook', function() { | ||||
|         // skip this case since it is same as other cases. | ||||
|         it.skip('Subscribe to a topic'); | ||||
|  | ||||
|         it('Receive a parsed JSON message', function() { | ||||
|         it('Receive a parsed JSON message', function () { | ||||
|             var injectNode = workspace.addNode("inject"); | ||||
|             var mqttOutNode = workspace.addNode("mqttOut"); | ||||
|  | ||||
|   | ||||
| @@ -331,7 +331,7 @@ describe('cookbook', function() { | ||||
|             httpRequetNode.clickOk(); | ||||
|  | ||||
|             debugNode.edit(); | ||||
|             debugNode.setOutput("payload.title"); | ||||
|             debugNode.setOutput(".title"); | ||||
|             debugNode.clickOk(); | ||||
|  | ||||
|             injectNode.connect(changeNodeSetPost); | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
|  **/ | ||||
|  | ||||
| exports.config = { | ||||
|  | ||||
|      | ||||
|     // | ||||
|     // ================== | ||||
|     // Specify Test Files | ||||
| @@ -150,12 +150,12 @@ exports.config = { | ||||
|     // The only one supported by default is 'dot' | ||||
|     // see also: http://webdriver.io/guide/reporters/dot.html | ||||
|     reporters: ['spec'], | ||||
|  | ||||
|      | ||||
|     // | ||||
|     // Options to be passed to Mocha. | ||||
|     // See the full list at http://mochajs.org/ | ||||
|     mochaOpts: { | ||||
|         timeout: 60000, | ||||
|         timeout: 100000, | ||||
|         ui: 'bdd' | ||||
|     }, | ||||
|     // | ||||
| @@ -197,7 +197,7 @@ exports.config = { | ||||
|      */ | ||||
|     // beforeCommand: function (commandName, args) { | ||||
|     // }, | ||||
|  | ||||
|      | ||||
|     /** | ||||
|      * Hook that gets executed before the suite starts | ||||
|      * @param {Object} suite suite details | ||||
| @@ -217,13 +217,13 @@ exports.config = { | ||||
|     // beforeHook: function () { | ||||
|     // }, | ||||
|     /** | ||||
|      * Hook that gets executed _after_ a hook within the suite starts (e.g. runs after calling | ||||
|      * Hook that gets executed _after_ a hook within the suite ends (e.g. runs after calling | ||||
|      * afterEach in Mocha) | ||||
|      */ | ||||
|     // afterHook: function () { | ||||
|     // }, | ||||
|     /** | ||||
|      * Function to be executed after a test (in Mocha/Jasmine) or a step (in Cucumber) starts. | ||||
|      * Function to be executed after a test (in Mocha/Jasmine) or a step (in Cucumber) ends. | ||||
|      * @param {Object} test test details | ||||
|      */ | ||||
|     // afterTest: function (test) { | ||||
| @@ -234,7 +234,7 @@ exports.config = { | ||||
|      */ | ||||
|     // afterSuite: function (suite) { | ||||
|     // }, | ||||
|  | ||||
|      | ||||
|     /** | ||||
|      * Runs after a WebdriverIO command gets executed | ||||
|      * @param {String} commandName hook command name | ||||
|   | ||||
		Reference in New Issue
	
	Block a user