@applitools/driver 1.2.3 → 1.2.7

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,355 +0,0 @@
1
- const {inspect} = require('util')
2
- const utils = require('@applitools/utils')
3
- const snippets = require('@applitools/snippets')
4
-
5
- const WELL_KNOWN_SCRIPTS = {
6
- 'dom-snapshot': script => /\/\* @applitools\/dom-snapshot@[\d.]+ \*\//.test(script),
7
- 'dom-capture': script => /\/\* @applitools\/dom-capture@[\d.]+ \*\//.test(script),
8
- }
9
-
10
- const DEFAULT_DESKTOP_UA =
11
- 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36'
12
- const DEFAULT_MOBILE_UA =
13
- 'Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Mobile Safari/537.36'
14
-
15
- const DEFAULT_STYLES = {
16
- 'border-left-width': '0px',
17
- 'border-top-width': '0px',
18
- overflow: null,
19
- }
20
-
21
- const DEFAULT_PROPS = {
22
- clientWidth: 300,
23
- clientHeight: 400,
24
- overflow: null,
25
- }
26
-
27
- class MockDriver {
28
- constructor({viewport = {width: 1000, height: 1000}, device, platform, browser, ua} = {}) {
29
- this._device = device
30
- this._platform = platform
31
- this._browser = browser
32
- this._ua = ua
33
- this._window = {
34
- title: 'Default Page Title',
35
- url: 'http://default.url',
36
- rect: {x: 0, y: 0, ...viewport},
37
- }
38
- this._methods = new Map()
39
- this._scripts = new Map()
40
- this._elements = new Map()
41
- this._contexts = new Map()
42
- this._contexts.set(null, {
43
- document: {id: Symbol('documentId')},
44
- state: {
45
- get name() {
46
- return null
47
- },
48
- },
49
- })
50
- this._contextId = null
51
- this.mockElement('html', {scrollPosition: {x: 0, y: 0}})
52
- this.mockScript(snippets.getContextInfo, async () => {
53
- const context = this._contexts.get(this._contextId)
54
- const isRoot = !this._contextId
55
- const isCORS = !isRoot && context.isCORS
56
- const contentDocument = await this.findElement('html')
57
- const selector = !isCORS && !isRoot ? context.element.selector : null
58
- return [contentDocument, selector, isRoot, isCORS]
59
- })
60
- this.mockScript(snippets.isEqualElements, async ([element1, element2]) => {
61
- return element1.id === element2.id
62
- })
63
- this.mockScript(snippets.getChildFramesInfo, () => {
64
- return Array.from(this._contexts.values())
65
- .filter(frame => frame.parentId === this._contextId)
66
- .map(frame => [frame.element, frame.isCORS])
67
- })
68
- this.mockScript(snippets.getElementRect, ([element]) => {
69
- return element.rect || {x: 0, y: 0, width: 100, height: 100}
70
- })
71
- this.mockScript(snippets.getElementComputedStyleProperties, ([element, properties]) => {
72
- return properties.map(property => (element.styles || {})[property] || DEFAULT_STYLES[property])
73
- })
74
- this.mockScript(snippets.getElementProperties, ([element, properties]) => {
75
- return properties.map(property => (element.props || {})[property] || DEFAULT_PROPS[property])
76
- })
77
- this.mockScript(snippets.setElementStyleProperties, ([element, properties]) => {
78
- return Object.entries(properties).reduce((original, [name, value]) => {
79
- original[name] = {value: element.style[name], important: false}
80
- element.style[name] = value
81
- return original
82
- }, {})
83
- })
84
- this.mockScript(snippets.setElementAttributes, ([element, attributes]) => {
85
- return Object.entries(attributes).reduce((original, [name, value]) => {
86
- original[name] = element.attrs[name]
87
- element.attrs[name] = value
88
- return original
89
- }, {})
90
- })
91
- this.mockScript(snippets.scrollTo, ([element, offset]) => {
92
- let scrollingElement = element
93
- if (!element) {
94
- scrollingElement = this.findElement('html')
95
- }
96
- scrollingElement.scrollPosition = offset
97
- return [scrollingElement.scrollPosition.x, scrollingElement.scrollPosition.y]
98
- })
99
- this.mockScript(snippets.getElementScrollOffset, ([element]) => {
100
- let scrollingElement = element
101
- if (!element) {
102
- scrollingElement = this.findElement('html')
103
- }
104
- if (!scrollingElement.scrollPosition) {
105
- scrollingElement.scrollPosition = {x: 0, y: 0}
106
- }
107
- return {x: scrollingElement.scrollPosition.x, y: scrollingElement.scrollPosition.y}
108
- })
109
- this.mockScript(snippets.getElementInnerOffset, ([element]) => {
110
- let scrollingElement = element
111
- if (!element) {
112
- scrollingElement = this.findElement('html')
113
- }
114
- if (!scrollingElement.scrollPosition) {
115
- scrollingElement.scrollPosition = {x: 0, y: 0}
116
- }
117
- return {x: scrollingElement.scrollPosition.x, y: scrollingElement.scrollPosition.y}
118
- })
119
- this.mockScript(snippets.getPixelRatio, () => {
120
- return 1
121
- })
122
- this.mockScript(snippets.getShadowRoot, ([element]) => {
123
- return element
124
- })
125
- this.mockScript(snippets.getUserAgent, () => {
126
- if (this._ua !== undefined) return this._ua
127
- return this.info.isMobile ? DEFAULT_MOBILE_UA : DEFAULT_DESKTOP_UA
128
- })
129
- this.mockScript(snippets.getViewportSize, () => {
130
- return {width: this._window.rect.width, height: this._window.rect.height}
131
- })
132
- this.mockScript(snippets.getElementXpath, ([element]) => {
133
- if (element.xpath) return element.xpath
134
- const elements = Array.from(this._elements.values()).reduce((elements, array) => elements.concat(array), [])
135
- const index = elements.findIndex(({id}) => id === element.id)
136
- return index >= 0 ? `/HTML[1]/BODY[1]/DIV[${index + 1}]` : `//[data-fake-selector="${element.selector}"]`
137
- })
138
- this.mockScript(snippets.blurElement, () => {
139
- return null
140
- })
141
- this.mockScript(snippets.addElementIds, ([elements, ids]) => {
142
- const selectors = []
143
- for (const [index, element] of elements.entries()) {
144
- const elementId = ids[index]
145
- element.attributes = element.attributes || []
146
- element.attributes.push({name: 'data-applitools-selector', value: elementId})
147
- const selector = `[data-applitools-selector~="${elementId}"]`
148
- selectors.push([selector])
149
- }
150
- return selectors
151
- })
152
- this.mockScript(snippets.cleanupElementIds, ([elements]) => {
153
- for (const el of elements) {
154
- el.attributes.splice(
155
- el.attributes.findIndex(({name}) => name === 'data-applitools-marker'),
156
- 1,
157
- )
158
- }
159
- })
160
- this.mockScript(snippets.getElementContentSize, ([element]) => {
161
- return element.rect || {x: 0, y: 0, width: 100, height: 100}
162
- })
163
- this.mockScript(snippets.getDocumentSize, () => {
164
- // TODO get window for context: `this.contexts.get(this._contextId)`
165
- return {width: this._window.rect.width, height: this._window.rect.height}
166
- })
167
- }
168
- mockScript(scriptMatcher, resultGenerator) {
169
- this._scripts.set(String(scriptMatcher), resultGenerator)
170
- }
171
- mockElement(selector, state) {
172
- const element = {
173
- id: Symbol('elementId' + Math.floor(Math.random() * 100)),
174
- attrs: {},
175
- style: {},
176
- selector,
177
- parentId: null,
178
- parentContextId: null,
179
- parentRootId: null,
180
- ...state,
181
- }
182
- if (element.shadow) {
183
- element.shadowRootId = Symbol('shadowId' + (element.name || Math.floor(Math.random() * 100)))
184
- }
185
- if (element.frame) {
186
- const contextId = Symbol('contextId' + (element.name || Math.floor(Math.random() * 100)))
187
- this._contexts.set(contextId, {
188
- id: contextId,
189
- parentId: state.parentContextId,
190
- isCORS: state.isCORS,
191
- element,
192
- document: {id: Symbol('documentId' + (element.name || Math.floor(Math.random() * 100)))},
193
- state: {
194
- get name() {
195
- return element.name || element.selector
196
- },
197
- },
198
- })
199
- element.contextId = contextId
200
- this.mockElement('html', {
201
- parentContextId: contextId,
202
- scrollPosition: {x: 0, y: 0},
203
- })
204
- }
205
- this.mockSelector(selector, element)
206
- return element
207
- }
208
- mockElements(nodes, {parentId = null, parentContextId = null, parentRootId = null} = {}) {
209
- for (const node of nodes) {
210
- const element = this.mockElement(node.selector, {...node, parentId, parentContextId, parentRootId})
211
- if (node.children) {
212
- this.mockElements(node.children, {
213
- parentId: element.frame ? null : element.id,
214
- parentContextId: element.frame ? element.contextId : parentContextId,
215
- parentRootId: element.shadow ? element.shadowRootId : parentRootId,
216
- })
217
- }
218
- }
219
- }
220
- mockSelector(selector, element) {
221
- let elements = this._elements.get(selector)
222
- if (!elements) {
223
- elements = []
224
- this._elements.set(selector, elements)
225
- }
226
- elements.push(element)
227
- }
228
- wrapMethod(name, wrapper) {
229
- if (!this[name] || name.startsWith('_') || !utils.types.isFunction(this[name])) return
230
- if (this._methods.has(name)) this.unwrapMethod(name)
231
- this._methods.set(name, this[name])
232
- this[name] = new Proxy(this[name], {
233
- apply: (method, driver, args) => wrapper(method, driver, args),
234
- })
235
- }
236
- unwrapMethod(name) {
237
- const method = this._methods.get(name)
238
- if (!method) return
239
- this[name] = method
240
- }
241
-
242
- get info() {
243
- return {
244
- isMobile: this._device ? Boolean(this._device.isMobile) : false,
245
- isNative: this._device ? Boolean(this._device.isNative) : false,
246
- deviceName: this._device ? this._device.name : null,
247
- platformName: this._platform ? this._platform.name : null,
248
- platformVersion: this._platform ? this._platform.version : null,
249
- browserName: this._browser ? this._browser.name : null,
250
- browserVersion: this._browser ? this._browser.version : null,
251
- }
252
- }
253
- async executeScript(script, args = []) {
254
- if (this.info.isNative) throw new Error("Native context doesn't support this method")
255
- let result = this._scripts.get(String(script))
256
- if (!result) {
257
- const name = Object.keys(WELL_KNOWN_SCRIPTS).find(name => WELL_KNOWN_SCRIPTS[name](script))
258
- if (!name) return null
259
- result = this._scripts.get(name)
260
- }
261
- const {state} = this._contexts.get(this._contextId)
262
- return utils.types.isFunction(result) ? result.call(state, ...args) : result
263
- }
264
- async findElement(selector, rootElement) {
265
- const elements = this._elements.get(selector)
266
- return elements
267
- ? elements.find(
268
- element =>
269
- element.parentContextId === this._contextId &&
270
- element.parentRootId === ((rootElement || {}).shadowRootId || null),
271
- )
272
- : null
273
- }
274
- async findElements(selector, rootElement) {
275
- const elements = this._elements.get(selector)
276
- return elements
277
- ? elements.filter(
278
- element =>
279
- element.parentContextId === this._contextId &&
280
- element.parentRootId === ((rootElement || {}).shadowRootId || null),
281
- )
282
- : []
283
- }
284
- async switchToFrame(reference) {
285
- if (reference === null) {
286
- this._contextId = null
287
- return this
288
- }
289
- if (utils.types.isString(reference)) {
290
- reference = await this.findElement(reference)
291
- }
292
-
293
- const frame = this._contexts.get(reference.contextId)
294
- if (frame && this._contextId === frame.parentId) {
295
- this._contextId = frame.id
296
- return this
297
- } else {
298
- throw new Error('Frame not found')
299
- }
300
- }
301
- async switchToParentFrame() {
302
- if (!this._contextId) return this
303
- for (const frame of this._contexts.values()) {
304
- if (frame.id === this._contextId) {
305
- this._contextId = frame.parentId
306
- return this
307
- }
308
- }
309
- return this
310
- }
311
- async getWindowRect() {
312
- return this._window.rect
313
- }
314
- async setWindowRect(rect) {
315
- Object.assign(this._window.rect, rect)
316
- }
317
- async getUrl() {
318
- if (this.info.isNative) throw new Error("Native context doesn't support this method")
319
- return this._window.url
320
- }
321
- async getTitle() {
322
- if (this.info.isNative) throw new Error("Native context doesn't support this method")
323
- return this._window.title
324
- }
325
- async visit(url) {
326
- if (this.info.isNative) throw new Error("Native context doesn't support this method")
327
- this._window.url = url
328
- }
329
- async takeScreenshot() {
330
- // const image = new png.Image({
331
- // width: this._window.rect.width,
332
- // height: this._window.rect.height,
333
- // })
334
- // const stream = image.pack()
335
- // return new Promise((resolve, reject) => {
336
- // let buffer = Buffer.from([])
337
- // stream.on('data', chunk => {
338
- // buffer = Buffer.concat([buffer, chunk])
339
- // })
340
- // stream.on('end', () => resolve(buffer))
341
- // stream.on('error', reject)
342
- // })
343
- }
344
- toString() {
345
- return '<MockDriver>'
346
- }
347
- toJSON() {
348
- return '<MockDriver>'
349
- }
350
- [inspect.custom]() {
351
- return '<MockDriver>'
352
- }
353
- }
354
-
355
- module.exports = {MockDriver}
@@ -1,11 +0,0 @@
1
- import * as types from '@applitools/types'
2
- import {MockDriver} from './mock-driver'
3
-
4
- export type Driver = MockDriver
5
- export type Context = MockDriver
6
- export type Element = any
7
- export type Selector = string | {using: string; value: string}
8
-
9
- export type FakeSpecDriver = types.SpecDriver<Driver, Context, Element, Selector>
10
-
11
- export const spec: FakeSpecDriver
@@ -1,66 +0,0 @@
1
- const utils = require('@applitools/utils')
2
-
3
- const spec = {
4
- isDriver(driver) {
5
- return driver && driver.constructor.name === 'MockDriver'
6
- },
7
- isElement(element) {
8
- return utils.types.has(element, 'id')
9
- },
10
- isSelector(selector) {
11
- return utils.types.isString(selector) || utils.types.has(selector, ['using', 'value'])
12
- },
13
- transformSelector(selector) {
14
- return selector.selector || selector
15
- },
16
- isStaleElementError() {
17
- return false
18
- },
19
- isEqualElements(_driver, element1, element2) {
20
- return element1.id === element2.id
21
- },
22
- executeScript(driver, script, ...args) {
23
- return driver.executeScript(script, args)
24
- },
25
- findElement(driver, selector, parent) {
26
- return driver.findElement(selector.selector || selector, parent)
27
- },
28
- findElements(driver, selector, parent) {
29
- return driver.findElements(selector.selector || selector, parent)
30
- },
31
- mainContext(driver) {
32
- return driver.switchToFrame(null)
33
- },
34
- parentContext(driver) {
35
- return driver.switchToParentFrame()
36
- },
37
- childContext(driver, reference) {
38
- return driver.switchToFrame(reference)
39
- },
40
- takeScreenshot(driver) {
41
- return driver.takeScreenshot()
42
- },
43
- getDriverInfo(driver) {
44
- return driver.info
45
- },
46
- async getWindowSize(driver) {
47
- const rect = await driver.getWindowRect()
48
- return rect
49
- },
50
- async setWindowSize(driver, size) {
51
- await driver.setWindowRect(size)
52
- },
53
- async getUrl(driver) {
54
- if (this._isNative) return null
55
- return driver.getUrl()
56
- },
57
- async getTitle(driver) {
58
- if (this._isNative) return null
59
- return driver.getTitle()
60
- },
61
- async visit(driver, url) {
62
- await driver.visit(url)
63
- },
64
- }
65
-
66
- module.exports = {spec}
package/src/index.ts DELETED
@@ -1,6 +0,0 @@
1
- export * from './driver'
2
- export * from './context'
3
- export * from './element'
4
-
5
- export * from './fake/mock-driver'
6
- export * as fake from './fake/spec-driver'
package/src/user-agent.ts DELETED
@@ -1,99 +0,0 @@
1
- import * as utils from '@applitools/utils'
2
-
3
- type PlatformInfo = {platformName: string; platformVersion?: string}
4
- type BrowserInfo = {browserName: string; browserVersion?: string}
5
-
6
- const MAJOR_MINOR = '(\\d+)(?:[_.](\\d+))?'
7
-
8
- const PLATFORM_REGEXES = [
9
- new RegExp(`(?:(Windows NT) ${MAJOR_MINOR})`),
10
- new RegExp('(?:(Windows XP))'),
11
- new RegExp('(?:(Windows 2000))'),
12
- new RegExp('(?:(Windows NT))'),
13
- new RegExp('(?:(Windows))'),
14
- new RegExp(`(?:(Mac OS X) ${MAJOR_MINOR})`),
15
- new RegExp(`(?:(Android) ${MAJOR_MINOR})`),
16
- new RegExp(`(?:(CPU(?: i[a-zA-Z]+)? OS) ${MAJOR_MINOR})`),
17
- new RegExp('(?:(Mac OS X))'),
18
- new RegExp('(?:(Mac_PowerPC))'),
19
- new RegExp('(?:(Linux))'),
20
- new RegExp('(?:(CrOS))'),
21
- new RegExp('(?:(SymbOS))'),
22
- ]
23
-
24
- const BROWSER_REGEXPES = [
25
- new RegExp(`(?:(Opera)/${MAJOR_MINOR})`),
26
- new RegExp(`(?:(Edg)/${MAJOR_MINOR})`),
27
- new RegExp(`(?:(Edge)/${MAJOR_MINOR})`),
28
- new RegExp(`(?:(Chrome)/${MAJOR_MINOR})`),
29
- new RegExp(`(?:(Safari)/${MAJOR_MINOR})`),
30
- new RegExp(`(?:(Firefox)/${MAJOR_MINOR})`),
31
- new RegExp(`(?:MS(IE) ${MAJOR_MINOR})`),
32
- ]
33
-
34
- const HIDDEN_IE_REGEX = new RegExp(`(?:rv:${MAJOR_MINOR}\\) like Gecko)`)
35
-
36
- const BROWSER_VERSION_REGEX = new RegExp(`(?:Version/${MAJOR_MINOR})`)
37
-
38
- export function parseUserAgent(userAgent: string): PlatformInfo & BrowserInfo {
39
- utils.guard.notNull(userAgent, {name: 'userAgent'})
40
-
41
- userAgent = userAgent.trim()
42
- return {
43
- ...parsePlatform(userAgent),
44
- ...parseBrowser(userAgent),
45
- }
46
- }
47
-
48
- export function parsePlatform(userAgent: string): PlatformInfo {
49
- const platformRegExp = PLATFORM_REGEXES.find(regexp => regexp.test(userAgent))
50
-
51
- if (!platformRegExp) return {platformName: 'Unknown'}
52
-
53
- const [_, platformName, platformMajorVersion, platformMinorVersion] = platformRegExp.exec(userAgent)
54
-
55
- if (platformName.startsWith('CPU')) {
56
- return {platformName: 'iOS', platformVersion: platformMajorVersion}
57
- } else if (platformName === 'Windows 2000' || platformName === 'Windows XP') {
58
- return {platformName: 'Windows', platformVersion: '5'}
59
- } else if (platformName === 'Windows NT') {
60
- const result = {platformName: 'Windows', platformVersion: platformMajorVersion}
61
- if (!platformMajorVersion) {
62
- result.platformVersion = '4'
63
- } else if (platformMajorVersion === '6' && platformMinorVersion === '1') {
64
- result.platformVersion = '7'
65
- } else if (platformMajorVersion === '6' && (platformMinorVersion === '2' || platformMinorVersion === '3')) {
66
- result.platformVersion = '8'
67
- }
68
- return result
69
- } else if (platformName === 'Mac_PowerPC') {
70
- return {platformName: 'Macintosh', platformVersion: platformMajorVersion}
71
- } else if (platformName === 'CrOS') {
72
- return {platformName: 'Chrome OS', platformVersion: platformMajorVersion}
73
- } else {
74
- return {platformName, platformVersion: platformMajorVersion}
75
- }
76
- }
77
-
78
- export function parseBrowser(userAgent: string): BrowserInfo {
79
- const browserRegExp = BROWSER_REGEXPES.find(regexp => regexp.test(userAgent))
80
- if (!browserRegExp) {
81
- if (HIDDEN_IE_REGEX.test(userAgent)) {
82
- const [_, browserVersion] = HIDDEN_IE_REGEX.exec(userAgent)
83
- return {browserName: 'IE', browserVersion}
84
- } else {
85
- return {browserName: 'Unknown'}
86
- }
87
- }
88
-
89
- const [_, browserName, browserVersion] = browserRegExp.exec(userAgent)
90
- const result = {browserName, browserVersion}
91
-
92
- if (result.browserName === 'Edg') result.browserName = 'Edge'
93
- if (BROWSER_VERSION_REGEX.test(userAgent)) {
94
- const [_, browserVersion] = BROWSER_VERSION_REGEX.exec(userAgent)
95
- result.browserVersion = browserVersion
96
- }
97
-
98
- return result
99
- }
package/src/utils.ts DELETED
@@ -1,77 +0,0 @@
1
- import type * as types from '@applitools/types'
2
- import * as utils from '@applitools/utils'
3
-
4
- const snippets = require('@applitools/snippets')
5
-
6
- export type SpecUtils<_TDriver, TContext, TElement, TSelector> = {
7
- isSelector(selector: any): selector is types.Selector<TSelector>
8
- transformSelector(selector: types.Selector<TSelector>): TSelector
9
- splitSelector(selector: types.Selector<TSelector>): types.Selector<TSelector>[]
10
- findRootElement(
11
- context: TContext,
12
- selector: types.Selector<TSelector>,
13
- ): Promise<{root: TElement; selector: types.Selector<TSelector>}>
14
- }
15
-
16
- export function makeSpecUtils<TDriver, TContext, TElement, TSelector>(
17
- spec: types.SpecDriver<TDriver, TContext, TElement, TSelector>,
18
- ): SpecUtils<TDriver, TContext, TElement, TSelector> {
19
- return {isSelector, transformSelector, splitSelector, findRootElement}
20
-
21
- function isSelector(selector: any): selector is types.Selector<TSelector> {
22
- return (
23
- spec.isSelector(selector) ||
24
- utils.types.isString(selector) ||
25
- (utils.types.isPlainObject(selector) &&
26
- utils.types.has(selector, 'selector') &&
27
- (utils.types.isString(selector.selector) || spec.isSelector(selector.selector)))
28
- )
29
- }
30
- function transformSelector(selector: types.Selector<TSelector>): TSelector {
31
- return spec.transformSelector?.(selector) ?? (selector as TSelector)
32
- }
33
- function splitSelector(selector: types.Selector<TSelector>): types.Selector<TSelector>[] {
34
- let current = selector
35
- let active = {} as any
36
- const path = [active]
37
- while (
38
- utils.types.has(current, 'selector') &&
39
- (utils.types.has(current, 'frame') || utils.types.has(current, 'shadow'))
40
- ) {
41
- active.selector = current.selector
42
- if (current.type) active.type = current.type
43
- if (current.frame) {
44
- active = {}
45
- path.push(active)
46
- current = current.frame
47
- } else if (current.shadow) {
48
- active = active.shadow = {}
49
- current = current.shadow
50
- }
51
- }
52
-
53
- if (spec.isSelector(current) || utils.types.isString(current)) {
54
- active.selector = current
55
- } else {
56
- active.selector = current.selector
57
- if (current.type) active.type = current.type
58
- }
59
- return path
60
- }
61
-
62
- async function findRootElement(
63
- context: TContext,
64
- selector: types.Selector<TSelector>,
65
- ): Promise<{root: TElement; selector: types.Selector<TSelector>}> {
66
- let root = null as TElement
67
- let currentSelector = selector
68
- while (utils.types.has(currentSelector, ['selector', 'shadow']) && isSelector(currentSelector.shadow)) {
69
- const element = await spec.findElement(context, transformSelector(currentSelector), root)
70
- if (!element) break
71
- root = await spec.executeScript(context, snippets.getShadowRoot, [element])
72
- if (!root) break
73
- currentSelector = currentSelector.shadow
74
- }
75
- return {root, selector: currentSelector}
76
- }
77
- }