@applitools/driver 1.2.5 → 1.3.1
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/CHANGELOG.md +24 -0
- package/dist/capabilities.js +54 -0
- package/dist/context.js +7 -0
- package/dist/driver.js +43 -15
- package/dist/element.js +10 -2
- package/dist/fake/index.js +25 -0
- package/dist/fake/mock-driver.js +7 -2
- package/dist/fake/spec-driver.js +103 -65
- package/dist/index.js +0 -15
- package/package.json +20 -9
- package/types/capabilities.d.ts +4 -0
- package/types/context.d.ts +71 -0
- package/types/driver.d.ts +62 -0
- package/types/element.d.ts +55 -0
- package/types/fake/index.d.ts +3 -0
- package/types/fake/mock-driver.d.ts +35 -0
- package/types/fake/spec-driver.d.ts +29 -0
- package/types/index.d.ts +3 -0
- package/types/user-agent.d.ts +12 -0
- package/types/utils.d.ts +11 -0
- package/.bongo/dry-run/package-lock.json +0 -30
- package/.bongo/dry-run.tgz +0 -0
- package/.eslintrc +0 -36
- package/src/context.ts +0 -519
- package/src/driver.ts +0 -456
- package/src/element.ts +0 -502
- package/src/fake/mock-driver.d.ts +0 -3
- package/src/fake/mock-driver.js +0 -355
- package/src/fake/spec-driver.d.ts +0 -11
- package/src/fake/spec-driver.js +0 -66
- package/src/index.ts +0 -6
- package/src/user-agent.ts +0 -99
- package/src/utils.ts +0 -77
- package/test/unit/context.spec.ts +0 -243
- package/test/unit/driver.spec.ts +0 -482
- package/test/unit/user-agent.spec.d.ts +0 -1
- package/tsconfig.json +0 -24
package/src/context.ts
DELETED
|
@@ -1,519 +0,0 @@
|
|
|
1
|
-
import type * as types from '@applitools/types'
|
|
2
|
-
import type {Driver} from './driver'
|
|
3
|
-
import type {SpecUtils} from './utils'
|
|
4
|
-
import * as utils from '@applitools/utils'
|
|
5
|
-
import {makeSpecUtils} from './utils'
|
|
6
|
-
import {Element} from './element'
|
|
7
|
-
|
|
8
|
-
const snippets = require('@applitools/snippets')
|
|
9
|
-
|
|
10
|
-
export type ContextReference<TDriver, TContext, TElement, TSelector> =
|
|
11
|
-
| Context<TDriver, TContext, TElement, TSelector>
|
|
12
|
-
| Element<TDriver, TContext, TElement, TSelector>
|
|
13
|
-
| TElement
|
|
14
|
-
| types.Selector<TSelector>
|
|
15
|
-
| string
|
|
16
|
-
| number
|
|
17
|
-
|
|
18
|
-
export type ContextPlain<TDriver, TContext, TElement, TSelector> =
|
|
19
|
-
| ContextReference<TDriver, TContext, TElement, TSelector>
|
|
20
|
-
| {
|
|
21
|
-
reference: ContextReference<TDriver, TContext, TElement, TSelector>
|
|
22
|
-
scrollingElement?: Element<TDriver, TContext, TElement, TSelector>
|
|
23
|
-
parent?: ContextPlain<TDriver, TContext, TElement, TSelector>
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export type ContextState = {
|
|
27
|
-
region?: types.Region
|
|
28
|
-
clientRegion?: types.Region
|
|
29
|
-
scrollingRegion?: types.Region
|
|
30
|
-
innerOffset?: types.Location
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class Context<TDriver, TContext, TElement, TSelector> {
|
|
34
|
-
private _target: TContext
|
|
35
|
-
|
|
36
|
-
private _driver: Driver<TDriver, TContext, TElement, TSelector>
|
|
37
|
-
private _parent: Context<TDriver, TContext, TElement, TSelector>
|
|
38
|
-
private _element: Element<TDriver, TContext, TElement, TSelector>
|
|
39
|
-
private _reference: ContextReference<TDriver, TContext, TElement, TSelector>
|
|
40
|
-
private _scrollingElement: Element<TDriver, TContext, TElement, TSelector>
|
|
41
|
-
private _state: ContextState = {}
|
|
42
|
-
private _logger: any
|
|
43
|
-
private _utils: SpecUtils<TDriver, TContext, TElement, TSelector>
|
|
44
|
-
|
|
45
|
-
private _isReference(reference: any): reference is ContextReference<TDriver, TContext, TElement, TSelector> {
|
|
46
|
-
return (
|
|
47
|
-
reference instanceof Context ||
|
|
48
|
-
utils.types.isInteger(reference) ||
|
|
49
|
-
utils.types.isString(reference) ||
|
|
50
|
-
reference instanceof Element ||
|
|
51
|
-
this._spec.isElement(reference) ||
|
|
52
|
-
this._utils.isSelector(reference)
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
protected readonly _spec: types.SpecDriver<TDriver, TContext, TElement, TSelector>
|
|
57
|
-
|
|
58
|
-
constructor(options: {
|
|
59
|
-
spec: types.SpecDriver<TDriver, TContext, TElement, TSelector>
|
|
60
|
-
context?: TContext | Context<TDriver, TContext, TElement, TSelector>
|
|
61
|
-
driver?: Driver<TDriver, TContext, TElement, TSelector>
|
|
62
|
-
parent?: Context<TDriver, TContext, TElement, TSelector>
|
|
63
|
-
reference?: ContextReference<TDriver, TContext, TElement, TSelector>
|
|
64
|
-
element?: Element<TDriver, TContext, TElement, TSelector>
|
|
65
|
-
scrollingElement?: Element<TDriver, TContext, TElement, TSelector>
|
|
66
|
-
logger?: any
|
|
67
|
-
}) {
|
|
68
|
-
if (options.context instanceof Context) return options.context
|
|
69
|
-
|
|
70
|
-
this._spec = options.spec
|
|
71
|
-
this._utils = makeSpecUtils(options.spec)
|
|
72
|
-
|
|
73
|
-
if (options.logger) this._logger = options.logger
|
|
74
|
-
|
|
75
|
-
if (options.context) {
|
|
76
|
-
if (this._spec.isContext?.(options.context) ?? this._spec.isDriver(options.context)) {
|
|
77
|
-
this._target = options.context
|
|
78
|
-
} else {
|
|
79
|
-
throw new TypeError('Context constructor called with argument of unknown type of context!')
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (this._isReference(options.reference)) {
|
|
84
|
-
if (options.reference instanceof Context) return options.reference
|
|
85
|
-
if (!options.parent) {
|
|
86
|
-
throw new TypeError('Cannot construct child context without reference to the parent')
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
this._reference = options.reference
|
|
90
|
-
this._parent = options.parent
|
|
91
|
-
this._scrollingElement = options.scrollingElement
|
|
92
|
-
this._driver = options.driver || this._parent.driver
|
|
93
|
-
} else if (!options.reference) {
|
|
94
|
-
this._element = null
|
|
95
|
-
this._parent = null
|
|
96
|
-
this._scrollingElement = options.scrollingElement
|
|
97
|
-
this._driver = options.driver
|
|
98
|
-
} else {
|
|
99
|
-
throw new TypeError('Context constructor called with argument of unknown type!')
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
get target(): TContext {
|
|
104
|
-
return this._target
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
get driver(): Driver<TDriver, TContext, TElement, TSelector> {
|
|
108
|
-
return this._driver
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
get parent(): Context<TDriver, TContext, TElement, TSelector> | null {
|
|
112
|
-
return this._parent ?? null
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
get main(): Context<TDriver, TContext, TElement, TSelector> {
|
|
116
|
-
return this.parent?.main ?? this
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
get path(): Context<TDriver, TContext, TElement, TSelector>[] {
|
|
120
|
-
return [...(this.parent?.path ?? []), this]
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
get isMain(): boolean {
|
|
124
|
-
return this.main === this
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
get isCurrent(): boolean {
|
|
128
|
-
return this.driver.currentContext === this
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
get isInitialized(): boolean {
|
|
132
|
-
return Boolean(this._element) || this.isMain
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
get isRef(): boolean {
|
|
136
|
-
return !this._target
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async init(): Promise<this> {
|
|
140
|
-
if (this.isInitialized) return this
|
|
141
|
-
if (!this._reference) throw new TypeError('Cannot initialize context without a reference to the context element')
|
|
142
|
-
|
|
143
|
-
await this.parent.focus()
|
|
144
|
-
|
|
145
|
-
this._logger.log('Context initialization')
|
|
146
|
-
|
|
147
|
-
if (utils.types.isInteger(this._reference)) {
|
|
148
|
-
this._logger.log('Getting context element using index:', this._reference)
|
|
149
|
-
const elements = await this.parent.elements('frame, iframe')
|
|
150
|
-
if (this._reference > elements.length) {
|
|
151
|
-
throw new TypeError(`Context element with index ${this._reference} is not found`)
|
|
152
|
-
}
|
|
153
|
-
this._element = elements[this._reference]
|
|
154
|
-
} else if (utils.types.isString(this._reference) || this._utils.isSelector(this._reference)) {
|
|
155
|
-
if (utils.types.isString(this._reference)) {
|
|
156
|
-
this._logger.log('Getting context element by name or id', this._reference)
|
|
157
|
-
this._element = await this.parent
|
|
158
|
-
.element(`iframe[name="${this._reference}"], iframe#${this._reference}`)
|
|
159
|
-
.catch(() => null)
|
|
160
|
-
}
|
|
161
|
-
if (!this._element && this._utils.isSelector(this._reference)) {
|
|
162
|
-
this._logger.log('Getting context element by selector', this._reference)
|
|
163
|
-
this._element = await this.parent.element(this._reference)
|
|
164
|
-
}
|
|
165
|
-
if (!this._element) {
|
|
166
|
-
throw new TypeError(
|
|
167
|
-
`Context element with name, id, or selector ${JSON.stringify(this._reference)}' is not found`,
|
|
168
|
-
)
|
|
169
|
-
}
|
|
170
|
-
} else if (this._spec.isElement(this._reference) || this._reference instanceof Element) {
|
|
171
|
-
this._logger.log('Initialize context from reference element', this._reference)
|
|
172
|
-
this._element = new Element({
|
|
173
|
-
spec: this._spec,
|
|
174
|
-
context: this.parent,
|
|
175
|
-
element: this._reference,
|
|
176
|
-
logger: this._logger,
|
|
177
|
-
})
|
|
178
|
-
} else {
|
|
179
|
-
throw new TypeError('Reference type does not supported')
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
this._reference = null
|
|
183
|
-
|
|
184
|
-
return this
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async focus(): Promise<this> {
|
|
188
|
-
if (this.isCurrent) {
|
|
189
|
-
return this
|
|
190
|
-
} else if (this.isMain) {
|
|
191
|
-
await this.driver.switchToMainContext()
|
|
192
|
-
return this
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (this.isRef) {
|
|
196
|
-
await this.init()
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (!this.parent.isCurrent) {
|
|
200
|
-
await this.driver.switchTo(this)
|
|
201
|
-
return this
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
await this.parent.preserveInnerOffset()
|
|
205
|
-
|
|
206
|
-
if (this.parent.isMain) await this.parent.preserveContextRegions()
|
|
207
|
-
await this.preserveContextRegions()
|
|
208
|
-
|
|
209
|
-
this._target = await this._spec.childContext(this.parent.target, this._element.target)
|
|
210
|
-
|
|
211
|
-
this.driver.updateCurrentContext(this)
|
|
212
|
-
|
|
213
|
-
return this
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
async equals(
|
|
217
|
-
context: Context<TDriver, TContext, TElement, TSelector> | Element<TDriver, TContext, TElement, TSelector>,
|
|
218
|
-
): Promise<boolean> {
|
|
219
|
-
if (context === this || (this.isMain && context === null)) return true
|
|
220
|
-
if (!this._element) return false
|
|
221
|
-
return this._element.equals(context instanceof Context ? await context.getContextElement() : context)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
async context(
|
|
225
|
-
reference: ContextPlain<TDriver, TContext, TElement, TSelector>,
|
|
226
|
-
): Promise<Context<TDriver, TContext, TElement, TSelector>> {
|
|
227
|
-
if (reference instanceof Context) {
|
|
228
|
-
if (reference.parent !== this && !(await this.equals(reference.parent))) {
|
|
229
|
-
throw Error('Cannot attach a child context because it has a different parent')
|
|
230
|
-
}
|
|
231
|
-
return reference
|
|
232
|
-
} else if (this._isReference(reference)) {
|
|
233
|
-
return new Context({spec: this._spec, parent: this, driver: this.driver, reference, logger: this._logger})
|
|
234
|
-
} else if (utils.types.has(reference, 'reference')) {
|
|
235
|
-
const parent = reference.parent ? await this.context(reference.parent) : this
|
|
236
|
-
return new Context({
|
|
237
|
-
spec: this._spec,
|
|
238
|
-
parent,
|
|
239
|
-
driver: this.driver,
|
|
240
|
-
reference: reference.reference,
|
|
241
|
-
scrollingElement: reference?.scrollingElement,
|
|
242
|
-
logger: this._logger,
|
|
243
|
-
})
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
async element(
|
|
248
|
-
elementOrSelector: TElement | types.Selector<TSelector>,
|
|
249
|
-
): Promise<Element<TDriver, TContext, TElement, TSelector>> {
|
|
250
|
-
if (this._spec.isElement(elementOrSelector)) {
|
|
251
|
-
return new Element({spec: this._spec, context: this, element: elementOrSelector, logger: this._logger})
|
|
252
|
-
} else if (this._utils.isSelector(elementOrSelector)) {
|
|
253
|
-
if (this.isRef) {
|
|
254
|
-
return new Element({spec: this._spec, context: this, selector: elementOrSelector, logger: this._logger})
|
|
255
|
-
}
|
|
256
|
-
await this.focus()
|
|
257
|
-
|
|
258
|
-
const selectors = this._utils.splitSelector(elementOrSelector)
|
|
259
|
-
const contextSelectors = selectors.slice(0, -1)
|
|
260
|
-
const elementSelector = selectors[selectors.length - 1]
|
|
261
|
-
|
|
262
|
-
let context = this as Context<TDriver, TContext, TElement, TSelector>
|
|
263
|
-
for (const contextSelector of contextSelectors) {
|
|
264
|
-
context = await context
|
|
265
|
-
.context(contextSelector)
|
|
266
|
-
.then(context => context.focus())
|
|
267
|
-
.catch(() => null)
|
|
268
|
-
if (!context) return null
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const {root, selector} = this.driver.features?.shadowSelector
|
|
272
|
-
? {root: null, selector: elementSelector}
|
|
273
|
-
: await this._utils.findRootElement(context.target, elementSelector)
|
|
274
|
-
|
|
275
|
-
if (!root && selector !== elementSelector) return null
|
|
276
|
-
|
|
277
|
-
const element = await this._spec.findElement(context.target, this._utils.transformSelector(selector), root)
|
|
278
|
-
return element
|
|
279
|
-
? new Element({spec: this._spec, context, element, selector: elementSelector, logger: this._logger})
|
|
280
|
-
: null
|
|
281
|
-
} else {
|
|
282
|
-
throw new TypeError('Cannot find element using argument of unknown type!')
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
async elements(
|
|
287
|
-
elementOrSelector: TElement | types.Selector<TSelector>,
|
|
288
|
-
): Promise<Element<TDriver, TContext, TElement, TSelector>[]> {
|
|
289
|
-
if (this._spec.isElement(elementOrSelector)) {
|
|
290
|
-
return [new Element({spec: this._spec, context: this, element: elementOrSelector, logger: this._logger})]
|
|
291
|
-
} else if (this._utils.isSelector(elementOrSelector)) {
|
|
292
|
-
if (this.isRef) {
|
|
293
|
-
return [new Element({spec: this._spec, context: this, selector: elementOrSelector, logger: this._logger})]
|
|
294
|
-
}
|
|
295
|
-
await this.focus()
|
|
296
|
-
|
|
297
|
-
const selectors = this._utils.splitSelector(elementOrSelector)
|
|
298
|
-
const contextSelectors = selectors.slice(0, -1)
|
|
299
|
-
const elementSelector = selectors[selectors.length - 1]
|
|
300
|
-
|
|
301
|
-
let context = this as Context<TDriver, TContext, TElement, TSelector>
|
|
302
|
-
for (const contextSelector of contextSelectors) {
|
|
303
|
-
context = await context
|
|
304
|
-
.context(contextSelector)
|
|
305
|
-
.then(context => context.focus())
|
|
306
|
-
.catch(() => null)
|
|
307
|
-
if (!context) return []
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
const {root, selector} = this.driver.features?.shadowSelector
|
|
311
|
-
? {root: null, selector: elementSelector}
|
|
312
|
-
: await this._utils.findRootElement(context.target, elementSelector)
|
|
313
|
-
|
|
314
|
-
if (!root && selector !== elementSelector) return []
|
|
315
|
-
|
|
316
|
-
const elements = await this._spec.findElements(context.target, this._utils.transformSelector(selector), root)
|
|
317
|
-
return elements.map((element, index) => {
|
|
318
|
-
return new Element({
|
|
319
|
-
spec: this._spec,
|
|
320
|
-
context,
|
|
321
|
-
element,
|
|
322
|
-
selector: elementSelector,
|
|
323
|
-
index,
|
|
324
|
-
logger: this._logger,
|
|
325
|
-
})
|
|
326
|
-
})
|
|
327
|
-
} else {
|
|
328
|
-
throw new TypeError('Cannot find elements using argument of unknown type!')
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
async execute(script: ((args: any) => any) | string, arg?: any): Promise<any> {
|
|
333
|
-
await this.focus()
|
|
334
|
-
try {
|
|
335
|
-
return await this._spec.executeScript(this.target, script, serialize.call(this, arg))
|
|
336
|
-
} catch (err) {
|
|
337
|
-
this._logger.warn('Error during script execution with argument', arg)
|
|
338
|
-
this._logger.error(err)
|
|
339
|
-
throw err
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
function serialize(this: Context<TDriver, TContext, TElement, TSelector>, value: any): any {
|
|
343
|
-
if (this._spec.isElement(value) || value instanceof Element) {
|
|
344
|
-
return value instanceof Element ? value.toJSON() : value
|
|
345
|
-
} else if (utils.types.isArray(value)) {
|
|
346
|
-
return value.map(value => serialize.call(this, value))
|
|
347
|
-
} else if (utils.types.isObject(value)) {
|
|
348
|
-
return Object.entries(value.toJSON?.() ?? value).reduce((serialized, [key, value]) => {
|
|
349
|
-
return Object.assign(serialized, {[key]: serialize.call(this, value)})
|
|
350
|
-
}, {})
|
|
351
|
-
} else {
|
|
352
|
-
return value
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
async getContextElement(): Promise<Element<TDriver, TContext, TElement, TSelector>> {
|
|
358
|
-
if (this.isMain) return null
|
|
359
|
-
await this.init()
|
|
360
|
-
return this._element
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
async getScrollingElement(): Promise<Element<TDriver, TContext, TElement, TSelector>> {
|
|
364
|
-
if (!(this._scrollingElement instanceof Element)) {
|
|
365
|
-
await this.focus()
|
|
366
|
-
if (this._scrollingElement) {
|
|
367
|
-
this._scrollingElement = await this.element(this._scrollingElement)
|
|
368
|
-
} else {
|
|
369
|
-
this._scrollingElement = await this.element(
|
|
370
|
-
this.driver.isWeb ? {type: 'css', selector: 'html'} : {type: 'xpath', selector: '//*[@scrollable="true"]'},
|
|
371
|
-
)
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
return this._scrollingElement
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
async setScrollingElement(
|
|
378
|
-
scrollingElement: Element<TDriver, TContext, TElement, TSelector> | TElement | types.Selector<TSelector>,
|
|
379
|
-
): Promise<void> {
|
|
380
|
-
if (scrollingElement === undefined) return
|
|
381
|
-
else if (scrollingElement === null) this._scrollingElement = null
|
|
382
|
-
else {
|
|
383
|
-
this._scrollingElement =
|
|
384
|
-
scrollingElement instanceof Element ? scrollingElement : await this.element(scrollingElement)
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
async blurElement(element?: Element<TDriver, TContext, TElement, TSelector>): Promise<TElement> {
|
|
389
|
-
try {
|
|
390
|
-
return await this.execute(snippets.blurElement, [element])
|
|
391
|
-
} catch (err) {
|
|
392
|
-
this._logger.warn('Cannot blur element', element)
|
|
393
|
-
this._logger.error(err)
|
|
394
|
-
return null
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
async focusElement(element: Element<TDriver, TContext, TElement, TSelector>) {
|
|
399
|
-
try {
|
|
400
|
-
return await this.execute(snippets.focusElement, [element])
|
|
401
|
-
} catch (err) {
|
|
402
|
-
this._logger.warn('Cannot focus element', element)
|
|
403
|
-
this._logger.error(err)
|
|
404
|
-
return null
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
async getRegion(): Promise<types.Region> {
|
|
409
|
-
if (this.isMain && this.isCurrent) {
|
|
410
|
-
const viewportRegion = utils.geometry.region({x: 0, y: 0}, await this.driver.getViewportSize())
|
|
411
|
-
this._state.region = this._scrollingElement
|
|
412
|
-
? utils.geometry.region(
|
|
413
|
-
{x: 0, y: 0},
|
|
414
|
-
utils.geometry.intersect(viewportRegion, await this._scrollingElement.getRegion()),
|
|
415
|
-
)
|
|
416
|
-
: viewportRegion
|
|
417
|
-
} else if (this.parent?.isCurrent) {
|
|
418
|
-
await this.init()
|
|
419
|
-
this._state.region = await this._element.getRegion()
|
|
420
|
-
}
|
|
421
|
-
return this._state.region
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
async getClientRegion(): Promise<types.Region> {
|
|
425
|
-
if (this.isMain && this.isCurrent) {
|
|
426
|
-
const viewportRegion = utils.geometry.region({x: 0, y: 0}, await this.driver.getViewportSize())
|
|
427
|
-
this._state.clientRegion = this._scrollingElement
|
|
428
|
-
? utils.geometry.region(
|
|
429
|
-
{x: 0, y: 0},
|
|
430
|
-
utils.geometry.intersect(viewportRegion, await this._scrollingElement.getClientRegion()),
|
|
431
|
-
)
|
|
432
|
-
: viewportRegion
|
|
433
|
-
} else if (this.parent?.isCurrent) {
|
|
434
|
-
await this.init()
|
|
435
|
-
this._state.clientRegion = await this._element.getClientRegion()
|
|
436
|
-
}
|
|
437
|
-
return this._state.clientRegion
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
async getScrollingRegion(): Promise<types.Region> {
|
|
441
|
-
if (this.isCurrent) {
|
|
442
|
-
const scrollingElement = await this.getScrollingElement()
|
|
443
|
-
this._state.scrollingRegion = await scrollingElement.getClientRegion()
|
|
444
|
-
}
|
|
445
|
-
return this._state.scrollingRegion
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
async getContentSize(): Promise<types.Size> {
|
|
449
|
-
return this.execute(snippets.getDocumentSize)
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
async getInnerOffset(): Promise<types.Location> {
|
|
453
|
-
if (this.isCurrent) {
|
|
454
|
-
const scrollingElement = await this.getScrollingElement()
|
|
455
|
-
this._state.innerOffset = scrollingElement ? await scrollingElement.getInnerOffset() : {x: 0, y: 0}
|
|
456
|
-
}
|
|
457
|
-
return this._state.innerOffset
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
async getLocationInMainContext(): Promise<types.Location> {
|
|
461
|
-
return this.path.reduce((location, context) => {
|
|
462
|
-
return location.then(async location => {
|
|
463
|
-
return utils.geometry.offset(location, utils.geometry.location(await context.getClientRegion()))
|
|
464
|
-
})
|
|
465
|
-
}, Promise.resolve({x: 0, y: 0}))
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
async getLocationInViewport(): Promise<types.Location> {
|
|
469
|
-
let location = utils.geometry.offsetNegative({x: 0, y: 0}, await this.getInnerOffset())
|
|
470
|
-
|
|
471
|
-
if (this.isMain) return location
|
|
472
|
-
|
|
473
|
-
let currentContext = this as Context<TDriver, TContext, TElement, TSelector>
|
|
474
|
-
while (currentContext) {
|
|
475
|
-
const contextLocation = utils.geometry.location(await currentContext.getClientRegion())
|
|
476
|
-
const parentContextInnerOffset = (await currentContext.parent?.getInnerOffset()) ?? {x: 0, y: 0}
|
|
477
|
-
|
|
478
|
-
location = utils.geometry.offsetNegative(
|
|
479
|
-
utils.geometry.offset(location, contextLocation),
|
|
480
|
-
parentContextInnerOffset,
|
|
481
|
-
)
|
|
482
|
-
currentContext = currentContext.parent
|
|
483
|
-
}
|
|
484
|
-
return location
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
async getRegionInViewport(region: types.Region): Promise<types.Region> {
|
|
488
|
-
let currentContext = this as Context<TDriver, TContext, TElement, TSelector>
|
|
489
|
-
|
|
490
|
-
if (region) region = utils.geometry.offsetNegative(region, await currentContext.getInnerOffset())
|
|
491
|
-
else region = {x: 0, y: 0, width: Infinity, height: Infinity}
|
|
492
|
-
|
|
493
|
-
while (currentContext) {
|
|
494
|
-
const contextRegion = await currentContext.getClientRegion()
|
|
495
|
-
// const contextScrollingRegion = await currentContext.getScrollingRegion()
|
|
496
|
-
const parentContextInnerOffset = (await currentContext.parent?.getInnerOffset()) ?? {x: 0, y: 0}
|
|
497
|
-
|
|
498
|
-
region = utils.geometry.intersect(contextRegion, utils.geometry.offset(region, contextRegion))
|
|
499
|
-
// region = utils.geometry.intersect(contextScrollingRegion, region)
|
|
500
|
-
region = utils.geometry.offsetNegative(region, parentContextInnerOffset)
|
|
501
|
-
|
|
502
|
-
currentContext = currentContext.parent
|
|
503
|
-
}
|
|
504
|
-
return region
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
private async preserveInnerOffset() {
|
|
508
|
-
this._state.innerOffset = await this.getInnerOffset()
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
private async preserveContextRegions() {
|
|
512
|
-
this._state.region = await this.getRegion()
|
|
513
|
-
this._state.clientRegion = await this.getClientRegion()
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
private async preserveScrollingRegion() {
|
|
517
|
-
this._state.scrollingRegion = await this.getScrollingRegion()
|
|
518
|
-
}
|
|
519
|
-
}
|