@nodebug/browser-element-finder 1.1.7 → 1.1.9
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.
- package/README.md +233 -81
- package/index.js +351 -21
- package/index.min.js +15 -1
- package/package.json +9 -14
- package/src/element-definitions.json +1 -1
- package/src/searchable-attributes.json +1 -0
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @nodebug/browser-element-finder
|
|
2
2
|
|
|
3
|
+
**Version**: 1.1.8
|
|
4
|
+
|
|
3
5
|
**A robust, agent-friendly JavaScript library for identifying DOM elements by type and/or text content, with full support for shadow DOM, iframes, and automation workflows.**
|
|
4
6
|
|
|
5
7
|
---
|
|
@@ -18,6 +20,14 @@ const results = ElementFinder.findElements('button', 'Submit')
|
|
|
18
20
|
// Find by text only (any type)
|
|
19
21
|
const results = ElementFinder.findElements(null, 'seleniumbase')
|
|
20
22
|
|
|
23
|
+
// Count semantic element types on the screen
|
|
24
|
+
const counts = ElementFinder.getElementCounts()
|
|
25
|
+
// Returns counts for all defined non-generic types, excluding `element`
|
|
26
|
+
|
|
27
|
+
// Count one semantic type
|
|
28
|
+
const buttonCount = ElementFinder.getElementCounts('button')
|
|
29
|
+
// Returns `{ button: 3 }`
|
|
30
|
+
|
|
21
31
|
// Find in all frames (default)
|
|
22
32
|
const results = ElementFinder.findElements('button')
|
|
23
33
|
|
|
@@ -43,6 +53,7 @@ results.elements.forEach((e) => {
|
|
|
43
53
|
- For iframe results, switch context before interacting (see Selenium/Playwright docs)
|
|
44
54
|
- Use `getValidTypes()` to enumerate all supported semantic types
|
|
45
55
|
- Use `getSearchableAttributes()` to see which attributes are searched for text
|
|
56
|
+
- Use `getSearchableAttributeValues(element)` to inspect which searchable attributes are present on a specific element
|
|
46
57
|
|
|
47
58
|
---
|
|
48
59
|
|
|
@@ -52,7 +63,7 @@ results.elements.forEach((e) => {
|
|
|
52
63
|
- **Text content search**: Search within element text, attributes, and placeholders
|
|
53
64
|
- **Shadow DOM support**: Automatically traverses shadow roots to find nested elements
|
|
54
65
|
- **Iframe support**: Automatically searches all frames (main document + iframes) by default
|
|
55
|
-
- **Visibility detection**: All elements returned with `
|
|
66
|
+
- **Visibility detection**: All elements returned with `isHidden` property (`true`/`false`)
|
|
56
67
|
- **Bounding box data**: Returns position and dimensions for each found element
|
|
57
68
|
- **XPath-like type definitions**: Extensible element type matching using XPath-like expressions
|
|
58
69
|
- **Optimized performance**: Pre-compiled type matchers, O(n) innermost element filtering, and efficient Set-based lookups
|
|
@@ -92,14 +103,18 @@ browser-element-finder/
|
|
|
92
103
|
|
|
93
104
|
```js
|
|
94
105
|
// Find all elements (visible and hidden)
|
|
95
|
-
const results = ElementFinder.
|
|
106
|
+
const results = ElementFinder.findElements('button')
|
|
96
107
|
// Find by text
|
|
97
|
-
const results = ElementFinder.
|
|
108
|
+
const results = ElementFinder.findElements('button', 'Submit')
|
|
98
109
|
// Find by text only
|
|
99
|
-
const results = ElementFinder.
|
|
110
|
+
const results = ElementFinder.findElements(null, 'seleniumbase')
|
|
111
|
+
// Count element types
|
|
112
|
+
const counts = ElementFinder.getElementCounts()
|
|
113
|
+
// Count one type
|
|
114
|
+
const buttonCount = ElementFinder.getElementCounts('button')
|
|
100
115
|
// Check visibility of found elements
|
|
101
116
|
results.elements.forEach((e) => {
|
|
102
|
-
console.log('
|
|
117
|
+
console.log('Hidden:', e.isHidden)
|
|
103
118
|
})
|
|
104
119
|
```
|
|
105
120
|
|
|
@@ -113,7 +128,7 @@ The library automatically searches all frames (main + iframes). For agent/automa
|
|
|
113
128
|
**Example**:
|
|
114
129
|
|
|
115
130
|
```js
|
|
116
|
-
const results = ElementFinder.
|
|
131
|
+
const results = ElementFinder.findElements('button')
|
|
117
132
|
for (const item of results.elements) {
|
|
118
133
|
if (item.frameIndex === -1 && item.element) {
|
|
119
134
|
// Interact directly
|
|
@@ -125,14 +140,72 @@ for (const item of results.elements) {
|
|
|
125
140
|
}
|
|
126
141
|
```
|
|
127
142
|
|
|
143
|
+
### Customizing Searchable Attributes
|
|
144
|
+
|
|
145
|
+
You can customize which attributes the library searches for text (e.g., adding a custom `data-test-id` or removing `placeholder`).
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
// Get current attributes
|
|
149
|
+
const currentAttrs = ElementFinder.getSearchableAttributes()
|
|
150
|
+
|
|
151
|
+
// Set new priority list
|
|
152
|
+
ElementFinder.setSearchableAttributes([
|
|
153
|
+
'id',
|
|
154
|
+
'name',
|
|
155
|
+
'data-testid',
|
|
156
|
+
'placeholder',
|
|
157
|
+
])
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Inspecting Attribute Values
|
|
161
|
+
|
|
162
|
+
Use `getSearchableAttributeValues(element)` to inspect which current searchable attributes are present on a specific element and what values they contain.
|
|
163
|
+
|
|
164
|
+
```js
|
|
165
|
+
const input = document.querySelector('input')
|
|
166
|
+
const values = ElementFinder.getSearchableAttributeValues(input)
|
|
167
|
+
|
|
168
|
+
console.log(values)
|
|
169
|
+
// { placeholder: 'Email', 'data-testid': 'email-input', id: 'email' }
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The returned object only includes searchable attributes that exist on the element and have non-empty values. It respects any custom attribute order set with `setSearchableAttributes()`.
|
|
173
|
+
|
|
174
|
+
### Pausing Animations for Screenshots
|
|
175
|
+
|
|
176
|
+
When taking screenshots or performing visual assertions, animations can cause flaky tests. Use `pauseAnimations()` and `resumeAnimations()` to freeze and restore animations:
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
// Pause all CSS animations and transitions
|
|
180
|
+
const pauseState = ElementFinder.pauseAnimations()
|
|
181
|
+
|
|
182
|
+
// Take screenshot or perform visual assertions
|
|
183
|
+
// ... screenshot code here ...
|
|
184
|
+
|
|
185
|
+
// Resume animations
|
|
186
|
+
ElementFinder.resumeAnimations(pauseState)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
For Selenium WebDriver tests, call the functions directly in the browser context:
|
|
190
|
+
|
|
191
|
+
```js
|
|
192
|
+
// Pause animations (state is stored internally in browser)
|
|
193
|
+
await driver.executeScript('return ElementFinder.pauseAnimations()')
|
|
194
|
+
|
|
195
|
+
// ... take screenshot ...
|
|
196
|
+
|
|
197
|
+
// Resume animations (pops from internal stack - no argument needed)
|
|
198
|
+
await driver.executeScript('ElementFinder.resumeAnimations()')
|
|
199
|
+
```
|
|
200
|
+
|
|
128
201
|
### Accessing Element Definitions and Searchable Attributes
|
|
129
202
|
|
|
130
203
|
The package exports JSON files containing element type definitions and searchable attributes:
|
|
131
204
|
|
|
132
205
|
```javascript
|
|
133
206
|
// ESM - Import JSON directly
|
|
134
|
-
import ELEMENT_DEFINITIONS from '@nodebug/browser-element-finder/element-definitions.json'
|
|
135
|
-
import SEARCHABLE_ATTRIBUTES from '@nodebug/browser-element-finder/searchable-attributes.json'
|
|
207
|
+
import ELEMENT_DEFINITIONS from '@nodebug/browser-element-finder/element-definitions.json' with { type: 'json' }
|
|
208
|
+
import SEARCHABLE_ATTRIBUTES from '@nodebug/browser-element-finder/searchable-attributes.json' with { type: 'json' }
|
|
136
209
|
|
|
137
210
|
// Get all valid element types
|
|
138
211
|
console.log(Object.keys(ELEMENT_DEFINITIONS)) // ['button', 'checkbox', 'dropdown', ...]
|
|
@@ -141,34 +214,37 @@ console.log(Object.keys(ELEMENT_DEFINITIONS)) // ['button', 'checkbox', 'dropdow
|
|
|
141
214
|
console.log(SEARCHABLE_ATTRIBUTES) // ['placeholder', 'value', 'data-test-id', ...]
|
|
142
215
|
```
|
|
143
216
|
|
|
144
|
-
|
|
145
|
-
// CommonJS - Use require
|
|
146
|
-
const ELEMENT_DEFINITIONS = require('@nodebug/browser-element-finder/element-definitions.json')
|
|
147
|
-
const SEARCHABLE_ATTRIBUTES = require('@nodebug/browser-element-finder/searchable-attributes.json')
|
|
148
|
-
```
|
|
217
|
+
The package is ESM-only (`"type": "module"`), so CommonJS `require()` examples are not supported.
|
|
149
218
|
|
|
150
219
|
---
|
|
151
220
|
|
|
152
221
|
## API Summary
|
|
153
222
|
|
|
154
|
-
| Function | Description
|
|
155
|
-
| ------------------------------------------------- |
|
|
156
|
-
| `findElements(type, text, exact, parent)` | Find elements by type/text, returns `{ elements: [...] }`
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
164
|
-
| `
|
|
165
|
-
| `
|
|
166
|
-
| `
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
169
|
-
| `
|
|
170
|
-
| `
|
|
171
|
-
| `
|
|
223
|
+
| Function | Description |
|
|
224
|
+
| ------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
225
|
+
| `findElements(type, text, exact, parent)` | Find elements by type/text, returns `{ elements: [...] }` |
|
|
226
|
+
| `findElementsByType(type, parent)` | Find elements by type only, returns `{ elements: [...] }` |
|
|
227
|
+
| `findElementsByAttribute(value, exact, parent)` | Find elements by text/attribute, returns `{ elements: [...] }` |
|
|
228
|
+
| `getElementCounts(type, parent)` | Count elements by semantic type, excluding generic `element` by default |
|
|
229
|
+
| `findProbableElements(type, text, exact, parent)` | Find elements with fallback to nearby elements, returns `{ elements: [...] }` |
|
|
230
|
+
| `highlight(elements, color, width)` | Highlight elements with outline |
|
|
231
|
+
| `unhighlight(elements)` | Remove highlight |
|
|
232
|
+
| `pauseAnimations()` | Pause all CSS animations and transitions, returns state object |
|
|
233
|
+
| `resumeAnimations(state)` | Resume animations using state from `pauseAnimations()` |
|
|
234
|
+
| `getValidTypes()` | List all supported element types |
|
|
235
|
+
| `getValidAttributes()` | List all valid searchable attribute names |
|
|
236
|
+
| `getBoundingBox(element)` | Get bounding box for an element |
|
|
237
|
+
| `setSearchableAttributes(attributes)` | Set custom attributes for text search |
|
|
238
|
+
| `getSearchableAttributes()` | Get current searchable attributes |
|
|
239
|
+
| `getSearchableAttributeValues(element)` | Get current non-empty searchable attribute values from an element |
|
|
240
|
+
| `getElementDescriptor(element)` | Get identifiable text, source attribute, occurrence index, type, and tag name for an element |
|
|
241
|
+
| `matchesType(el, type)` | Check if element matches a type |
|
|
242
|
+
| `matchesAttribute(el, value, exact)` | Check if element matches text/attribute |
|
|
243
|
+
| `getAllElements(root)` | Get all elements (with shadow DOM) |
|
|
244
|
+
| `getAllFrames(root)` | Get all frames (main + iframes) |
|
|
245
|
+
| `parseXPath(expr, el, depth)` | Parse XPath-like type expressions |
|
|
246
|
+
| `splitByOperator(expr, op)` | Split XPath by operator |
|
|
247
|
+
| `isHidden(el)` | Check if element is hidden (display:none, visibility:hidden, hidden attribute) |
|
|
172
248
|
|
|
173
249
|
---
|
|
174
250
|
|
|
@@ -176,17 +252,18 @@ const SEARCHABLE_ATTRIBUTES = require('@nodebug/browser-element-finder/searchabl
|
|
|
176
252
|
|
|
177
253
|
Finds elements matching the specified type and/or text. Combines type and attribute matching in a single call. Searches all frames (main document + iframes) by default.
|
|
178
254
|
|
|
179
|
-
| Parameter | Type | Default | Description
|
|
180
|
-
| --------- | --------- | ------- |
|
|
181
|
-
| `type` | `string` | `null` | Element type (see supported types below). If `null`, matches any type. Throws `TypeError` for non-string values. |
|
|
182
|
-
| `text` | `string` | `null` | Text to search for in content/attributes. If `null`/`''`/`undefined`, matches any text.
|
|
183
|
-
| `exact` | `boolean` | `false` | Exact text match vs substring (only used when text is provided)
|
|
184
|
-
| `parent` | `Element` | `null` | Parent element to search within
|
|
255
|
+
| Parameter | Type | Default | Description |
|
|
256
|
+
| --------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
257
|
+
| `type` | `string` | `null` | Element type (see supported types below). If `null` or `undefined`, matches any type. Throws `TypeError` for non-string values. |
|
|
258
|
+
| `text` | `string` | `null` | Text to search for in content/attributes. If `null`/`''`/`undefined`, matches any text. |
|
|
259
|
+
| `exact` | `boolean` | `false` | Exact text match vs substring (only used when text is provided) |
|
|
260
|
+
| `parent` | `Element` | `null` | Parent element to search within |
|
|
185
261
|
|
|
186
|
-
**Returns**: `{ elements: [{ element, boundingBox, tagName, frameIndex }] }`
|
|
262
|
+
**Returns**: `{ elements: [{ element, boundingBox, tagName, frameIndex, isHidden }] }`
|
|
187
263
|
|
|
188
264
|
- `element`: Raw DOM element (main frame only; for iframes, use `frameIndex` and re-query after switching context)
|
|
189
265
|
- `frameIndex`: `-1` for main frame, `0, 1, 2...` for iframes
|
|
266
|
+
- `isHidden`: `true` if element is hidden (display:none, visibility:hidden, hidden attribute, or zero dimensions)
|
|
190
267
|
|
|
191
268
|
**Agent/Automation Note**: Iframe elements cannot be interacted with directly. Use `frameIndex` to switch context, then re-run `findElements` inside the iframe.
|
|
192
269
|
|
|
@@ -203,12 +280,12 @@ Finds elements matching the specified type with intelligent fallback to nearby e
|
|
|
203
280
|
| `exact` | `boolean` | `false` | Exact text match vs substring (only used when text is provided) |
|
|
204
281
|
| `parent` | `Element` | `null` | Parent element to search within |
|
|
205
282
|
|
|
206
|
-
**Returns**: `{ elements: [{ element, boundingBox, tagName, frameIndex }] }`
|
|
283
|
+
**Returns**: `{ elements: [{ element, boundingBox, tagName, frameIndex, isHidden }] }`
|
|
207
284
|
|
|
208
285
|
**Behavior**:
|
|
209
286
|
|
|
210
|
-
- If only `type` is provided: delegates to `
|
|
211
|
-
- If only `text` is provided: delegates to `
|
|
287
|
+
- If only `type` is provided: delegates to `findElementsByType(type, parent)`
|
|
288
|
+
- If only `text` is provided: delegates to `findElementsByAttribute(text, exact, parent)`
|
|
212
289
|
- If both are provided: attempts direct match, then falls back to nearby elements
|
|
213
290
|
|
|
214
291
|
**Fallback Strategy**: When no element matches both type and text directly, searches for nearby elements in this order:
|
|
@@ -220,11 +297,11 @@ Finds elements matching the specified type with intelligent fallback to nearby e
|
|
|
220
297
|
**Example**:
|
|
221
298
|
|
|
222
299
|
```javascript
|
|
223
|
-
// Type-only search (delegates to
|
|
300
|
+
// Type-only search (delegates to findElementsByType)
|
|
224
301
|
const result1 = ElementFinder.findProbableElements('button')
|
|
225
302
|
// Returns all buttons on the page
|
|
226
303
|
|
|
227
|
-
// Text-only search (delegates to
|
|
304
|
+
// Text-only search (delegates to findElementsByAttribute)
|
|
228
305
|
const result2 = ElementFinder.findProbableElements(null, 'Submit')
|
|
229
306
|
// Returns all elements containing "Submit"
|
|
230
307
|
|
|
@@ -265,6 +342,10 @@ Removes highlighting from elements.
|
|
|
265
342
|
|
|
266
343
|
Returns an array of all valid element type names.
|
|
267
344
|
|
|
345
|
+
### `getValidAttributes()`
|
|
346
|
+
|
|
347
|
+
Returns an array of all valid searchable attribute names (same as `getSearchableAttributes()`).
|
|
348
|
+
|
|
268
349
|
### `getBoundingBox(element)`
|
|
269
350
|
|
|
270
351
|
Returns the bounding box for an element.
|
|
@@ -277,6 +358,47 @@ Sets custom searchable attributes.
|
|
|
277
358
|
|
|
278
359
|
Returns the current searchable attributes array.
|
|
279
360
|
|
|
361
|
+
### `getElementDescriptor(element)`
|
|
362
|
+
|
|
363
|
+
Returns identifiable text for a DOM element, plus structured metadata about where it came from, its 1-based occurrence index, its semantic type, and its HTML tag name. Uniqueness can be inferred from `index`: `index === 1` means the identifiable text is unique within the current frame.
|
|
364
|
+
|
|
365
|
+
```javascript
|
|
366
|
+
const descriptor = ElementFinder.getElementDescriptor(element)
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Returns**:
|
|
370
|
+
|
|
371
|
+
```javascript
|
|
372
|
+
{
|
|
373
|
+
identifiableText: 'Save', // Plain searchable text only; no CSS/XPath/index syntax
|
|
374
|
+
attributeName: 'title', // Attribute name, or 'text' for direct/textContent fallback
|
|
375
|
+
index: 2, // 1-based occurrence index; index > 1 means not unique
|
|
376
|
+
type: 'button', // Semantic element type, or null for non-elements
|
|
377
|
+
tagName: 'button' // Lowercase HTML tag name, or null for non-elements
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Descriptor selection follows the same searchable-attribute priority as text search:
|
|
382
|
+
|
|
383
|
+
1. First non-empty searchable attribute value is used.
|
|
384
|
+
2. `aria-labelledby` is resolved to referenced element text before returning the identifiable text.
|
|
385
|
+
3. `src` values are returned as the image filename without path, query string, fragment, or extension.
|
|
386
|
+
4. If no searchable attribute exists, direct text nodes are used and `attributeName` is set to `'text'`.
|
|
387
|
+
5. If direct text is empty, trimmed full `textContent` is used and `attributeName` is set to `'text'`.
|
|
388
|
+
6. If no text exists, `identifiableText` and `attributeName` are `null`, but `index`, `type`, and `tagName` are still returned.
|
|
389
|
+
|
|
390
|
+
Null or non-element input returns:
|
|
391
|
+
|
|
392
|
+
```javascript
|
|
393
|
+
{
|
|
394
|
+
identifiableText: null,
|
|
395
|
+
attributeName: null,
|
|
396
|
+
index: 1,
|
|
397
|
+
type: null,
|
|
398
|
+
tagName: null
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
280
402
|
### `matchesType(el, type)`
|
|
281
403
|
|
|
282
404
|
Checks if an element matches the specified type definition.
|
|
@@ -285,7 +407,7 @@ Checks if an element matches the specified type definition.
|
|
|
285
407
|
|
|
286
408
|
Checks if an element matches the specified text/attribute value. Safely handles edge case elements that may throw errors on attribute access.
|
|
287
409
|
|
|
288
|
-
### `
|
|
410
|
+
### `findElementsByType(type, parent)`
|
|
289
411
|
|
|
290
412
|
Finds elements by type only. Searches all frames by default.
|
|
291
413
|
|
|
@@ -294,7 +416,37 @@ Finds elements by type only. Searches all frames by default.
|
|
|
294
416
|
| `type` | `string` | `"element"` | Element type (see supported types below). Throws `TypeError` for non-string values. |
|
|
295
417
|
| `parent` | `Element` | `null` | Parent element to search within |
|
|
296
418
|
|
|
297
|
-
### `
|
|
419
|
+
### `getElementCounts(type, parent)`
|
|
420
|
+
|
|
421
|
+
Counts elements by semantic type on the current screen. Searches all frames (main document + iframes) by default.
|
|
422
|
+
|
|
423
|
+
| Parameter | Type | Default | Description |
|
|
424
|
+
| --------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------- |
|
|
425
|
+
| `type` | `string` | `null` | Specific element type to count. If `null`/`undefined`, returns counts for all defined types except `element`. |
|
|
426
|
+
| `parent` | `Element` | `null` | Parent element to count within |
|
|
427
|
+
|
|
428
|
+
**Returns**: `Object.<string, number>` keyed by semantic element type.
|
|
429
|
+
|
|
430
|
+
```javascript
|
|
431
|
+
// Count all defined non-generic types
|
|
432
|
+
const counts = ElementFinder.getElementCounts()
|
|
433
|
+
// { button: 3, textbox: 2, link: 1, ... }
|
|
434
|
+
|
|
435
|
+
// Count one type
|
|
436
|
+
const buttons = ElementFinder.getElementCounts('button')
|
|
437
|
+
// { button: 3 }
|
|
438
|
+
|
|
439
|
+
// Count within a parent element
|
|
440
|
+
const inputs = ElementFinder.getElementCounts(
|
|
441
|
+
'textbox',
|
|
442
|
+
document.querySelector('form'),
|
|
443
|
+
)
|
|
444
|
+
// { textbox: 2 }
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
The generic `element` type is excluded from the all-types count so the result contains only semantic types such as `button`, `textbox`, `link`, and `table`.
|
|
448
|
+
|
|
449
|
+
### `findElementsByAttribute(value, exact, parent)`
|
|
298
450
|
|
|
299
451
|
Finds elements by text/attribute value only. Searches all frames by default.
|
|
300
452
|
|
|
@@ -329,7 +481,7 @@ The library automatically searches all frames (main + iframes) by default. Howev
|
|
|
329
481
|
### Iframe Element Limitations
|
|
330
482
|
|
|
331
483
|
```javascript
|
|
332
|
-
const results = ElementFinder.
|
|
484
|
+
const results = ElementFinder.findElements('button')
|
|
333
485
|
|
|
334
486
|
results.elements.forEach((item) => {
|
|
335
487
|
if (item.frameIndex === -1) {
|
|
@@ -352,7 +504,7 @@ To interact with elements inside an iframe, you must switch the Selenium driver
|
|
|
352
504
|
```javascript
|
|
353
505
|
// Find iframe elements
|
|
354
506
|
const results = await driver.executeScript(`
|
|
355
|
-
return ElementFinder.
|
|
507
|
+
return ElementFinder.findElements('button');
|
|
356
508
|
`)
|
|
357
509
|
|
|
358
510
|
// Switch to iframe and interact
|
|
@@ -363,7 +515,7 @@ if (iframeElements.length > 0) {
|
|
|
363
515
|
|
|
364
516
|
// Now find and interact with elements in the iframe
|
|
365
517
|
const iframeResults = await driver.executeScript(`
|
|
366
|
-
return ElementFinder.
|
|
518
|
+
return ElementFinder.findElements('button');
|
|
367
519
|
`)
|
|
368
520
|
// These elements will have the element property since we're in the iframe context
|
|
369
521
|
}
|
|
@@ -373,33 +525,33 @@ if (iframeElements.length > 0) {
|
|
|
373
525
|
|
|
374
526
|
## Supported Element Types
|
|
375
527
|
|
|
376
|
-
| Type | Description
|
|
377
|
-
| ------------- |
|
|
378
|
-
| `button` | `<button>`, `[role="button"]`, `[type="button"]`
|
|
379
|
-
| `checkbox` | `<input type="checkbox">`, `[role="checkbox"]`
|
|
380
|
-
| `switch` | Toggle switches, checkboxes with switch role
|
|
381
|
-
| `slider` | `<input type="range">`, `[role="slider"]`
|
|
382
|
-
| `datepicker` | `<input type="date"
|
|
383
|
-
| `colorpicker` | `<input type="color"
|
|
384
|
-
| `radio` | `<input type="radio">`, `[role="radio"]`
|
|
385
|
-
| `dropdown` | `<select>`, `[role="combobox"]`, `[role="listbox"]
|
|
386
|
-
| `textbox` | `<
|
|
387
|
-
| `link` | `<a>`, `[role="link"]`, `[href]`
|
|
388
|
-
| `heading` | `<h1>-<h6>`, `[role="heading"]`
|
|
389
|
-
| `navigation` | `<nav>`, `[role="navigation"]`
|
|
390
|
-
| `list` | `<ul>`, `<ol>`, `[role="list"]`
|
|
391
|
-
| `listitem` | `<li>`, `[role="listitem"]`
|
|
392
|
-
| `menu` | `<menu>`, `[role="menu"]`
|
|
393
|
-
| `menuitem` | `[role="menuitem"]`
|
|
394
|
-
| `toolbar` | `[role="toolbar"]`
|
|
395
|
-
| `dialog` | `[role="dialog"]`
|
|
396
|
-
| `table` | `<table>`, `[role="table"]`
|
|
397
|
-
| `row` | `<tr>`, `[role="row"]`
|
|
398
|
-
| `column` | `<td>`, `<th>`, `[role="cell"]`
|
|
399
|
-
| `cell` | `<td>`, `[role="cell"]` (data cells only, no expansion)
|
|
400
|
-
| `image` | `<img>`, `[role="img"]`
|
|
401
|
-
| `file` | `<input type="file"
|
|
402
|
-
| `element` | Matches all elements
|
|
528
|
+
| Type | Description |
|
|
529
|
+
| ------------- | ---------------------------------------------------------------------------------------------------- |
|
|
530
|
+
| `button` | `<button>`, `[role="button"]`, `[type="button"]`, `[type="submit"]` |
|
|
531
|
+
| `checkbox` | `<input type="checkbox">`, `[role="checkbox"]` |
|
|
532
|
+
| `switch` | Toggle switches, checkboxes with switch role, buttons with `class="switch"` or `data-state` |
|
|
533
|
+
| `slider` | `<input type="range">`, `[role="slider"]` |
|
|
534
|
+
| `datepicker` | `<input type="date">`, `[role="date"]` |
|
|
535
|
+
| `colorpicker` | `<input type="color">`, `[role="color"]` |
|
|
536
|
+
| `radio` | `<input type="radio">`, `[role="radio"]` |
|
|
537
|
+
| `dropdown` | `<select>`, `[role="combobox"]`, `[role="listbox"]`, class-based dropdown/trigger, ancestor matching |
|
|
538
|
+
| `textbox` | `<textarea>`, `<input>` (text/password/search/email/number/tel/url), `[role="textbox"]` |
|
|
539
|
+
| `link` | `<a>`, `[role="link"]`, `[href]` |
|
|
540
|
+
| `heading` | `<h1>-<h6>`, `[role="heading"]` |
|
|
541
|
+
| `navigation` | `<nav>`, `[role="navigation"]` |
|
|
542
|
+
| `list` | `<ul>`, `<ol>`, `[role="list"]` |
|
|
543
|
+
| `listitem` | `<li>`, `[role="listitem"]` |
|
|
544
|
+
| `menu` | `<menu>`, `[role="menu"]` |
|
|
545
|
+
| `menuitem` | `[role="menuitem"]` |
|
|
546
|
+
| `toolbar` | `[role="toolbar"]` |
|
|
547
|
+
| `dialog` | `[role="dialog"]`, `[role="alertdialog"]` |
|
|
548
|
+
| `table` | `<table>`, `[role="table"]` |
|
|
549
|
+
| `row` | `<tr>`, `[role="row"]` |
|
|
550
|
+
| `column` | `<td>`, `<th>`, `[role="cell"]`, `[role="gridcell"]`, `[role="columnheader"]` |
|
|
551
|
+
| `cell` | `<td>`, `[role="cell"]`, `[role="gridcell"]` (data cells only, no expansion) |
|
|
552
|
+
| `image` | `<img>`, `[role="img"]`, `[alt]` |
|
|
553
|
+
| `file` | `<input type="file">` |
|
|
554
|
+
| `element` | Matches all elements |
|
|
403
555
|
|
|
404
556
|
---
|
|
405
557
|
|
|
@@ -416,19 +568,19 @@ Both `column` and `cell` types find table cells, but they behave differently:
|
|
|
416
568
|
|
|
417
569
|
```javascript
|
|
418
570
|
// Find all cells in the "City" column (header + 3 data cells = 4 total)
|
|
419
|
-
const columnResult = ElementFinder.
|
|
571
|
+
const columnResult = ElementFinder.findElements('column', 'City')
|
|
420
572
|
// Returns: [th:City, td:New York, td:London, td:Paris]
|
|
421
573
|
|
|
422
574
|
// Find all cells when searching for a data cell value
|
|
423
|
-
const columnResult2 = ElementFinder.
|
|
575
|
+
const columnResult2 = ElementFinder.findElements('column', 'Paris')
|
|
424
576
|
// Returns: [th:City, td:New York, td:London, td:Paris]
|
|
425
577
|
|
|
426
578
|
// Find only the specific cell containing "Paris"
|
|
427
|
-
const cellResult = ElementFinder.
|
|
579
|
+
const cellResult = ElementFinder.findElements('cell', 'Paris')
|
|
428
580
|
// Returns: [td:Paris]
|
|
429
581
|
|
|
430
582
|
// Find by header text with cell type - returns only the header cell
|
|
431
|
-
const headerCell = ElementFinder.
|
|
583
|
+
const headerCell = ElementFinder.findElements('cell', 'City')
|
|
432
584
|
// Returns: [] (no td elements match "City" header text)
|
|
433
585
|
```
|
|
434
586
|
|
|
@@ -438,8 +590,8 @@ const headerCell = ElementFinder.findElement('cell', 'City')
|
|
|
438
590
|
|
|
439
591
|
By default, the library searches these attributes (in priority order):
|
|
440
592
|
|
|
441
|
-
- `placeholder`, `value`, `data-test-id`, `data-testid`, `id`
|
|
442
|
-
- `resource-id`, `name`, `aria-label`, `
|
|
593
|
+
- `placeholder`, `value`, `data-value`, `data-test-id`, `data-testid`, `id`
|
|
594
|
+
- `resource-id`, `name`, `aria-label`, `hint`
|
|
443
595
|
- `title`, `tooltip`, `alt`, `src`, `aria-labelledby`
|
|
444
596
|
|
|
445
597
|
---
|
package/index.js
CHANGED
|
@@ -21,21 +21,27 @@ var ElementFinder = (() => {
|
|
|
21
21
|
var element_finder_exports = {};
|
|
22
22
|
__export(element_finder_exports, {
|
|
23
23
|
ELEMENT_DEFINITIONS: () => ELEMENT_DEFINITIONS,
|
|
24
|
-
findElementByAttributes: () => findElementByAttributes,
|
|
25
|
-
findElementByType: () => findElementByType,
|
|
26
24
|
findElements: () => findElements,
|
|
25
|
+
findElementsByAttribute: () => findElementsByAttribute,
|
|
26
|
+
findElementsByType: () => findElementsByType,
|
|
27
27
|
findProbableElements: () => findProbableElements,
|
|
28
28
|
getAllElements: () => getAllElements,
|
|
29
29
|
getAllFrames: () => getAllFrames,
|
|
30
30
|
getBoundingBox: () => getBoundingBox,
|
|
31
|
+
getElementCounts: () => getElementCounts,
|
|
32
|
+
getElementDescriptor: () => getElementDescriptor,
|
|
33
|
+
getSearchableAttributeValues: () => getSearchableAttributeValues,
|
|
31
34
|
getSearchableAttributes: () => getSearchableAttributes,
|
|
32
35
|
getValidAttributes: () => getValidAttributes,
|
|
33
36
|
getValidTypes: () => getValidTypes,
|
|
34
37
|
highlight: () => highlight,
|
|
38
|
+
isHidden: () => isHidden,
|
|
35
39
|
matchesAttribute: () => matchesAttribute,
|
|
36
40
|
matchesType: () => matchesType,
|
|
37
41
|
parseCondition: () => parseCondition,
|
|
38
42
|
parseXPath: () => parseXPath,
|
|
43
|
+
pauseAnimations: () => pauseAnimations,
|
|
44
|
+
resumeAnimations: () => resumeAnimations,
|
|
39
45
|
setSearchableAttributes: () => setSearchableAttributes,
|
|
40
46
|
splitByOperator: () => splitByOperator,
|
|
41
47
|
unhighlight: () => unhighlight
|
|
@@ -61,7 +67,7 @@ var ElementFinder = (() => {
|
|
|
61
67
|
menu: "self::menu or @role='menu'",
|
|
62
68
|
menuitem: "@role='menuitem'",
|
|
63
69
|
toolbar: "@role='toolbar'",
|
|
64
|
-
dialog: "@role='dialog'",
|
|
70
|
+
dialog: "@role='dialog' or @role='alertdialog'",
|
|
65
71
|
table: "self::table or @role='table'",
|
|
66
72
|
row: "self::tr or @role='row'",
|
|
67
73
|
column: "self::td or self::th or @role='cell' or @role='gridcell' or @role='columnheader'",
|
|
@@ -74,6 +80,7 @@ var ElementFinder = (() => {
|
|
|
74
80
|
var searchable_attributes_default = [
|
|
75
81
|
"placeholder",
|
|
76
82
|
"value",
|
|
83
|
+
"data-value",
|
|
77
84
|
"data-test-id",
|
|
78
85
|
"data-testid",
|
|
79
86
|
"id",
|
|
@@ -118,6 +125,156 @@ var ElementFinder = (() => {
|
|
|
118
125
|
function getSearchableAttributes() {
|
|
119
126
|
return [...SEARCHABLE_ATTRIBUTES];
|
|
120
127
|
}
|
|
128
|
+
function getSearchableAttributeValues(el) {
|
|
129
|
+
if (el == null || el.nodeType !== Node.ELEMENT_NODE) return {};
|
|
130
|
+
const values = {};
|
|
131
|
+
const attrs = SEARCHABLE_ATTRIBUTES;
|
|
132
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
133
|
+
const attr = attrs[i];
|
|
134
|
+
let attrValue;
|
|
135
|
+
try {
|
|
136
|
+
attrValue = el.getAttribute(attr);
|
|
137
|
+
} catch (e) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (attrValue !== null && attrValue !== void 0 && attrValue !== "") {
|
|
141
|
+
values[attr] = attrValue;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return values;
|
|
145
|
+
}
|
|
146
|
+
function normalizeDescriptorText(text) {
|
|
147
|
+
if (text == null) return "";
|
|
148
|
+
return String(text).replace(/\s+/g, " ").trim();
|
|
149
|
+
}
|
|
150
|
+
function getImageFilenameWithoutExtension(src) {
|
|
151
|
+
const normalizedSrc = normalizeDescriptorText(src);
|
|
152
|
+
if (!normalizedSrc) return "";
|
|
153
|
+
const withoutQueryOrFragment = normalizedSrc.split(/[?#]/)[0];
|
|
154
|
+
const lastSlashIndex = Math.max(
|
|
155
|
+
withoutQueryOrFragment.lastIndexOf("/"),
|
|
156
|
+
withoutQueryOrFragment.lastIndexOf("\\")
|
|
157
|
+
);
|
|
158
|
+
const filenameWithExtension = lastSlashIndex >= 0 ? withoutQueryOrFragment.slice(lastSlashIndex + 1) : withoutQueryOrFragment;
|
|
159
|
+
const lastDotIndex = filenameWithExtension.lastIndexOf(".");
|
|
160
|
+
return lastDotIndex > 0 ? filenameWithExtension.slice(0, lastDotIndex) : filenameWithExtension;
|
|
161
|
+
}
|
|
162
|
+
function getResolvedAriaLabelledByText(el) {
|
|
163
|
+
const labelledBy = el.getAttribute("aria-labelledby");
|
|
164
|
+
if (!labelledBy) return "";
|
|
165
|
+
const ids = labelledBy.split(/\s+/);
|
|
166
|
+
const ownerDocument = el.ownerDocument || document;
|
|
167
|
+
let text = "";
|
|
168
|
+
for (const id of ids) {
|
|
169
|
+
try {
|
|
170
|
+
const refEl = ownerDocument.getElementById(id);
|
|
171
|
+
if (!refEl) continue;
|
|
172
|
+
const refText = normalizeDescriptorText(refEl.textContent);
|
|
173
|
+
if (refText) {
|
|
174
|
+
text = text ? `${text} ${refText}` : refText;
|
|
175
|
+
}
|
|
176
|
+
} catch (e) {
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return text;
|
|
180
|
+
}
|
|
181
|
+
function getElementDescriptorText(el) {
|
|
182
|
+
const values = getSearchableAttributeValues(el);
|
|
183
|
+
const attrs = SEARCHABLE_ATTRIBUTES;
|
|
184
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
185
|
+
const attr = attrs[i];
|
|
186
|
+
if (!Object.prototype.hasOwnProperty.call(values, attr)) continue;
|
|
187
|
+
const rawText = attr === "aria-labelledby" ? getResolvedAriaLabelledByText(el) : attr === "src" ? getImageFilenameWithoutExtension(values[attr]) : values[attr];
|
|
188
|
+
const identifiableText = normalizeDescriptorText(rawText);
|
|
189
|
+
if (identifiableText) {
|
|
190
|
+
return { attributeName: attr, identifiableText };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const directText = normalizeDescriptorText(getDirectText(el));
|
|
194
|
+
if (directText) {
|
|
195
|
+
return { attributeName: "text", identifiableText: directText };
|
|
196
|
+
}
|
|
197
|
+
const fullText = normalizeDescriptorText(el.textContent);
|
|
198
|
+
if (fullText) {
|
|
199
|
+
return { attributeName: "text", identifiableText: fullText };
|
|
200
|
+
}
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
function getElementDescriptorFrame(el) {
|
|
204
|
+
if (!el || !el.ownerDocument) return null;
|
|
205
|
+
try {
|
|
206
|
+
const frames = getAllFrames(window);
|
|
207
|
+
for (let i = 0; i < frames.length; i++) {
|
|
208
|
+
if (frames[i].document === el.ownerDocument) {
|
|
209
|
+
return frames[i].document;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} catch (e) {
|
|
213
|
+
}
|
|
214
|
+
return el.ownerDocument;
|
|
215
|
+
}
|
|
216
|
+
function getElementDescriptorUniqueness(el, text) {
|
|
217
|
+
const root = getElementDescriptorFrame(el);
|
|
218
|
+
if (!root) {
|
|
219
|
+
return { index: 1 };
|
|
220
|
+
}
|
|
221
|
+
const elements = getAllElements(root);
|
|
222
|
+
let index = 1;
|
|
223
|
+
let count = 0;
|
|
224
|
+
for (let i = 0; i < elements.length; i++) {
|
|
225
|
+
const candidate = elements[i];
|
|
226
|
+
if (candidate !== el && (candidate === root.documentElement || candidate.tagName === "BODY")) {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const candidateDescriptor = getElementDescriptorText(candidate);
|
|
230
|
+
if (!candidateDescriptor || candidateDescriptor.identifiableText !== text) continue;
|
|
231
|
+
count++;
|
|
232
|
+
if (candidate === el) {
|
|
233
|
+
index = count;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return { index };
|
|
237
|
+
}
|
|
238
|
+
function getElementDescriptorType(el) {
|
|
239
|
+
if (el == null || el.nodeType !== Node.ELEMENT_NODE) return null;
|
|
240
|
+
const types = Object.keys(ELEMENT_DEFINITIONS);
|
|
241
|
+
for (let i = 0; i < types.length; i++) {
|
|
242
|
+
const type = types[i];
|
|
243
|
+
if (type === "element") continue;
|
|
244
|
+
if (matchesType(el, type)) return type;
|
|
245
|
+
}
|
|
246
|
+
return "element";
|
|
247
|
+
}
|
|
248
|
+
function getElementDescriptor(el) {
|
|
249
|
+
if (el == null || el.nodeType !== Node.ELEMENT_NODE) {
|
|
250
|
+
return {
|
|
251
|
+
identifiableText: null,
|
|
252
|
+
attributeName: null,
|
|
253
|
+
index: 1,
|
|
254
|
+
type: null,
|
|
255
|
+
tagName: null
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
const type = getElementDescriptorType(el);
|
|
259
|
+
const descriptorSource = getElementDescriptorText(el);
|
|
260
|
+
if (!descriptorSource) {
|
|
261
|
+
return {
|
|
262
|
+
identifiableText: null,
|
|
263
|
+
attributeName: null,
|
|
264
|
+
index: 1,
|
|
265
|
+
type,
|
|
266
|
+
tagName: el.tagName.toLowerCase()
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const uniqueness = getElementDescriptorUniqueness(el, descriptorSource.identifiableText);
|
|
270
|
+
return {
|
|
271
|
+
identifiableText: descriptorSource.identifiableText,
|
|
272
|
+
attributeName: descriptorSource.attributeName,
|
|
273
|
+
index: uniqueness.index,
|
|
274
|
+
type,
|
|
275
|
+
tagName: el.tagName.toLowerCase()
|
|
276
|
+
};
|
|
277
|
+
}
|
|
121
278
|
function parseXPath(expr, el, depth = 0) {
|
|
122
279
|
if (expr == null || el == null) return false;
|
|
123
280
|
if (depth > MAX_RECURSION_DEPTH) {
|
|
@@ -387,15 +544,40 @@ var ElementFinder = (() => {
|
|
|
387
544
|
tagName: el.tagName.toLowerCase()
|
|
388
545
|
};
|
|
389
546
|
}
|
|
390
|
-
function
|
|
547
|
+
function isHidden(el) {
|
|
548
|
+
if (el == null) return true;
|
|
549
|
+
if (el.offsetWidth === 0 && el.offsetHeight === 0) {
|
|
550
|
+
return true;
|
|
551
|
+
}
|
|
552
|
+
try {
|
|
553
|
+
const style = window.getComputedStyle(el);
|
|
554
|
+
if (style.visibility === "hidden" || style.visibility === "collapse") {
|
|
555
|
+
return true;
|
|
556
|
+
}
|
|
557
|
+
if (style.display === "none") {
|
|
558
|
+
return true;
|
|
559
|
+
}
|
|
560
|
+
} catch (e) {
|
|
561
|
+
}
|
|
562
|
+
if (el.hasAttribute("hidden")) {
|
|
563
|
+
return true;
|
|
564
|
+
}
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
function findElementsByType(type = "element", parent = null, options = null) {
|
|
391
568
|
if (type === null || type === void 0) {
|
|
392
569
|
type = "element";
|
|
393
570
|
}
|
|
394
571
|
if (typeof type !== "string") {
|
|
395
572
|
throw new TypeError(`type must be a string, got ${typeof type}`);
|
|
396
573
|
}
|
|
574
|
+
const failOnUnknownType = options && options.failOnUnknownType === true;
|
|
397
575
|
if (type && !ELEMENT_DEFINITIONS[type]) {
|
|
398
|
-
|
|
576
|
+
const message = `Unknown element type: ${type}. Valid types: ${Object.keys(ELEMENT_DEFINITIONS).join(", ")}`;
|
|
577
|
+
if (failOnUnknownType) {
|
|
578
|
+
throw new TypeError(`Unknown element type: ${type}`);
|
|
579
|
+
}
|
|
580
|
+
console.warn(message);
|
|
399
581
|
return { elements: [] };
|
|
400
582
|
}
|
|
401
583
|
const matches = [];
|
|
@@ -430,23 +612,26 @@ var ElementFinder = (() => {
|
|
|
430
612
|
const qualified = innermostMatches.map((item) => {
|
|
431
613
|
const boundingBox = getBoundingBox(item.element);
|
|
432
614
|
const tagName = item.element.tagName.toLowerCase();
|
|
615
|
+
const hidden = isHidden(item.element);
|
|
433
616
|
if (!item.frame.isMainFrame) {
|
|
434
617
|
return {
|
|
435
618
|
boundingBox,
|
|
436
619
|
tagName,
|
|
437
|
-
frameIndex: item.frame.frameIndex
|
|
620
|
+
frameIndex: item.frame.frameIndex,
|
|
621
|
+
isHidden: hidden
|
|
438
622
|
};
|
|
439
623
|
}
|
|
440
624
|
return {
|
|
441
625
|
element: item.element,
|
|
442
626
|
boundingBox,
|
|
443
627
|
tagName,
|
|
444
|
-
frameIndex: item.frame.frameIndex
|
|
628
|
+
frameIndex: item.frame.frameIndex,
|
|
629
|
+
isHidden: hidden
|
|
445
630
|
};
|
|
446
631
|
});
|
|
447
632
|
return { elements: qualified };
|
|
448
633
|
}
|
|
449
|
-
function
|
|
634
|
+
function findElementsByAttribute(value, exact = false, parent = null) {
|
|
450
635
|
if (value === null || value === void 0) {
|
|
451
636
|
value = "";
|
|
452
637
|
}
|
|
@@ -477,18 +662,21 @@ var ElementFinder = (() => {
|
|
|
477
662
|
const qualified = filteredMatches.map((item) => {
|
|
478
663
|
const boundingBox = getBoundingBox(item.element);
|
|
479
664
|
const tagName = item.element.tagName.toLowerCase();
|
|
665
|
+
const hidden = isHidden(item.element);
|
|
480
666
|
if (!item.frame.isMainFrame) {
|
|
481
667
|
return {
|
|
482
668
|
boundingBox,
|
|
483
669
|
tagName,
|
|
484
|
-
frameIndex: item.frame.frameIndex
|
|
670
|
+
frameIndex: item.frame.frameIndex,
|
|
671
|
+
isHidden: hidden
|
|
485
672
|
};
|
|
486
673
|
}
|
|
487
674
|
return {
|
|
488
675
|
element: item.element,
|
|
489
676
|
boundingBox,
|
|
490
677
|
tagName,
|
|
491
|
-
frameIndex: item.frame.frameIndex
|
|
678
|
+
frameIndex: item.frame.frameIndex,
|
|
679
|
+
isHidden: hidden
|
|
492
680
|
};
|
|
493
681
|
});
|
|
494
682
|
return { elements: qualified };
|
|
@@ -526,7 +714,43 @@ var ElementFinder = (() => {
|
|
|
526
714
|
}
|
|
527
715
|
return false;
|
|
528
716
|
}
|
|
529
|
-
function
|
|
717
|
+
function getElementCounts(type = null, parent = null, options = null) {
|
|
718
|
+
const hasType = type !== null && type !== void 0;
|
|
719
|
+
if (hasType) {
|
|
720
|
+
if (typeof type !== "string") {
|
|
721
|
+
throw new TypeError(`type must be a string, got ${typeof type}`);
|
|
722
|
+
}
|
|
723
|
+
if (!ELEMENT_DEFINITIONS[type]) {
|
|
724
|
+
const message = `Unknown element type: ${type}. Valid types: ${Object.keys(ELEMENT_DEFINITIONS).join(", ")}`;
|
|
725
|
+
if (options && options.failOnUnknownType === true) {
|
|
726
|
+
throw new TypeError(`Unknown element type: ${type}`);
|
|
727
|
+
}
|
|
728
|
+
console.warn(message);
|
|
729
|
+
return { [type]: 0 };
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
const counts = {};
|
|
733
|
+
const targetTypes = hasType ? [type] : Object.keys(ELEMENT_DEFINITIONS).filter((item) => item !== "element");
|
|
734
|
+
for (let i = 0; i < targetTypes.length; i++) {
|
|
735
|
+
counts[targetTypes[i]] = 0;
|
|
736
|
+
}
|
|
737
|
+
const frames = getAllFrames(window);
|
|
738
|
+
for (let i = 0; i < frames.length; i++) {
|
|
739
|
+
const frame = frames[i];
|
|
740
|
+
const allElements = getAllElements(parent || frame.document);
|
|
741
|
+
for (let j = 0; j < allElements.length; j++) {
|
|
742
|
+
const el = allElements[j];
|
|
743
|
+
for (let k = 0; k < targetTypes.length; k++) {
|
|
744
|
+
const targetType = targetTypes[k];
|
|
745
|
+
if (matchesType(el, targetType)) {
|
|
746
|
+
counts[targetType] += 1;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return counts;
|
|
752
|
+
}
|
|
753
|
+
function findElements(type = null, text = null, exact = false, parent = null, options = null) {
|
|
530
754
|
if (text === null || text === void 0) {
|
|
531
755
|
text = "";
|
|
532
756
|
}
|
|
@@ -535,7 +759,11 @@ var ElementFinder = (() => {
|
|
|
535
759
|
throw new TypeError(`type must be a string, got ${typeof type}`);
|
|
536
760
|
}
|
|
537
761
|
if (!ELEMENT_DEFINITIONS[type]) {
|
|
538
|
-
|
|
762
|
+
const message = `Unknown element type: ${type}. Valid types: ${Object.keys(ELEMENT_DEFINITIONS).join(", ")}`;
|
|
763
|
+
if (options && options.failOnUnknownType === true) {
|
|
764
|
+
throw new TypeError(`Unknown element type: ${type}`);
|
|
765
|
+
}
|
|
766
|
+
console.warn(message);
|
|
539
767
|
return { elements: [] };
|
|
540
768
|
}
|
|
541
769
|
}
|
|
@@ -567,18 +795,21 @@ var ElementFinder = (() => {
|
|
|
567
795
|
const qualified = filteredMatches.map((item) => {
|
|
568
796
|
const boundingBox = getBoundingBox(item.element);
|
|
569
797
|
const tagName = item.element.tagName.toLowerCase();
|
|
798
|
+
const hidden = isHidden(item.element);
|
|
570
799
|
if (!item.frame.isMainFrame) {
|
|
571
800
|
return {
|
|
572
801
|
boundingBox,
|
|
573
802
|
tagName,
|
|
574
|
-
frameIndex: item.frame.frameIndex
|
|
803
|
+
frameIndex: item.frame.frameIndex,
|
|
804
|
+
isHidden: hidden
|
|
575
805
|
};
|
|
576
806
|
}
|
|
577
807
|
return {
|
|
578
808
|
element: item.element,
|
|
579
809
|
boundingBox,
|
|
580
810
|
tagName,
|
|
581
|
-
frameIndex: item.frame.frameIndex
|
|
811
|
+
frameIndex: item.frame.frameIndex,
|
|
812
|
+
isHidden: hidden
|
|
582
813
|
};
|
|
583
814
|
});
|
|
584
815
|
return { elements: qualified };
|
|
@@ -637,23 +868,45 @@ var ElementFinder = (() => {
|
|
|
637
868
|
}
|
|
638
869
|
}
|
|
639
870
|
}
|
|
871
|
+
let ancestor = el.parentElement;
|
|
872
|
+
while (ancestor) {
|
|
873
|
+
const ancestorSiblings = getSiblingElements(ancestor);
|
|
874
|
+
for (const sibling of ancestorSiblings) {
|
|
875
|
+
if (sibling !== ancestor) {
|
|
876
|
+
if (matchesType(sibling, targetType)) {
|
|
877
|
+
return sibling;
|
|
878
|
+
}
|
|
879
|
+
const siblingElements = getAllElements(sibling);
|
|
880
|
+
for (let i = 0; i < siblingElements.length; i++) {
|
|
881
|
+
if (matchesType(siblingElements[i], targetType)) {
|
|
882
|
+
return siblingElements[i];
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
ancestor = ancestor.parentElement;
|
|
888
|
+
}
|
|
640
889
|
return null;
|
|
641
890
|
}
|
|
642
|
-
function findProbableElements(elementType, attributeText, exact = false, parent = null) {
|
|
891
|
+
function findProbableElements(elementType, attributeText, exact = false, parent = null, options = null) {
|
|
643
892
|
const hasType = elementType !== null && elementType !== void 0 && elementType !== "";
|
|
644
893
|
const hasText = attributeText !== null && attributeText !== void 0 && attributeText !== "";
|
|
645
894
|
if (hasType && !hasText) {
|
|
646
|
-
return
|
|
895
|
+
return findElementsByType(elementType, parent, options);
|
|
647
896
|
}
|
|
648
897
|
if (!hasType && hasText) {
|
|
649
|
-
return
|
|
898
|
+
return findElementsByAttribute(attributeText, exact, parent);
|
|
650
899
|
}
|
|
651
900
|
if (hasType) {
|
|
652
901
|
if (typeof elementType !== "string") {
|
|
653
902
|
throw new TypeError(`elementType must be a string, got ${typeof elementType}`);
|
|
654
903
|
}
|
|
655
904
|
if (!ELEMENT_DEFINITIONS[elementType]) {
|
|
656
|
-
|
|
905
|
+
const message = `Unknown element type: ${elementType}. Valid types: ${Object.keys(ELEMENT_DEFINITIONS).join(", ")}`;
|
|
906
|
+
if (options && options.failOnUnknownType === true) {
|
|
907
|
+
throw new TypeError(`Unknown element type: ${elementType}`);
|
|
908
|
+
}
|
|
909
|
+
console.warn(message);
|
|
657
910
|
return { elements: [] };
|
|
658
911
|
}
|
|
659
912
|
}
|
|
@@ -680,7 +933,9 @@ var ElementFinder = (() => {
|
|
|
680
933
|
for (let i = 0; i < allElements.length; i++) {
|
|
681
934
|
const el = allElements[i];
|
|
682
935
|
if (!matchesAttribute(el, attributeText, exact)) continue;
|
|
683
|
-
|
|
936
|
+
if (hasOwnMatch(el, attributeText, exact)) {
|
|
937
|
+
attributeMatches.push({ element: el, frame });
|
|
938
|
+
}
|
|
684
939
|
}
|
|
685
940
|
}
|
|
686
941
|
const foundElements = /* @__PURE__ */ new Set();
|
|
@@ -706,18 +961,21 @@ var ElementFinder = (() => {
|
|
|
706
961
|
const qualified = filteredMatches.map((item) => {
|
|
707
962
|
const boundingBox = getBoundingBox(item.element);
|
|
708
963
|
const tagName = item.element.tagName.toLowerCase();
|
|
964
|
+
const hidden = isHidden(item.element);
|
|
709
965
|
if (!item.frame.isMainFrame) {
|
|
710
966
|
return {
|
|
711
967
|
boundingBox,
|
|
712
968
|
tagName,
|
|
713
|
-
frameIndex: item.frame.frameIndex
|
|
969
|
+
frameIndex: item.frame.frameIndex,
|
|
970
|
+
isHidden: hidden
|
|
714
971
|
};
|
|
715
972
|
}
|
|
716
973
|
return {
|
|
717
974
|
element: item.element,
|
|
718
975
|
boundingBox,
|
|
719
976
|
tagName,
|
|
720
|
-
frameIndex: item.frame.frameIndex
|
|
977
|
+
frameIndex: item.frame.frameIndex,
|
|
978
|
+
isHidden: hidden
|
|
721
979
|
};
|
|
722
980
|
});
|
|
723
981
|
return { elements: qualified };
|
|
@@ -755,6 +1013,78 @@ var ElementFinder = (() => {
|
|
|
755
1013
|
}
|
|
756
1014
|
}
|
|
757
1015
|
}
|
|
1016
|
+
var animationPauseStack = [];
|
|
1017
|
+
function pauseAnimations() {
|
|
1018
|
+
const originalStyles = /* @__PURE__ */ new Map();
|
|
1019
|
+
const elements = getAllElements();
|
|
1020
|
+
for (const el of elements) {
|
|
1021
|
+
if (el && el.style) {
|
|
1022
|
+
if (el.style.animationPlayState !== "paused") {
|
|
1023
|
+
originalStyles.set(el, {
|
|
1024
|
+
animationPlayState: el.style.animationPlayState,
|
|
1025
|
+
transitionProperty: el.style.transitionProperty,
|
|
1026
|
+
webkitAnimationPlayState: el.style.webkitAnimationPlayState,
|
|
1027
|
+
webkitTransitionProperty: el.style.webkitTransitionProperty
|
|
1028
|
+
});
|
|
1029
|
+
el.style.animationPlayState = "paused";
|
|
1030
|
+
el.style.transitionProperty = "none";
|
|
1031
|
+
el.style.webkitAnimationPlayState = "paused";
|
|
1032
|
+
el.style.webkitTransitionProperty = "none";
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
let styleSheet = document.getElementById("elementfinder-animation-pause");
|
|
1037
|
+
if (!styleSheet) {
|
|
1038
|
+
styleSheet = document.createElement("style");
|
|
1039
|
+
styleSheet.id = "elementfinder-animation-pause";
|
|
1040
|
+
styleSheet.textContent = `
|
|
1041
|
+
*, *::before, *::after {
|
|
1042
|
+
animation-play-state: paused !important;
|
|
1043
|
+
transition-property: none !important;
|
|
1044
|
+
-webkit-animation-play-state: paused !important;
|
|
1045
|
+
-webkit-transition-property: none !important;
|
|
1046
|
+
}
|
|
1047
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
1048
|
+
*, *::before, *::after {
|
|
1049
|
+
animation-duration: 0s !important;
|
|
1050
|
+
animation-iteration-count: 1 !important;
|
|
1051
|
+
transition-duration: 0s !important;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
`;
|
|
1055
|
+
document.head.appendChild(styleSheet);
|
|
1056
|
+
}
|
|
1057
|
+
const pauseState = { originalStyles, pausedCount: originalStyles.size };
|
|
1058
|
+
animationPauseStack.push(pauseState);
|
|
1059
|
+
return pauseState;
|
|
1060
|
+
}
|
|
1061
|
+
function resumeAnimations(pauseState) {
|
|
1062
|
+
if (!pauseState) {
|
|
1063
|
+
if (animationPauseStack.length === 0) return;
|
|
1064
|
+
pauseState = animationPauseStack.pop();
|
|
1065
|
+
} else {
|
|
1066
|
+
const index = animationPauseStack.indexOf(pauseState);
|
|
1067
|
+
if (index === -1) return;
|
|
1068
|
+
animationPauseStack.splice(index, 1);
|
|
1069
|
+
}
|
|
1070
|
+
const originalStyles = pauseState.originalStyles;
|
|
1071
|
+
if (originalStyles) {
|
|
1072
|
+
for (const [el, styles] of originalStyles) {
|
|
1073
|
+
if (el && el.style) {
|
|
1074
|
+
el.style.animationPlayState = styles.animationPlayState || "";
|
|
1075
|
+
el.style.transitionProperty = styles.transitionProperty || "";
|
|
1076
|
+
el.style.webkitAnimationPlayState = styles.webkitAnimationPlayState || "";
|
|
1077
|
+
el.style.webkitTransitionProperty = styles.webkitTransitionProperty || "";
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
if (animationPauseStack.length === 0) {
|
|
1082
|
+
const styleSheet = document.getElementById("elementfinder-animation-pause");
|
|
1083
|
+
if (styleSheet) {
|
|
1084
|
+
styleSheet.remove();
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
758
1088
|
function getValidTypes() {
|
|
759
1089
|
return Object.keys(ELEMENT_DEFINITIONS);
|
|
760
1090
|
}
|
package/index.min.js
CHANGED
|
@@ -1 +1,15 @@
|
|
|
1
|
-
var ElementFinder=(()=>{var M=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var U=(e,t)=>{for(var n in t)M(e,n,{get:t[n],enumerable:!0})},V=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of _(t))!F.call(e,r)&&r!==n&&M(e,r,{get:()=>t[r],enumerable:!(i=j(t,r))||i.enumerable});return e};var z=e=>V(M({},"__esModule",{value:!0}),e);var oe={};U(oe,{ELEMENT_DEFINITIONS:()=>p,findElementByAttributes:()=>q,findElementByType:()=>$,findElements:()=>Q,findProbableElements:()=>v,getAllElements:()=>w,getAllFrames:()=>N,getBoundingBox:()=>x,getSearchableAttributes:()=>H,getValidAttributes:()=>re,getValidTypes:()=>ne,highlight:()=>ee,matchesAttribute:()=>y,matchesType:()=>g,parseCondition:()=>k,parseXPath:()=>b,setSearchableAttributes:()=>W,splitByOperator:()=>T,unhighlight:()=>te});var I={link:"self::a or @role='link' or @href",navigation:"@role='navigation' or self::nav",heading:"@role='heading' or self::h1 or self::h2 or self::h3 or self::h4 or self::h5 or self::h6",button:"self::button or @role='button' or @type='button' or @type='submit'",checkbox:"(self::input and @type='checkbox') or @role='checkbox'",switch:"(self::input and @type='checkbox') or @role='switch' or (self::button and (contains(@class, 'switch') or @data-state))",slider:"self::input[@type='range'] or @role='slider'",datepicker:"self::input[@type='date'] or @role='date'",colorpicker:"self::input[@type='color'] or @role='color'",radio:"(self::input and @type='radio') or @role='radio'",dropdown:"(self::select[descendant::option] or @role='combobox' or @role='listbox' or contains(@class, 'dropdown') or contains(@class, 'trigger') or ancestor::*[contains(@class, 'dropdown') or @role='combobox'])",textbox:"self::textarea or (self::input and (@type='text' or @type='password' or @type='search' or @type='email' or @type='number' or @type='tel' or @type='url')) or @role='textbox'",file:"self::input and @type='file'",list:"self::ul or self::ol or @role='list'",listitem:"self::li or @role='listitem'",menu:"self::menu or @role='menu'",menuitem:"@role='menuitem'",toolbar:"@role='toolbar'",dialog:"@role='dialog'",table:"self::table or @role='table'",row:"self::tr or @role='row'",column:"self::td or self::th or @role='cell' or @role='gridcell' or @role='columnheader'",cell:"self::td or @role='cell' or @role='gridcell'",image:"self::img or @role='img' or @alt",element:"true()"};var O=["placeholder","value","data-test-id","data-testid","id","resource-id","name","aria-label","hint","title","tooltip","alt","src","aria-labelledby"];var h={selfWithTag:/^self::([a-zA-Z0-9-]+)(?:\[([^\]]+)\])?$/,contains:/contains\(@([a-zA-Z0-9-]+),\s*['"]([^'"]+)['"]\)/i,attrEquals:/@([a-zA-Z0-9-]+)\s*=\s*['"]([^'"]*)['"]/,attrExists:/^@([a-zA-Z0-9-]+)$/,descendant:/descendant::([a-zA-Z0-9-]+)/i,ancestor:/ancestor::\*\[([^\]]+)\]/i,operatorOr:/^\s*\bor\b\s*/i,operatorAnd:/^\s*\band\b\s*/i},Z=100,S=new Map;for(let[e,t]of Object.entries(I))t==="true()"?S.set(e,()=>!0):S.set(e,n=>b(t,n));var E=O;function W(e){if(!Array.isArray(e))throw new TypeError("attributes must be an array");E=e}function H(){return[...E]}function b(e,t,n=0){if(e==null||t==null)return!1;if(n>Z)throw new Error("XPath expression exceeds maximum recursion depth");if(e=e.trim(),e==="true()")return!0;if(e[0]==="("&&e[e.length-1]===")"){let o=1,l=!0;for(let a=1;a<e.length-1;a++)if(e[a]==="("?o++:e[a]===")"&&o--,o===0){l=!1;break}if(l)return b(e.slice(1,-1),t,n+1)}let i=T(e,"or");if(i.length>1){for(let o of i)if(b(o,t,n+1))return!0;return!1}let r=T(e,"and");if(r.length>1){for(let o of r)if(!b(o,t,n+1))return!1;return!0}return k(e,t,n)}function T(e,t){let n=[],i=0,r="",o=!1,l="",a=t==="or"?h.operatorOr:h.operatorAnd;for(let s=0;s<e.length;s++){let f=e[s];if((f==="'"||f==='"')&&(s===0||e[s-1]!=="\\")&&(o?f===l&&(o=!1):(o=!0,l=f)),!o&&(f==="("?i++:f===")"&&i--,i===0)){let u=e.slice(s).match(a);if(u){n.push(r.trim()),s+=u[0].length-1,r="";continue}}r+=f}return r.trim()&&n.push(r.trim()),n}function k(e,t,n=0){if(e==null||t==null)return!1;e=e.trim();let i=e.match(h.selfWithTag);if(i){let f=i[1].toUpperCase();return t.tagName!==f?!1:i[2]?b(i[2],t,n+1):!0}let r=e.match(h.contains);if(r)return(t.getAttribute(r[1])||"").toLowerCase().includes(r[2].toLowerCase());let o=e.match(h.attrEquals);if(o)return t.getAttribute(o[1])===o[2];let l=e.match(h.attrExists);if(l)return t.hasAttribute(l[1]);let a=e.match(h.descendant);if(a)return t.querySelector(a[1])!==null;let s=e.match(h.ancestor);if(s){let f=t.parentElement;for(;f;){if(b(s[1],f,n+1))return!0;f=f.parentElement}return!1}return!1}var p=Object.freeze(I);function L(e){let t="";for(let n=0;n<e.childNodes.length;n++){let i=e.childNodes[n];i.nodeType===Node.TEXT_NODE&&(t+=i.textContent)}return t.trim()}function G(e){if(e.tagName==="STYLE"||e.tagName==="SCRIPT"||e.querySelector("STYLE, SCRIPT"))return!0;let t=e.parentElement;for(;t;){if(t.tagName==="STYLE"||t.tagName==="SCRIPT")return!0;t=t.parentElement}return!1}function R(e){let t=e.getAttribute("aria-labelledby");if(!t)return"";let n=t.split(/\s+/),i="";for(let r of n)try{let o=document.getElementById(r);o&&(i+=o.textContent)}catch(o){}return i}function y(e,t,n=!1){if(e==null)return!1;if(t==null||t==="")return!0;if(G(e))return!1;let i=E;for(let l=0;l<i.length;l++){let a=i[l],s;try{s=e.getAttribute(a)}catch(f){continue}if(s){if(a==="aria-labelledby"){if(n?s===t:s.includes(t))return!0;let f=R(e);if(f&&(n?f===t:f.includes(t)))return!0}else if(n?s===t:s.includes(t))return!0}}let r=L(e);if(n?r===t:r.includes(t))return!0;let o=e.textContent;return!!(n?o.trim()===t:o.includes(t))}function g(e,t){if(e==null)return!1;let n=S.get(t);return n?n(e):!1}function w(e=document){let t=[];if(e==null)return t;let n=e.nodeType===Node.DOCUMENT_NODE?e.documentElement:e;if(!n)return t;let i=[n];for(;i.length>0;){let r=i.pop();if(r.nodeType!==Node.ELEMENT_NODE||r.tagName==="SCRIPT"||r.tagName==="STYLE")continue;t.push(r);let o=r.children;for(let l=o.length-1;l>=0;l--)i.push(o[l]);try{if(r.shadowRoot){let l=r.shadowRoot.children;for(let a=l.length-1;a>=0;a--)i.push(l[a])}}catch(l){}}return t}function N(e=window){let t=[];try{t.push({window:e,document:e.document,isMainFrame:!0,frameIndex:-1});let n=e.document.querySelectorAll("iframe");for(let i=0;i<n.length;i++){let r=n[i];try{r.contentWindow&&r.contentDocument&&t.push({window:r.contentWindow,document:r.contentDocument,isMainFrame:!1,frameElement:r,frameIndex:i})}catch(o){o.name==="SecurityError"?console.warn("Skipping cross-origin iframe:",o.message):console.warn("Error accessing iframe:",o.message)}}}catch(n){console.warn("Error getting frames:",n.message)}return t}function x(e){let t=e.getBoundingClientRect();return{x:t.x,y:t.y,width:t.width,height:t.height,top:t.top,bottom:t.bottom,left:t.left,right:t.right,midx:t.x+t.width/2,midy:t.y+t.height/2,tagName:e.tagName.toLowerCase()}}function $(e="element",t=null){if(e==null&&(e="element"),typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(e&&!p[e])return console.warn(`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`),{elements:[]};let n=[],i=N(window);for(let l of i){let a=w(t||l.document);for(let s=0;s<a.length;s++){let f=a[s];e&&!g(f,e)||n.push({element:f,frame:l})}}let r=[];if(n.length>0){let l=new Set(n.map(s=>s.element)),a=new Set;for(let s=n.length-1;s>=0;s--){let f=n[s],c=f.element;if(!a.has(c)){r.unshift(f);let u=c.parentElement;for(;u;)l.has(u)&&a.add(u),u=u.parentElement}}}return{elements:r.map(l=>{let a=x(l.element),s=l.element.tagName.toLowerCase();return l.frame.isMainFrame?{element:l.element,boundingBox:a,tagName:s,frameIndex:l.frame.frameIndex}:{boundingBox:a,tagName:s,frameIndex:l.frame.frameIndex}})}}function q(e,t=!1,n=null){if(e==null&&(e=""),typeof e!="string")throw new TypeError(`value must be a string, got ${typeof e}`);let i=[],r=N(window);for(let a of r){let s=w(n||a.document);for(let f=0;f<s.length;f++){let c=s[f];y(c,e,t)&&i.push({element:c,frame:a})}}return{elements:i.filter(a=>{let s=a.element;if(B(s,e,t))return!0;for(let c of i)if(c.element!==s&&s.contains(c.element))return!1;return!0}).map(a=>{let s=x(a.element),f=a.element.tagName.toLowerCase();return a.frame.isMainFrame?{element:a.element,boundingBox:s,tagName:f,frameIndex:a.frame.frameIndex}:{boundingBox:s,tagName:f,frameIndex:a.frame.frameIndex}})}}function B(e,t,n=!1){if(t==null||t==="")return!0;let i=E;for(let o=0;o<i.length;o++){let l=i[o],a;try{a=e.getAttribute(l)}catch(s){continue}if(a){if(l==="aria-labelledby"){if(n?a===t:a.includes(t))return!0;let s=R(e);if(s&&(n?s===t:s.includes(t)))return!0}else if(n?a===t:a.includes(t))return!0}}let r=L(e);return!!(n?r===t:r.includes(t))}function Q(e=null,t=null,n=!1,i=null){if(t==null&&(t=""),e!=null){if(typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(!p[e])return console.warn(`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`),{elements:[]}}if(t!==""&&typeof t!="string")throw new TypeError(`text must be a string, got ${typeof t}`);let r=[],o=N(window);for(let s of o){let f=w(i||s.document);for(let c=0;c<f.length;c++){let u=f[c];e!=null&&!g(u,e)||t!==""&&!y(u,t,n)||r.push({element:u,frame:s})}}return{elements:(t!==""?r.filter(s=>{let f=s.element;if(B(f,t,n))return!0;for(let u of r)if(u.element!==f&&f.contains(u.element))return!1;return!0}):r).map(s=>{let f=x(s.element),c=s.element.tagName.toLowerCase();return s.frame.isMainFrame?{element:s.element,boundingBox:f,tagName:c,frameIndex:s.frame.frameIndex}:{boundingBox:f,tagName:c,frameIndex:s.frame.frameIndex}})}}function C(e){if(e.parentElement)return e.parentElement;try{let t=e.getRootNode();if(t&&t.host)return t.host}catch(t){}return null}function J(e){let t=C(e);if(!t)return[];if(t.shadowRoot)try{return Array.from(t.shadowRoot.children)}catch(n){return[]}return Array.from(t.children)}function K(e,t){let n=C(e);for(;n;){if(g(n,t))return n;n=C(n)}let i=e.children||[];for(let o of i)if(g(o,t))return o;let r=J(e);for(let o of r)if(o!==e&&g(o,t))return o;for(let o of r){if(o===e)continue;let l=w(o);for(let a=0;a<l.length;a++)if(g(l[a],t))return l[a]}return null}function v(e,t,n=!1,i=null){let r=e!=null&&e!=="",o=t!=null&&t!=="";if(r&&!o)return $(e,i);if(!r&&o)return q(t,n,i);if(r){if(typeof e!="string")throw new TypeError(`elementType must be a string, got ${typeof e}`);if(!p[e])return console.warn(`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`),{elements:[]}}if(o&&typeof t!="string")throw new TypeError(`attributeText must be a string, got ${typeof t}`);let l=[],a=N(window);for(let c of a){let u=w(i||c.document);for(let d=0;d<u.length;d++){let m=u[d];r&&!g(m,e)||o&&!y(m,t,n)||l.push({element:m,frame:c})}}if(l.length===0&&r&&o){let c=[];for(let d of a){let m=w(i||d.document);for(let A=0;A<m.length;A++){let D=m[A];y(D,t,n)&&c.push({element:D,frame:d})}}let u=new Set;for(let d of c){let m=K(d.element,e);m&&!u.has(m)&&(u.add(m),l.push({element:m,frame:d.frame}))}}return{elements:(o?l.filter(c=>{let u=c.element;if(B(u,t,n))return!0;for(let m of l)if(m.element!==u&&u.contains(m.element))return!1;return!0}):l).map(c=>{let u=x(c.element),d=c.element.tagName.toLowerCase();return c.frame.isMainFrame?{element:c.element,boundingBox:u,tagName:d,frameIndex:c.frame.frameIndex}:{boundingBox:u,tagName:d,frameIndex:c.frame.frameIndex}})}}function P(e){return e?e&&e.elements&&Array.isArray(e.elements)?e.elements:Array.isArray(e)?e:[e]:[]}function ee(e,t="red",n=3){let i=P(e);for(let r=0;r<i.length;r++){let o=i[r],l=o.element?o.element:o;l&&l.style&&(l.style.outline=`${n}px solid ${t}`,l.style.outlineOffset="2px",l.style.boxShadow="0 0 0 2px rgba(255, 255, 255, 0.8)",l.classList.add("elementfinder-highlighted"))}}function te(e){let t=P(e);for(let n=0;n<t.length;n++){let i=t[n],r=i.element?i.element:i;r&&r.style&&(r.style.outline="",r.style.outlineOffset="",r.style.boxShadow="",r.classList.remove("elementfinder-highlighted"))}}function ne(){return Object.keys(p)}function re(){return[...E]}return z(oe);})();
|
|
1
|
+
var ElementFinder=(()=>{var P=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var X=Object.prototype.hasOwnProperty;var Z=(e,t)=>{for(var n in t)P(e,n,{get:t[n],enumerable:!0})},Q=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Y(t))!X.call(e,r)&&r!==n&&P(e,r,{get:()=>t[r],enumerable:!(o=W(t,r))||o.enumerable});return e};var G=e=>Q(P({},"__esModule",{value:!0}),e);var we={};Z(we,{ELEMENT_DEFINITIONS:()=>p,findElements:()=>ce,findElementsByAttribute:()=>V,findElementsByType:()=>F,findProbableElements:()=>me,getAllElements:()=>y,getAllFrames:()=>x,getBoundingBox:()=>A,getElementCounts:()=>fe,getElementDescriptor:()=>le,getSearchableAttributeValues:()=>j,getSearchableAttributes:()=>te,getValidAttributes:()=>be,getValidTypes:()=>ye,highlight:()=>de,isHidden:()=>k,matchesAttribute:()=>S,matchesType:()=>g,parseCondition:()=>H,parseXPath:()=>w,pauseAnimations:()=>ge,resumeAnimations:()=>pe,setSearchableAttributes:()=>ee,splitByOperator:()=>B,unhighlight:()=>he});var D={link:"self::a or @role='link' or @href",navigation:"@role='navigation' or self::nav",heading:"@role='heading' or self::h1 or self::h2 or self::h3 or self::h4 or self::h5 or self::h6",button:"self::button or @role='button' or @type='button' or @type='submit'",checkbox:"(self::input and @type='checkbox') or @role='checkbox'",switch:"(self::input and @type='checkbox') or @role='switch' or (self::button and (contains(@class, 'switch') or @data-state))",slider:"self::input[@type='range'] or @role='slider'",datepicker:"self::input[@type='date'] or @role='date'",colorpicker:"self::input[@type='color'] or @role='color'",radio:"(self::input and @type='radio') or @role='radio'",dropdown:"(self::select[descendant::option] or @role='combobox' or @role='listbox' or contains(@class, 'dropdown') or contains(@class, 'trigger') or ancestor::*[contains(@class, 'dropdown') or @role='combobox'])",textbox:"self::textarea or (self::input and (@type='text' or @type='password' or @type='search' or @type='email' or @type='number' or @type='tel' or @type='url')) or @role='textbox'",file:"self::input and @type='file'",list:"self::ul or self::ol or @role='list'",listitem:"self::li or @role='listitem'",menu:"self::menu or @role='menu'",menuitem:"@role='menuitem'",toolbar:"@role='toolbar'",dialog:"@role='dialog' or @role='alertdialog'",table:"self::table or @role='table'",row:"self::tr or @role='row'",column:"self::td or self::th or @role='cell' or @role='gridcell' or @role='columnheader'",cell:"self::td or @role='cell' or @role='gridcell'",image:"self::img or @role='img' or @alt",element:"true()"};var R=["placeholder","value","data-value","data-test-id","data-testid","id","resource-id","name","aria-label","hint","title","tooltip","alt","src","aria-labelledby"];var b={selfWithTag:/^self::([a-zA-Z0-9-]+)(?:\[([^\]]+)\])?$/,contains:/contains\(@([a-zA-Z0-9-]+),\s*['"]([^'"]+)['"]\)/i,attrEquals:/@([a-zA-Z0-9-]+)\s*=\s*['"]([^'"]*)['"]/,attrExists:/^@([a-zA-Z0-9-]+)$/,descendant:/descendant::([a-zA-Z0-9-]+)/i,ancestor:/ancestor::\*\[([^\]]+)\]/i,operatorOr:/^\s*\bor\b\s*/i,operatorAnd:/^\s*\band\b\s*/i},v=100,C=new Map;for(let[e,t]of Object.entries(D))t==="true()"?C.set(e,()=>!0):C.set(e,n=>w(t,n));var E=R;function ee(e){if(!Array.isArray(e))throw new TypeError("attributes must be an array");E=e}function te(){return[...E]}function j(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return{};let t={},n=E;for(let o=0;o<n.length;o++){let r=n[o],i;try{i=e.getAttribute(r)}catch(l){continue}i!=null&&i!==""&&(t[r]=i)}return t}function T(e){return e==null?"":String(e).replace(/\s+/g," ").trim()}function ne(e){let t=T(e);if(!t)return"";let n=t.split(/[?#]/)[0],o=Math.max(n.lastIndexOf("/"),n.lastIndexOf("\\")),r=o>=0?n.slice(o+1):n,i=r.lastIndexOf(".");return i>0?r.slice(0,i):r}function re(e){let t=e.getAttribute("aria-labelledby");if(!t)return"";let n=t.split(/\s+/),o=e.ownerDocument||document,r="";for(let i of n)try{let l=o.getElementById(i);if(!l)continue;let s=T(l.textContent);s&&(r=r?`${r} ${s}`:s)}catch(l){}return r}function q(e){let t=j(e),n=E;for(let i=0;i<n.length;i++){let l=n[i];if(!Object.prototype.hasOwnProperty.call(t,l))continue;let s=l==="aria-labelledby"?re(e):l==="src"?ne(t[l]):t[l],a=T(s);if(a)return{attributeName:l,identifiableText:a}}let o=T(L(e));if(o)return{attributeName:"text",identifiableText:o};let r=T(e.textContent);return r?{attributeName:"text",identifiableText:r}:null}function oe(e){if(!e||!e.ownerDocument)return null;try{let t=x(window);for(let n=0;n<t.length;n++)if(t[n].document===e.ownerDocument)return t[n].document}catch(t){}return e.ownerDocument}function ie(e,t){let n=oe(e);if(!n)return{index:1};let o=y(n),r=1,i=0;for(let l=0;l<o.length;l++){let s=o[l];if(s!==e&&(s===n.documentElement||s.tagName==="BODY"))continue;let a=q(s);!a||a.identifiableText!==t||(i++,s===e&&(r=i))}return{index:r}}function se(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return null;let t=Object.keys(p);for(let n=0;n<t.length;n++){let o=t[n];if(o!=="element"&&g(e,o))return o}return"element"}function le(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return{identifiableText:null,attributeName:null,index:1,type:null,tagName:null};let t=se(e),n=q(e);if(!n)return{identifiableText:null,attributeName:null,index:1,type:t,tagName:e.tagName.toLowerCase()};let o=ie(e,n.identifiableText);return{identifiableText:n.identifiableText,attributeName:n.attributeName,index:o.index,type:t,tagName:e.tagName.toLowerCase()}}function w(e,t,n=0){if(e==null||t==null)return!1;if(n>v)throw new Error("XPath expression exceeds maximum recursion depth");if(e=e.trim(),e==="true()")return!0;if(e[0]==="("&&e[e.length-1]===")"){let i=1,l=!0;for(let s=1;s<e.length-1;s++)if(e[s]==="("?i++:e[s]===")"&&i--,i===0){l=!1;break}if(l)return w(e.slice(1,-1),t,n+1)}let o=B(e,"or");if(o.length>1){for(let i of o)if(w(i,t,n+1))return!0;return!1}let r=B(e,"and");if(r.length>1){for(let i of r)if(!w(i,t,n+1))return!1;return!0}return H(e,t,n)}function B(e,t){let n=[],o=0,r="",i=!1,l="",s=t==="or"?b.operatorOr:b.operatorAnd;for(let a=0;a<e.length;a++){let f=e[a];if((f==="'"||f==='"')&&(a===0||e[a-1]!=="\\")&&(i?f===l&&(i=!1):(i=!0,l=f)),!i&&(f==="("?o++:f===")"&&o--,o===0)){let c=e.slice(a).match(s);if(c){n.push(r.trim()),a+=c[0].length-1,r="";continue}}r+=f}return r.trim()&&n.push(r.trim()),n}function H(e,t,n=0){if(e==null||t==null)return!1;e=e.trim();let o=e.match(b.selfWithTag);if(o){let f=o[1].toUpperCase();return t.tagName!==f?!1:o[2]?w(o[2],t,n+1):!0}let r=e.match(b.contains);if(r)return(t.getAttribute(r[1])||"").toLowerCase().includes(r[2].toLowerCase());let i=e.match(b.attrEquals);if(i)return t.getAttribute(i[1])===i[2];let l=e.match(b.attrExists);if(l)return t.hasAttribute(l[1]);let s=e.match(b.descendant);if(s)return t.querySelector(s[1])!==null;let a=e.match(b.ancestor);if(a){let f=t.parentElement;for(;f;){if(w(a[1],f,n+1))return!0;f=f.parentElement}return!1}return!1}var p=Object.freeze(D);function L(e){let t="";for(let n=0;n<e.childNodes.length;n++){let o=e.childNodes[n];o.nodeType===Node.TEXT_NODE&&(t+=o.textContent)}return t.trim()}function ae(e){if(e.tagName==="STYLE"||e.tagName==="SCRIPT"||e.querySelector("STYLE, SCRIPT"))return!0;let t=e.parentElement;for(;t;){if(t.tagName==="STYLE"||t.tagName==="SCRIPT")return!0;t=t.parentElement}return!1}function _(e){let t=e.getAttribute("aria-labelledby");if(!t)return"";let n=t.split(/\s+/),o="";for(let r of n)try{let i=document.getElementById(r);i&&(o+=i.textContent)}catch(i){}return o}function S(e,t,n=!1){if(e==null)return!1;if(t==null||t==="")return!0;if(ae(e))return!1;let o=E;for(let l=0;l<o.length;l++){let s=o[l],a;try{a=e.getAttribute(s)}catch(f){continue}if(a){if(s==="aria-labelledby"){if(n?a===t:a.includes(t))return!0;let f=_(e);if(f&&(n?f===t:f.includes(t)))return!0}else if(n?a===t:a.includes(t))return!0}}let r=L(e);if(n?r===t:r.includes(t))return!0;let i=e.textContent;return!!(n?i.trim()===t:i.includes(t))}function g(e,t){if(e==null)return!1;let n=C.get(t);return n?n(e):!1}function y(e=document){let t=[];if(e==null)return t;let n=e.nodeType===Node.DOCUMENT_NODE?e.documentElement:e;if(!n)return t;let o=[n];for(;o.length>0;){let r=o.pop();if(r.nodeType!==Node.ELEMENT_NODE||r.tagName==="SCRIPT"||r.tagName==="STYLE")continue;t.push(r);let i=r.children;for(let l=i.length-1;l>=0;l--)o.push(i[l]);try{if(r.shadowRoot){let l=r.shadowRoot.children;for(let s=l.length-1;s>=0;s--)o.push(l[s])}}catch(l){}}return t}function x(e=window){let t=[];try{t.push({window:e,document:e.document,isMainFrame:!0,frameIndex:-1});let n=e.document.querySelectorAll("iframe");for(let o=0;o<n.length;o++){let r=n[o];try{r.contentWindow&&r.contentDocument&&t.push({window:r.contentWindow,document:r.contentDocument,isMainFrame:!1,frameElement:r,frameIndex:o})}catch(i){i.name==="SecurityError"?console.warn("Skipping cross-origin iframe:",i.message):console.warn("Error accessing iframe:",i.message)}}}catch(n){console.warn("Error getting frames:",n.message)}return t}function A(e){let t=e.getBoundingClientRect();return{x:t.x,y:t.y,width:t.width,height:t.height,top:t.top,bottom:t.bottom,left:t.left,right:t.right,midx:t.x+t.width/2,midy:t.y+t.height/2,tagName:e.tagName.toLowerCase()}}function k(e){if(e==null||e.offsetWidth===0&&e.offsetHeight===0)return!0;try{let t=window.getComputedStyle(e);if(t.visibility==="hidden"||t.visibility==="collapse"||t.display==="none")return!0}catch(t){}return!!e.hasAttribute("hidden")}function F(e="element",t=null,n=null){if(e==null&&(e="element"),typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);let o=n&&n.failOnUnknownType===!0;if(e&&!p[e]){let a=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(o)throw new TypeError(`Unknown element type: ${e}`);return console.warn(a),{elements:[]}}let r=[],i=x(window);for(let a of i){let f=y(t||a.document);for(let u=0;u<f.length;u++){let c=f[u];e&&!g(c,e)||r.push({element:c,frame:a})}}let l=[];if(r.length>0){let a=new Set(r.map(u=>u.element)),f=new Set;for(let u=r.length-1;u>=0;u--){let c=r[u],m=c.element;if(!f.has(m)){l.unshift(c);let d=m.parentElement;for(;d;)a.has(d)&&f.add(d),d=d.parentElement}}}return{elements:l.map(a=>{let f=A(a.element),u=a.element.tagName.toLowerCase(),c=k(a.element);return a.frame.isMainFrame?{element:a.element,boundingBox:f,tagName:u,frameIndex:a.frame.frameIndex,isHidden:c}:{boundingBox:f,tagName:u,frameIndex:a.frame.frameIndex,isHidden:c}})}}function V(e,t=!1,n=null){if(e==null&&(e=""),typeof e!="string")throw new TypeError(`value must be a string, got ${typeof e}`);let o=[],r=x(window);for(let s of r){let a=y(n||s.document);for(let f=0;f<a.length;f++){let u=a[f];S(u,e,t)&&o.push({element:u,frame:s})}}return{elements:o.filter(s=>{let a=s.element;if(I(a,e,t))return!0;for(let u of o)if(u.element!==a&&a.contains(u.element))return!1;return!0}).map(s=>{let a=A(s.element),f=s.element.tagName.toLowerCase(),u=k(s.element);return s.frame.isMainFrame?{element:s.element,boundingBox:a,tagName:f,frameIndex:s.frame.frameIndex,isHidden:u}:{boundingBox:a,tagName:f,frameIndex:s.frame.frameIndex,isHidden:u}})}}function I(e,t,n=!1){if(t==null||t==="")return!0;let o=E;for(let i=0;i<o.length;i++){let l=o[i],s;try{s=e.getAttribute(l)}catch(a){continue}if(s){if(l==="aria-labelledby"){if(n?s===t:s.includes(t))return!0;let a=_(e);if(a&&(n?a===t:a.includes(t)))return!0}else if(n?s===t:s.includes(t))return!0}}let r=L(e);return!!(n?r===t:r.includes(t))}function fe(e=null,t=null,n=null){let o=e!=null;if(o){if(typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(!p[e]){let s=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(n&&n.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(s),{[e]:0}}}let r={},i=o?[e]:Object.keys(p).filter(s=>s!=="element");for(let s=0;s<i.length;s++)r[i[s]]=0;let l=x(window);for(let s=0;s<l.length;s++){let a=l[s],f=y(t||a.document);for(let u=0;u<f.length;u++){let c=f[u];for(let m=0;m<i.length;m++){let d=i[m];g(c,d)&&(r[d]+=1)}}}return r}function ce(e=null,t=null,n=!1,o=null,r=null){if(t==null&&(t=""),e!=null){if(typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(!p[e]){let f=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(r&&r.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(f),{elements:[]}}}if(t!==""&&typeof t!="string")throw new TypeError(`text must be a string, got ${typeof t}`);let i=[],l=x(window);for(let f of l){let u=y(o||f.document);for(let c=0;c<u.length;c++){let m=u[c];e!=null&&!g(m,e)||t!==""&&!S(m,t,n)||i.push({element:m,frame:f})}}return{elements:(t!==""?i.filter(f=>{let u=f.element;if(I(u,t,n))return!0;for(let m of i)if(m.element!==u&&u.contains(m.element))return!1;return!0}):i).map(f=>{let u=A(f.element),c=f.element.tagName.toLowerCase(),m=k(f.element);return f.frame.isMainFrame?{element:f.element,boundingBox:u,tagName:c,frameIndex:f.frame.frameIndex,isHidden:m}:{boundingBox:u,tagName:c,frameIndex:f.frame.frameIndex,isHidden:m}})}}function $(e){if(e.parentElement)return e.parentElement;try{let t=e.getRootNode();if(t&&t.host)return t.host}catch(t){}return null}function U(e){let t=$(e);if(!t)return[];if(t.shadowRoot)try{return Array.from(t.shadowRoot.children)}catch(n){return[]}return Array.from(t.children)}function ue(e,t){let n=$(e);for(;n;){if(g(n,t))return n;n=$(n)}let o=e.children||[];for(let l of o)if(g(l,t))return l;let r=U(e);for(let l of r)if(l!==e&&g(l,t))return l;for(let l of r){if(l===e)continue;let s=y(l);for(let a=0;a<s.length;a++)if(g(s[a],t))return s[a]}let i=e.parentElement;for(;i;){let l=U(i);for(let s of l)if(s!==i){if(g(s,t))return s;let a=y(s);for(let f=0;f<a.length;f++)if(g(a[f],t))return a[f]}i=i.parentElement}return null}function me(e,t,n=!1,o=null,r=null){let i=e!=null&&e!=="",l=t!=null&&t!=="";if(i&&!l)return F(e,o,r);if(!i&&l)return V(t,n,o);if(i){if(typeof e!="string")throw new TypeError(`elementType must be a string, got ${typeof e}`);if(!p[e]){let c=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(r&&r.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(c),{elements:[]}}}if(l&&typeof t!="string")throw new TypeError(`attributeText must be a string, got ${typeof t}`);let s=[],a=x(window);for(let c of a){let m=y(o||c.document);for(let d=0;d<m.length;d++){let h=m[d];i&&!g(h,e)||l&&!S(h,t,n)||s.push({element:h,frame:c})}}if(s.length===0&&i&&l){let c=[];for(let d of a){let h=y(o||d.document);for(let M=0;M<h.length;M++){let O=h[M];S(O,t,n)&&I(O,t,n)&&c.push({element:O,frame:d})}}let m=new Set;for(let d of c){let h=ue(d.element,e);h&&!m.has(h)&&(m.add(h),s.push({element:h,frame:d.frame}))}}return{elements:(l?s.filter(c=>{let m=c.element;if(I(m,t,n))return!0;for(let h of s)if(h.element!==m&&m.contains(h.element))return!1;return!0}):s).map(c=>{let m=A(c.element),d=c.element.tagName.toLowerCase(),h=k(c.element);return c.frame.isMainFrame?{element:c.element,boundingBox:m,tagName:d,frameIndex:c.frame.frameIndex,isHidden:h}:{boundingBox:m,tagName:d,frameIndex:c.frame.frameIndex,isHidden:h}})}}function z(e){return e?e&&e.elements&&Array.isArray(e.elements)?e.elements:Array.isArray(e)?e:[e]:[]}function de(e,t="red",n=3){let o=z(e);for(let r=0;r<o.length;r++){let i=o[r],l=i.element?i.element:i;l&&l.style&&(l.style.outline=`${n}px solid ${t}`,l.style.outlineOffset="2px",l.style.boxShadow="0 0 0 2px rgba(255, 255, 255, 0.8)",l.classList.add("elementfinder-highlighted"))}}function he(e){let t=z(e);for(let n=0;n<t.length;n++){let o=t[n],r=o.element?o.element:o;r&&r.style&&(r.style.outline="",r.style.outlineOffset="",r.style.boxShadow="",r.classList.remove("elementfinder-highlighted"))}}var N=[];function ge(){let e=new Map,t=y();for(let r of t)r&&r.style&&r.style.animationPlayState!=="paused"&&(e.set(r,{animationPlayState:r.style.animationPlayState,transitionProperty:r.style.transitionProperty,webkitAnimationPlayState:r.style.webkitAnimationPlayState,webkitTransitionProperty:r.style.webkitTransitionProperty}),r.style.animationPlayState="paused",r.style.transitionProperty="none",r.style.webkitAnimationPlayState="paused",r.style.webkitTransitionProperty="none");let n=document.getElementById("elementfinder-animation-pause");n||(n=document.createElement("style"),n.id="elementfinder-animation-pause",n.textContent=`
|
|
2
|
+
*, *::before, *::after {
|
|
3
|
+
animation-play-state: paused !important;
|
|
4
|
+
transition-property: none !important;
|
|
5
|
+
-webkit-animation-play-state: paused !important;
|
|
6
|
+
-webkit-transition-property: none !important;
|
|
7
|
+
}
|
|
8
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
9
|
+
*, *::before, *::after {
|
|
10
|
+
animation-duration: 0s !important;
|
|
11
|
+
animation-iteration-count: 1 !important;
|
|
12
|
+
transition-duration: 0s !important;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
`,document.head.appendChild(n));let o={originalStyles:e,pausedCount:e.size};return N.push(o),o}function pe(e){if(e){let n=N.indexOf(e);if(n===-1)return;N.splice(n,1)}else{if(N.length===0)return;e=N.pop()}let t=e.originalStyles;if(t)for(let[n,o]of t)n&&n.style&&(n.style.animationPlayState=o.animationPlayState||"",n.style.transitionProperty=o.transitionProperty||"",n.style.webkitAnimationPlayState=o.webkitAnimationPlayState||"",n.style.webkitTransitionProperty=o.webkitTransitionProperty||"");if(N.length===0){let n=document.getElementById("elementfinder-animation-pause");n&&n.remove()}}function ye(){return Object.keys(p)}function be(){return[...E]}return G(we);})();
|
package/package.json
CHANGED
|
@@ -1,29 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodebug/browser-element-finder",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"description": "Browser Element Finder - Find elements by type and text content",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
|
-
"browser": "./index.js",
|
|
8
|
-
"require": "./index.js",
|
|
9
7
|
"import": "./src/element-finder.js",
|
|
8
|
+
"default": "./src/element-finder.js"
|
|
9
|
+
},
|
|
10
|
+
"./browser": {
|
|
10
11
|
"default": "./index.js"
|
|
11
12
|
},
|
|
12
13
|
"./min": {
|
|
13
|
-
"browser": "./index.min.js",
|
|
14
|
-
"require": "./index.min.js",
|
|
15
|
-
"import": "./index.min.js",
|
|
16
14
|
"default": "./index.min.js"
|
|
17
15
|
},
|
|
18
16
|
"./element-definitions.json": {
|
|
19
|
-
"browser": "./src/element-definitions.json",
|
|
20
|
-
"require": "./src/element-definitions.json",
|
|
21
17
|
"import": "./src/element-definitions.json",
|
|
22
18
|
"default": "./src/element-definitions.json"
|
|
23
19
|
},
|
|
24
20
|
"./searchable-attributes.json": {
|
|
25
|
-
"browser": "./src/searchable-attributes.json",
|
|
26
|
-
"require": "./src/searchable-attributes.json",
|
|
27
21
|
"import": "./src/searchable-attributes.json",
|
|
28
22
|
"default": "./src/searchable-attributes.json"
|
|
29
23
|
}
|
|
@@ -54,7 +48,8 @@
|
|
|
54
48
|
"url": "https://github.com/node-bug/browser-element-finder/issues"
|
|
55
49
|
},
|
|
56
50
|
"scripts": {
|
|
57
|
-
"build": "node build.js",
|
|
51
|
+
"build": "node scripts/build.js",
|
|
52
|
+
"prepack": "npm run build",
|
|
58
53
|
"lint": "eslint .",
|
|
59
54
|
"test": "npm run build && vitest run",
|
|
60
55
|
"test:watch": "npm run build && vitest",
|
|
@@ -63,7 +58,7 @@
|
|
|
63
58
|
},
|
|
64
59
|
"devDependencies": {
|
|
65
60
|
"@eslint/js": "^10.0.1",
|
|
66
|
-
"@vitest/coverage-v8": "^3.2.
|
|
61
|
+
"@vitest/coverage-v8": "^3.2.6",
|
|
67
62
|
"esbuild": "^0.28.0",
|
|
68
63
|
"eslint": "^10.2.0",
|
|
69
64
|
"eslint-config-prettier": "^10.1.8",
|
|
@@ -73,10 +68,10 @@
|
|
|
73
68
|
"lint-staged": "^16.4.0",
|
|
74
69
|
"prettier": "^3.8.2",
|
|
75
70
|
"selenium-webdriver": "^4.43.0",
|
|
76
|
-
"vitest": "^3.
|
|
71
|
+
"vitest": "^3.2.6"
|
|
77
72
|
},
|
|
78
73
|
"lint-staged": {
|
|
79
|
-
"*.
|
|
74
|
+
"*.js": [
|
|
80
75
|
"eslint --fix"
|
|
81
76
|
],
|
|
82
77
|
"*.{json,yaml,yml,md,sh,groovy}": [
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"menu": "self::menu or @role='menu'",
|
|
18
18
|
"menuitem": "@role='menuitem'",
|
|
19
19
|
"toolbar": "@role='toolbar'",
|
|
20
|
-
"dialog": "@role='dialog'",
|
|
20
|
+
"dialog": "@role='dialog' or @role='alertdialog'",
|
|
21
21
|
"table": "self::table or @role='table'",
|
|
22
22
|
"row": "self::tr or @role='row'",
|
|
23
23
|
"column": "self::td or self::th or @role='cell' or @role='gridcell' or @role='columnheader'",
|