-
Notifications
You must be signed in to change notification settings - Fork 4
/
ActionsHelper.js
134 lines (115 loc) · 4.2 KB
/
ActionsHelper.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
* Useful helpers that can be used by any action
*/
export default class ActionsHelper {
/**
* @param {Object} config
*/
constructor(config) {
this._config = config;
}
/**
* Resolves when page readyState equals to one of specified states.
* If the states are not equal after specified timeout, error is thrown.
* @param {puppeteer.Page} page
* @param {Object} [options]
* @param {number} [options.timeout=30000]
* @param {string[]} [options.states=[interactive,complete]] document.readyState values
* @param {number} [options.checkInterval=50]
*/
async waitForReadyState(page, options) {
let start = Date.now();
let state;
options = options || {
timeout: 30000,
states: ['interactive', 'complete'],
checkInterval: 50,
};
while (Date.now() - start <= options.timeout) {
state = await page.evaluate(() => document.readyState);
if (options.states.includes(state)) {
return;
}
await page.waitForTimeout(options.checkInterval);
}
throw Error(`Expected ready state to be one of ${options.states.join(', ')}, but it was ${state}`);
}
/**
* Searches for all visible elements in DOM
* @param {puppeteer.Page} page
* @returns {Promise<puppeteer.ElementHandle[]>} Array of elements
*/
async getAllVisiblePageElements(page) {
let visibleElements = [];
let allElements = await page.$x(this._config.elementSelector);
await Promise.all(
allElements.map(async (element) => {
let executionContext = await element.executionContext();
let numberOfChildren = await executionContext.evaluate((element) => {
return element && element.childElementCount;
}, element);
if (numberOfChildren > 0 || !this.isElementVisible(element)) {
return;
}
visibleElements.push(element);
})
);
return visibleElements;
}
/**
* Searches for an element based on action configuration
* @param {puppeteer.Page} page
* @param {Object} [actionConfig={}]
* @returns {Promise<puppeteer.ElementHandle>} element
*/
async getElement(page, actionConfig = {}) {
return page.waitForXPath(actionConfig.selector);
}
/**
* Creates a selector for the element
* @param {puppeteer.ElementHandle} element
* @returns {Promise<string>} selector
*/
async getElementSelector(element) {
let executionContext = await element.executionContext();
return executionContext.evaluate(this._config.getElementSelector, element);
}
/**
* Highlights the element in the dom by adding some styles
* @param {puppeteer.ElementHandle} element
* @returns {Promise} Resolves when element highlight is started
*/
async highlightElement(element) {
let executionContext = await element.executionContext();
await executionContext.evaluate(
(element, timeout) => {
let originalColor = element.style['color'];
let originalBorder = element.style['border'];
element.style['color'] = 'red';
element.style['border'] = 'solid';
setTimeout(() => {
element.style['color'] = originalColor;
element.style['border'] = originalBorder;
}, timeout);
},
element,
this._config.previewModePauseTime - 250
);
}
/**
* @param {puppeteer.ElementHandle} element
* @returns {Promise<string>} element.outerHTML
*/
async getElementHTML(element) {
let executionContext = await element.executionContext();
return executionContext.evaluate((element) => element.outerHTML, element);
}
/**
* Checks if an element is visible
* @param {puppeteer.ElementHandle} element
* @returns {Promise<boolean>} true if an element is visible
*/
async isElementVisible(element) {
return !!(await element.boundingBox());
}
}