browsertime 14.4.0 → 14.7.0
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 +29 -1
- package/bin/browsertime.js +1 -1
- package/lib/android/index.js +1 -1
- package/lib/chrome/har.js +4 -4
- package/lib/chrome/longTaskMetrics.js +1 -1
- package/lib/chrome/speedline.js +2 -2
- package/lib/chrome/webdriver/builder.js +1 -1
- package/lib/chrome/webdriver/setupChromiumOptions.js +7 -2
- package/lib/connectivity/trafficShapeParser.js +2 -2
- package/lib/connectivity/tsProxy.js +3 -3
- package/lib/core/engine/command/measure.js +16 -10
- package/lib/core/engine/command/mouse/clickAndHold.js +146 -0
- package/lib/core/engine/command/mouse/contextClick.js +61 -0
- package/lib/core/engine/command/mouse/doubleClick.js +76 -0
- package/lib/core/engine/command/mouse/index.js +9 -0
- package/lib/core/engine/command/mouse/mouseMove.js +81 -0
- package/lib/core/engine/command/mouse/singleClick.js +79 -0
- package/lib/core/engine/command/switch.js +2 -8
- package/lib/core/engine/iteration.js +5 -6
- package/lib/core/engine/run.js +2 -2
- package/lib/core/seleniumRunner.js +23 -22
- package/lib/core/webdriver/index.js +1 -1
- package/lib/edge/webdriver/builder.js +1 -1
- package/lib/extensionserver/setup.js +1 -1
- package/lib/firefox/geckoProfiler.js +2 -3
- package/lib/firefox/getHAR.js +1 -1
- package/lib/firefox/webdriver/builder.js +12 -7
- package/lib/firefox/webdriver/firefox.js +6 -7
- package/lib/safari/webdriver/builder.js +1 -1
- package/lib/support/browserScript.js +1 -1
- package/lib/support/cli.js +12 -0
- package/lib/support/engineUtils.js +1 -1
- package/lib/support/getViewPort.js +1 -1
- package/lib/support/har/index.js +13 -14
- package/lib/support/pathToFolder.js +4 -10
- package/lib/support/preURL.js +1 -1
- package/lib/support/setResourceTimingBufferSize.js +1 -1
- package/lib/support/statistics.js +1 -1
- package/lib/support/stop.js +1 -1
- package/lib/support/storageManager.js +5 -10
- package/lib/video/postprocessing/finetune/addTextToVideo.js +1 -1
- package/lib/video/postprocessing/finetune/convertFps.js +1 -1
- package/lib/video/postprocessing/finetune/getFont.js +1 -1
- package/lib/video/postprocessing/finetune/getTimingMetrics.js +5 -4
- package/lib/video/postprocessing/finetune/index.js +1 -1
- package/lib/video/postprocessing/finetune/removeOrange.js +1 -1
- package/lib/video/postprocessing/visualmetrics/extraMetrics.js +1 -1
- package/lib/video/postprocessing/visualmetrics/getVideoMetrics.js +1 -1
- package/lib/video/screenRecording/desktop/ffmpegRecorder.js +3 -3
- package/lib/video/screenRecording/desktop/osx/getSPDisplaysDataType.js +1 -1
- package/lib/video/screenRecording/desktop/osx/getScreen.js +1 -1
- package/lib/video/screenRecording/firefox/firefoxWindowRecorder.js +2 -2
- package/lib/video/screenRecording/setOrangeBackground.js +1 -1
- package/package.json +9 -9
- package/lib/core/engine/command/mouse.js +0 -314
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,36 @@
|
|
|
1
1
|
# Browsertime changelog (we do [semantic versioning](https://semver.org))
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## 14.7.0 - 2021-10-20
|
|
5
|
+
### Added
|
|
6
|
+
* Updated to Chromedriver 95. Added Chrome 95 in the Docker container.
|
|
7
|
+
|
|
8
|
+
## 14.6.1 - 2021-10-18
|
|
9
|
+
### Fixed
|
|
10
|
+
* If loading the URL fails (we get an exception, the browser crashes etc) make sure we stop the video correctly so it can be used [#1657](https://github.com/sitespeedio/browsertime/pull/1657).
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## 14.6.0 - 2021-10-13
|
|
14
|
+
### Added
|
|
15
|
+
* Updated to Selenium 4.0.0 [#1655](https://github.com/sitespeedio/browsertime/pull/1655).
|
|
16
|
+
* You can skip setting Browsertime default Firefox preferences with `--firefox.noDefaultPrefs`, thank you [Gregory Mierzwinski](https://github.com/gmierz) for PR [#1650](https://github.com/sitespeedio/browsertime/pull/1650).
|
|
17
|
+
* You can skip setting Browsertime default Chrome options with `--chrome.noDefaultOptions`, fixed in [#1651](https://github.com/sitespeedio/browsertime/pull/1651).
|
|
18
|
+
* Updated to Firefox 93 in the Docker container.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
* Updated eslint and prettier dependencies [#1652](https://github.com/sitespeedio/browsertime/pull/1652).
|
|
22
|
+
* Log Firefox preference and Chrome args on debug level [#1654](https://github.com/sitespeedio/browsertime/pull/1654)
|
|
23
|
+
## 14.5.0 - 2021-09-30
|
|
24
|
+
### Added
|
|
25
|
+
* Added CSS selector support for mouse commands [#1645](https://github.com/sitespeedio/browsertime/pull/1645)
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
* Internal refactoring of the mouse command [#1646](https://github.com/sitespeedio/browsertime/pull/1646) and [#1647](https://github.com/sitespeedio/browsertime/pull/1647).
|
|
29
|
+
|
|
3
30
|
## 14.4.0 - 2021-09-22
|
|
4
31
|
### Added
|
|
5
|
-
* Updated to
|
|
32
|
+
* Updated to Ch
|
|
33
|
+
romedriver 94 and Chrome 94 in the Docker container [#1643](https://github.com/sitespeedio/browsertime/pull/1643).
|
|
6
34
|
## 14.3.0 - 2021-09-16
|
|
7
35
|
### Added
|
|
8
36
|
* Update to Edgedriver 93. Update to Edge 93 in the Docker container [#1641](https://github.com/sitespeedio/browsertime/pull/1641).
|
package/bin/browsertime.js
CHANGED
|
@@ -11,7 +11,7 @@ const fs = require('fs');
|
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const log = require('intel').getLogger('browsertime');
|
|
13
13
|
const engineUtils = require('../lib/support/engineUtils');
|
|
14
|
-
const AsyncFunction = Object.getPrototypeOf(async function() {}).constructor;
|
|
14
|
+
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
15
15
|
const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
16
16
|
|
|
17
17
|
async function parseUserScripts(scripts) {
|
package/lib/android/index.js
CHANGED
package/lib/chrome/har.js
CHANGED
|
@@ -5,7 +5,7 @@ const perflogParser = require('chrome-har');
|
|
|
5
5
|
const harBuilder = require('../support/har');
|
|
6
6
|
const { Type } = require('selenium-webdriver').logging;
|
|
7
7
|
|
|
8
|
-
module.exports = async function(
|
|
8
|
+
module.exports = async function (
|
|
9
9
|
runner,
|
|
10
10
|
result,
|
|
11
11
|
index,
|
|
@@ -38,9 +38,9 @@ module.exports = async function(
|
|
|
38
38
|
await cdpClient.setResponseBodies(har);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const versionInfo = (
|
|
42
|
-
'Browser.getVersion'
|
|
43
|
-
)
|
|
41
|
+
const versionInfo = (
|
|
42
|
+
await cdpClient.send('Browser.getVersion')
|
|
43
|
+
).product.split('/');
|
|
44
44
|
const info = {
|
|
45
45
|
name: versionInfo[0],
|
|
46
46
|
version: versionInfo[1]
|
package/lib/chrome/speedline.js
CHANGED
|
@@ -18,13 +18,13 @@ function pad(n) {
|
|
|
18
18
|
* Use SpeedLine to analyse the Chrome trace log to get Visual Metrics.
|
|
19
19
|
* Not as good as using a video but maybe usable in some cases.
|
|
20
20
|
*/
|
|
21
|
-
module.exports = async function(trace, result, index) {
|
|
21
|
+
module.exports = async function (trace, result, index) {
|
|
22
22
|
try {
|
|
23
23
|
const navStart = trace.traceEvents.filter(
|
|
24
24
|
task =>
|
|
25
25
|
task.cat === 'blink.user_timing' && task.name === 'navigationStart'
|
|
26
26
|
);
|
|
27
|
-
navStart.sort(function(a, b) {
|
|
27
|
+
navStart.sort(function (a, b) {
|
|
28
28
|
return a.ts - b.ts;
|
|
29
29
|
});
|
|
30
30
|
log.debug('Get Speedline result from the trace');
|
|
@@ -14,7 +14,7 @@ let hasConfiguredChromeDriverService = false;
|
|
|
14
14
|
* @param builder
|
|
15
15
|
* @param {Object} options the options for a web driver.
|
|
16
16
|
*/
|
|
17
|
-
module.exports.configureBuilder = function(builder, baseDir, options) {
|
|
17
|
+
module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
18
18
|
const chromeConfig = options.chrome || {};
|
|
19
19
|
|
|
20
20
|
if (!hasConfiguredChromeDriverService) {
|
|
@@ -5,7 +5,7 @@ const getViewPort = require('../../support/getViewPort');
|
|
|
5
5
|
const util = require('../../support/util');
|
|
6
6
|
const log = require('intel').getLogger('browsertime.chrome');
|
|
7
7
|
|
|
8
|
-
module.exports = function(seleniumOptions, browserOptions, options, baseDir) {
|
|
8
|
+
module.exports = function (seleniumOptions, browserOptions, options, baseDir) {
|
|
9
9
|
// Fixing save password popup, only on Desktop
|
|
10
10
|
if (!options.android) {
|
|
11
11
|
seleniumOptions.setUserPreferences({
|
|
@@ -109,10 +109,15 @@ module.exports = function(seleniumOptions, browserOptions, options, baseDir) {
|
|
|
109
109
|
'--remote-debugging-port=' + options.devToolsPort
|
|
110
110
|
);
|
|
111
111
|
} else {
|
|
112
|
-
|
|
112
|
+
if (!browserOptions.noDefaultOptions) {
|
|
113
|
+
seleniumOptions.addArguments(defaultChromeOptions);
|
|
114
|
+
} else {
|
|
115
|
+
log.info('Skip setting default options for Chrome');
|
|
116
|
+
}
|
|
113
117
|
}
|
|
114
118
|
|
|
115
119
|
if (browserOptions.args) {
|
|
120
|
+
log.debug('Set Chrome args %j', browserOptions.args);
|
|
116
121
|
seleniumOptions.addArguments(browserOptions.args);
|
|
117
122
|
}
|
|
118
123
|
|
|
@@ -104,7 +104,7 @@ const legacyProfiles = {
|
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
module.exports = {
|
|
107
|
-
parseTrafficShapeConfig: function(options) {
|
|
107
|
+
parseTrafficShapeConfig: function (options) {
|
|
108
108
|
if (options.connectivity && options.connectivity.profile === 'custom') {
|
|
109
109
|
return {
|
|
110
110
|
down: options.connectivity.down,
|
|
@@ -133,7 +133,7 @@ module.exports = {
|
|
|
133
133
|
return null;
|
|
134
134
|
}
|
|
135
135
|
},
|
|
136
|
-
getProfiles: function() {
|
|
136
|
+
getProfiles: function () {
|
|
137
137
|
return newProfiles;
|
|
138
138
|
}
|
|
139
139
|
};
|
|
@@ -14,7 +14,7 @@ const TS_PROXY_SCRIPT_PATH = path.join(
|
|
|
14
14
|
);
|
|
15
15
|
|
|
16
16
|
function getStartupCriteriaListener(resolve, reject) {
|
|
17
|
-
return function(data) {
|
|
17
|
+
return function (data) {
|
|
18
18
|
const logLine = data.toString();
|
|
19
19
|
if (logLine.startsWith('Started Socks5 proxy server on')) {
|
|
20
20
|
log.debug('Started TSproxy');
|
|
@@ -65,12 +65,12 @@ class TSProxy {
|
|
|
65
65
|
const tsProxyProcess = this.tsProxyProcess;
|
|
66
66
|
|
|
67
67
|
if (this.logVerbose) {
|
|
68
|
-
tsProxyProcess.stderr.on('data', function(data) {
|
|
68
|
+
tsProxyProcess.stderr.on('data', function (data) {
|
|
69
69
|
log.verbose(data.toString().trim());
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
return new Promise(function(resolve, reject) {
|
|
73
|
+
return new Promise(function (resolve, reject) {
|
|
74
74
|
tsProxyProcess.stdout.on(
|
|
75
75
|
'data',
|
|
76
76
|
getStartupCriteriaListener(resolve, reject)
|
|
@@ -96,6 +96,13 @@ class Measure {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
async _stopVideo(url) {
|
|
100
|
+
if (this.recordVideo && !this.options.videoParams.debug) {
|
|
101
|
+
await this.video.stop(url);
|
|
102
|
+
this.videos.push(this.video);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
99
106
|
_error(message) {
|
|
100
107
|
// If we already are measuring a page, associate the error woth that page
|
|
101
108
|
if (this.areWeMeasuring === true) {
|
|
@@ -223,6 +230,9 @@ class Measure {
|
|
|
223
230
|
this.numberOfMeasuredPages++;
|
|
224
231
|
this.numberOfVisitedPages++;
|
|
225
232
|
this.engineDelegate.failing(url);
|
|
233
|
+
// If we got an error we still should stop the video to make sure we can use it to
|
|
234
|
+
// try to understand what went wrong
|
|
235
|
+
await this._stopVideo(url);
|
|
226
236
|
throw e;
|
|
227
237
|
}
|
|
228
238
|
} else {
|
|
@@ -261,14 +271,12 @@ class Measure {
|
|
|
261
271
|
// we also need to add that to the meta data so that the correct folder is created
|
|
262
272
|
if (this.result[this.numberOfMeasuredPages].alias) {
|
|
263
273
|
if (this.options.urlMetaData) {
|
|
264
|
-
this.options.urlMetaData[url] =
|
|
265
|
-
this.numberOfMeasuredPages
|
|
266
|
-
].alias;
|
|
274
|
+
this.options.urlMetaData[url] =
|
|
275
|
+
this.result[this.numberOfMeasuredPages].alias;
|
|
267
276
|
} else {
|
|
268
277
|
this.options.urlMetaData = {};
|
|
269
|
-
this.options.urlMetaData[url] =
|
|
270
|
-
this.numberOfMeasuredPages
|
|
271
|
-
].alias;
|
|
278
|
+
this.options.urlMetaData[url] =
|
|
279
|
+
this.result[this.numberOfMeasuredPages].alias;
|
|
272
280
|
}
|
|
273
281
|
}
|
|
274
282
|
|
|
@@ -276,10 +284,8 @@ class Measure {
|
|
|
276
284
|
await this.storageManager.createSubDataDir(
|
|
277
285
|
path.join(pathToFolder(url, this.options))
|
|
278
286
|
);
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
this.videos.push(this.video);
|
|
282
|
-
}
|
|
287
|
+
await this._stopVideo(url);
|
|
288
|
+
|
|
283
289
|
const alias = this.options.urlMetaData
|
|
284
290
|
? this.options.urlMetaData[url]
|
|
285
291
|
: undefined || this.result[this.numberOfMeasuredPages].alias;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('intel').getLogger('browsertime.command.mouse');
|
|
4
|
+
const webdriver = require('selenium-webdriver');
|
|
5
|
+
|
|
6
|
+
class ClickAndHold {
|
|
7
|
+
constructor(browser) {
|
|
8
|
+
this.driver = browser.getDriver();
|
|
9
|
+
this.actions = this.driver.actions({ async: true });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Click and hold an element that matches a XPath selector.
|
|
14
|
+
* @param {string} xpath
|
|
15
|
+
* @returns {Promise} Promise object represents when mouse is pressed.
|
|
16
|
+
* @throws Will throw an error if the element is not found.
|
|
17
|
+
*/
|
|
18
|
+
async byXpath(xpath) {
|
|
19
|
+
try {
|
|
20
|
+
const element = await this.driver.findElement(webdriver.By.xpath(xpath));
|
|
21
|
+
return this.actions.move({ origin: element }).press().perform();
|
|
22
|
+
} catch (e) {
|
|
23
|
+
log.error('Could not click and hold on element with xpath %s', xpath);
|
|
24
|
+
log.verbose(e);
|
|
25
|
+
throw Error('Could not click and hold on element with xpath ' + xpath);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Click and hold an element that matches a CSS selector.
|
|
31
|
+
* @param {string} selector
|
|
32
|
+
* @returns {Promise} Promise object represents when mouse is pressed.
|
|
33
|
+
* @throws Will throw an error if the element is not found.
|
|
34
|
+
*/
|
|
35
|
+
async bySelector(selector) {
|
|
36
|
+
try {
|
|
37
|
+
const element = await this.driver.findElement(webdriver.By.css(selector));
|
|
38
|
+
return this.actions.move({ origin: element }).press().perform();
|
|
39
|
+
} catch (e) {
|
|
40
|
+
log.error(
|
|
41
|
+
'Could not click and hold on element with selector %s',
|
|
42
|
+
selector
|
|
43
|
+
);
|
|
44
|
+
log.verbose(e);
|
|
45
|
+
throw Error(
|
|
46
|
+
'Could not click and hold on element with selector ' + selector
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Click and hold an element at the cursor's position.
|
|
53
|
+
* @returns {Promise} Promise object represents when mouse is pressed.
|
|
54
|
+
* @throws Will throw an error if action cannot be performed.
|
|
55
|
+
*/
|
|
56
|
+
async atCursor() {
|
|
57
|
+
try {
|
|
58
|
+
return this.actions
|
|
59
|
+
.move({ origin: webdriver.Origin.POINTER })
|
|
60
|
+
.press()
|
|
61
|
+
.perform();
|
|
62
|
+
} catch (e) {
|
|
63
|
+
log.error('Could not click and hold at cursor');
|
|
64
|
+
log.verbose(e);
|
|
65
|
+
throw Error('Could not click and hold at cursor');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Click and hold an element at the given coordinates.
|
|
71
|
+
* @param {integer} xPos
|
|
72
|
+
* @param {integer} yPos
|
|
73
|
+
* @returns {Promise} Promise object represents when mouse is pressed.
|
|
74
|
+
* @throws Will throw an error if action cannot be performed.
|
|
75
|
+
*/
|
|
76
|
+
async atPosition(xPos, yPos) {
|
|
77
|
+
try {
|
|
78
|
+
return this.actions
|
|
79
|
+
.move({ x: xPos, y: yPos, origin: webdriver.Origin.VIEWPORT })
|
|
80
|
+
.press()
|
|
81
|
+
.perform();
|
|
82
|
+
} catch (e) {
|
|
83
|
+
log.error('Could not click and hold at position (%d,%d)', xPos, yPos);
|
|
84
|
+
log.verbose(e);
|
|
85
|
+
throw Error(
|
|
86
|
+
'Could not click and hold at position (' + xPos + ',' + yPos + ')'
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Release mouse on element that matches the specified Xpath.
|
|
93
|
+
* @param {string} xpath
|
|
94
|
+
* @returns {Promise} Promise object represents when mouse is released.
|
|
95
|
+
* @throws Will throw an error if action cannot be performed.
|
|
96
|
+
*/
|
|
97
|
+
async releaseAtXpath(xpath) {
|
|
98
|
+
try {
|
|
99
|
+
const element = await this.driver.findElement(webdriver.By.xpath(xpath));
|
|
100
|
+
return this.actions.move({ origin: element }).release().perform();
|
|
101
|
+
} catch (e) {
|
|
102
|
+
log.error('Could not release on xpath %s', xpath);
|
|
103
|
+
log.verbose(e);
|
|
104
|
+
throw Error('Could not release on xpath ' + xpath);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Release mouse on element that matches the specified CSS selector.
|
|
110
|
+
* @param {string} selector
|
|
111
|
+
* @returns {Promise} Promise object represents when mouse is released.
|
|
112
|
+
* @throws Will throw an error if action cannot be performed.
|
|
113
|
+
*/
|
|
114
|
+
async releaseAtSelector(selector) {
|
|
115
|
+
try {
|
|
116
|
+
const element = await this.driver.findElement(webdriver.By.css(selector));
|
|
117
|
+
return this.actions.move({ origin: element }).release().perform();
|
|
118
|
+
} catch (e) {
|
|
119
|
+
log.error('Could not release on selector %s', selector);
|
|
120
|
+
log.verbose(e);
|
|
121
|
+
throw Error('Could not release on selector ' + selector);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Release mouse at specified coordinates.
|
|
127
|
+
* @param {integer} xPos
|
|
128
|
+
* @param {integer} yPos
|
|
129
|
+
* @returns {Promise} Promise object represents when mouse is released.
|
|
130
|
+
* @throws Will throw an error if action cannot be performed.
|
|
131
|
+
*/
|
|
132
|
+
async releaseAtPosition(xPos, yPos) {
|
|
133
|
+
try {
|
|
134
|
+
return this.actions
|
|
135
|
+
.move({ x: xPos, y: yPos, origin: webdriver.Origin.VIEWPORT })
|
|
136
|
+
.release()
|
|
137
|
+
.perform();
|
|
138
|
+
} catch (e) {
|
|
139
|
+
log.error('Could not release at position (%d,%d)', xPos, yPos);
|
|
140
|
+
log.verbose(e);
|
|
141
|
+
throw Error('Could not release at position (' + xPos + ',' + yPos + ')');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = ClickAndHold;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('intel').getLogger('browsertime.command.mouse');
|
|
4
|
+
const webdriver = require('selenium-webdriver');
|
|
5
|
+
|
|
6
|
+
class ContextClick {
|
|
7
|
+
constructor(browser) {
|
|
8
|
+
this.driver = browser.getDriver();
|
|
9
|
+
this.actions = this.driver.actions({ async: true });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Perform ContextClick on an element that matches a XPath selector.
|
|
14
|
+
* @param {string} xpath
|
|
15
|
+
* @returns {Promise} Promise object represents when context click occurs.
|
|
16
|
+
* @throws Will throw an error if the element is not found
|
|
17
|
+
*/
|
|
18
|
+
async byXpath(xpath) {
|
|
19
|
+
try {
|
|
20
|
+
const element = await this.driver.findElement(webdriver.By.xpath(xpath));
|
|
21
|
+
return this.actions.contextClick(element).perform();
|
|
22
|
+
} catch (e) {
|
|
23
|
+
log.error('Could not context click on element with xpath %s', xpath);
|
|
24
|
+
log.verbose(e);
|
|
25
|
+
throw Error('Could not context click on element with xpath ' + xpath);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Perform ContextClick on an element that matches a CSS selector.
|
|
31
|
+
* @param {string} css selector
|
|
32
|
+
* @returns {Promise} Promise object represents when context click occurs.
|
|
33
|
+
* @throws Will throw an error if the element is not found
|
|
34
|
+
*/
|
|
35
|
+
async bySelector(selector) {
|
|
36
|
+
try {
|
|
37
|
+
const element = await this.driver.findElement(webdriver.By.css(selector));
|
|
38
|
+
return this.actions.contextClick(element).perform();
|
|
39
|
+
} catch (e) {
|
|
40
|
+
log.error('Could not context click on element with css %s', selector);
|
|
41
|
+
log.verbose(e);
|
|
42
|
+
throw Error('Could not context click on element with css ' + selector);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Perform ContextClick at the cursor's position.
|
|
48
|
+
* @returns {Promise} Promise object represents when context click occurs.
|
|
49
|
+
* @throws Will throw an error if context click cannot be performed.
|
|
50
|
+
*/
|
|
51
|
+
async atCursor() {
|
|
52
|
+
try {
|
|
53
|
+
return this.actions.contextClick().perform();
|
|
54
|
+
} catch (e) {
|
|
55
|
+
log.error('Could not perform context click');
|
|
56
|
+
log.verbose(e);
|
|
57
|
+
throw Error('Could not perform context click');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
module.exports = ContextClick;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('intel').getLogger('browsertime.command.mouse');
|
|
4
|
+
const webdriver = require('selenium-webdriver');
|
|
5
|
+
|
|
6
|
+
class DoubleClick {
|
|
7
|
+
constructor(browser, pageCompleteCheck) {
|
|
8
|
+
this.browser = browser;
|
|
9
|
+
this.actions = this.browser.getDriver().actions({ async: true });
|
|
10
|
+
this.pageCompleteCheck = pageCompleteCheck;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Perform mouse double click on an element matches a XPath selector.
|
|
15
|
+
* @param {string} xpath
|
|
16
|
+
* @returns {Promise} Promise object represents when the element has been double clicked.
|
|
17
|
+
* @throws Will throw an error if the element is not found.
|
|
18
|
+
*/
|
|
19
|
+
async byXpath(xpath, options) {
|
|
20
|
+
try {
|
|
21
|
+
const element = await this.browser
|
|
22
|
+
.getDriver()
|
|
23
|
+
.findElement(webdriver.By.xpath(xpath));
|
|
24
|
+
await this.actions.doubleClick(element).perform();
|
|
25
|
+
if (options && 'wait' in options && options.wait === true) {
|
|
26
|
+
return this.browser.extraWait(this.pageCompleteCheck);
|
|
27
|
+
}
|
|
28
|
+
} catch (e) {
|
|
29
|
+
log.error('Could not double click on element with xpath %s', xpath);
|
|
30
|
+
log.verbose(e);
|
|
31
|
+
throw Error('Could not double click on element with xpath ' + xpath);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Perform mouse double click on an element matches a CSS selector.
|
|
37
|
+
* @param {string} selector
|
|
38
|
+
* @returns {Promise} Promise object represents when the element has been double clicked.
|
|
39
|
+
* @throws Will throw an error if the element is not found.
|
|
40
|
+
*/
|
|
41
|
+
async bySelector(selector, options) {
|
|
42
|
+
try {
|
|
43
|
+
const element = await this.browser
|
|
44
|
+
.getDriver()
|
|
45
|
+
.findElement(webdriver.By.css(selector));
|
|
46
|
+
await this.actions.doubleClick(element).perform();
|
|
47
|
+
if (options && 'wait' in options && options.wait === true) {
|
|
48
|
+
return this.browser.extraWait(this.pageCompleteCheck);
|
|
49
|
+
}
|
|
50
|
+
} catch (e) {
|
|
51
|
+
log.error('Could not double click on element with xpath %s', selector);
|
|
52
|
+
log.verbose(e);
|
|
53
|
+
throw Error('Could not double click on element with xpath ' + selector);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Perform mouse double click at the cursor's position.
|
|
59
|
+
* @returns {Promise} Promise object represents when double click occurs.
|
|
60
|
+
* @throws Will throw an error if double click cannot be performed.
|
|
61
|
+
*/
|
|
62
|
+
async atCursor(options) {
|
|
63
|
+
try {
|
|
64
|
+
await this.actions.doubleClick().perform();
|
|
65
|
+
if (options && 'wait' in options && options.wait === true) {
|
|
66
|
+
return this.browser.extraWait(this.pageCompleteCheck);
|
|
67
|
+
}
|
|
68
|
+
} catch (e) {
|
|
69
|
+
log.error('Could not perform double click');
|
|
70
|
+
log.verbose(e);
|
|
71
|
+
throw Error('Could not perform double click');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = DoubleClick;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('intel').getLogger('browsertime.command.mouse');
|
|
4
|
+
const webdriver = require('selenium-webdriver');
|
|
5
|
+
|
|
6
|
+
class MouseMove {
|
|
7
|
+
constructor(browser) {
|
|
8
|
+
this.driver = browser.getDriver();
|
|
9
|
+
this.actions = this.driver.actions({ async: true });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Move mouse to an element that matches a XPath selector.
|
|
14
|
+
* @param {string} xpath
|
|
15
|
+
* @returns {Promise} Promise object represents when the mouse has moved
|
|
16
|
+
* @throws Will throw an error if the element is not found
|
|
17
|
+
*/
|
|
18
|
+
async byXpath(xpath) {
|
|
19
|
+
try {
|
|
20
|
+
const element = await this.driver.findElement(webdriver.By.xpath(xpath));
|
|
21
|
+
return this.actions.move({ origin: element }).perform();
|
|
22
|
+
} catch (e) {
|
|
23
|
+
log.error('Could not find element by xpath %s', xpath);
|
|
24
|
+
log.verbose(e);
|
|
25
|
+
throw Error('Could not find element by xpath ' + xpath);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Move mouse to an element that matches a CSS selector.
|
|
31
|
+
* @param {string} selector
|
|
32
|
+
* @returns {Promise} Promise object represents when the mouse has moved
|
|
33
|
+
* @throws Will throw an error if the element is not found
|
|
34
|
+
*/
|
|
35
|
+
async bySelector(selector) {
|
|
36
|
+
try {
|
|
37
|
+
const element = await this.driver.findElement(webdriver.By.css(selector));
|
|
38
|
+
return this.actions.move({ origin: element }).perform();
|
|
39
|
+
} catch (e) {
|
|
40
|
+
log.error('Could not find element by selector %s', selector);
|
|
41
|
+
log.verbose(e);
|
|
42
|
+
throw Error('Could not find element by selector ' + selector);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Move mouse to a position
|
|
48
|
+
* @param {number} xPos, {number} yPos
|
|
49
|
+
* @returns {Promise} Promise object represents when the mouse has moved
|
|
50
|
+
* @throws Will throw an error if the element is not found
|
|
51
|
+
*/
|
|
52
|
+
async toPosition(xPos, yPos) {
|
|
53
|
+
try {
|
|
54
|
+
return this.actions.move({ x: xPos, y: yPos }).perform();
|
|
55
|
+
} catch (e) {
|
|
56
|
+
log.error('Could not move mouse to position.');
|
|
57
|
+
log.verbose(e);
|
|
58
|
+
throw Error('Could not move mouse to position.');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Move mouse by an offset
|
|
64
|
+
* @param {number} xOffset, {number} yOffset
|
|
65
|
+
* @returns {Promise} Promise object represents when the mouse has moved
|
|
66
|
+
* @throws Will throw an error if the element is not found
|
|
67
|
+
*/
|
|
68
|
+
async byOffset(xOffset, yOffset) {
|
|
69
|
+
try {
|
|
70
|
+
return this.actions
|
|
71
|
+
.move({ x: xOffset, y: yOffset, origin: webdriver.Origin.POINTER })
|
|
72
|
+
.perform();
|
|
73
|
+
} catch (e) {
|
|
74
|
+
log.error('Could not move mouse by offset');
|
|
75
|
+
log.verbose(e);
|
|
76
|
+
throw Error('Could not move mouse by offset');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = MouseMove;
|