codeceptjs 4.0.0-beta.2 → 4.0.0-beta.21

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.
Files changed (209) hide show
  1. package/README.md +133 -120
  2. package/bin/codecept.js +107 -96
  3. package/bin/test-server.js +64 -0
  4. package/docs/webapi/clearCookie.mustache +1 -1
  5. package/docs/webapi/click.mustache +5 -1
  6. package/lib/actor.js +73 -103
  7. package/lib/ai.js +159 -188
  8. package/lib/assert/empty.js +22 -24
  9. package/lib/assert/equal.js +30 -37
  10. package/lib/assert/error.js +14 -14
  11. package/lib/assert/include.js +43 -48
  12. package/lib/assert/throws.js +11 -11
  13. package/lib/assert/truth.js +22 -22
  14. package/lib/assert.js +20 -18
  15. package/lib/codecept.js +262 -162
  16. package/lib/colorUtils.js +50 -52
  17. package/lib/command/check.js +206 -0
  18. package/lib/command/configMigrate.js +56 -51
  19. package/lib/command/definitions.js +96 -109
  20. package/lib/command/dryRun.js +77 -79
  21. package/lib/command/generate.js +234 -194
  22. package/lib/command/gherkin/init.js +42 -33
  23. package/lib/command/gherkin/snippets.js +76 -74
  24. package/lib/command/gherkin/steps.js +20 -17
  25. package/lib/command/info.js +74 -38
  26. package/lib/command/init.js +301 -290
  27. package/lib/command/interactive.js +41 -32
  28. package/lib/command/list.js +28 -27
  29. package/lib/command/run-multiple/chunk.js +51 -48
  30. package/lib/command/run-multiple/collection.js +5 -5
  31. package/lib/command/run-multiple/run.js +5 -1
  32. package/lib/command/run-multiple.js +97 -97
  33. package/lib/command/run-rerun.js +19 -25
  34. package/lib/command/run-workers.js +68 -92
  35. package/lib/command/run.js +39 -27
  36. package/lib/command/utils.js +80 -64
  37. package/lib/command/workers/runTests.js +388 -226
  38. package/lib/config.js +109 -50
  39. package/lib/container.js +765 -261
  40. package/lib/data/context.js +60 -61
  41. package/lib/data/dataScenarioConfig.js +47 -47
  42. package/lib/data/dataTableArgument.js +32 -32
  43. package/lib/data/table.js +22 -22
  44. package/lib/effects.js +307 -0
  45. package/lib/element/WebElement.js +327 -0
  46. package/lib/els.js +160 -0
  47. package/lib/event.js +173 -163
  48. package/lib/globals.js +141 -0
  49. package/lib/heal.js +89 -85
  50. package/lib/helper/AI.js +131 -41
  51. package/lib/helper/ApiDataFactory.js +107 -75
  52. package/lib/helper/Appium.js +542 -404
  53. package/lib/helper/FileSystem.js +100 -79
  54. package/lib/helper/GraphQL.js +44 -43
  55. package/lib/helper/GraphQLDataFactory.js +52 -52
  56. package/lib/helper/JSONResponse.js +126 -88
  57. package/lib/helper/Mochawesome.js +54 -29
  58. package/lib/helper/Playwright.js +2547 -1316
  59. package/lib/helper/Puppeteer.js +1578 -1181
  60. package/lib/helper/REST.js +209 -68
  61. package/lib/helper/WebDriver.js +1482 -1342
  62. package/lib/helper/errors/ConnectionRefused.js +6 -6
  63. package/lib/helper/errors/ElementAssertion.js +11 -16
  64. package/lib/helper/errors/ElementNotFound.js +5 -9
  65. package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
  66. package/lib/helper/extras/Console.js +11 -11
  67. package/lib/helper/extras/PlaywrightLocator.js +110 -0
  68. package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
  69. package/lib/helper/extras/PlaywrightReactVueLocator.js +17 -8
  70. package/lib/helper/extras/PlaywrightRestartOpts.js +25 -11
  71. package/lib/helper/extras/Popup.js +22 -22
  72. package/lib/helper/extras/React.js +27 -28
  73. package/lib/helper/network/actions.js +36 -42
  74. package/lib/helper/network/utils.js +78 -84
  75. package/lib/helper/scripts/blurElement.js +5 -5
  76. package/lib/helper/scripts/focusElement.js +5 -5
  77. package/lib/helper/scripts/highlightElement.js +8 -8
  78. package/lib/helper/scripts/isElementClickable.js +34 -34
  79. package/lib/helper.js +2 -3
  80. package/lib/history.js +23 -19
  81. package/lib/hooks.js +8 -8
  82. package/lib/html.js +94 -104
  83. package/lib/index.js +38 -27
  84. package/lib/listener/config.js +30 -23
  85. package/lib/listener/emptyRun.js +54 -0
  86. package/lib/listener/enhancedGlobalRetry.js +110 -0
  87. package/lib/listener/exit.js +16 -18
  88. package/lib/listener/globalRetry.js +70 -0
  89. package/lib/listener/globalTimeout.js +181 -0
  90. package/lib/listener/helpers.js +76 -51
  91. package/lib/listener/mocha.js +10 -11
  92. package/lib/listener/result.js +11 -0
  93. package/lib/listener/retryEnhancer.js +85 -0
  94. package/lib/listener/steps.js +71 -59
  95. package/lib/listener/store.js +20 -0
  96. package/lib/locator.js +214 -197
  97. package/lib/mocha/asyncWrapper.js +274 -0
  98. package/lib/mocha/bdd.js +167 -0
  99. package/lib/mocha/cli.js +341 -0
  100. package/lib/mocha/factory.js +163 -0
  101. package/lib/mocha/featureConfig.js +89 -0
  102. package/lib/mocha/gherkin.js +231 -0
  103. package/lib/mocha/hooks.js +121 -0
  104. package/lib/mocha/index.js +21 -0
  105. package/lib/mocha/inject.js +46 -0
  106. package/lib/{interfaces → mocha}/scenarioConfig.js +58 -34
  107. package/lib/mocha/suite.js +89 -0
  108. package/lib/mocha/test.js +184 -0
  109. package/lib/mocha/types.d.ts +42 -0
  110. package/lib/mocha/ui.js +242 -0
  111. package/lib/output.js +141 -71
  112. package/lib/parser.js +54 -44
  113. package/lib/pause.js +173 -145
  114. package/lib/plugin/analyze.js +403 -0
  115. package/lib/plugin/{autoLogin.js → auth.js} +178 -79
  116. package/lib/plugin/autoDelay.js +36 -40
  117. package/lib/plugin/coverage.js +131 -78
  118. package/lib/plugin/customLocator.js +22 -21
  119. package/lib/plugin/customReporter.js +53 -0
  120. package/lib/plugin/enhancedRetryFailedStep.js +99 -0
  121. package/lib/plugin/heal.js +101 -110
  122. package/lib/plugin/htmlReporter.js +3648 -0
  123. package/lib/plugin/pageInfo.js +140 -0
  124. package/lib/plugin/pauseOnFail.js +12 -11
  125. package/lib/plugin/retryFailedStep.js +82 -47
  126. package/lib/plugin/screenshotOnFail.js +111 -92
  127. package/lib/plugin/stepByStepReport.js +159 -101
  128. package/lib/plugin/stepTimeout.js +20 -25
  129. package/lib/plugin/subtitles.js +38 -38
  130. package/lib/recorder.js +193 -130
  131. package/lib/rerun.js +94 -49
  132. package/lib/result.js +238 -0
  133. package/lib/retryCoordinator.js +207 -0
  134. package/lib/secret.js +20 -18
  135. package/lib/session.js +95 -89
  136. package/lib/step/base.js +239 -0
  137. package/lib/step/comment.js +10 -0
  138. package/lib/step/config.js +50 -0
  139. package/lib/step/func.js +46 -0
  140. package/lib/step/helper.js +50 -0
  141. package/lib/step/meta.js +99 -0
  142. package/lib/step/record.js +74 -0
  143. package/lib/step/retry.js +11 -0
  144. package/lib/step/section.js +55 -0
  145. package/lib/step.js +18 -329
  146. package/lib/steps.js +54 -0
  147. package/lib/store.js +38 -7
  148. package/lib/template/heal.js +3 -12
  149. package/lib/template/prompts/generatePageObject.js +31 -0
  150. package/lib/template/prompts/healStep.js +13 -0
  151. package/lib/template/prompts/writeStep.js +9 -0
  152. package/lib/test-server.js +334 -0
  153. package/lib/timeout.js +60 -0
  154. package/lib/transform.js +8 -8
  155. package/lib/translation.js +34 -21
  156. package/lib/utils/loaderCheck.js +124 -0
  157. package/lib/utils/mask_data.js +47 -0
  158. package/lib/utils/typescript.js +237 -0
  159. package/lib/utils.js +411 -228
  160. package/lib/workerStorage.js +37 -34
  161. package/lib/workers.js +532 -296
  162. package/package.json +124 -95
  163. package/translations/de-DE.js +5 -3
  164. package/translations/fr-FR.js +5 -4
  165. package/translations/index.js +22 -12
  166. package/translations/it-IT.js +4 -3
  167. package/translations/ja-JP.js +4 -3
  168. package/translations/nl-NL.js +76 -0
  169. package/translations/pl-PL.js +4 -3
  170. package/translations/pt-BR.js +4 -3
  171. package/translations/ru-RU.js +4 -3
  172. package/translations/utils.js +10 -0
  173. package/translations/zh-CN.js +4 -3
  174. package/translations/zh-TW.js +4 -3
  175. package/typings/index.d.ts +546 -185
  176. package/typings/promiseBasedTypes.d.ts +150 -875
  177. package/typings/types.d.ts +547 -992
  178. package/lib/cli.js +0 -249
  179. package/lib/dirname.js +0 -5
  180. package/lib/helper/Expect.js +0 -425
  181. package/lib/helper/ExpectHelper.js +0 -399
  182. package/lib/helper/MockServer.js +0 -223
  183. package/lib/helper/Nightmare.js +0 -1411
  184. package/lib/helper/Protractor.js +0 -1835
  185. package/lib/helper/SoftExpectHelper.js +0 -381
  186. package/lib/helper/TestCafe.js +0 -1410
  187. package/lib/helper/clientscripts/nightmare.js +0 -213
  188. package/lib/helper/testcafe/testControllerHolder.js +0 -42
  189. package/lib/helper/testcafe/testcafe-utils.js +0 -63
  190. package/lib/interfaces/bdd.js +0 -98
  191. package/lib/interfaces/featureConfig.js +0 -69
  192. package/lib/interfaces/gherkin.js +0 -195
  193. package/lib/listener/artifacts.js +0 -19
  194. package/lib/listener/retry.js +0 -68
  195. package/lib/listener/timeout.js +0 -109
  196. package/lib/mochaFactory.js +0 -110
  197. package/lib/plugin/allure.js +0 -15
  198. package/lib/plugin/commentStep.js +0 -136
  199. package/lib/plugin/debugErrors.js +0 -67
  200. package/lib/plugin/eachElement.js +0 -127
  201. package/lib/plugin/fakerTransform.js +0 -49
  202. package/lib/plugin/retryTo.js +0 -121
  203. package/lib/plugin/selenoid.js +0 -371
  204. package/lib/plugin/standardActingHelpers.js +0 -9
  205. package/lib/plugin/tryTo.js +0 -105
  206. package/lib/plugin/wdio.js +0 -246
  207. package/lib/scenario.js +0 -222
  208. package/lib/ui.js +0 -238
  209. package/lib/within.js +0 -70
@@ -1,15 +1,18 @@
1
- import colors from 'chalk';
2
- import crypto from 'crypto';
3
- import figures from 'figures';
4
- import fs from 'fs';
5
- import mkdirp from 'mkdirp';
6
- import path from 'path';
7
- import Container from '../container.js';
8
- import recorder from '../recorder.js';
9
- import * as event from '../event.js';
10
- import * as output from '../output.js';
11
- import { template, deleteDir } from '../utils.js';
12
- import supportedHelpers from './standardActingHelpers.js';
1
+ import colors from 'chalk'
2
+ import crypto from 'crypto'
3
+ import figures from 'figures'
4
+ import fs from 'fs'
5
+ import { mkdirp } from 'mkdirp'
6
+ import path from 'path'
7
+ import cheerio from 'cheerio'
8
+
9
+ import Container from '../container.js'
10
+ import recorder from '../recorder.js'
11
+ import event from '../event.js'
12
+ import output from '../output.js'
13
+ import { template, deleteDir } from '../utils.js'
14
+
15
+ const supportedHelpers = Container.STANDARD_ACTING_HELPERS
13
16
 
14
17
  const defaultConfig = {
15
18
  deleteSuccessful: true,
@@ -19,9 +22,9 @@ const defaultConfig = {
19
22
  output: global.output_dir,
20
23
  screenshotsForAllureReport: false,
21
24
  disableScreenshotOnFail: true,
22
- };
25
+ }
23
26
 
24
- const templates = {};
27
+ const templates = {}
25
28
 
26
29
  /**
27
30
  * ![step-by-step-report](https://codecept.io/img/codeceptjs-slideshow.gif)
@@ -61,134 +64,189 @@ const templates = {};
61
64
  */
62
65
 
63
66
  export default function (config) {
64
- const helpers = Container.helpers();
65
- let helper;
67
+ const helpers = Container.helpers()
68
+ let helper
66
69
 
67
- config = Object.assign(defaultConfig, config);
70
+ config = Object.assign(defaultConfig, config)
68
71
 
69
72
  for (const helperName of supportedHelpers) {
70
73
  if (Object.keys(helpers).indexOf(helperName) > -1) {
71
- helper = helpers[helperName];
74
+ helper = helpers[helperName]
72
75
  }
73
76
  }
74
77
 
75
- if (!helper) return; // no helpers for screenshot
76
-
77
- let dir;
78
- let stepNum;
79
- let slides = {};
80
- let error;
81
- let savedStep = null;
82
- let currentTest = null;
83
- let scenarioFailed = false;
84
-
85
- const recordedTests = {};
86
- const pad = '0000';
87
- const reportDir = config.output ? path.resolve(global.codecept_dir, config.output) : defaultConfig.output;
88
-
89
- event.dispatcher.on(event.test.before, (test) => {
90
- const sha256hash = crypto.createHash('sha256').update(test.file + test.title).digest('hex');
91
- dir = path.join(reportDir, `record_${sha256hash}`);
92
- mkdirp.sync(dir);
93
- stepNum = 0;
94
- error = null;
95
- slides = {};
96
- savedStep = null;
97
- currentTest = test;
98
- });
99
-
100
- event.dispatcher.on(event.step.failed, (step) => {
101
- recorder.add('screenshot of failed test', async () => persistStep(step), true);
102
- });
103
-
104
- event.dispatcher.on(event.step.after, persistStep);
105
-
106
- event.dispatcher.on(event.test.passed, (test) => {
107
- if (!config.deleteSuccessful) return persist(test);
78
+ if (!helper) return // no helpers for screenshot
79
+
80
+ let dir
81
+ let stepNum
82
+ let slides = {}
83
+ let error
84
+ let savedStep = null
85
+ let currentTest = null
86
+ let scenarioFailed = false
87
+
88
+ const recordedTests = {}
89
+ const pad = '0000'
90
+ const reportDir = config.output ? path.resolve(global.codecept_dir, config.output) : defaultConfig.output
91
+
92
+ event.dispatcher.on(event.suite.before, suite => {
93
+ stepNum = -1
94
+ })
95
+
96
+ event.dispatcher.on(event.test.before, test => {
97
+ const sha256hash = crypto
98
+ .createHash('sha256')
99
+ .update(test.file + test.title)
100
+ .digest('hex')
101
+ dir = path.join(reportDir, `record_${sha256hash}`)
102
+ mkdirp.sync(dir)
103
+ stepNum = 0
104
+ error = null
105
+ slides = {}
106
+ savedStep = null
107
+ currentTest = test
108
+ })
109
+
110
+ event.dispatcher.on(event.step.failed, step => {
111
+ recorder.add('screenshot of failed test', async () => persistStep(step), true)
112
+ })
113
+
114
+ event.dispatcher.on(event.step.after, step => {
115
+ recorder.add('screenshot of step of test', async () => persistStep(step), true)
116
+ })
117
+
118
+ event.dispatcher.on(event.test.passed, test => {
119
+ if (!config.deleteSuccessful) return persist(test)
108
120
  // cleanup
109
- deleteDir(dir);
110
- });
121
+ deleteDir(dir)
122
+ })
111
123
 
112
- event.dispatcher.on(event.test.failed, (test, err) => {
113
- if (test.ctx._runnable.title.includes('hook: ')) {
114
- output.output.plugin('stepByStepReport', 'BeforeSuite/AfterSuite do not have any access to the browser, hence it could not take screenshot.');
115
- return;
124
+ event.dispatcher.on(event.test.failed, (test, _err, hookName) => {
125
+ if (hookName === 'BeforeSuite' || hookName === 'AfterSuite') {
126
+ // no browser here
127
+ return
116
128
  }
117
- });
129
+
130
+ persist(test)
131
+ })
118
132
 
119
133
  event.dispatcher.on(event.all.result, () => {
120
- if (!Object.keys(slides).length) return;
134
+ if (Object.keys(recordedTests).length === 0 || !Object.keys(slides).length) return
135
+ generateRecordsHtml(recordedTests)
136
+ })
137
+
138
+ event.dispatcher.on(event.workers.result, async () => {
139
+ await recorder.add(() => {
140
+ const recordedTests = getRecordFoldersWithDetails(reportDir)
141
+ generateRecordsHtml(recordedTests)
142
+ })
143
+ })
144
+
145
+ function getRecordFoldersWithDetails(dirPath) {
146
+ let results = {}
147
+
148
+ try {
149
+ const items = fs.readdirSync(dirPath, { withFileTypes: true })
150
+
151
+ items.forEach(item => {
152
+ if (item.isDirectory() && item.name.startsWith('record_')) {
153
+ const recordFolderPath = path.join(dirPath, item.name)
154
+ const indexPath = path.join(recordFolderPath, 'index.html')
155
+
156
+ let name = ''
157
+ if (fs.existsSync(indexPath)) {
158
+ try {
159
+ const htmlContent = fs.readFileSync(indexPath, 'utf-8')
160
+ const $ = cheerio.load(htmlContent)
161
+ name = $('.navbar-brand').text().trim()
162
+ } catch (err) {
163
+ console.error(`Error reading index.html in ${recordFolderPath}:`, err.message)
164
+ }
165
+ }
166
+
167
+ results[name || 'Unkown'] = `${item.name}/index.html`
168
+ }
169
+ })
170
+ } catch (err) {
171
+ console.error(`Error reading directory ${dirPath}:`, err.message)
172
+ }
173
+
174
+ return results
175
+ }
121
176
 
122
- let links = '';
177
+ function generateRecordsHtml(recordedTests) {
178
+ let links = ''
123
179
 
124
180
  for (const link in recordedTests) {
125
- links += `<li><a href="${recordedTests[link]}">${link}</a></li>\n`;
181
+ links += `<li><a href="${recordedTests[link]}">${link}</a></li>\n`
126
182
  }
127
183
 
128
184
  const indexHTML = template(templates.index, {
129
185
  time: Date().toString(),
130
186
  records: links,
131
- });
187
+ })
132
188
 
133
- fs.writeFileSync(path.join(reportDir, 'records.html'), indexHTML);
189
+ fs.writeFileSync(path.join(reportDir, 'records.html'), indexHTML)
134
190
 
135
- output.print(`${figures.circleFilled} Step-by-step preview: ${colors.white.bold(`file://${reportDir}/records.html`)}`);
136
- });
191
+ output.print(`${figures.circleFilled} Step-by-step preview: ${colors.white.bold(`file://${reportDir}/records.html`)}`)
192
+ }
137
193
 
138
194
  async function persistStep(step) {
139
- if (isStepIgnored(step)) return;
140
- if (savedStep === step) return; // already saved
195
+ if (stepNum === -1) return // Ignore steps from BeforeSuite function
196
+ if (isStepIgnored(step)) return
197
+ if (savedStep === step) return // already saved
141
198
  // Ignore steps from BeforeSuite function
142
- if (scenarioFailed && config.disableScreenshotOnFail) return;
143
- if (step.metaStep && step.metaStep.name === 'BeforeSuite') return;
199
+ if (scenarioFailed && config.disableScreenshotOnFail) return
200
+ if (step.metaStep && step.metaStep.name === 'BeforeSuite') return
201
+ if (!step.test) return // Ignore steps from AfterSuite
144
202
 
145
- const fileName = `${pad.substring(0, pad.length - stepNum.toString().length) + stepNum.toString()}.png`;
203
+ const fileName = `${pad.substring(0, pad.length - stepNum.toString().length) + stepNum.toString()}.png`
146
204
  if (step.status === 'failed') {
147
- scenarioFailed = true;
205
+ scenarioFailed = true
148
206
  }
149
- stepNum++;
150
- slides[fileName] = step;
207
+ stepNum++
208
+ slides[fileName] = step
151
209
  try {
152
- await helper.saveScreenshot(path.relative(reportDir, path.join(dir, fileName)), config.fullPageScreenshots);
210
+ await helper.saveScreenshot(path.join(dir, fileName), config.fullPageScreenshots)
153
211
  } catch (err) {
154
- output.output.plugin(`Can't save step screenshot: ${err}`);
155
- error = err;
156
- return;
212
+ output.plugin(`Can't save step screenshot: ${err}`)
213
+ error = err
214
+ return
157
215
  } finally {
158
- savedStep = step;
216
+ savedStep = step
159
217
  }
160
218
 
161
- if (!currentTest.artifacts.screenshots) currentTest.artifacts.screenshots = [];
219
+ if (!currentTest.artifacts.screenshots) currentTest.artifacts.screenshots = []
162
220
  // added attachments to test
163
- currentTest.artifacts.screenshots.push(path.join(dir, fileName));
221
+ currentTest.artifacts.screenshots.push(path.join(dir, fileName))
164
222
 
165
- const allureReporter = Container.plugins('allure');
223
+ const allureReporter = Container.plugins('allure')
166
224
  if (allureReporter && config.screenshotsForAllureReport) {
167
- output.output.plugin('stepByStepReport', 'Adding screenshot to Allure');
168
- allureReporter.addAttachment(`Screenshot of step ${step}`, fs.readFileSync(path.join(dir, fileName)), 'image/png');
225
+ output.plugin('stepByStepReport', 'Adding screenshot to Allure')
226
+ allureReporter.addAttachment(`Screenshot of step ${step}`, fs.readFileSync(path.join(dir, fileName)), 'image/png')
169
227
  }
170
228
  }
171
229
 
172
230
  function persist(test) {
173
- if (error) return;
231
+ if (error) return
174
232
 
175
- let indicatorHtml = '';
176
- let slideHtml = '';
233
+ let indicatorHtml = ''
234
+ let slideHtml = ''
177
235
 
178
236
  for (const i in slides) {
179
- const step = slides[i];
180
- const stepNum = parseInt(i, 10);
237
+ const step = slides[i]
238
+ const stepNum = parseInt(i, 10)
181
239
  indicatorHtml += template(templates.indicator, {
182
240
  step: stepNum,
183
241
  isActive: stepNum ? '' : 'class="active"',
184
- });
242
+ })
185
243
 
186
244
  slideHtml += template(templates.slides, {
187
245
  image: i,
188
246
  caption: step.toString().replace(/\[\d{2}m/g, ''), // remove ANSI escape sequence
189
247
  isActive: stepNum ? '' : 'active',
190
248
  isError: step.status === 'failed' ? 'error' : '',
191
- });
249
+ })
192
250
  }
193
251
 
194
252
  const html = template(templates.global, {
@@ -197,19 +255,19 @@ export default function (config) {
197
255
  feature: test.parent && test.parent.title,
198
256
  test: test.title,
199
257
  carousel_class: config.animateSlides ? ' slide' : '',
200
- });
258
+ })
201
259
 
202
- const index = path.join(dir, 'index.html');
203
- fs.writeFileSync(index, html);
204
- recordedTests[`${test.parent.title}: ${test.title}`] = path.relative(reportDir, index);
260
+ const index = path.join(dir, 'index.html')
261
+ fs.writeFileSync(index, html)
262
+ recordedTests[`${test.parent.title}: ${test.title}`] = path.relative(reportDir, index)
205
263
  }
206
264
 
207
265
  function isStepIgnored(step) {
208
- if (!config.ignoreSteps) return;
266
+ if (!config.ignoreSteps) return
209
267
  for (const pattern of config.ignoreSteps || []) {
210
- if (step.name.match(pattern)) return true;
268
+ if (step.name.match(pattern)) return true
211
269
  }
212
- return false;
270
+ return false
213
271
  }
214
272
  }
215
273
 
@@ -223,11 +281,11 @@ templates.slides = `
223
281
  <small>scroll up and down to see the full page</small>
224
282
  </div>
225
283
  </div>
226
- `;
284
+ `
227
285
 
228
286
  templates.indicator = `
229
287
  <li data-target="#steps" data-slide-to="{{step}}" {{isActive}}></li>
230
- `;
288
+ `
231
289
 
232
290
  templates.index = `
233
291
  <!DOCTYPE html>
@@ -256,7 +314,7 @@ templates.index = `
256
314
 
257
315
  </body>
258
316
  </html>
259
- `;
317
+ `
260
318
 
261
319
  templates.global = `
262
320
  <!DOCTYPE html>
@@ -366,4 +424,4 @@ templates.global = `
366
424
  </body>
367
425
 
368
426
  </html>
369
- `;
427
+ `
@@ -1,15 +1,13 @@
1
- import * as event from '../event.js';
2
- import { Step } from '../step.js';
1
+ import event from '../event.js'
2
+
3
+ import { TIMEOUT_ORDER } from '../timeout.js'
3
4
 
4
5
  const defaultConfig = {
5
6
  timeout: 150,
6
7
  overrideStepLimits: false,
7
- noTimeoutSteps: [
8
- 'amOnPage',
9
- 'wait*',
10
- ],
8
+ noTimeoutSteps: ['amOnPage', 'wait*'],
11
9
  customTimeoutSteps: [],
12
- };
10
+ }
13
11
 
14
12
  /**
15
13
  * Set timeout for test steps globally.
@@ -64,28 +62,25 @@ const defaultConfig = {
64
62
  * ```
65
63
  *
66
64
  */
67
- export default (config) => {
68
- config = Object.assign(defaultConfig, config);
65
+ export default function(config) {
66
+ config = Object.assign(defaultConfig, config)
69
67
  // below override rule makes sure customTimeoutSteps go first but then they override noTimeoutSteps in case of exact pattern match
70
- config.customTimeoutSteps = config.customTimeoutSteps.concat(config.noTimeoutSteps).concat(config.customTimeoutSteps);
68
+ config.customTimeoutSteps = config.customTimeoutSteps.concat(config.noTimeoutSteps).concat(config.customTimeoutSteps)
71
69
 
72
- event.dispatcher.on(event.step.before, (step) => {
73
- let stepTimeout;
70
+ event.dispatcher.on(event.step.before, step => {
71
+ let stepTimeout
74
72
  for (let stepRule of config.customTimeoutSteps) {
75
- let customTimeout = 0;
73
+ let customTimeout = 0
76
74
  if (Array.isArray(stepRule)) {
77
- if (stepRule.length > 1) customTimeout = stepRule[1];
78
- stepRule = stepRule[0];
75
+ if (stepRule.length > 1) customTimeout = stepRule[1]
76
+ stepRule = stepRule[0]
79
77
  }
80
- if (stepRule instanceof RegExp
81
- ? step.name.match(stepRule)
82
- : (step.name === stepRule || stepRule.indexOf('*') && step.name.startsWith(stepRule.slice(0, -1)))
83
- ) {
84
- stepTimeout = customTimeout;
85
- break;
78
+ if (stepRule instanceof RegExp ? step.name.match(stepRule) : step.name === stepRule || (stepRule.indexOf('*') && step.name.startsWith(stepRule.slice(0, -1)))) {
79
+ stepTimeout = customTimeout
80
+ break
86
81
  }
87
82
  }
88
- stepTimeout = stepTimeout === undefined ? config.timeout : stepTimeout;
89
- step.setTimeout(stepTimeout * 1000, config.overrideStepLimits ? Step.TIMEOUT_ORDER.stepTimeoutHard : Step.TIMEOUT_ORDER.stepTimeoutSoft);
90
- });
91
- };
83
+ stepTimeout = stepTimeout === undefined ? config.timeout : stepTimeout
84
+ step.setTimeout(stepTimeout * 1000, config.overrideStepLimits ? TIMEOUT_ORDER.stepTimeoutHard : TIMEOUT_ORDER.stepTimeoutSoft)
85
+ })
86
+ }
@@ -1,22 +1,22 @@
1
- import { v4 as uuidv4 } from 'uuid';
2
- import { promises as fsPromise } from 'fs';
3
- import path from 'path';
4
- import * as event from '../event.js';
1
+ import { v4 as uuidv4 } from 'uuid'
2
+ import fs from 'fs'
3
+ const fsPromise = fs.promises
4
+ import path from 'path'
5
+ import event from '../event.js'
5
6
 
6
7
  // This will convert a given timestamp in milliseconds to
7
8
  // an SRT recognized timestamp, ie HH:mm:ss,SSS
8
9
  function formatTimestamp(timestampInMs) {
9
- const date = new Date(0, 0, 0, 0, 0, 0, timestampInMs);
10
- const hours = date.getHours();
11
- const minutes = date.getMinutes();
12
- const seconds = date.getSeconds();
13
- const ms = timestampInMs - (hours * 3600000 + minutes * 60000 + seconds * 1000);
14
- return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')},${ms.toString().padStart(3, '0')}`;
10
+ const date = new Date(0, 0, 0, 0, 0, 0, timestampInMs)
11
+ const hours = date.getHours()
12
+ const minutes = date.getMinutes()
13
+ const seconds = date.getSeconds()
14
+ const ms = timestampInMs - (hours * 3600000 + minutes * 60000 + seconds * 1000)
15
+ return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')},${ms.toString().padStart(3, '0')}`
15
16
  }
16
17
 
17
- let steps = {};
18
- let testStartedAt;
19
-
18
+ let steps = {}
19
+ let testStartedAt
20
20
  /**
21
21
  * Automatically captures steps as subtitle, and saves it as an artifact when a video is found for a failed test
22
22
  *
@@ -30,41 +30,41 @@ let testStartedAt;
30
30
  * ```
31
31
  */
32
32
  export default function () {
33
- event.dispatcher.on(event.test.before, (_) => {
34
- testStartedAt = Date.now();
35
- steps = {};
36
- });
33
+ event.dispatcher.on(event.test.before, _ => {
34
+ testStartedAt = Date.now()
35
+ steps = {}
36
+ })
37
37
 
38
- event.dispatcher.on(event.step.started, (step) => {
39
- const stepStartedAt = Date.now();
40
- step.id = uuidv4();
38
+ event.dispatcher.on(event.step.started, step => {
39
+ const stepStartedAt = Date.now()
40
+ step.id = uuidv4()
41
41
 
42
- let title = `${step.actor}.${step.name}(${step.args ? step.args.join(',') : ''})`;
42
+ let title = `${step.actor}.${step.name}(${step.args ? step.args.join(',') : ''})`
43
43
  if (title.length > 100) {
44
- title = `${title.substring(0, 100)}...`;
44
+ title = `${title.substring(0, 100)}...`
45
45
  }
46
46
 
47
47
  steps[step.id] = {
48
48
  start: formatTimestamp(stepStartedAt - testStartedAt),
49
49
  startedAt: stepStartedAt,
50
50
  title,
51
- };
52
- });
51
+ }
52
+ })
53
53
 
54
- event.dispatcher.on(event.step.finished, (step) => {
54
+ event.dispatcher.on(event.step.finished, step => {
55
55
  if (step && step.id && steps[step.id]) {
56
- steps[step.id].end = formatTimestamp(Date.now() - testStartedAt);
56
+ steps[step.id].end = formatTimestamp(Date.now() - testStartedAt)
57
57
  }
58
- });
58
+ })
59
59
 
60
- event.dispatcher.on(event.test.after, async (test) => {
60
+ event.dispatcher.on(event.test.after, async test => {
61
61
  if (test && test.artifacts && test.artifacts.video) {
62
- const stepsSortedByStartTime = Object.values(steps);
62
+ const stepsSortedByStartTime = Object.values(steps)
63
63
  stepsSortedByStartTime.sort((stepA, stepB) => {
64
- return stepA.startedAt - stepB.startedAt;
65
- });
64
+ return stepA.startedAt - stepB.startedAt
65
+ })
66
66
 
67
- let subtitle = '';
67
+ let subtitle = ''
68
68
 
69
69
  // For an SRT file, every subtitle has to be in the format as mentioned below:
70
70
  //
@@ -77,13 +77,13 @@ export default function () {
77
77
  ${step.start} --> ${step.end}
78
78
  ${step.title}
79
79
 
80
- `;
80
+ `
81
81
  }
82
- });
82
+ })
83
83
 
84
- const { dir: artifactsDirectory, name: fileName } = path.parse(test.artifacts.video);
85
- await fsPromise.writeFile(`${artifactsDirectory}/${fileName}.srt`, subtitle);
86
- test.artifacts.subtitle = `${artifactsDirectory}/${fileName}.srt`;
84
+ const { dir: artifactsDirectory, name: fileName } = path.parse(test.artifacts.video)
85
+ await fsPromise.writeFile(`${artifactsDirectory}/${fileName}.srt`, subtitle)
86
+ test.artifacts.subtitle = `${artifactsDirectory}/${fileName}.srt`
87
87
  }
88
- });
88
+ })
89
89
  }