@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.
- package/CHANGELOG.md +17 -0
- package/dist/context.js +1 -1
- package/dist/driver.js +11 -4
- package/dist/element.js +4 -4
- package/package.json +10 -5
- package/types/context.d.ts +70 -0
- package/types/driver.d.ts +60 -0
- package/types/element.d.ts +55 -0
- package/types/fake/mock-driver.d.ts +71 -0
- package/types/fake/spec-driver.d.ts +40 -0
- package/types/index.d.ts +5 -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 -451
- 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/fake/mock-driver.js
DELETED
|
@@ -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
|
package/src/fake/spec-driver.js
DELETED
|
@@ -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
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
|
-
}
|