codeceptjs 2.3.4 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/README.md +28 -6
- package/bin/codecept.js +42 -0
- package/docs/advanced.md +45 -1
- package/docs/angular.md +3 -3
- package/docs/basics.md +162 -118
- package/docs/bdd.md +30 -5
- package/docs/best.md +8 -6
- package/docs/books.md +6 -1
- package/docs/build/Appium.js +95 -85
- package/docs/build/FileSystem.js +48 -3
- package/docs/build/GraphQL.js +3 -2
- package/docs/build/GraphQLDataFactory.js +1 -0
- package/docs/build/Mochawesome.js +3 -2
- package/docs/build/MockRequest.js +23 -5
- package/docs/build/Nightmare.js +87 -128
- package/docs/build/Protractor.js +107 -155
- package/docs/build/Puppeteer.js +190 -174
- package/docs/build/REST.js +13 -9
- package/docs/build/SeleniumWebdriver.js +0 -17
- package/docs/build/TestCafe.js +164 -158
- package/docs/build/WebDriver.js +236 -211
- package/docs/build/WebDriverIO.js +218 -187
- package/docs/changelog.md +57 -1
- package/docs/commands.md +41 -2
- package/docs/community-helpers.md +12 -1
- package/docs/configuration.md +5 -2
- package/docs/continuous-integration.md +22 -0
- package/docs/{helpers.md → custom-helpers.md} +16 -10
- package/docs/data.md +7 -6
- package/docs/detox.md +6 -6
- package/docs/email.md +4 -2
- package/docs/examples.md +22 -3
- package/docs/helpers/ApiDataFactory.md +15 -13
- package/docs/helpers/Appium.md +1011 -468
- package/docs/helpers/Detox.md +33 -26
- package/docs/helpers/FileSystem.md +43 -13
- package/docs/helpers/GraphQL.md +17 -15
- package/docs/helpers/GraphQLDataFactory.md +15 -13
- package/docs/helpers/Mochawesome.md +3 -1
- package/docs/helpers/MockRequest.md +37 -19
- package/docs/helpers/Nightmare.md +129 -240
- package/docs/helpers/Polly.md +1 -1
- package/docs/helpers/Protractor.md +157 -298
- package/docs/helpers/Puppeteer.md +216 -335
- package/docs/helpers/REST.md +29 -24
- package/docs/helpers/TestCafe.md +137 -235
- package/docs/helpers/WebDriver.md +250 -347
- package/docs/hooks.md +14 -10
- package/docs/index.md +112 -0
- package/docs/installation.md +3 -1
- package/docs/locators.md +19 -8
- package/docs/mobile-react-native-locators.md +2 -2
- package/docs/mobile.md +5 -3
- package/docs/nightmare.md +2 -1
- package/docs/pageobjects.md +4 -2
- package/docs/parallel.md +4 -2
- package/docs/plugins.md +41 -15
- package/docs/puppeteer.md +8 -6
- package/docs/quickstart.md +130 -0
- package/docs/react.md +4 -2
- package/docs/reports.md +6 -4
- package/docs/testcafe.md +10 -8
- package/docs/translation.md +4 -2
- package/docs/ui.md +56 -0
- package/docs/videos.md +11 -2
- package/docs/visual.md +7 -5
- package/docs/vue.md +121 -0
- package/docs/webapi/appendField.mustache +1 -1
- package/docs/webapi/attachFile.mustache +1 -1
- package/docs/webapi/checkOption.mustache +2 -2
- package/docs/webapi/clearCookie.mustache +1 -1
- package/docs/webapi/click.mustache +2 -2
- package/docs/webapi/clickLink.mustache +2 -2
- package/docs/webapi/dontSee.mustache +1 -2
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +1 -1
- package/docs/webapi/dontSeeElement.mustache +1 -1
- package/docs/webapi/dontSeeElementInDOM.mustache +1 -1
- package/docs/webapi/dontSeeInField.mustache +1 -1
- package/docs/webapi/doubleClick.mustache +2 -2
- package/docs/webapi/downloadFile.mustache +1 -1
- package/docs/webapi/dragSlider.mustache +1 -1
- package/docs/webapi/executeAsyncScript.mustache +2 -1
- package/docs/webapi/executeScript.mustache +2 -1
- package/docs/webapi/fillField.mustache +1 -1
- package/docs/webapi/grabAttributeFrom.mustache +1 -1
- package/docs/webapi/grabBrowserLogs.mustache +1 -1
- package/docs/webapi/grabCookie.mustache +2 -2
- package/docs/webapi/grabCssPropertyFrom.mustache +1 -1
- package/docs/webapi/grabHTMLFrom.mustache +1 -1
- package/docs/webapi/grabNumberOfVisibleElements.mustache +1 -1
- package/docs/webapi/grabPageScrollPosition.mustache +1 -1
- package/docs/webapi/grabTextFrom.mustache +2 -2
- package/docs/webapi/grabValueFrom.mustache +1 -1
- package/docs/webapi/moveCursorTo.mustache +3 -3
- package/docs/webapi/pressKey.mustache +1 -1
- package/docs/webapi/pressKeyWithKeyNormalization.mustache +1 -1
- package/docs/webapi/rightClick.mustache +2 -2
- package/docs/webapi/saveScreenshot.mustache +1 -1
- package/docs/webapi/scrollIntoView.mustache +10 -0
- package/docs/webapi/scrollTo.mustache +3 -3
- package/docs/webapi/see.mustache +1 -1
- package/docs/webapi/seeAttributesOnElements.mustache +1 -1
- package/docs/webapi/seeCheckboxIsChecked.mustache +1 -1
- package/docs/webapi/seeCssPropertiesOnElements.mustache +1 -1
- package/docs/webapi/seeElement.mustache +1 -1
- package/docs/webapi/seeElementInDOM.mustache +1 -1
- package/docs/webapi/seeInField.mustache +1 -1
- package/docs/webapi/seeNumberOfElements.mustache +1 -1
- package/docs/webapi/seeNumberOfVisibleElements.mustache +1 -1
- package/docs/webapi/seeTextEquals.mustache +8 -0
- package/docs/webapi/selectOption.mustache +2 -2
- package/docs/webapi/switchTo.mustache +1 -1
- package/docs/webapi/uncheckOption.mustache +2 -2
- package/docs/webapi/waitForClickable.mustache +10 -0
- package/docs/webapi/waitForDetached.mustache +2 -2
- package/docs/webapi/waitForElement.mustache +2 -2
- package/docs/webapi/waitForEnabled.mustache +2 -2
- package/docs/webapi/waitForFunction.mustache +2 -2
- package/docs/webapi/waitForInvisible.mustache +2 -2
- package/docs/webapi/waitForText.mustache +2 -2
- package/docs/webapi/waitForValue.mustache +1 -1
- package/docs/webapi/waitForVisible.mustache +2 -2
- package/docs/webapi/waitInUrl.mustache +1 -1
- package/docs/webapi/waitNumberOfVisibleElements.mustache +2 -2
- package/docs/webapi/waitToHide.mustache +2 -2
- package/docs/webapi/waitUntil.mustache +3 -2
- package/docs/webapi/waitUrlEquals.mustache +1 -1
- package/docs/webdriver.md +20 -18
- package/docs/wiki/.git/FETCH_HEAD +1 -0
- package/docs/wiki/.git/HEAD +1 -0
- package/docs/wiki/.git/ORIG_HEAD +1 -0
- package/docs/wiki/.git/config +11 -0
- package/docs/wiki/.git/description +1 -0
- package/docs/wiki/.git/hooks/applypatch-msg.sample +15 -0
- package/docs/wiki/.git/hooks/commit-msg.sample +24 -0
- package/docs/wiki/.git/hooks/fsmonitor-watchman.sample +114 -0
- package/docs/wiki/.git/hooks/post-update.sample +8 -0
- package/docs/wiki/.git/hooks/pre-applypatch.sample +14 -0
- package/docs/wiki/.git/hooks/pre-commit.sample +49 -0
- package/docs/wiki/.git/hooks/pre-push.sample +53 -0
- package/docs/wiki/.git/hooks/pre-rebase.sample +169 -0
- package/docs/wiki/.git/hooks/pre-receive.sample +24 -0
- package/docs/wiki/.git/hooks/prepare-commit-msg.sample +42 -0
- package/docs/wiki/.git/hooks/update.sample +128 -0
- package/docs/wiki/.git/index +0 -0
- package/docs/wiki/.git/info/exclude +6 -0
- package/docs/wiki/.git/logs/HEAD +4 -0
- package/docs/wiki/.git/logs/refs/heads/master +4 -0
- package/docs/wiki/.git/logs/refs/remotes/origin/HEAD +1 -0
- package/docs/wiki/.git/logs/refs/remotes/origin/master +3 -0
- package/docs/wiki/.git/objects/00/d216b0774d15db2d0a2a0d4ce249b5251acc55 +3 -0
- package/docs/wiki/.git/objects/09/01d87c5241905fdfe3493cfe8f04df4a2685ea +0 -0
- package/docs/wiki/.git/objects/0d/bdd0c20c4deb6a8cc81dbbf32ecf8c09238983 +2 -0
- package/docs/wiki/.git/objects/1a/c29e4fa82422c52392f22f0f2b8d1a759535bf +0 -0
- package/docs/wiki/.git/objects/27/12f92898d3e8f68e229b6cda76570d6c66d781 +0 -0
- package/docs/wiki/.git/objects/2d/dbe22c257166b648928eeb9460ecfb71ba702d +0 -0
- package/docs/wiki/.git/objects/2f/c942ec3773efd2678d9ff98035c61fcded81a1 +0 -0
- package/docs/wiki/.git/objects/40/a2856342c67796b48911a256b764fb06888b94 +5 -0
- package/docs/wiki/.git/objects/47/53181844fc4dc563cf3aa5e80462243cb58d38 +0 -0
- package/docs/wiki/.git/objects/4e/24a95fb2e4f8ffef51f19b694451a205c06f10 +3 -0
- package/docs/wiki/.git/objects/73/31ebd96f3c7e08a9f63f05a25f939afa0d4de1 +0 -0
- package/docs/wiki/.git/objects/86/19cbb2289caa502e33fccf0ed14eecf6ba2ba0 +0 -0
- package/docs/wiki/.git/objects/a4/72f797d9d74b87c9f71a2b1539d75bb07d1e35 +0 -0
- package/docs/wiki/.git/objects/c9/9f3e4bd227d6b050b2e416f9876df49583dbf6 +0 -0
- package/docs/wiki/.git/objects/ca/e609b4ef3e0ef85fcbe0d68d1a58246584b915 +0 -0
- package/docs/wiki/.git/objects/d5/8386ca72f6d550548f3d71d74e3ac73d5ad488 +0 -0
- package/docs/wiki/.git/objects/d9/c6874a6de524bdafeb563a20d847f4fdd59a86 +0 -0
- package/docs/wiki/.git/objects/f1/c944675bb38b40ae553b0be36c14674c79af54 +0 -0
- package/docs/wiki/.git/objects/pack/pack-28da0fc7e6c08d4c5350717bfbb7b1c53e8198ad.idx +0 -0
- package/docs/wiki/.git/objects/pack/pack-28da0fc7e6c08d4c5350717bfbb7b1c53e8198ad.pack +0 -0
- package/docs/wiki/.git/packed-refs +2 -0
- package/docs/wiki/.git/refs/heads/master +1 -0
- package/docs/wiki/.git/refs/remotes/origin/HEAD +1 -0
- package/docs/wiki/.git/refs/remotes/origin/master +1 -0
- package/docs/wiki/Books-&-Posts.md +27 -0
- package/docs/wiki/Community-Helpers.md +41 -0
- package/docs/wiki/Examples.md +138 -0
- package/docs/wiki/Home.md +11 -0
- package/docs/wiki/Release-process.md +25 -0
- package/docs/wiki/Roadmap.md +23 -0
- package/docs/wiki/Videos.md +19 -0
- package/lib/actor.js +18 -1
- package/lib/assert/error.js +3 -3
- package/lib/codecept.js +9 -6
- package/lib/command/configMigrate.js +7 -6
- package/lib/command/definitions.js +98 -350
- package/lib/command/generate.js +22 -17
- package/lib/command/gherkin/init.js +2 -1
- package/lib/command/gherkin/snippets.js +6 -6
- package/lib/command/gherkin/steps.js +0 -1
- package/lib/command/info.js +40 -0
- package/lib/command/init.js +54 -41
- package/lib/command/run-multiple.js +5 -4
- package/lib/command/run-rerun.js +39 -0
- package/lib/command/run-workers.js +4 -6
- package/lib/command/run.js +8 -18
- package/lib/command/utils.js +23 -2
- package/lib/command/workers/runTests.js +1 -2
- package/lib/config.js +10 -4
- package/lib/container.js +31 -6
- package/lib/data/dataTableArgument.js +31 -0
- package/lib/data/table.js +4 -0
- package/lib/event.js +65 -1
- package/lib/helper/Appium.js +52 -38
- package/lib/helper/FileSystem.js +48 -3
- package/lib/helper/GraphQL.js +3 -2
- package/lib/helper/GraphQLDataFactory.js +1 -0
- package/lib/helper/Mochawesome.js +3 -2
- package/lib/helper/MockRequest.js +23 -5
- package/lib/helper/Nightmare.js +5 -6
- package/lib/helper/Protractor.js +7 -8
- package/lib/helper/Puppeteer.js +76 -20
- package/lib/helper/REST.js +13 -9
- package/lib/helper/SeleniumWebdriver.js +0 -17
- package/lib/helper/TestCafe.js +84 -36
- package/lib/helper/WebDriver.js +113 -59
- package/lib/helper/WebDriverIO.js +43 -59
- package/lib/helper/clientscripts/nightmare.js +66 -4
- package/lib/helper/scripts/isElementClickable.js +24 -0
- package/lib/helper.js +34 -10
- package/lib/history.js +1 -1
- package/lib/hooks.js +2 -1
- package/lib/index.js +19 -0
- package/lib/interfaces/bdd.js +4 -0
- package/lib/interfaces/featureConfig.js +10 -3
- package/lib/interfaces/gherkin.js +6 -2
- package/lib/interfaces/scenarioConfig.js +17 -6
- package/lib/listener/config.js +1 -1
- package/lib/listener/exit.js +6 -0
- package/lib/listener/steps.js +0 -1
- package/lib/listener/trace.js +0 -1
- package/lib/locator.js +67 -2
- package/lib/output.js +53 -0
- package/lib/parser.js +2 -71
- package/lib/pause.js +3 -2
- package/lib/plugin/allure.js +41 -22
- package/lib/plugin/autoLogin.js +4 -1
- package/lib/plugin/pauseOnFail.js +38 -0
- package/lib/plugin/puppeteerCoverage.js +8 -7
- package/lib/plugin/screenshotOnFail.js +13 -8
- package/lib/plugin/stepByStepReport.js +7 -6
- package/lib/plugin/wdio.js +2 -1
- package/lib/recorder.js +85 -7
- package/lib/rerun.js +81 -0
- package/lib/secret.js +6 -0
- package/lib/session.js +9 -2
- package/lib/step.js +37 -2
- package/lib/store.js +5 -1
- package/lib/ui.js +34 -8
- package/lib/utils.js +6 -13
- package/lib/within.js +5 -0
- package/package.json +49 -29
- package/typings/Mocha.d.ts +21 -0
- package/typings/Protractor.d.ts +16 -0
- package/typings/index.d.ts +169 -0
- package/typings/jsdoc.conf.js +34 -0
- package/typings/jsdoc.namespace.js +29 -0
- package/typings/types.d.ts +9827 -0
- package/typings/utils.d.ts +7 -0
- package/docs/acceptance.md +0 -409
- package/docs/api/codecept.md +0 -75
- package/docs/api/config.md +0 -49
- package/docs/api/container.md +0 -66
- package/docs/api/helper.md +0 -116
- package/docs/api/output.md +0 -67
- package/docs/api/recorder.md +0 -63
- package/docs/helpers/SeleniumWebdriver.md +0 -92
- package/docs/helpers/WebDriverIO.md +0 -1671
package/lib/locator.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
const cssToXPath = require('css-to-xpath');
|
|
2
|
-
const xpathLocator = require('./utils').xpathLocator;
|
|
3
2
|
const sprintf = require('sprintf-js').sprintf;
|
|
4
3
|
|
|
4
|
+
const xpathLocator = require('./utils').xpathLocator;
|
|
5
|
+
|
|
6
|
+
/** @class */
|
|
5
7
|
class Locator {
|
|
8
|
+
/**
|
|
9
|
+
* @param {CodeceptJS.LocatorOrString} locator
|
|
10
|
+
* @param {string} [defaultType]
|
|
11
|
+
*/
|
|
6
12
|
constructor(locator, defaultType = '') {
|
|
7
13
|
this.type = null;
|
|
8
14
|
if (!locator) return;
|
|
@@ -63,6 +69,9 @@ class Locator {
|
|
|
63
69
|
return { [this.type]: this.value };
|
|
64
70
|
}
|
|
65
71
|
|
|
72
|
+
/**
|
|
73
|
+
* @return {string}
|
|
74
|
+
*/
|
|
66
75
|
toString() {
|
|
67
76
|
return this.output || `{${this.type}: ${this.value}}`;
|
|
68
77
|
}
|
|
@@ -95,6 +104,9 @@ class Locator {
|
|
|
95
104
|
return this.isFuzzy() && this.value[0] === '~';
|
|
96
105
|
}
|
|
97
106
|
|
|
107
|
+
/**
|
|
108
|
+
* @return {string}
|
|
109
|
+
*/
|
|
98
110
|
toXPath() {
|
|
99
111
|
if (this.isXPath()) return this.value;
|
|
100
112
|
if (this.isCSS()) return cssToXPath(this.value);
|
|
@@ -102,6 +114,10 @@ class Locator {
|
|
|
102
114
|
}
|
|
103
115
|
|
|
104
116
|
// DSL
|
|
117
|
+
/**
|
|
118
|
+
* @param {CodeceptJS.LocatorOrString} locator
|
|
119
|
+
* @return {Locator}
|
|
120
|
+
*/
|
|
105
121
|
or(locator) {
|
|
106
122
|
const xpath = xpathLocator.combine([
|
|
107
123
|
this.toXPath(),
|
|
@@ -110,21 +126,37 @@ class Locator {
|
|
|
110
126
|
return new Locator({ xpath });
|
|
111
127
|
}
|
|
112
128
|
|
|
129
|
+
/**
|
|
130
|
+
* @param {CodeceptJS.LocatorOrString} locator
|
|
131
|
+
* @return {Locator}
|
|
132
|
+
*/
|
|
113
133
|
find(locator) {
|
|
114
134
|
const xpath = sprintf('%s//%s', this.toXPath(), convertToSubSelector(locator));
|
|
115
135
|
return new Locator({ xpath });
|
|
116
136
|
}
|
|
117
137
|
|
|
138
|
+
/**
|
|
139
|
+
* @param {CodeceptJS.LocatorOrString} locator
|
|
140
|
+
* @return {Locator}
|
|
141
|
+
*/
|
|
118
142
|
withChild(locator) {
|
|
119
143
|
const xpath = sprintf('%s[./child::%s]', this.toXPath(), convertToSubSelector(locator));
|
|
120
144
|
return new Locator({ xpath });
|
|
121
145
|
}
|
|
122
146
|
|
|
147
|
+
/**
|
|
148
|
+
* @param {CodeceptJS.LocatorOrString} locator
|
|
149
|
+
* @return {Locator}
|
|
150
|
+
*/
|
|
123
151
|
withDescendant(locator) {
|
|
124
152
|
const xpath = sprintf('%s[./descendant::%s]', this.toXPath(), convertToSubSelector(locator));
|
|
125
153
|
return new Locator({ xpath });
|
|
126
154
|
}
|
|
127
155
|
|
|
156
|
+
/**
|
|
157
|
+
* @param {number} position
|
|
158
|
+
* @return {Locator}
|
|
159
|
+
*/
|
|
128
160
|
at(position) {
|
|
129
161
|
if (position < 0) {
|
|
130
162
|
position++; // -1 points to the last element
|
|
@@ -137,20 +169,34 @@ class Locator {
|
|
|
137
169
|
return new Locator({ xpath });
|
|
138
170
|
}
|
|
139
171
|
|
|
172
|
+
/**
|
|
173
|
+
* @return {Locator}
|
|
174
|
+
*/
|
|
140
175
|
first() {
|
|
141
176
|
return this.at(1);
|
|
142
177
|
}
|
|
143
178
|
|
|
179
|
+
/**
|
|
180
|
+
* @return {Locator}
|
|
181
|
+
*/
|
|
144
182
|
last() {
|
|
145
183
|
return this.at(-1);
|
|
146
184
|
}
|
|
147
185
|
|
|
186
|
+
/**
|
|
187
|
+
* @param {string} text
|
|
188
|
+
* @return {Locator}
|
|
189
|
+
*/
|
|
148
190
|
withText(text) {
|
|
149
191
|
text = xpathLocator.literal(text);
|
|
150
192
|
const xpath = sprintf('%s[%s]', this.toXPath(), `contains(., ${text})`);
|
|
151
193
|
return new Locator({ xpath });
|
|
152
194
|
}
|
|
153
195
|
|
|
196
|
+
/**
|
|
197
|
+
* @param {Object.<string, string>} attrs
|
|
198
|
+
* @return {Locator}
|
|
199
|
+
*/
|
|
154
200
|
withAttr(attrs) {
|
|
155
201
|
const operands = [];
|
|
156
202
|
for (const attr of Object.keys(attrs)) {
|
|
@@ -160,27 +206,47 @@ class Locator {
|
|
|
160
206
|
return new Locator({ xpath });
|
|
161
207
|
}
|
|
162
208
|
|
|
209
|
+
/**
|
|
210
|
+
* @param {string} output
|
|
211
|
+
* @return {Locator}
|
|
212
|
+
*/
|
|
163
213
|
as(output) {
|
|
164
214
|
this.output = output;
|
|
165
215
|
return this;
|
|
166
216
|
}
|
|
167
217
|
|
|
218
|
+
/**
|
|
219
|
+
* @param {CodeceptJS.LocatorOrString} locator
|
|
220
|
+
* @return {Locator}
|
|
221
|
+
*/
|
|
168
222
|
inside(locator) {
|
|
169
223
|
const xpath = sprintf('%s[ancestor::%s]', this.toXPath(), convertToSubSelector(locator));
|
|
170
224
|
return new Locator({ xpath });
|
|
171
225
|
}
|
|
172
226
|
|
|
227
|
+
/**
|
|
228
|
+
* @param {CodeceptJS.LocatorOrString} locator
|
|
229
|
+
* @return {Locator}
|
|
230
|
+
*/
|
|
173
231
|
after(locator) {
|
|
174
232
|
const xpath = sprintf('%s[preceding-sibling::%s]', this.toXPath(), convertToSubSelector(locator));
|
|
175
233
|
return new Locator({ xpath });
|
|
176
234
|
}
|
|
177
235
|
|
|
236
|
+
/**
|
|
237
|
+
* @param {CodeceptJS.LocatorOrString} locator
|
|
238
|
+
* @return {Locator}
|
|
239
|
+
*/
|
|
178
240
|
before(locator) {
|
|
179
241
|
const xpath = sprintf('%s[following-sibling::%s]', this.toXPath(), convertToSubSelector(locator));
|
|
180
242
|
return new Locator({ xpath });
|
|
181
243
|
}
|
|
182
244
|
}
|
|
183
245
|
|
|
246
|
+
/**
|
|
247
|
+
* @param {CodeceptJS.LocatorOrString} locator
|
|
248
|
+
* @returns {Locator}
|
|
249
|
+
*/
|
|
184
250
|
Locator.build = (locator) => {
|
|
185
251
|
if (!locator) return new Locator({ xpath: '//*' });
|
|
186
252
|
return new Locator(locator, 'css');
|
|
@@ -190,7 +256,6 @@ Locator.filters = [];
|
|
|
190
256
|
|
|
191
257
|
Locator.addFilter = fn => Locator.filters.push(fn);
|
|
192
258
|
|
|
193
|
-
|
|
194
259
|
Locator.clickable = {
|
|
195
260
|
narrow: literal => xpathLocator.combine([
|
|
196
261
|
`.//a[normalize-space(.)=${literal}]`,
|
package/lib/output.js
CHANGED
|
@@ -15,14 +15,21 @@ let outputLevel = 0;
|
|
|
15
15
|
let outputProcess = '';
|
|
16
16
|
let newline = true;
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* @alias output
|
|
20
|
+
* @namespace
|
|
21
|
+
*/
|
|
18
22
|
module.exports = {
|
|
19
23
|
colors,
|
|
20
24
|
styles,
|
|
21
25
|
print,
|
|
26
|
+
/** @type {number} */
|
|
22
27
|
stepShift: 0,
|
|
23
28
|
|
|
24
29
|
/**
|
|
25
30
|
* Set or return current verbosity level
|
|
31
|
+
* @param {number} level
|
|
32
|
+
* @return {number}
|
|
26
33
|
*/
|
|
27
34
|
level(level) {
|
|
28
35
|
if (level !== undefined) outputLevel = level;
|
|
@@ -32,6 +39,8 @@ module.exports = {
|
|
|
32
39
|
/**
|
|
33
40
|
* Print information for a process
|
|
34
41
|
* Used in multiple-run
|
|
42
|
+
* @param {string} process
|
|
43
|
+
* @return {string}
|
|
35
44
|
*/
|
|
36
45
|
process(process) {
|
|
37
46
|
if (process === null) return outputProcess = '';
|
|
@@ -41,6 +50,7 @@ module.exports = {
|
|
|
41
50
|
|
|
42
51
|
/**
|
|
43
52
|
* Print information in --debug mode
|
|
53
|
+
* @param {string} msg
|
|
44
54
|
*/
|
|
45
55
|
debug(msg) {
|
|
46
56
|
if (outputLevel >= 2) {
|
|
@@ -50,6 +60,7 @@ module.exports = {
|
|
|
50
60
|
|
|
51
61
|
/**
|
|
52
62
|
* Print information in --verbose mode
|
|
63
|
+
* @param {string} msg
|
|
53
64
|
*/
|
|
54
65
|
log(msg) {
|
|
55
66
|
if (outputLevel >= 3) print(' '.repeat(this.stepShift), styles.log(truncate(` ${msg}`, this.spaceShift)));
|
|
@@ -57,6 +68,7 @@ module.exports = {
|
|
|
57
68
|
|
|
58
69
|
/**
|
|
59
70
|
* Print error
|
|
71
|
+
* @param {string} msg
|
|
60
72
|
*/
|
|
61
73
|
error(msg) {
|
|
62
74
|
print(styles.error(msg));
|
|
@@ -64,17 +76,23 @@ module.exports = {
|
|
|
64
76
|
|
|
65
77
|
/**
|
|
66
78
|
* Print a successful message
|
|
79
|
+
* @param {string} msg
|
|
67
80
|
*/
|
|
68
81
|
success(msg) {
|
|
69
82
|
print(styles.success(msg));
|
|
70
83
|
},
|
|
71
84
|
|
|
85
|
+
/**
|
|
86
|
+
* @param {string} name
|
|
87
|
+
* @param {string} msg
|
|
88
|
+
*/
|
|
72
89
|
plugin(name, msg) {
|
|
73
90
|
this.debug(`<${name}> ${msg}`);
|
|
74
91
|
},
|
|
75
92
|
|
|
76
93
|
/**
|
|
77
94
|
* Print a step
|
|
95
|
+
* @param {CodeceptJS.Step} step
|
|
78
96
|
*/
|
|
79
97
|
step(step) {
|
|
80
98
|
if (outputLevel === 0) return;
|
|
@@ -98,7 +116,11 @@ module.exports = {
|
|
|
98
116
|
print(' '.repeat(this.stepShift), truncate(stepLine, this.spaceShift));
|
|
99
117
|
},
|
|
100
118
|
|
|
119
|
+
/** @namespace */
|
|
101
120
|
suite: {
|
|
121
|
+
/**
|
|
122
|
+
* @param {Mocha.Suite} suite
|
|
123
|
+
*/
|
|
102
124
|
started: (suite) => {
|
|
103
125
|
if (!suite.title) return;
|
|
104
126
|
print(`${colors.bold(suite.title)} --`);
|
|
@@ -106,27 +128,50 @@ module.exports = {
|
|
|
106
128
|
},
|
|
107
129
|
},
|
|
108
130
|
|
|
131
|
+
/** @namespace */
|
|
109
132
|
test: {
|
|
133
|
+
/**
|
|
134
|
+
* @param {Mocha.Test} test
|
|
135
|
+
*/
|
|
110
136
|
started(test) {
|
|
111
137
|
print(` ${colors.magenta.bold(test.title)}`);
|
|
112
138
|
},
|
|
139
|
+
/**
|
|
140
|
+
* @param {Mocha.Test} test
|
|
141
|
+
*/
|
|
113
142
|
passed(test) {
|
|
114
143
|
print(` ${colors.green.bold(figures.tick)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`);
|
|
115
144
|
},
|
|
145
|
+
/**
|
|
146
|
+
* @param {Mocha.Test} test
|
|
147
|
+
*/
|
|
116
148
|
failed(test) {
|
|
117
149
|
print(` ${colors.red.bold(figures.cross)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`);
|
|
118
150
|
},
|
|
151
|
+
/**
|
|
152
|
+
* @param {Mocha.Test} test
|
|
153
|
+
*/
|
|
119
154
|
skipped(test) {
|
|
120
155
|
print(` ${colors.yellow.bold('S')} ${test.title}`);
|
|
121
156
|
},
|
|
122
157
|
},
|
|
123
158
|
|
|
159
|
+
/** @namespace */
|
|
124
160
|
scenario: {
|
|
161
|
+
/**
|
|
162
|
+
* @param {Mocha.Test} test
|
|
163
|
+
*/
|
|
125
164
|
started(test) {},
|
|
165
|
+
/**
|
|
166
|
+
* @param {Mocha.Test} test
|
|
167
|
+
*/
|
|
126
168
|
passed(test) {
|
|
127
169
|
print(` ${colors.green.bold(`${figures.tick} OK`)} ${colors.grey(`in ${test.duration}ms`)}`);
|
|
128
170
|
print();
|
|
129
171
|
},
|
|
172
|
+
/**
|
|
173
|
+
* @param {Mocha.Test} test
|
|
174
|
+
*/
|
|
130
175
|
failed(test) {
|
|
131
176
|
print(` ${colors.red.bold(`${figures.cross} FAILED`)} ${colors.grey(`in ${test.duration}ms`)}`);
|
|
132
177
|
print();
|
|
@@ -136,11 +181,19 @@ module.exports = {
|
|
|
136
181
|
/**
|
|
137
182
|
*
|
|
138
183
|
* Print a text in console log
|
|
184
|
+
* @param {string} message
|
|
185
|
+
* @param {string} [color]
|
|
139
186
|
*/
|
|
140
187
|
say(message, color = 'cyan') {
|
|
141
188
|
if (outputLevel >= 1) print(` ${colors[color].bold(message)}`);
|
|
142
189
|
},
|
|
143
190
|
|
|
191
|
+
/**
|
|
192
|
+
* @param {number} passed
|
|
193
|
+
* @param {number} failed
|
|
194
|
+
* @param {number} skipped
|
|
195
|
+
* @param {number} duration
|
|
196
|
+
*/
|
|
144
197
|
result(passed, failed, skipped, duration) {
|
|
145
198
|
let style = colors.bgGreen;
|
|
146
199
|
let msg = ` ${passed || 0} passed`;
|
package/lib/parser.js
CHANGED
|
@@ -1,78 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
1
|
+
function _interopDefault(ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex.default : ex; }
|
|
2
|
+
const parser = _interopDefault(require('parse-function'))({ ecmaVersion: 2017 });
|
|
3
3
|
|
|
4
4
|
module.exports.getParamsToString = function (fn) {
|
|
5
5
|
return getParams(fn).join(', ');
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
module.exports.toTypeDef = function (fn) {
|
|
9
|
-
const types = [];
|
|
10
|
-
const paramNames = [];
|
|
11
|
-
const params = getParams(fn);
|
|
12
|
-
for (const key in params) {
|
|
13
|
-
let paramName = params[key];
|
|
14
|
-
const paramValue = paramName.split('=');
|
|
15
|
-
const isOptional = paramValue.length !== 1;
|
|
16
|
-
if (isOptional) {
|
|
17
|
-
paramName = paramValue[0];
|
|
18
|
-
}
|
|
19
|
-
paramNames[key] = paramName;
|
|
20
|
-
if (isOptional) {
|
|
21
|
-
paramNames[key] += '?';
|
|
22
|
-
}
|
|
23
|
-
types[key] = guessParamTypes(paramName);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
let combinedTypes = types[types.length - 1];
|
|
27
|
-
if (!combinedTypes) return methodSignature(fn);
|
|
28
|
-
if (types.length === 1) {
|
|
29
|
-
return combinedTypes.map(type => methodSignature(fn, paramNames, [type])).join('');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
for (let i = types.length - 2; i >= 0; i--) {
|
|
33
|
-
combinedTypes = flatTail(combinedTypes, types[i]);
|
|
34
|
-
}
|
|
35
|
-
return combinedTypes.map(type => methodSignature(fn, paramNames, type)).join('');
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
function methodSignature(fn, paramNames, params) {
|
|
39
|
-
if (!fn.name) return;
|
|
40
|
-
if (!params) params = [];
|
|
41
|
-
params = params.map((p, i) => `${paramNames[i]}: ${p}`).join(', ');
|
|
42
|
-
let returnType = 'void';
|
|
43
|
-
if (fn.name.indexOf('grab') === 0) {
|
|
44
|
-
if (fn.name.indexOf('BrowserLog') > 0 || fn.name.indexOf('ScrollPosition') > 0) {
|
|
45
|
-
returnType = 'Promise<object>';
|
|
46
|
-
}
|
|
47
|
-
if (fn.name.indexOf('Number') > 0) {
|
|
48
|
-
returnType = 'Promise<number>';
|
|
49
|
-
}
|
|
50
|
-
returnType = 'Promise<string>';
|
|
51
|
-
}
|
|
52
|
-
return ` ${fn.name}(${params}) : ${returnType},\n`;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function guessParamTypes(paramName) {
|
|
56
|
-
switch (paramName) {
|
|
57
|
-
case 'fn':
|
|
58
|
-
return ['Function'];
|
|
59
|
-
case 'locator':
|
|
60
|
-
case 'field':
|
|
61
|
-
case 'context':
|
|
62
|
-
case 'select':
|
|
63
|
-
return ['LocatorOrString'];
|
|
64
|
-
case 'num':
|
|
65
|
-
case 'sec':
|
|
66
|
-
case 'width':
|
|
67
|
-
case 'height':
|
|
68
|
-
case 'offset':
|
|
69
|
-
case 'offsetX':
|
|
70
|
-
case 'offsetY':
|
|
71
|
-
return ['number'];
|
|
72
|
-
}
|
|
73
|
-
return ['string'];
|
|
74
|
-
}
|
|
75
|
-
|
|
76
8
|
function getParams(fn) {
|
|
77
9
|
if (fn.isSinonProxy) return [];
|
|
78
10
|
const newFn = fn.toString().replace(/^async/, 'async function');
|
|
@@ -91,4 +23,3 @@ function getParams(fn) {
|
|
|
91
23
|
console.error(err);
|
|
92
24
|
}
|
|
93
25
|
}
|
|
94
|
-
|
package/lib/pause.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
const colors = require('chalk');
|
|
2
|
+
const readline = require('readline');
|
|
3
|
+
|
|
1
4
|
const container = require('./container');
|
|
2
5
|
const history = require('./history');
|
|
3
6
|
const store = require('./store');
|
|
@@ -6,8 +9,6 @@ const event = require('./event');
|
|
|
6
9
|
const output = require('./output');
|
|
7
10
|
const methodsOfObject = require('./utils').methodsOfObject;
|
|
8
11
|
|
|
9
|
-
const readline = require('readline');
|
|
10
|
-
const colors = require('chalk');
|
|
11
12
|
// npm install colors
|
|
12
13
|
let rl;
|
|
13
14
|
let nextStep;
|
package/lib/plugin/allure.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
const event = require('../event');
|
|
2
1
|
const Allure = require('allure-js-commons');
|
|
2
|
+
|
|
3
|
+
const event = require('../event');
|
|
3
4
|
const logger = require('../output');
|
|
4
5
|
const ansiRegExp = require('../utils').ansiRegExp;
|
|
5
6
|
|
|
@@ -73,6 +74,8 @@ const defaultConfig = {
|
|
|
73
74
|
module.exports = (config) => {
|
|
74
75
|
config = Object.assign(defaultConfig, config);
|
|
75
76
|
|
|
77
|
+
const plugin = {};
|
|
78
|
+
|
|
76
79
|
const reporter = new Allure();
|
|
77
80
|
reporter.setOptions({ targetDir: config.outputDir });
|
|
78
81
|
|
|
@@ -80,15 +83,31 @@ module.exports = (config) => {
|
|
|
80
83
|
let currentStep;
|
|
81
84
|
let isHookSteps = false;
|
|
82
85
|
|
|
83
|
-
|
|
86
|
+
reporter.pendingCase = function (testName, timestamp, opts = {}) {
|
|
87
|
+
reporter.startCase(testName, timestamp);
|
|
88
|
+
|
|
89
|
+
if (opts.description) plugin.setDescription(opts.description);
|
|
90
|
+
if (opts.severity) plugin.severity(opts.severity);
|
|
91
|
+
if (opts.severity) plugin.addLabel('tag', opts.severity);
|
|
92
|
+
|
|
93
|
+
reporter.endCase('pending', { message: opts.message || 'Test ignored' }, timestamp);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
plugin.addAttachment = (name, buffer, type) => {
|
|
84
97
|
reporter.addAttachment(name, buffer, type);
|
|
85
98
|
};
|
|
86
99
|
|
|
87
|
-
|
|
88
|
-
reporter.
|
|
100
|
+
plugin.setDescription = (description, type) => {
|
|
101
|
+
const currentTest = reporter.getCurrentTest();
|
|
102
|
+
if (currentTest) {
|
|
103
|
+
currentTest.setDescription(description, type);
|
|
104
|
+
} else {
|
|
105
|
+
logger.error(`The test is not run. Please use "setDescription" for events:
|
|
106
|
+
"test.start", "test.before", "test.after", "test.passed", "test.failed", "test.finish"`);
|
|
107
|
+
}
|
|
89
108
|
};
|
|
90
109
|
|
|
91
|
-
|
|
110
|
+
plugin.createStep = (name, stepFunc = () => {}) => {
|
|
92
111
|
let result;
|
|
93
112
|
let status = 'passed';
|
|
94
113
|
reporter.startStep(name);
|
|
@@ -110,7 +129,7 @@ module.exports = (config) => {
|
|
|
110
129
|
return result;
|
|
111
130
|
};
|
|
112
131
|
|
|
113
|
-
|
|
132
|
+
plugin.createAttachment = (name, content, type) => {
|
|
114
133
|
if (typeof content === 'function') {
|
|
115
134
|
const attachmentName = name;
|
|
116
135
|
const buffer = content.apply(this, arguments);
|
|
@@ -118,27 +137,27 @@ module.exports = (config) => {
|
|
|
118
137
|
} reporter.addAttachment(name, content, type);
|
|
119
138
|
};
|
|
120
139
|
|
|
121
|
-
|
|
122
|
-
|
|
140
|
+
plugin.severity = (severity) => {
|
|
141
|
+
plugin.addLabel('severity', severity);
|
|
123
142
|
};
|
|
124
143
|
|
|
125
|
-
|
|
126
|
-
|
|
144
|
+
plugin.epic = (epic) => {
|
|
145
|
+
plugin.addLabel('epic', epic);
|
|
127
146
|
};
|
|
128
147
|
|
|
129
|
-
|
|
130
|
-
|
|
148
|
+
plugin.feature = (feature) => {
|
|
149
|
+
plugin.addLabel('feature', feature);
|
|
131
150
|
};
|
|
132
151
|
|
|
133
|
-
|
|
134
|
-
|
|
152
|
+
plugin.story = (story) => {
|
|
153
|
+
plugin.addLabel('story', story);
|
|
135
154
|
};
|
|
136
155
|
|
|
137
|
-
|
|
138
|
-
|
|
156
|
+
plugin.issue = (issue) => {
|
|
157
|
+
plugin.addLabel('issue', issue);
|
|
139
158
|
};
|
|
140
159
|
|
|
141
|
-
|
|
160
|
+
plugin.addLabel = (name, value) => {
|
|
142
161
|
const currentTest = reporter.getCurrentTest();
|
|
143
162
|
if (currentTest) {
|
|
144
163
|
currentTest.addLabel(name, value);
|
|
@@ -155,16 +174,16 @@ module.exports = (config) => {
|
|
|
155
174
|
event.dispatcher.on(event.suite.before, (suite) => {
|
|
156
175
|
for (const test of suite.tests) {
|
|
157
176
|
if (test.pending) {
|
|
158
|
-
reporter.pendingCase(test.title);
|
|
177
|
+
reporter.pendingCase(test.title, null, test.opts.skipInfo);
|
|
159
178
|
}
|
|
160
179
|
}
|
|
161
180
|
});
|
|
162
181
|
|
|
163
|
-
event.dispatcher.on(event.hook.started, (
|
|
182
|
+
event.dispatcher.on(event.hook.started, () => {
|
|
164
183
|
isHookSteps = true;
|
|
165
184
|
});
|
|
166
185
|
|
|
167
|
-
event.dispatcher.on(event.hook.passed, (
|
|
186
|
+
event.dispatcher.on(event.hook.passed, () => {
|
|
168
187
|
isHookSteps = false;
|
|
169
188
|
});
|
|
170
189
|
|
|
@@ -199,7 +218,7 @@ module.exports = (config) => {
|
|
|
199
218
|
reporter.endCase('failed', err);
|
|
200
219
|
});
|
|
201
220
|
|
|
202
|
-
event.dispatcher.on(event.test.passed, (
|
|
221
|
+
event.dispatcher.on(event.test.passed, () => {
|
|
203
222
|
if (currentStep) reporter.endStep('passed');
|
|
204
223
|
if (currentMetaStep.length) {
|
|
205
224
|
currentMetaStep.forEach(() => reporter.endStep('passed'));
|
|
@@ -262,5 +281,5 @@ module.exports = (config) => {
|
|
|
262
281
|
}
|
|
263
282
|
}
|
|
264
283
|
|
|
265
|
-
return
|
|
284
|
+
return plugin;
|
|
266
285
|
};
|
package/lib/plugin/autoLogin.js
CHANGED
|
@@ -217,7 +217,10 @@ const defaultConfig = {
|
|
|
217
217
|
*/
|
|
218
218
|
module.exports = function (config) {
|
|
219
219
|
config = Object.assign(defaultConfig, config);
|
|
220
|
-
Object.keys(config.users).map(u => config.users[u] =
|
|
220
|
+
Object.keys(config.users).map(u => config.users[u] = {
|
|
221
|
+
...defaultUser,
|
|
222
|
+
...config.users[u],
|
|
223
|
+
});
|
|
221
224
|
|
|
222
225
|
if (config.saveToFile) {
|
|
223
226
|
// loading from file
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const event = require('../event');
|
|
2
|
+
const pause = require('../pause');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Automatically launches [interactive pause](/basics/#pause) when a test fails.
|
|
6
|
+
*
|
|
7
|
+
* Useful for debugging flaky tests on local environment.
|
|
8
|
+
* Add this plugin to config file:
|
|
9
|
+
*
|
|
10
|
+
* ```js
|
|
11
|
+
* plugins: {
|
|
12
|
+
* pauseOnFail: {},
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Unlike other plugins, `pauseOnFail` is not recommended to be enabled by default.
|
|
17
|
+
* Enable it manually on each run via `-p` option:
|
|
18
|
+
*
|
|
19
|
+
* ```
|
|
20
|
+
* npx codeceptjs run -p pauseOnFail
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
module.exports = (config) => {
|
|
25
|
+
let failed = false;
|
|
26
|
+
|
|
27
|
+
event.dispatcher.on(event.test.started, (step) => {
|
|
28
|
+
failed = false;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
event.dispatcher.on(event.step.failed, (step) => {
|
|
32
|
+
failed = true;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
event.dispatcher.on(event.test.after, (step) => {
|
|
36
|
+
if (failed) pause();
|
|
37
|
+
});
|
|
38
|
+
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
const debug = require('debug')('codeceptjs:plugin:puppeteerCoverage');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
1
5
|
const Container = require('../container');
|
|
2
6
|
const recorder = require('../recorder');
|
|
3
7
|
const event = require('../event');
|
|
4
8
|
const output = require('../output');
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const path = require('path');
|
|
7
9
|
const { clearString } = require('../utils');
|
|
8
|
-
const debug = require('debug')('codeceptjs:plugin:puppeteerCoverage');
|
|
9
10
|
|
|
10
11
|
const defaultConfig = {
|
|
11
12
|
coverageDir: 'output/coverage',
|
|
@@ -27,10 +28,10 @@ function buildFileName(test, uniqueFileName) {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
if (uniqueFileName) {
|
|
30
|
-
const uuid =
|
|
31
|
-
test.uuid
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const uuid = test.uuid
|
|
32
|
+
|| test.ctx.test.uuid
|
|
33
|
+
|| Math.floor(new Date().getTime() / 1000);
|
|
34
|
+
|
|
34
35
|
fileName = `${fileName.substring(0, 10)}_${uuid}.coverage.json`;
|
|
35
36
|
} else {
|
|
36
37
|
fileName = `${fileName}.coverage.json`;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
1
4
|
const Container = require('../container');
|
|
2
5
|
const recorder = require('../recorder');
|
|
3
6
|
const event = require('../event');
|
|
4
7
|
const output = require('../output');
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const path = require('path');
|
|
7
8
|
const { fileExists, clearString } = require('../utils');
|
|
8
9
|
const Codeceptjs = require('../index');
|
|
9
10
|
|
|
@@ -99,7 +100,7 @@ module.exports = function (config) {
|
|
|
99
100
|
try {
|
|
100
101
|
if (options.reportDir) {
|
|
101
102
|
fileName = path.join(options.reportDir, fileName);
|
|
102
|
-
const mochaReportDir = path.
|
|
103
|
+
const mochaReportDir = path.resolve(process.cwd(), options.reportDir);
|
|
103
104
|
if (!fileExists(mochaReportDir)) {
|
|
104
105
|
fs.mkdirSync(mochaReportDir);
|
|
105
106
|
}
|
|
@@ -115,11 +116,15 @@ module.exports = function (config) {
|
|
|
115
116
|
allureReporter.addAttachment('Last Seen Screenshot', fs.readFileSync(path.join(global.output_dir, fileName)), 'image/png');
|
|
116
117
|
}
|
|
117
118
|
} catch (err) {
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
if (
|
|
120
|
+
err
|
|
121
|
+
&& err.type
|
|
122
|
+
&& err.type === 'RuntimeError'
|
|
123
|
+
&& err.message
|
|
124
|
+
&& (
|
|
125
|
+
err.message.indexOf('was terminated due to') > -1
|
|
126
|
+
|| err.message.indexOf('no such window: target window already closed') > -1
|
|
127
|
+
)
|
|
123
128
|
) {
|
|
124
129
|
helper.isRunning = false;
|
|
125
130
|
}
|