codeceptjs 4.0.0-beta.1 → 4.0.0-beta.10.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 (207) 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 +71 -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 +238 -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 +300 -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 +124 -50
  39. package/lib/container.js +751 -260
  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 +47 -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/mask_data.js +47 -0
  157. package/lib/utils.js +411 -228
  158. package/lib/workerStorage.js +37 -34
  159. package/lib/workers.js +532 -296
  160. package/package.json +115 -95
  161. package/translations/de-DE.js +5 -3
  162. package/translations/fr-FR.js +5 -4
  163. package/translations/index.js +22 -12
  164. package/translations/it-IT.js +4 -3
  165. package/translations/ja-JP.js +4 -3
  166. package/translations/nl-NL.js +76 -0
  167. package/translations/pl-PL.js +4 -3
  168. package/translations/pt-BR.js +4 -3
  169. package/translations/ru-RU.js +4 -3
  170. package/translations/utils.js +10 -0
  171. package/translations/zh-CN.js +4 -3
  172. package/translations/zh-TW.js +4 -3
  173. package/typings/index.d.ts +546 -185
  174. package/typings/promiseBasedTypes.d.ts +150 -879
  175. package/typings/types.d.ts +547 -996
  176. package/lib/cli.js +0 -249
  177. package/lib/dirname.js +0 -5
  178. package/lib/helper/Expect.js +0 -425
  179. package/lib/helper/ExpectHelper.js +0 -399
  180. package/lib/helper/MockServer.js +0 -223
  181. package/lib/helper/Nightmare.js +0 -1411
  182. package/lib/helper/Protractor.js +0 -1835
  183. package/lib/helper/SoftExpectHelper.js +0 -381
  184. package/lib/helper/TestCafe.js +0 -1410
  185. package/lib/helper/clientscripts/nightmare.js +0 -213
  186. package/lib/helper/testcafe/testControllerHolder.js +0 -42
  187. package/lib/helper/testcafe/testcafe-utils.js +0 -63
  188. package/lib/interfaces/bdd.js +0 -98
  189. package/lib/interfaces/featureConfig.js +0 -69
  190. package/lib/interfaces/gherkin.js +0 -195
  191. package/lib/listener/artifacts.js +0 -19
  192. package/lib/listener/retry.js +0 -68
  193. package/lib/listener/timeout.js +0 -109
  194. package/lib/mochaFactory.js +0 -110
  195. package/lib/plugin/allure.js +0 -15
  196. package/lib/plugin/commentStep.js +0 -136
  197. package/lib/plugin/debugErrors.js +0 -67
  198. package/lib/plugin/eachElement.js +0 -127
  199. package/lib/plugin/fakerTransform.js +0 -49
  200. package/lib/plugin/retryTo.js +0 -121
  201. package/lib/plugin/selenoid.js +0 -371
  202. package/lib/plugin/standardActingHelpers.js +0 -9
  203. package/lib/plugin/tryTo.js +0 -105
  204. package/lib/plugin/wdio.js +0 -246
  205. package/lib/scenario.js +0 -222
  206. package/lib/ui.js +0 -238
  207. package/lib/within.js +0 -70
@@ -1,68 +0,0 @@
1
- import * as event from '../event.js';
2
- import * as output from '../output.js';
3
- import Config from '../config.js';
4
- import { isNotSet } from '../utils.js';
5
-
6
- const hooks = ['Before', 'After', 'BeforeSuite', 'AfterSuite'];
7
-
8
- export default function () {
9
- event.dispatcher.on(event.suite.before, (suite) => {
10
- let retryConfig = Config.get('retry');
11
- if (!retryConfig) return;
12
-
13
- if (Number.isInteger(+retryConfig)) {
14
- // is number
15
- const retryNum = +retryConfig;
16
- output.output.log(`Retries: ${retryNum}`);
17
- suite.retries(retryNum);
18
- return;
19
- }
20
-
21
- if (!Array.isArray(retryConfig)) {
22
- retryConfig = [retryConfig];
23
- }
24
-
25
- for (const config of retryConfig) {
26
- if (config.grep) {
27
- if (!suite.title.includes(config.grep)) continue;
28
- }
29
-
30
- hooks.filter(hook => !!config[hook]).forEach((hook) => {
31
- if (isNotSet(suite.opts[`retry${hook}`])) suite.opts[`retry${hook}`] = config[hook];
32
- });
33
-
34
- if (config.Feature) {
35
- if (isNotSet(suite.retries())) suite.retries(config.Feature);
36
- }
37
-
38
- output.output.log(`Retries: ${JSON.stringify(config)}`);
39
- }
40
- });
41
-
42
- event.dispatcher.on(event.test.before, (test) => {
43
- let retryConfig = Config.get('retry');
44
- if (!retryConfig) return;
45
-
46
- if (Number.isInteger(+retryConfig)) {
47
- if (test.retries() === -1) test.retries(retryConfig);
48
- return;
49
- }
50
-
51
- if (!Array.isArray(retryConfig)) {
52
- retryConfig = [retryConfig];
53
- }
54
-
55
- retryConfig = retryConfig.filter(config => !!config.Scenario);
56
-
57
- for (const config of retryConfig) {
58
- if (config.grep) {
59
- if (!test.fullTitle().includes(config.grep)) continue;
60
- }
61
-
62
- if (config.Scenario) {
63
- if (test.retries() === -1) test.retries(config.Scenario);
64
- output.output.log(`Retries: ${config.Scenario}`);
65
- }
66
- }
67
- });
68
- }
@@ -1,109 +0,0 @@
1
- import * as event from '../event.js';
2
- import * as output from '../output.js';
3
- import recorder from '../recorder.js';
4
- import Config from '../config.js';
5
- import { timeouts } from '../store.js';
6
- import { Step } from '../step.js';
7
-
8
- export default function () {
9
- let timeout;
10
- let suiteTimeout = [];
11
- let currentTest;
12
- let currentTimeout;
13
-
14
- if (!timeouts) {
15
- console.log('Timeouts were disabled');
16
- return;
17
- }
18
-
19
- event.dispatcher.on(event.suite.before, (suite) => {
20
- suiteTimeout = [];
21
- let timeoutConfig = Config.get('timeout');
22
-
23
- if (timeoutConfig) {
24
- if (!Number.isNaN(+timeoutConfig)) {
25
- checkForSeconds(timeoutConfig);
26
- suiteTimeout.push(timeoutConfig);
27
- }
28
-
29
- if (!Array.isArray(timeoutConfig)) {
30
- timeoutConfig = [timeoutConfig];
31
- }
32
-
33
- for (const config of timeoutConfig.filter(c => !!c.Feature)) {
34
- if (config.grep) {
35
- if (!suite.title.includes(config.grep)) continue;
36
- }
37
- suiteTimeout.push(config.Feature);
38
- }
39
- }
40
-
41
- if (suite.totalTimeout) suiteTimeout.push(suite.totalTimeout);
42
- output.output.log(`Timeouts: ${suiteTimeout}`);
43
- });
44
-
45
- event.dispatcher.on(event.test.before, (test) => {
46
- currentTest = test;
47
- let testTimeout = null;
48
-
49
- let timeoutConfig = Config.get('timeout');
50
-
51
- if (typeof timeoutConfig === 'object' || Array.isArray(timeoutConfig)) {
52
- if (!Array.isArray(timeoutConfig)) {
53
- timeoutConfig = [timeoutConfig];
54
- }
55
-
56
- for (const config of timeoutConfig.filter(c => !!c.Scenario)) {
57
- console.log('Test Timeout', config, test.title.includes(config.grep));
58
- if (config.grep) {
59
- if (!test.title.includes(config.grep)) continue;
60
- }
61
- testTimeout = config.Scenario;
62
- }
63
- }
64
-
65
- timeout = test.totalTimeout || testTimeout || suiteTimeout[suiteTimeout.length - 1];
66
- if (!timeout) return;
67
- currentTimeout = timeout;
68
- output.output.debug(`Test Timeout: ${timeout}s`);
69
- timeout *= 1000;
70
- });
71
-
72
- event.dispatcher.on(event.test.passed, (test) => {
73
- currentTest = null;
74
- });
75
-
76
- event.dispatcher.on(event.test.failed, (test) => {
77
- currentTest = null;
78
- });
79
-
80
- event.dispatcher.on(event.step.before, (step) => {
81
- if (typeof timeout !== 'number') return;
82
-
83
- if (timeout < 0) {
84
- step.setTimeout(0.01, Step.TIMEOUT_ORDER.testOrSuite);
85
- } else {
86
- step.setTimeout(timeout, Step.TIMEOUT_ORDER.testOrSuite);
87
- }
88
- });
89
-
90
- event.dispatcher.on(event.step.finished, (step) => {
91
- if (typeof timeout === 'number' && !Number.isNaN(timeout)) timeout -= step.duration;
92
-
93
- if (typeof timeout === 'number' && timeout <= 0 && recorder.isRunning()) {
94
- if (currentTest && currentTest.callback) {
95
- recorder.reset();
96
- // replace mocha timeout with custom timeout
97
- currentTest.timeout(0);
98
- currentTest.callback(new Error(`Timeout ${currentTimeout}s exceeded (with Before hook)`));
99
- currentTest.timedOut = true;
100
- }
101
- }
102
- });
103
- }
104
-
105
- function checkForSeconds(timeout) {
106
- if (timeout >= 1000) {
107
- console.log(`Warning: Timeout was set to ${timeout}secs.\nGlobal timeout should be specified in seconds.`);
108
- }
109
- }
@@ -1,110 +0,0 @@
1
- import Mocha from 'mocha';
2
- import fs from 'fs';
3
- import reporter from './cli.js';
4
- import gherkinParser from './interfaces/gherkin.js';
5
- import * as output from './output.js';
6
- import { genTestId } from './utils.js';
7
- import ConnectionRefused from './helper/errors/ConnectionRefused.js';
8
-
9
- import scenarioUi from './ui.js';
10
-
11
- let mocha;
12
-
13
- export class MochaFactory {
14
- static create(config, opts) {
15
- mocha = new Mocha(Object.assign(config, opts));
16
- output.output.process(opts.child);
17
- mocha.ui(scenarioUi);
18
-
19
- Mocha.Runner.prototype.uncaught = function (err) {
20
- if (err) {
21
- if (err.toString().indexOf('ECONNREFUSED') >= 0) {
22
- err = new ConnectionRefused(err);
23
- }
24
- output.output.error(err);
25
- output.output.print(err.stack);
26
- process.exit(1);
27
- }
28
- output.output.error('Uncaught undefined exception');
29
- process.exit(1);
30
- };
31
-
32
- mocha.loadFiles = (fn) => {
33
- // load features
34
- if (mocha.suite.suites.length === 0) {
35
- mocha.files
36
- .filter(file => file.match(/\.feature$/))
37
- .forEach(file => mocha.suite.addSuite(gherkinParser(fs.readFileSync(file, 'utf8'), file)));
38
-
39
- // remove feature files
40
- mocha.files = mocha.files.filter(file => !file.match(/\.feature$/));
41
-
42
- Mocha.prototype.loadFiles.call(mocha, fn);
43
-
44
- // add ids for each test and check uniqueness
45
- const dupes = [];
46
- let missingFeatureInFile = [];
47
- const seenTests = [];
48
- mocha.suite.eachTest(test => {
49
- test.uid = genTestId(test);
50
-
51
- const name = test.fullTitle();
52
- if (seenTests.includes(test.uid)) {
53
- dupes.push(name);
54
- }
55
- seenTests.push(test.uid);
56
-
57
- if (name.slice(0, name.indexOf(':')) === '') {
58
- missingFeatureInFile.push(test.file);
59
- }
60
- });
61
- if (dupes.length) {
62
- // ideally this should be no-op and throw (breaking change)...
63
- output.output.error(`Duplicate test names detected - Feature + Scenario name should be unique:\n${dupes.join('\n')}`);
64
- }
65
-
66
- if (missingFeatureInFile.length) {
67
- missingFeatureInFile = [...new Set(missingFeatureInFile)];
68
- output.output.error(`Missing Feature section in:\n${missingFeatureInFile.join('\n')}`);
69
- }
70
- }
71
- };
72
-
73
- const presetReporter = opts.reporter || config.reporter;
74
- // use standard reporter
75
- if (!presetReporter) {
76
- mocha.reporter(reporter, opts);
77
- return mocha;
78
- }
79
-
80
- // load custom reporter with options
81
- const reporterOptions = Object.assign(config.reporterOptions || {});
82
-
83
- if (opts.reporterOptions !== undefined) {
84
- opts.reporterOptions.split(',').forEach((opt) => {
85
- const L = opt.split('=');
86
- if (L.length > 2 || L.length === 0) {
87
- throw new Error(`invalid reporter option '${opt}'`);
88
- } else if (L.length === 2) {
89
- reporterOptions[L[0]] = L[1];
90
- } else {
91
- reporterOptions[L[0]] = true;
92
- }
93
- });
94
- }
95
-
96
- const attributes = Object.getOwnPropertyDescriptor(reporterOptions, 'codeceptjs-cli-reporter');
97
- if (reporterOptions['codeceptjs-cli-reporter'] && attributes) {
98
- Object.defineProperty(
99
- reporterOptions,
100
- 'codeceptjs/lib/cli',
101
- attributes,
102
- );
103
- delete reporterOptions['codeceptjs-cli-reporter'];
104
- }
105
-
106
- // custom reporters
107
- mocha.reporter(presetReporter, reporterOptions);
108
- return mocha;
109
- }
110
- }
@@ -1,15 +0,0 @@
1
- export default () => {
2
- console.log('Allure plugin was moved to @codeceptjs/allure-legacy. Please install it and update your config');
3
- console.log();
4
- console.log('npm install @codeceptjs/allure-legacy --save-dev');
5
- console.log();
6
- console.log('Then update your config to use it:');
7
- console.log();
8
- console.log('plugins: {');
9
- console.log(' allure: {');
10
- console.log(' enabled: true,');
11
- console.log(' require: \'@codeceptjs/allure-legacy\',');
12
- console.log(' }');
13
- console.log('}');
14
- console.log();
15
- };
@@ -1,136 +0,0 @@
1
- import * as event from '../event.js';
2
- import recorder from '../recorder.js';
3
- import { MetaStep } from '../step.js';
4
-
5
- let currentCommentStep;
6
-
7
- const defaultGlobalName = '__';
8
-
9
- /**
10
- * Add descriptive nested steps for your tests:
11
- *
12
- * ```js
13
- * Scenario('project update test', async (I) => {
14
- * __`Given`;
15
- * const projectId = await I.have('project');
16
- *
17
- * __`When`;
18
- * projectPage.update(projectId, { title: 'new title' });
19
- *
20
- * __`Then`;
21
- * projectPage.open(projectId);
22
- * I.see('new title', 'h1');
23
- * })
24
- * ```
25
- * Steps prefixed with `__` will be printed as nested steps in `--steps` output:
26
- *
27
- * ```
28
- * Given
29
- * I have "project"
30
- * When
31
- * projectPage update
32
- * Then
33
- * projectPage open
34
- * I see "new title", "h1"
35
- * ```
36
- *
37
- * Also those steps will be exported to allure reports.
38
- *
39
- * This plugin can be used
40
- *
41
- * ### Config
42
- *
43
- * * `enabled` - (default: false) enable a plugin
44
- * * `registerGlobal` - (default: false) register `__` template literal function globally. You can override function global name by providing a name as a value.
45
- *
46
- * ### Examples
47
- *
48
- * Registering `__` globally:
49
- *
50
- * ```js
51
- * plugins: {
52
- * commentStep: {
53
- * enabled: true,
54
- * registerGlobal: true
55
- * }
56
- * }
57
- * ```
58
- *
59
- * Registering `Step` globally:
60
- * ```js
61
- * plugins: {
62
- * commentStep: {
63
- * enabled: true,
64
- * registerGlobal: 'Step'
65
- * }
66
- * }
67
- * ```
68
- *
69
- * Using only local function names:
70
- * ```js
71
- * plugins: {
72
- * commentStep: {
73
- * enabled: true
74
- * }
75
- * }
76
- * ```
77
- * Then inside a test import a comment function from a plugin.
78
- * For instance, you can prepare Given/When/Then functions to use them inside tests:
79
- *
80
- * ```js
81
- * // inside a test
82
- * const step = codeceptjs.container.plugins('commentStep');
83
- *
84
- * const Given = () => step`Given`;
85
- * const When = () => step`When`;
86
- * const Then = () => step`Then`;
87
- * ```
88
- *
89
- * Scenario('project update test', async (I) => {
90
- * Given();
91
- * const projectId = await I.have('project');
92
- *
93
- * When();
94
- * projectPage.update(projectId, { title: 'new title' });
95
- *
96
- * Then();
97
- * projectPage.open(projectId);
98
- * I.see('new title', 'h1');
99
- * });
100
- * ```
101
- */
102
- export default function commentStep(config) {
103
- event.dispatcher.on(event.test.started, () => {
104
- currentCommentStep = null;
105
- });
106
-
107
- event.dispatcher.on(event.step.started, (step) => {
108
- if (currentCommentStep) {
109
- const metaStep = getRootMetaStep(step);
110
-
111
- if (metaStep !== currentCommentStep) {
112
- metaStep.metaStep = currentCommentStep;
113
- }
114
- }
115
- });
116
-
117
- if (config.registerGlobal) {
118
- if (config.registerGlobal === true) {
119
- config.registerGlobal = defaultGlobalName;
120
- }
121
- global[config.registerGlobal] = setCommentString;
122
- }
123
-
124
- return setCommentString;
125
- }
126
-
127
- function getRootMetaStep(step) {
128
- if (step.metaStep) return getRootMetaStep(step.metaStep);
129
- return step;
130
- }
131
-
132
- function setCommentString(string) {
133
- recorder.add('set comment metastep', () => {
134
- currentCommentStep = new MetaStep(String.raw(string), '');
135
- });
136
- }
@@ -1,67 +0,0 @@
1
- import Container from '../container.js';
2
- import recorder from '../recorder.js';
3
- import * as event from '../event.js';
4
- import supportedHelpers from './standardActingHelpers.js';
5
- import { scanForErrorMessages } from '../html';
6
- import { output } from '..';
7
-
8
- const defaultConfig = {
9
- errorClasses: ['error', 'warning', 'alert', 'danger'],
10
- };
11
-
12
- /**
13
- * Prints errors found in HTML code after each failed test.
14
- *
15
- * It scans HTML and searches for elements with error classes.
16
- * If an element found prints a text from it to console and adds as artifact to the test.
17
- *
18
- * Enable this plugin in config:
19
- *
20
- * ```js
21
- * plugins: {
22
- * debugErrors: {
23
- * enabled: true,
24
- * }
25
- * ```
26
- *
27
- * Additional config options:
28
- *
29
- * * `errorClasses` - list of classes to search for errors (default: `['error', 'warning', 'alert', 'danger']`)
30
- *
31
- */
32
- export default function (config = {}) {
33
- const helpers = Container.helpers();
34
- let helper;
35
-
36
- config = Object.assign(defaultConfig, config);
37
-
38
- for (const helperName of supportedHelpers) {
39
- if (Object.keys(helpers).indexOf(helperName) > -1) {
40
- helper = helpers[helperName];
41
- }
42
- }
43
-
44
- if (!helper) return; // no helpers for screenshot
45
-
46
- event.dispatcher.on(event.test.failed, (test) => {
47
- recorder.add('HTML snapshot failed test', async () => {
48
- try {
49
- const currentOutputLevel = output.level();
50
- output.level(0);
51
- const html = await helper.grabHTMLFrom('body');
52
- output.level(currentOutputLevel);
53
-
54
- if (!html) return;
55
-
56
- const errors = scanForErrorMessages(html, config.errorClasses);
57
- if (errors.length) {
58
- output.debug('Detected errors in HTML code');
59
- errors.forEach((error) => output.debug(error));
60
- test.artifacts.errors = errors;
61
- }
62
- } catch (err) {
63
- // not really needed
64
- }
65
- });
66
- });
67
- }
@@ -1,127 +0,0 @@
1
- import * as output from '../output.js';
2
- import { store } from '../store.js';
3
- import recorder from '../recorder.js';
4
- import container from '../container.js';
5
- import * as event from '../event.js';
6
- import { Step } from '../step.js';
7
- import { isAsyncFunction } from '../utils.js';
8
-
9
- const defaultConfig = {
10
- registerGlobal: true,
11
- };
12
-
13
- /**
14
- * Provides `eachElement` global function to iterate over found elements to perform actions on them.
15
- *
16
- * `eachElement` takes following args:
17
- * * `purpose` - the goal of an action. A comment text that will be displayed in output.output.
18
- * * `locator` - a CSS/XPath locator to match elements
19
- * * `fn(element, index)` - **asynchronous** function which will be executed for each matched element.
20
- *
21
- * Example of usage:
22
- *
23
- * ```js
24
- * // this example works with Playwright and Puppeteer helper
25
- * await eachElement('click all checkboxes', 'form input[type=checkbox]', async (el) => {
26
- * await el.click();
27
- * });
28
- * ```
29
- * Click odd elements:
30
- *
31
- * ```js
32
- * // this example works with Playwright and Puppeteer helper
33
- * await eachElement('click odd buttons', '.button-select', async (el, index) => {
34
- * if (index % 2) await el.click();
35
- * });
36
- * ```
37
- *
38
- * Check all elements for visibility:
39
- *
40
- * ```js
41
- * // this example works with Playwright and Puppeteer helper
42
- * const assert = require('assert');
43
- * await eachElement('check all items are visible', '.item', async (el) => {
44
- * assert(await el.isVisible());
45
- * });
46
- * ```
47
- * This method works with WebDriver, Playwright, Puppeteer, Appium helpers.
48
- *
49
- * Function parameter `el` represents a matched element.
50
- * Depending on a helper API of `el` can be different. Refer to API of corresponding browser testing engine for a complete API list:
51
- *
52
- * * [Playwright ElementHandle](https://playwright.dev/docs/api/class-elementhandle)
53
- * * [Puppeteer](https://pptr.dev/#?product=Puppeteer&show=api-class-elementhandle)
54
- * * [webdriverio element](https://webdriver.io/docs/api)
55
- *
56
- * #### Configuration
57
- *
58
- * * `registerGlobal` - to register `eachElement` function globally, true by default
59
- *
60
- * If `registerGlobal` is false you can use eachElement from the plugin:
61
- *
62
- * ```js
63
- * const eachElement = codeceptjs.container.plugins('eachElement');
64
- * ```
65
- *
66
- * @param {string} purpose
67
- * @param {CodeceptJS.LocatorOrString} locator
68
- * @param {Function} fn
69
- * @return {Promise<*> | undefined}
70
- */
71
- function eachElement(purpose, locator, fn) {
72
- if (store.dryRun) return;
73
- const helpers = Object.values(container.helpers());
74
-
75
- const helper = helpers.filter(h => !!h._locate)[0];
76
-
77
- if (!helper) {
78
- throw new Error('No helper enabled with _locate method with returns a list of elements.');
79
- }
80
-
81
- if (!isAsyncFunction(fn)) {
82
- throw new Error('Async function should be passed into each element');
83
- }
84
-
85
- const step = new Step(helper, `${purpose || 'each element'} within "${locator}"`);
86
- step.helperMethod = '_locate';
87
- // eachElement('select all users', 'locator', async (el) => {
88
- event.dispatcher.emit(event.step.before, step);
89
-
90
- return recorder.add('register each element wrapper', async () => {
91
- event.emit(event.step.started, step);
92
- const els = await helper._locate(locator);
93
- output.output.debug(`Found ${els.length} elements for each elements to iterate`);
94
-
95
- const errs = [];
96
- let i = 0;
97
- for (const el of els) {
98
- try {
99
- await fn(el, i);
100
- } catch (err) {
101
- output.output.error(`eachElement: failed operation on element #${i} ${el}`);
102
- errs.push(err);
103
- }
104
- i++;
105
- }
106
-
107
- if (errs.length) {
108
- event.dispatcher.emit(event.step.after, step);
109
- event.emit(event.step.failed, step, errs[0]);
110
- event.emit(event.step.finished, step);
111
- throw errs[0];
112
- }
113
-
114
- event.dispatcher.emit(event.step.after, step);
115
- event.emit(event.step.passed, step, null);
116
- event.emit(event.step.finished, step);
117
- });
118
- }
119
-
120
- export default function (config) {
121
- config = Object.assign(defaultConfig, config);
122
-
123
- if (config.registerGlobal) {
124
- global.eachElement = eachElement;
125
- }
126
- return eachElement;
127
- }
@@ -1,49 +0,0 @@
1
- import { faker } from '@faker-js/faker';
2
- import transform from '../transform';
3
-
4
- /**
5
- * Use the `@faker-js/faker` package to generate fake data inside examples on your gherkin tests
6
- *
7
- * #### Usage
8
- *
9
- * To start please install `@faker-js/faker` package
10
- *
11
- * ```
12
- * npm install -D @faker-js/faker
13
- * ```
14
- *
15
- * ```
16
- * yarn add -D @faker-js/faker
17
- * ```
18
- *
19
- * Add this plugin to config file:
20
- *
21
- * ```js
22
- * plugins: {
23
- * fakerTransform: {
24
- * enabled: true
25
- * }
26
- * }
27
- * ```
28
- *
29
- * Add the faker API using a mustache string format inside examples tables in your gherkin scenario outline
30
- *
31
- * ```feature
32
- * Scenario Outline: ...
33
- * Given ...
34
- * When ...
35
- * Then ...
36
- * Examples:
37
- * | productName | customer | email | anythingMore |
38
- * | {{commerce.product}} | Dr. {{name.findName}} | {{internet.email}} | staticData |
39
- * ```
40
- *
41
- */
42
- export default function (config) {
43
- transform.addTransformerBeforeAll('gherkin.examples', (value) => {
44
- if (typeof value === 'string' && value.length > 0) {
45
- return faker.helpers.fake(value);
46
- }
47
- return value;
48
- });
49
- }