codeceptjs 4.0.0-beta.4 → 4.0.0-beta.6.esm-aria

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 (188) hide show
  1. package/README.md +89 -119
  2. package/bin/codecept.js +53 -54
  3. package/docs/webapi/clearCookie.mustache +1 -1
  4. package/lib/actor.js +70 -102
  5. package/lib/ai.js +131 -121
  6. package/lib/assert/empty.js +11 -12
  7. package/lib/assert/equal.js +16 -21
  8. package/lib/assert/error.js +2 -2
  9. package/lib/assert/include.js +11 -15
  10. package/lib/assert/throws.js +3 -5
  11. package/lib/assert/truth.js +10 -7
  12. package/lib/assert.js +18 -18
  13. package/lib/codecept.js +112 -101
  14. package/lib/colorUtils.js +48 -50
  15. package/lib/command/check.js +206 -0
  16. package/lib/command/configMigrate.js +13 -14
  17. package/lib/command/definitions.js +24 -36
  18. package/lib/command/dryRun.js +16 -16
  19. package/lib/command/generate.js +38 -39
  20. package/lib/command/gherkin/init.js +36 -38
  21. package/lib/command/gherkin/snippets.js +76 -74
  22. package/lib/command/gherkin/steps.js +21 -18
  23. package/lib/command/info.js +49 -15
  24. package/lib/command/init.js +41 -37
  25. package/lib/command/interactive.js +22 -13
  26. package/lib/command/list.js +11 -10
  27. package/lib/command/run-multiple/chunk.js +50 -47
  28. package/lib/command/run-multiple/collection.js +5 -5
  29. package/lib/command/run-multiple/run.js +3 -3
  30. package/lib/command/run-multiple.js +27 -47
  31. package/lib/command/run-rerun.js +6 -7
  32. package/lib/command/run-workers.js +15 -66
  33. package/lib/command/run.js +8 -8
  34. package/lib/command/utils.js +22 -21
  35. package/lib/command/workers/runTests.js +131 -241
  36. package/lib/config.js +111 -49
  37. package/lib/container.js +589 -244
  38. package/lib/data/context.js +16 -18
  39. package/lib/data/dataScenarioConfig.js +9 -9
  40. package/lib/data/dataTableArgument.js +7 -7
  41. package/lib/data/table.js +6 -12
  42. package/lib/effects.js +307 -0
  43. package/lib/els.js +160 -0
  44. package/lib/event.js +24 -19
  45. package/lib/globals.js +141 -0
  46. package/lib/heal.js +89 -81
  47. package/lib/helper/AI.js +3 -2
  48. package/lib/helper/ApiDataFactory.js +19 -19
  49. package/lib/helper/Appium.js +47 -51
  50. package/lib/helper/FileSystem.js +35 -15
  51. package/lib/helper/GraphQL.js +1 -1
  52. package/lib/helper/GraphQLDataFactory.js +4 -4
  53. package/lib/helper/JSONResponse.js +72 -45
  54. package/lib/helper/Mochawesome.js +14 -11
  55. package/lib/helper/Playwright.js +832 -434
  56. package/lib/helper/Puppeteer.js +393 -292
  57. package/lib/helper/REST.js +32 -27
  58. package/lib/helper/WebDriver.js +320 -219
  59. package/lib/helper/errors/ConnectionRefused.js +6 -6
  60. package/lib/helper/errors/ElementAssertion.js +11 -16
  61. package/lib/helper/errors/ElementNotFound.js +5 -9
  62. package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
  63. package/lib/helper/extras/Console.js +11 -11
  64. package/lib/helper/extras/PlaywrightLocator.js +110 -0
  65. package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
  66. package/lib/helper/extras/PlaywrightRestartOpts.js +23 -23
  67. package/lib/helper/extras/Popup.js +22 -22
  68. package/lib/helper/extras/React.js +29 -30
  69. package/lib/helper/network/actions.js +33 -48
  70. package/lib/helper/network/utils.js +76 -83
  71. package/lib/helper/scripts/blurElement.js +6 -6
  72. package/lib/helper/scripts/focusElement.js +6 -6
  73. package/lib/helper/scripts/highlightElement.js +9 -9
  74. package/lib/helper/scripts/isElementClickable.js +34 -34
  75. package/lib/helper.js +2 -1
  76. package/lib/history.js +23 -20
  77. package/lib/hooks.js +10 -10
  78. package/lib/html.js +90 -100
  79. package/lib/index.js +48 -21
  80. package/lib/listener/config.js +8 -9
  81. package/lib/listener/emptyRun.js +54 -0
  82. package/lib/listener/exit.js +10 -12
  83. package/lib/listener/{retry.js → globalRetry.js} +10 -10
  84. package/lib/listener/globalTimeout.js +166 -0
  85. package/lib/listener/helpers.js +43 -24
  86. package/lib/listener/mocha.js +4 -5
  87. package/lib/listener/result.js +11 -0
  88. package/lib/listener/steps.js +26 -23
  89. package/lib/listener/store.js +20 -0
  90. package/lib/locator.js +213 -192
  91. package/lib/mocha/asyncWrapper.js +264 -0
  92. package/lib/mocha/bdd.js +167 -0
  93. package/lib/mocha/cli.js +341 -0
  94. package/lib/mocha/factory.js +160 -0
  95. package/lib/{interfaces → mocha}/featureConfig.js +33 -13
  96. package/lib/{interfaces → mocha}/gherkin.js +75 -45
  97. package/lib/mocha/hooks.js +121 -0
  98. package/lib/mocha/index.js +21 -0
  99. package/lib/mocha/inject.js +46 -0
  100. package/lib/{interfaces → mocha}/scenarioConfig.js +32 -8
  101. package/lib/mocha/suite.js +89 -0
  102. package/lib/mocha/test.js +178 -0
  103. package/lib/mocha/types.d.ts +42 -0
  104. package/lib/mocha/ui.js +229 -0
  105. package/lib/output.js +86 -64
  106. package/lib/parser.js +44 -44
  107. package/lib/pause.js +160 -139
  108. package/lib/plugin/analyze.js +403 -0
  109. package/lib/plugin/{autoLogin.js → auth.js} +137 -43
  110. package/lib/plugin/autoDelay.js +19 -15
  111. package/lib/plugin/coverage.js +22 -27
  112. package/lib/plugin/customLocator.js +5 -5
  113. package/lib/plugin/customReporter.js +53 -0
  114. package/lib/plugin/heal.js +49 -17
  115. package/lib/plugin/pageInfo.js +140 -0
  116. package/lib/plugin/pauseOnFail.js +4 -3
  117. package/lib/plugin/retryFailedStep.js +60 -19
  118. package/lib/plugin/screenshotOnFail.js +80 -83
  119. package/lib/plugin/stepByStepReport.js +70 -31
  120. package/lib/plugin/stepTimeout.js +7 -13
  121. package/lib/plugin/subtitles.js +10 -9
  122. package/lib/recorder.js +167 -126
  123. package/lib/rerun.js +94 -50
  124. package/lib/result.js +161 -0
  125. package/lib/secret.js +18 -17
  126. package/lib/session.js +95 -89
  127. package/lib/step/base.js +239 -0
  128. package/lib/step/comment.js +10 -0
  129. package/lib/step/config.js +50 -0
  130. package/lib/step/func.js +46 -0
  131. package/lib/step/helper.js +50 -0
  132. package/lib/step/meta.js +99 -0
  133. package/lib/step/record.js +74 -0
  134. package/lib/step/retry.js +11 -0
  135. package/lib/step/section.js +55 -0
  136. package/lib/step.js +18 -332
  137. package/lib/steps.js +54 -0
  138. package/lib/store.js +37 -5
  139. package/lib/template/heal.js +2 -11
  140. package/lib/timeout.js +60 -0
  141. package/lib/transform.js +8 -8
  142. package/lib/translation.js +32 -18
  143. package/lib/utils.js +354 -250
  144. package/lib/workerStorage.js +16 -16
  145. package/lib/workers.js +366 -282
  146. package/package.json +107 -95
  147. package/translations/de-DE.js +5 -4
  148. package/translations/fr-FR.js +5 -4
  149. package/translations/index.js +23 -9
  150. package/translations/it-IT.js +5 -4
  151. package/translations/ja-JP.js +5 -4
  152. package/translations/nl-NL.js +76 -0
  153. package/translations/pl-PL.js +5 -4
  154. package/translations/pt-BR.js +5 -4
  155. package/translations/ru-RU.js +5 -4
  156. package/translations/utils.js +18 -0
  157. package/translations/zh-CN.js +5 -4
  158. package/translations/zh-TW.js +5 -4
  159. package/typings/index.d.ts +177 -186
  160. package/typings/promiseBasedTypes.d.ts +3573 -5941
  161. package/typings/types.d.ts +4042 -6370
  162. package/lib/cli.js +0 -256
  163. package/lib/helper/ExpectHelper.js +0 -391
  164. package/lib/helper/Nightmare.js +0 -1504
  165. package/lib/helper/Protractor.js +0 -1863
  166. package/lib/helper/SoftExpectHelper.js +0 -381
  167. package/lib/helper/TestCafe.js +0 -1414
  168. package/lib/helper/clientscripts/nightmare.js +0 -213
  169. package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -43
  170. package/lib/helper/testcafe/testControllerHolder.js +0 -42
  171. package/lib/helper/testcafe/testcafe-utils.js +0 -62
  172. package/lib/interfaces/bdd.js +0 -81
  173. package/lib/listener/artifacts.js +0 -19
  174. package/lib/listener/timeout.js +0 -109
  175. package/lib/mochaFactory.js +0 -113
  176. package/lib/plugin/allure.js +0 -15
  177. package/lib/plugin/commentStep.js +0 -136
  178. package/lib/plugin/debugErrors.js +0 -67
  179. package/lib/plugin/eachElement.js +0 -127
  180. package/lib/plugin/fakerTransform.js +0 -49
  181. package/lib/plugin/retryTo.js +0 -127
  182. package/lib/plugin/selenoid.js +0 -384
  183. package/lib/plugin/standardActingHelpers.js +0 -3
  184. package/lib/plugin/tryTo.js +0 -115
  185. package/lib/plugin/wdio.js +0 -249
  186. package/lib/scenario.js +0 -224
  187. package/lib/ui.js +0 -236
  188. package/lib/within.js +0 -70
@@ -1,12 +1,17 @@
1
- const fs = require('fs')
2
- const path = require('path')
1
+ import fs from 'fs'
2
+ import path from 'path'
3
3
 
4
- const Container = require('../container')
5
- const recorder = require('../recorder')
6
- const event = require('../event')
7
- const output = require('../output')
8
- const { fileExists, clearString } = require('../utils')
9
- const Codeceptjs = require('../index')
4
+ import Container from '../container.js'
5
+
6
+ import recorder from '../recorder.js'
7
+
8
+ import event from '../event.js'
9
+
10
+ import output from '../output.js'
11
+
12
+ import { fileExists } from '../utils.js'
13
+ import Codeceptjs from '../index.js'
14
+ import { testToFileName } from '../mocha/test.js'
10
15
 
11
16
  const defaultConfig = {
12
17
  uniqueScreenshotNames: false,
@@ -14,7 +19,7 @@ const defaultConfig = {
14
19
  fullPageScreenshots: false,
15
20
  }
16
21
 
17
- const supportedHelpers = require('./standardActingHelpers')
22
+ const supportedHelpers = Container.STANDARD_ACTING_HELPERS
18
23
 
19
24
  /**
20
25
  * Creates screenshot on failure. Screenshot is saved into `output` directory.
@@ -42,7 +47,7 @@ const supportedHelpers = require('./standardActingHelpers')
42
47
  *
43
48
  *
44
49
  */
45
- module.exports = function (config) {
50
+ export default function (config) {
46
51
  const helpers = Container.helpers()
47
52
  let helper
48
53
 
@@ -63,9 +68,7 @@ module.exports = function (config) {
63
68
  }
64
69
 
65
70
  if (Codeceptjs.container.mocha()) {
66
- options.reportDir =
67
- Codeceptjs.container.mocha().options.reporterOptions &&
68
- Codeceptjs.container.mocha().options.reporterOptions.reportDir
71
+ options.reportDir = Codeceptjs.container.mocha()?.options?.reporterOptions && Codeceptjs.container.mocha()?.options?.reporterOptions?.reportDir
69
72
  }
70
73
 
71
74
  if (options.disableScreenshots) {
@@ -73,32 +76,42 @@ module.exports = function (config) {
73
76
  return
74
77
  }
75
78
 
76
- event.dispatcher.on(event.test.failed, (test) => {
77
- if (test.ctx?._runnable.title.includes('hook: ')) {
78
- output.plugin(
79
- 'screenshotOnFail',
80
- 'BeforeSuite/AfterSuite do not have any access to the browser, hence it could not take screenshot.',
81
- )
79
+ event.dispatcher.on(event.test.failed, (test, _err, hookName) => {
80
+ if (hookName === 'BeforeSuite' || hookName === 'AfterSuite') {
81
+ // no browser here
82
82
  return
83
83
  }
84
+
84
85
  recorder.add(
85
86
  'screenshot of failed test',
86
87
  async () => {
87
- let fileName = clearString(test.title)
88
88
  const dataType = 'image/png'
89
89
  // This prevents data driven to be included in the failed screenshot file name
90
- if (fileName.indexOf('{') !== -1) {
91
- fileName = fileName.substr(0, fileName.indexOf('{') - 3).trim()
92
- }
93
- if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook')
94
- fileName = clearString(`${test.title}_${test.ctx.test.title}`)
90
+ let fileName
91
+
95
92
  if (options.uniqueScreenshotNames && test) {
96
- const uuid = _getUUID(test)
97
- fileName = `${fileName.substring(0, 10)}_${uuid}.failed.png`
93
+ fileName = `${testToFileName(test, { suffix: '', unique: true })}.failed.png`
98
94
  } else {
99
- fileName += '.failed.png'
95
+ fileName = `${testToFileName(test, { suffix: '', unique: false })}.failed.png`
96
+ }
97
+ const quietMode = !('output_dir' in global) || !global.output_dir
98
+ if (!quietMode) {
99
+ output.plugin('screenshotOnFail', 'Test failed, try to save a screenshot')
100
+ }
101
+
102
+ // Re-check helpers at runtime in case they weren't ready during plugin init
103
+ const runtimeHelpers = Container.helpers()
104
+ let runtimeHelper = null
105
+ for (const helperName of supportedHelpers) {
106
+ if (Object.keys(runtimeHelpers).indexOf(helperName) > -1) {
107
+ runtimeHelper = runtimeHelpers[helperName]
108
+ break
109
+ }
110
+ }
111
+
112
+ if (runtimeHelper && typeof runtimeHelper.saveScreenshot === 'function') {
113
+ helper = runtimeHelper
100
114
  }
101
- output.plugin('screenshotOnFail', 'Test failed, try to save a screenshot')
102
115
 
103
116
  try {
104
117
  if (options.reportDir) {
@@ -108,57 +121,53 @@ module.exports = function (config) {
108
121
  fs.mkdirSync(mochaReportDir)
109
122
  }
110
123
  }
111
- await helper.saveScreenshot(fileName, options.fullPageScreenshots)
112
124
 
113
- if (!test.artifacts) test.artifacts = {}
114
- test.artifacts.screenshot = path.join(global.output_dir, fileName)
115
- if (
116
- Container.mocha().options.reporterOptions['mocha-junit-reporter'] &&
117
- Container.mocha().options.reporterOptions['mocha-junit-reporter'].options.attachments
118
- ) {
119
- test.attachments = [path.join(global.output_dir, fileName)]
125
+ // Check if browser/page is still available before attempting screenshot
126
+ if (helper.page && helper.page.isClosed && helper.page.isClosed()) {
127
+ throw new Error('Browser page has been closed')
120
128
  }
121
-
122
- const allureReporter = Container.plugins('allure')
123
- if (allureReporter) {
124
- allureReporter.addAttachment(
125
- 'Main session - Last Seen Screenshot',
126
- fs.readFileSync(path.join(global.output_dir, fileName)),
127
- dataType,
128
- )
129
-
130
- if (helper.activeSessionName) {
131
- const sessions = helper.sessionPages || helper.sessionWindows
132
- for (const sessionName in sessions) {
133
- const screenshotFileName = `${sessionName}_${fileName}`
134
- test.artifacts[`${sessionName.replace(/ /g, '_')}_screenshot`] = path.join(
135
- global.output_dir,
136
- screenshotFileName,
137
- )
138
- allureReporter.addAttachment(
139
- `${sessionName} - Last Seen Screenshot`,
140
- fs.readFileSync(path.join(global.output_dir, screenshotFileName)),
141
- dataType,
142
- )
143
- }
144
- }
129
+ if (helper.browser && helper.browser.isConnected && !helper.browser.isConnected()) {
130
+ throw new Error('Browser has been disconnected')
145
131
  }
146
132
 
147
- const cucumberReporter = Container.plugins('cucumberJsonReporter')
148
- if (cucumberReporter) {
149
- cucumberReporter.addScreenshot(test.artifacts.screenshot)
133
+ // Add timeout wrapper to prevent hanging with shorter timeout for ESM
134
+ const screenshotPromise = helper.saveScreenshot(fileName, options.fullPageScreenshots)
135
+ const timeoutPromise = new Promise((_, reject) => {
136
+ setTimeout(() => reject(new Error('Screenshot timeout after 5 seconds')), 5000)
137
+ })
138
+
139
+ await Promise.race([screenshotPromise, timeoutPromise])
140
+
141
+ if (!test.artifacts) test.artifacts = {}
142
+ // Some unit tests may not define global.output_dir; avoid throwing when it is undefined
143
+ // Detect output directory safely (may not be initialized in narrow unit tests)
144
+ const baseOutputDir = 'output_dir' in global && typeof global.output_dir === 'string' && global.output_dir ? global.output_dir : null
145
+ if (baseOutputDir) {
146
+ test.artifacts.screenshot = path.join(baseOutputDir, fileName)
147
+ if (Container.mocha().options.reporterOptions['mocha-junit-reporter'] && Container.mocha().options.reporterOptions['mocha-junit-reporter'].options.attachments) {
148
+ test.attachments = [path.join(baseOutputDir, fileName)]
149
+ }
150
+ } else {
151
+ // Fallback: just store the file name to keep tests stable without triggering path errors
152
+ test.artifacts.screenshot = fileName
150
153
  }
151
154
  } catch (err) {
152
- output.plugin(err)
155
+ if (!quietMode) {
156
+ output.plugin('screenshotOnFail', `Failed to save screenshot: ${err.message}`)
157
+ }
158
+ // Enhanced error handling for browser closed scenarios
153
159
  if (
154
160
  err &&
155
- err.type &&
156
- err.type === 'RuntimeError' &&
157
- err.message &&
158
- (err.message.indexOf('was terminated due to') > -1 ||
159
- err.message.indexOf('no such window: target window already closed') > -1)
161
+ ((err.message &&
162
+ (err.message.includes('Target page, context or browser has been closed') ||
163
+ err.message.includes('Browser page has been closed') ||
164
+ err.message.includes('Browser has been disconnected') ||
165
+ err.message.includes('was terminated due to') ||
166
+ err.message.includes('no such window: target window already closed') ||
167
+ err.message.includes('Screenshot timeout after'))) ||
168
+ (err.type && err.type === 'RuntimeError'))
160
169
  ) {
161
- output.log(`Can't make screenshot, ${err}`)
170
+ output.log(`Can't make screenshot, ${err.message}`)
162
171
  helper.isRunning = false
163
172
  }
164
173
  }
@@ -166,16 +175,4 @@ module.exports = function (config) {
166
175
  true,
167
176
  )
168
177
  })
169
-
170
- function _getUUID(test) {
171
- if (test.uuid) {
172
- return test.uuid
173
- }
174
-
175
- if (test.ctx && test.ctx.test.uuid) {
176
- return test.ctx.test.uuid
177
- }
178
-
179
- return Math.floor(new Date().getTime() / 1000)
180
- }
181
178
  }
@@ -1,17 +1,18 @@
1
- const colors = require('chalk')
2
- const crypto = require('crypto')
3
- const figures = require('figures')
4
- const fs = require('fs')
5
- const mkdirp = require('mkdirp')
6
- const path = require('path')
7
-
8
- const Container = require('../container')
9
- const recorder = require('../recorder')
10
- const event = require('../event')
11
- const output = require('../output')
12
- const { template, deleteDir } = require('../utils')
13
-
14
- const supportedHelpers = require('./standardActingHelpers')
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
15
16
 
16
17
  const defaultConfig = {
17
18
  deleteSuccessful: true,
@@ -62,7 +63,7 @@ const templates = {}
62
63
  * @param {*} config
63
64
  */
64
65
 
65
- module.exports = function (config) {
66
+ export default function (config) {
66
67
  const helpers = Container.helpers()
67
68
  let helper
68
69
 
@@ -88,11 +89,11 @@ module.exports = function (config) {
88
89
  const pad = '0000'
89
90
  const reportDir = config.output ? path.resolve(global.codecept_dir, config.output) : defaultConfig.output
90
91
 
91
- event.dispatcher.on(event.suite.before, (suite) => {
92
+ event.dispatcher.on(event.suite.before, suite => {
92
93
  stepNum = -1
93
94
  })
94
95
 
95
- event.dispatcher.on(event.test.before, (test) => {
96
+ event.dispatcher.on(event.test.before, test => {
96
97
  const sha256hash = crypto
97
98
  .createHash('sha256')
98
99
  .update(test.file + test.title)
@@ -106,34 +107,74 @@ module.exports = function (config) {
106
107
  currentTest = test
107
108
  })
108
109
 
109
- event.dispatcher.on(event.step.failed, (step) => {
110
+ event.dispatcher.on(event.step.failed, step => {
110
111
  recorder.add('screenshot of failed test', async () => persistStep(step), true)
111
112
  })
112
113
 
113
- event.dispatcher.on(event.step.after, (step) => {
114
+ event.dispatcher.on(event.step.after, step => {
114
115
  recorder.add('screenshot of step of test', async () => persistStep(step), true)
115
116
  })
116
117
 
117
- event.dispatcher.on(event.test.passed, (test) => {
118
+ event.dispatcher.on(event.test.passed, test => {
118
119
  if (!config.deleteSuccessful) return persist(test)
119
120
  // cleanup
120
121
  deleteDir(dir)
121
122
  })
122
123
 
123
- event.dispatcher.on(event.test.failed, (test, err) => {
124
- if (test.ctx._runnable.title.includes('hook: ')) {
125
- output.plugin(
126
- 'stepByStepReport',
127
- 'BeforeSuite/AfterSuite do not have any access to the browser, hence it could not take screenshot.',
128
- )
124
+ event.dispatcher.on(event.test.failed, (test, _err, hookName) => {
125
+ if (hookName === 'BeforeSuite' || hookName === 'AfterSuite') {
126
+ // no browser here
129
127
  return
130
128
  }
131
- persist(test, err)
129
+
130
+ persist(test)
132
131
  })
133
132
 
134
133
  event.dispatcher.on(event.all.result, () => {
135
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
+ }
136
173
 
174
+ return results
175
+ }
176
+
177
+ function generateRecordsHtml(recordedTests) {
137
178
  let links = ''
138
179
 
139
180
  for (const link in recordedTests) {
@@ -147,10 +188,8 @@ module.exports = function (config) {
147
188
 
148
189
  fs.writeFileSync(path.join(reportDir, 'records.html'), indexHTML)
149
190
 
150
- output.print(
151
- `${figures.circleFilled} Step-by-step preview: ${colors.white.bold(`file://${reportDir}/records.html`)}`,
152
- )
153
- })
191
+ output.print(`${figures.circleFilled} Step-by-step preview: ${colors.white.bold(`file://${reportDir}/records.html`)}`)
192
+ }
154
193
 
155
194
  async function persistStep(step) {
156
195
  if (stepNum === -1) return // Ignore steps from BeforeSuite function
@@ -1,5 +1,6 @@
1
- const event = require('../event')
2
- const TIMEOUT_ORDER = require('../step').TIMEOUT_ORDER
1
+ import event from '../event.js'
2
+
3
+ import { TIMEOUT_ORDER } from '../timeout.js'
3
4
 
4
5
  const defaultConfig = {
5
6
  timeout: 150,
@@ -61,12 +62,12 @@ const defaultConfig = {
61
62
  * ```
62
63
  *
63
64
  */
64
- module.exports = (config) => {
65
+ export default function(config) {
65
66
  config = Object.assign(defaultConfig, config)
66
67
  // below override rule makes sure customTimeoutSteps go first but then they override noTimeoutSteps in case of exact pattern match
67
68
  config.customTimeoutSteps = config.customTimeoutSteps.concat(config.noTimeoutSteps).concat(config.customTimeoutSteps)
68
69
 
69
- event.dispatcher.on(event.step.before, (step) => {
70
+ event.dispatcher.on(event.step.before, step => {
70
71
  let stepTimeout
71
72
  for (let stepRule of config.customTimeoutSteps) {
72
73
  let customTimeout = 0
@@ -74,19 +75,12 @@ module.exports = (config) => {
74
75
  if (stepRule.length > 1) customTimeout = stepRule[1]
75
76
  stepRule = stepRule[0]
76
77
  }
77
- if (
78
- stepRule instanceof RegExp
79
- ? step.name.match(stepRule)
80
- : step.name === stepRule || (stepRule.indexOf('*') && step.name.startsWith(stepRule.slice(0, -1)))
81
- ) {
78
+ if (stepRule instanceof RegExp ? step.name.match(stepRule) : step.name === stepRule || (stepRule.indexOf('*') && step.name.startsWith(stepRule.slice(0, -1)))) {
82
79
  stepTimeout = customTimeout
83
80
  break
84
81
  }
85
82
  }
86
83
  stepTimeout = stepTimeout === undefined ? config.timeout : stepTimeout
87
- step.setTimeout(
88
- stepTimeout * 1000,
89
- config.overrideStepLimits ? TIMEOUT_ORDER.stepTimeoutHard : TIMEOUT_ORDER.stepTimeoutSoft,
90
- )
84
+ step.setTimeout(stepTimeout * 1000, config.overrideStepLimits ? TIMEOUT_ORDER.stepTimeoutHard : TIMEOUT_ORDER.stepTimeoutSoft)
91
85
  })
92
86
  }
@@ -1,7 +1,8 @@
1
- const { v4: uuidv4 } = require('uuid')
2
- const fsPromise = require('fs').promises
3
- const path = require('path')
4
- const event = require('../event')
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
@@ -28,13 +29,13 @@ let testStartedAt
28
29
  * }
29
30
  * ```
30
31
  */
31
- module.exports = function () {
32
- event.dispatcher.on(event.test.before, (_) => {
32
+ export default function () {
33
+ event.dispatcher.on(event.test.before, _ => {
33
34
  testStartedAt = Date.now()
34
35
  steps = {}
35
36
  })
36
37
 
37
- event.dispatcher.on(event.step.started, (step) => {
38
+ event.dispatcher.on(event.step.started, step => {
38
39
  const stepStartedAt = Date.now()
39
40
  step.id = uuidv4()
40
41
 
@@ -50,13 +51,13 @@ module.exports = function () {
50
51
  }
51
52
  })
52
53
 
53
- event.dispatcher.on(event.step.finished, (step) => {
54
+ event.dispatcher.on(event.step.finished, step => {
54
55
  if (step && step.id && steps[step.id]) {
55
56
  steps[step.id].end = formatTimestamp(Date.now() - testStartedAt)
56
57
  }
57
58
  })
58
59
 
59
- event.dispatcher.on(event.test.after, async (test) => {
60
+ event.dispatcher.on(event.test.after, async test => {
60
61
  if (test && test.artifacts && test.artifacts.video) {
61
62
  const stepsSortedByStartTime = Object.values(steps)
62
63
  stepsSortedByStartTime.sort((stepA, stepB) => {