codeceptjs 4.0.1-beta.25 → 4.0.1-beta.26

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.
@@ -1,135 +0,0 @@
1
- import Locator from '../../locator.js'
2
-
3
- /**
4
- * Error thrown when strict mode is enabled and multiple elements are found
5
- * for a single-element locator operation (click, fillField, etc.)
6
- */
7
- class MultipleElementsFound extends Error {
8
- /**
9
- * @param {Locator|string|object} locator - The locator used
10
- * @param {Array<HTMLElement>} elements - Array of Playwright element handles found
11
- */
12
- constructor(locator, elements) {
13
- super(`Multiple elements (${elements.length}) found for "${locator}". Call fetchDetails() for full information.`)
14
- this.name = 'MultipleElementsFound'
15
- this.locator = locator
16
- this.elements = elements
17
- this.count = elements.length
18
- this._detailsFetched = false
19
- }
20
-
21
- /**
22
- * Fetch detailed information about the found elements asynchronously
23
- * This updates the error message with XPath and element previews
24
- */
25
- async fetchDetails() {
26
- if (this._detailsFetched) return
27
-
28
- try {
29
- if (typeof this.locator === 'object' && !(this.locator instanceof Locator)) {
30
- this.locator = JSON.stringify(this.locator)
31
- }
32
-
33
- const locatorObj = new Locator(this.locator)
34
- const elementList = await this._generateElementList(this.elements, this.count)
35
-
36
- this.message = `Multiple elements (${this.count}) found for "${locatorObj.toString()}" in strict mode.\n` +
37
- elementList +
38
- `\nUse a more specific locator or use grabWebElements() to handle multiple elements.`
39
- } catch (err) {
40
- this.message = `Multiple elements (${this.count}) found. Failed to fetch details: ${err.message}`
41
- }
42
-
43
- this._detailsFetched = true
44
- }
45
-
46
- /**
47
- * Generate a formatted list of found elements with their XPath and preview
48
- * @param {Array<HTMLElement>} elements
49
- * @param {number} count
50
- * @returns {Promise<string>}
51
- */
52
- async _generateElementList(elements, count) {
53
- const items = []
54
- const maxToShow = Math.min(count, 10)
55
-
56
- for (let i = 0; i < maxToShow; i++) {
57
- const el = elements[i]
58
- try {
59
- const info = await this._getElementInfo(el)
60
- items.push(` ${i + 1}. ${info.xpath} (${info.preview})`)
61
- } catch (err) {
62
- // Element might be detached or inaccessible
63
- items.push(` ${i + 1}. [Unable to get element info: ${err.message}]`)
64
- }
65
- }
66
-
67
- if (count > 10) {
68
- items.push(` ... and ${count - 10} more`)
69
- }
70
-
71
- return items.join('\n')
72
- }
73
-
74
- /**
75
- * Get XPath and preview for an element by running JavaScript in browser context
76
- * @param {HTMLElement} element
77
- * @returns {Promise<{xpath: string, preview: string}>}
78
- */
79
- async _getElementInfo(element) {
80
- return element.evaluate((el) => {
81
- // Generate a unique XPath for this element
82
- const getUniqueXPath = (element) => {
83
- if (element.id) {
84
- return `//*[@id="${element.id}"]`
85
- }
86
-
87
- const parts = []
88
- let current = element
89
-
90
- while (current && current.nodeType === Node.ELEMENT_NODE) {
91
- let index = 0
92
- let sibling = current.previousSibling
93
-
94
- while (sibling) {
95
- if (sibling.nodeType === Node.ELEMENT_NODE && sibling.tagName === current.tagName) {
96
- index++
97
- }
98
- sibling = sibling.previousSibling
99
- }
100
-
101
- const tagName = current.tagName.toLowerCase()
102
- const pathIndex = index > 0 ? `[${index + 1}]` : ''
103
- parts.unshift(`${tagName}${pathIndex}`)
104
-
105
- current = current.parentElement
106
-
107
- // Stop at body to keep XPath reasonable
108
- if (current && current.tagName === 'BODY') {
109
- parts.unshift('body')
110
- break
111
- }
112
- }
113
-
114
- return '/' + parts.join('/')
115
- }
116
-
117
- // Get a preview of the element (tag, classes, id)
118
- const getPreview = (element) => {
119
- const tag = element.tagName.toLowerCase()
120
- const id = element.id ? `#${element.id}` : ''
121
- const classes = element.className
122
- ? '.' + element.className.split(' ').filter(c => c).join('.')
123
- : ''
124
- return `${tag}${id}${classes || ''}`
125
- }
126
-
127
- return {
128
- xpath: getUniqueXPath(el),
129
- preview: getPreview(el),
130
- }
131
- })
132
- }
133
- }
134
-
135
- export default MultipleElementsFound