codeceptjs 4.0.0-beta.9.esm-aria → 4.0.0-rc.10

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 (69) hide show
  1. package/README.md +39 -27
  2. package/bin/codecept.js +2 -2
  3. package/bin/mcp-server.js +610 -0
  4. package/docs/webapi/appendField.mustache +5 -0
  5. package/docs/webapi/attachFile.mustache +12 -0
  6. package/docs/webapi/checkOption.mustache +1 -1
  7. package/docs/webapi/clearField.mustache +5 -0
  8. package/docs/webapi/dontSeeCurrentPathEquals.mustache +10 -0
  9. package/docs/webapi/dontSeeElement.mustache +4 -0
  10. package/docs/webapi/dontSeeInField.mustache +5 -0
  11. package/docs/webapi/fillField.mustache +5 -0
  12. package/docs/webapi/moveCursorTo.mustache +5 -1
  13. package/docs/webapi/seeCurrentPathEquals.mustache +10 -0
  14. package/docs/webapi/seeElement.mustache +4 -0
  15. package/docs/webapi/seeInField.mustache +5 -0
  16. package/docs/webapi/selectOption.mustache +5 -0
  17. package/docs/webapi/uncheckOption.mustache +1 -1
  18. package/lib/actor.js +12 -8
  19. package/lib/codecept.js +51 -18
  20. package/lib/command/definitions.js +14 -7
  21. package/lib/command/init.js +2 -4
  22. package/lib/command/run-workers.js +13 -2
  23. package/lib/command/workers/runTests.js +121 -9
  24. package/lib/config.js +24 -33
  25. package/lib/container.js +177 -28
  26. package/lib/element/WebElement.js +81 -2
  27. package/lib/els.js +12 -6
  28. package/lib/helper/Appium.js +8 -8
  29. package/lib/helper/GraphQL.js +6 -4
  30. package/lib/helper/JSONResponse.js +3 -4
  31. package/lib/helper/Playwright.js +339 -505
  32. package/lib/helper/Puppeteer.js +324 -89
  33. package/lib/helper/REST.js +15 -9
  34. package/lib/helper/WebDriver.js +311 -81
  35. package/lib/helper/errors/ElementNotFound.js +5 -2
  36. package/lib/helper/errors/MultipleElementsFound.js +52 -0
  37. package/lib/helper/extras/elementSelection.js +58 -0
  38. package/lib/helper/scripts/dropFile.js +11 -0
  39. package/lib/html.js +14 -1
  40. package/lib/listener/config.js +11 -3
  41. package/lib/listener/globalRetry.js +32 -6
  42. package/lib/listener/helpers.js +2 -14
  43. package/lib/locator.js +32 -0
  44. package/lib/mocha/cli.js +16 -0
  45. package/lib/mocha/factory.js +7 -27
  46. package/lib/mocha/gherkin.js +4 -4
  47. package/lib/mocha/test.js +4 -2
  48. package/lib/output.js +2 -2
  49. package/lib/plugin/aiTrace.js +464 -0
  50. package/lib/plugin/auth.js +2 -1
  51. package/lib/plugin/retryFailedStep.js +28 -19
  52. package/lib/plugin/stepByStepReport.js +5 -1
  53. package/lib/step/base.js +14 -1
  54. package/lib/step/config.js +15 -2
  55. package/lib/step/meta.js +18 -1
  56. package/lib/step/record.js +9 -1
  57. package/lib/utils/loaderCheck.js +162 -0
  58. package/lib/utils/typescript.js +449 -0
  59. package/lib/utils.js +48 -0
  60. package/lib/workers.js +163 -54
  61. package/package.json +43 -32
  62. package/typings/index.d.ts +120 -4
  63. package/lib/helper/extras/PlaywrightLocator.js +0 -110
  64. package/lib/listener/enhancedGlobalRetry.js +0 -110
  65. package/lib/plugin/enhancedRetryFailedStep.js +0 -99
  66. package/lib/plugin/htmlReporter.js +0 -3648
  67. package/lib/retryCoordinator.js +0 -207
  68. package/typings/promiseBasedTypes.d.ts +0 -11011
  69. package/typings/types.d.ts +0 -13073
@@ -519,12 +519,12 @@ declare namespace CodeceptJS {
519
519
  retry(retries?: number): HookConfig
520
520
  }
521
521
 
522
- function addStep(step: string, fn: Function): Promise<void>
522
+ function addStep(step: string | RegExp, fn: Function): Promise<void>
523
523
  }
524
524
 
525
- type TryTo = <T>(fn: () => Promise<T> | T) => Promise<T | false>
526
- type HopeThat = <T>(fn: () => Promise<T> | T) => Promise<T | false>
527
- type RetryTo = <T>(fn: () => Promise<T> | T, retries?: number) => Promise<T>
525
+ type TryTo = (fn: () => void) => Promise<boolean>
526
+ type HopeThat = (fn: () => void) => Promise<boolean>
527
+ type RetryTo = (fn: (tries: number) => Promise<void> | void, maxTries: number, pollInterval?: number) => Promise<boolean>
528
528
 
529
529
  // Globals
530
530
  declare const codecept_dir: string
@@ -635,8 +635,105 @@ declare namespace Mocha {
635
635
  }
636
636
  }
637
637
 
638
+ // Internal API types
638
639
  declare module 'codeceptjs' {
639
640
  export default codeceptjs
641
+
642
+ /**
643
+ * Dependency Injection Container
644
+ * Provides access to helpers, support objects, plugins, and translation
645
+ */
646
+ export const container: typeof CodeceptJS.Container
647
+
648
+ /**
649
+ * Test runner class
650
+ */
651
+ export const codecept: typeof CodeceptJS.Codecept
652
+
653
+ /**
654
+ * Output module for printing messages
655
+ */
656
+ export const output: typeof CodeceptJS.output
657
+
658
+ /**
659
+ * Event dispatcher for listening to CodeceptJS events
660
+ */
661
+ export const event: typeof CodeceptJS.event
662
+
663
+ /**
664
+ * Global promise chain recorder
665
+ */
666
+ export const recorder: CodeceptJS.recorder
667
+
668
+ /**
669
+ * Configuration module
670
+ */
671
+ export const config: typeof CodeceptJS.Config
672
+
673
+ /**
674
+ * Actor (I) constructor
675
+ */
676
+ export const actor: CodeceptJS.actor
677
+
678
+ /**
679
+ * Base Helper class
680
+ */
681
+ export const helper: typeof CodeceptJS.Helper
682
+
683
+ /**
684
+ * Pause execution until user input
685
+ */
686
+ export const pause: typeof CodeceptJS.pause
687
+
688
+ /**
689
+ * Execute steps within specific context
690
+ */
691
+ export const within: typeof CodeceptJS.within
692
+
693
+ /**
694
+ * Create data tables for data-driven tests
695
+ */
696
+ export const dataTable: typeof CodeceptJS.DataTable
697
+
698
+ /**
699
+ * Create data table arguments
700
+ */
701
+ export const dataTableArgument: typeof CodeceptJS.DataTableArgument
702
+
703
+ /**
704
+ * Shared store for test data
705
+ */
706
+ export const store: typeof CodeceptJS.store
707
+
708
+ /**
709
+ * Locator builder
710
+ */
711
+ export const locator: typeof CodeceptJS.Locator
712
+
713
+ /**
714
+ * Auto-healing module
715
+ */
716
+ export const heal: any
717
+
718
+ /**
719
+ * AI assistant module
720
+ */
721
+ export const ai: any
722
+
723
+ /**
724
+ * Workers for parallel execution
725
+ */
726
+ export const Workers: any
727
+
728
+ /**
729
+ * Secret value type for sensitive data
730
+ */
731
+ export const Secret: typeof CodeceptJS.Secret
732
+
733
+ /**
734
+ * Create a secret value
735
+ */
736
+ export const secret: typeof CodeceptJS.Secret.secret
640
737
  }
641
738
 
642
739
  declare module '@codeceptjs/helper' {
@@ -648,3 +745,22 @@ declare module 'codeceptjs/effects' {
648
745
  export const retryTo: RetryTo
649
746
  export const hopeThat: HopeThat
650
747
  }
748
+
749
+ declare module 'codeceptjs/steps' {
750
+ const step: {
751
+ opts(opts: CodeceptJS.StepOptions): CodeceptJS.StepConfig;
752
+ timeout(timeout: number): CodeceptJS.StepConfig;
753
+ retry(retry: number): CodeceptJS.StepConfig;
754
+ stepOpts(opts: CodeceptJS.StepOptions): CodeceptJS.StepConfig;
755
+ stepTimeout(timeout: number): CodeceptJS.StepConfig;
756
+ stepRetry(retry: number): CodeceptJS.StepConfig;
757
+ section(name: string): any;
758
+ endSection(): any;
759
+ Section(name: string): any;
760
+ EndSection(): any;
761
+ Given(): any;
762
+ When(): any;
763
+ Then(): any;
764
+ }
765
+ export default step
766
+ }
@@ -1,110 +0,0 @@
1
- import Locator from '../../locator.js'
2
-
3
- function buildLocatorString(locator) {
4
- if (locator.isCustom()) {
5
- return `${locator.type}=${locator.value}`
6
- }
7
- if (locator.isXPath()) {
8
- return `xpath=${locator.value}`
9
- }
10
- return locator.simplify()
11
- }
12
-
13
- async function findElements(matcher, locator) {
14
- const matchedLocator = new Locator(locator, 'css')
15
-
16
- if (matchedLocator.type === 'react') return findReact(matcher, matchedLocator)
17
- if (matchedLocator.type === 'vue') return findVue(matcher, matchedLocator)
18
- if (matchedLocator.type === 'pw') return findByPlaywrightLocator(matcher, matchedLocator)
19
- if (matchedLocator.isRole()) return findByRole(matcher, matchedLocator)
20
-
21
- return matcher.locator(buildLocatorString(matchedLocator)).all()
22
- }
23
-
24
- async function findElement(matcher, locator) {
25
- const matchedLocator = new Locator(locator, 'css')
26
-
27
- if (matchedLocator.type === 'react') return findReact(matcher, matchedLocator)
28
- if (matchedLocator.type === 'vue') return findVue(matcher, matchedLocator)
29
- if (matchedLocator.type === 'pw') return findByPlaywrightLocator(matcher, matchedLocator, { first: true })
30
- if (matchedLocator.isRole()) return findByRole(matcher, matchedLocator, { first: true })
31
-
32
- return matcher.locator(buildLocatorString(matchedLocator)).first()
33
- }
34
-
35
- async function getVisibleElements(elements) {
36
- const visibleElements = []
37
- for (const element of elements) {
38
- if (await element.isVisible()) {
39
- visibleElements.push(element)
40
- }
41
- }
42
- if (visibleElements.length === 0) {
43
- return elements
44
- }
45
- return visibleElements
46
- }
47
-
48
- async function findReact(matcher, locator) {
49
- const details = locator.locator ?? { react: locator.value }
50
- let locatorString = `_react=${details.react}`
51
-
52
- if (details.props) {
53
- locatorString += propBuilder(details.props)
54
- }
55
-
56
- return matcher.locator(locatorString).all()
57
- }
58
-
59
- async function findVue(matcher, locator) {
60
- const details = locator.locator ?? { vue: locator.value }
61
- let locatorString = `_vue=${details.vue}`
62
-
63
- if (details.props) {
64
- locatorString += propBuilder(details.props)
65
- }
66
-
67
- return matcher.locator(locatorString).all()
68
- }
69
-
70
- async function findByPlaywrightLocator(matcher, locator, { first = false } = {}) {
71
- const details = locator.locator ?? { pw: locator.value }
72
- const locatorValue = details.pw
73
-
74
- const handle = matcher.locator(locatorValue)
75
- return first ? handle.first() : handle.all()
76
- }
77
-
78
- async function findByRole(matcher, locator, { first = false } = {}) {
79
- const details = locator.locator ?? { role: locator.value }
80
- const { role, text, name, exact, includeHidden, ...rest } = details
81
- const options = { ...rest }
82
-
83
- if (includeHidden !== undefined) options.includeHidden = includeHidden
84
-
85
- const accessibleName = name ?? text
86
- if (accessibleName !== undefined) {
87
- options.name = accessibleName
88
- if (exact === true) options.exact = true
89
- }
90
-
91
- const roleLocator = matcher.getByRole(role, options)
92
- return first ? roleLocator.first() : roleLocator.all()
93
- }
94
-
95
- function propBuilder(props) {
96
- let _props = ''
97
-
98
- for (const [key, value] of Object.entries(props)) {
99
- if (typeof value === 'object') {
100
- for (const [k, v] of Object.entries(value)) {
101
- _props += `[${key}.${k} = "${v}"]`
102
- }
103
- } else {
104
- _props += `[${key} = "${value}"]`
105
- }
106
- }
107
- return _props
108
- }
109
-
110
- export { buildLocatorString, findElements, findElement, getVisibleElements, findReact, findVue, findByPlaywrightLocator, findByRole }
@@ -1,110 +0,0 @@
1
- import event from '../event.js'
2
- import 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
- /**
9
- * Priority levels for retry mechanisms (higher number = higher priority)
10
- * This ensures consistent behavior when multiple retry mechanisms are active
11
- */
12
- const RETRY_PRIORITIES = {
13
- MANUAL_STEP: 100, // I.retry() or step.retry() - highest priority
14
- STEP_PLUGIN: 50, // retryFailedStep plugin
15
- SCENARIO_CONFIG: 30, // Global scenario retry config
16
- FEATURE_CONFIG: 20, // Global feature retry config
17
- HOOK_CONFIG: 10, // Hook retry config - lowest priority
18
- }
19
-
20
- /**
21
- * Enhanced global retry mechanism that coordinates with other retry types
22
- */
23
- export default function () {
24
- event.dispatcher.on(event.suite.before, suite => {
25
- let retryConfig = Config.get('retry')
26
- if (!retryConfig) return
27
-
28
- if (Number.isInteger(+retryConfig)) {
29
- // is number - apply as feature-level retry
30
- const retryNum = +retryConfig
31
- output.log(`[Global Retry] Feature retries: ${retryNum}`)
32
-
33
- // Only set if not already set by higher priority mechanism
34
- if (isNotSet(suite.retries())) {
35
- suite.retries(retryNum)
36
- suite.opts.retryPriority = RETRY_PRIORITIES.FEATURE_CONFIG
37
- }
38
- return
39
- }
40
-
41
- if (!Array.isArray(retryConfig)) {
42
- retryConfig = [retryConfig]
43
- }
44
-
45
- for (const config of retryConfig) {
46
- if (config.grep) {
47
- if (!suite.title.includes(config.grep)) continue
48
- }
49
-
50
- // Handle hook retries with priority awareness
51
- hooks
52
- .filter(hook => !!config[hook])
53
- .forEach(hook => {
54
- const retryKey = `retry${hook}`
55
- if (isNotSet(suite.opts[retryKey])) {
56
- suite.opts[retryKey] = config[hook]
57
- suite.opts[`${retryKey}Priority`] = RETRY_PRIORITIES.HOOK_CONFIG
58
- }
59
- })
60
-
61
- // Handle feature-level retries
62
- if (config.Feature) {
63
- if (isNotSet(suite.retries()) || (suite.opts.retryPriority || 0) <= RETRY_PRIORITIES.FEATURE_CONFIG) {
64
- suite.retries(config.Feature)
65
- suite.opts.retryPriority = RETRY_PRIORITIES.FEATURE_CONFIG
66
- output.log(`[Global Retry] Feature retries: ${config.Feature}`)
67
- }
68
- }
69
- }
70
- })
71
-
72
- event.dispatcher.on(event.test.before, test => {
73
- let retryConfig = Config.get('retry')
74
- if (!retryConfig) return
75
-
76
- if (Number.isInteger(+retryConfig)) {
77
- // Only set if not already set by higher priority mechanism
78
- if (test.retries() === -1) {
79
- test.retries(retryConfig)
80
- test.opts.retryPriority = RETRY_PRIORITIES.SCENARIO_CONFIG
81
- output.log(`[Global Retry] Scenario retries: ${retryConfig}`)
82
- }
83
- return
84
- }
85
-
86
- if (!Array.isArray(retryConfig)) {
87
- retryConfig = [retryConfig]
88
- }
89
-
90
- retryConfig = retryConfig.filter(config => !!config.Scenario)
91
-
92
- for (const config of retryConfig) {
93
- if (config.grep) {
94
- if (!test.fullTitle().includes(config.grep)) continue
95
- }
96
-
97
- if (config.Scenario) {
98
- // Respect priority system
99
- if (test.retries() === -1 || (test.opts.retryPriority || 0) <= RETRY_PRIORITIES.SCENARIO_CONFIG) {
100
- test.retries(config.Scenario)
101
- test.opts.retryPriority = RETRY_PRIORITIES.SCENARIO_CONFIG
102
- output.log(`[Global Retry] Scenario retries: ${config.Scenario}`)
103
- }
104
- }
105
- }
106
- })
107
- }
108
-
109
- // Export priority constants for use by other retry mechanisms
110
- export { RETRY_PRIORITIES }
@@ -1,99 +0,0 @@
1
- import event from '../event.js'
2
- import recorder from '../recorder.js'
3
- import store from '../store.js'
4
- import output from '../output.js'
5
- import { RETRY_PRIORITIES } from '../retryCoordinator.js'
6
-
7
- const defaultConfig = {
8
- retries: 3,
9
- defaultIgnoredSteps: ['amOnPage', 'wait*', 'send*', 'execute*', 'run*', 'have*'],
10
- factor: 1.5,
11
- ignoredSteps: [],
12
- }
13
-
14
- /**
15
- * Enhanced retryFailedStep plugin that coordinates with other retry mechanisms
16
- *
17
- * This plugin provides step-level retries and coordinates with global retry settings
18
- * to avoid conflicts and provide predictable behavior.
19
- */
20
- export default config => {
21
- config = Object.assign({}, defaultConfig, config)
22
- config.ignoredSteps = config.ignoredSteps.concat(config.defaultIgnoredSteps)
23
- const customWhen = config.when
24
-
25
- let enableRetry = false
26
-
27
- const when = err => {
28
- if (!enableRetry) return false
29
- if (store.debugMode) return false
30
- if (!store.autoRetries) return false
31
- if (customWhen) return customWhen(err)
32
- return true
33
- }
34
- config.when = when
35
-
36
- event.dispatcher.on(event.step.started, step => {
37
- // if a step is ignored - return
38
- for (const ignored of config.ignoredSteps) {
39
- if (step.name === ignored) return
40
- if (ignored instanceof RegExp) {
41
- if (step.name.match(ignored)) return
42
- } else if (ignored.indexOf('*') && step.name.startsWith(ignored.slice(0, -1))) return
43
- }
44
- enableRetry = true // enable retry for a step
45
- })
46
-
47
- event.dispatcher.on(event.step.finished, () => {
48
- enableRetry = false
49
- })
50
-
51
- event.dispatcher.on(event.test.before, test => {
52
- // pass disableRetryFailedStep is a preferred way to disable retries
53
- // test.disableRetryFailedStep is used for backward compatibility
54
- if (test.opts.disableRetryFailedStep || test.disableRetryFailedStep) {
55
- store.autoRetries = false
56
- output.log(`[Step Retry] Disabled for test: ${test.title}`)
57
- return // disable retry when a test is not active
58
- }
59
-
60
- // Check if step retries should be disabled due to higher priority scenario retries
61
- const scenarioRetries = test.retries()
62
- const stepRetryPriority = RETRY_PRIORITIES.STEP_PLUGIN
63
- const scenarioPriority = test.opts.retryPriority || 0
64
-
65
- if (scenarioRetries > 0 && config.deferToScenarioRetries !== false) {
66
- // Scenario retries are configured with higher or equal priority
67
- // Option 1: Disable step retries (conservative approach)
68
- store.autoRetries = false
69
- output.log(`[Step Retry] Deferred to scenario retries (${scenarioRetries} retries)`)
70
- return
71
-
72
- // Option 2: Reduce step retries to avoid excessive total retries
73
- // const reducedStepRetries = Math.max(1, Math.floor(config.retries / scenarioRetries))
74
- // config.retries = reducedStepRetries
75
- // output.log(`[Step Retry] Reduced to ${reducedStepRetries} retries due to scenario retries (${scenarioRetries})`)
76
- }
77
-
78
- // this option is used to set the retries inside _before() block of helpers
79
- store.autoRetries = true
80
- test.opts.conditionalRetries = config.retries
81
- test.opts.stepRetryPriority = stepRetryPriority
82
-
83
- recorder.retry(config)
84
-
85
- output.log(`[Step Retry] Enabled with ${config.retries} retries for test: ${test.title}`)
86
- })
87
-
88
- // Add coordination info for debugging
89
- event.dispatcher.on(event.test.finished, test => {
90
- if (test.state === 'passed' && test.opts.conditionalRetries && store.autoRetries) {
91
- const stepRetries = test.opts.conditionalRetries || 0
92
- const scenarioRetries = test.retries() || 0
93
-
94
- if (stepRetries > 0 && scenarioRetries > 0) {
95
- output.log(`[Retry Coordination] Test used both step retries (${stepRetries}) and scenario retries (${scenarioRetries})`)
96
- }
97
- }
98
- })
99
- }