Skip to content

Commit f2fea75

Browse files
Merge pull request #405 from GuillaumeGomez/device-pixel-ratio
Add device-pixel-ratio command and improve UI test execution speed
2 parents b6813ca + b1f9df2 commit f2fea75

File tree

11 files changed

+177
-29
lines changed

11 files changed

+177
-29
lines changed

goml-script.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ Here's the command list:
115115
* [`css`](#css)
116116
* [`debug`](#debug)
117117
* [`define-function`](#define-function)
118+
* [`device-pixel-ratio`](#device-pixel-ratio)
118119
* [`drag-and-drop`](#drag-and-drop)
119120
* [`emulate`](#emulate)
120121
* [`fail`](#fail)
@@ -959,6 +960,23 @@ So in this case, here is what will happen:
959960
6. `assert-attribute` is called.
960961
7. `assert-position` is called.
961962

963+
#### device-pixel-ratio
964+
965+
**device-pixel-ratio** commands allows you to change the device scale factor. You can find more information about it [here](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio). It expected a positive non-null number (can be a float). Example:
966+
967+
```
968+
device-pixel-ratio: 1 // the default value
969+
device-pixel-ratio: 0.5
970+
```
971+
972+
You can check its value like this:
973+
974+
```
975+
// We use `STARTS_WITH` because otherwise the check would very likely fail
976+
// because of floating numbers rounding.
977+
assert-window-property: ({"devicePixelRatio": "0.5"}, [STARTS_WITH])
978+
```
979+
962980
#### drag-and-drop
963981

964982
**drag-and-drop** command allows to move an element to another place (assuming it implements the necessary JS and is draggable). It expects a tuple of two elements. Each element can be a position or a CSS selector or an XPath. Example:

src/commands.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const ORDERS = {
4444
'compare-elements-text-false': commands.parseCompareElementsTextFalse,
4545
'css': commands.parseCss,
4646
'debug': commands.parseDebug,
47+
'device-pixel-ratio': commands.parseDevicePixelRatio,
4748
'define-function': commands.parseDefineFunction,
4849
'drag-and-drop': commands.parseDragAndDrop,
4950
'emulate': commands.parseEmulate,
@@ -94,6 +95,7 @@ const FATAL_ERROR_COMMANDS = [
9495
'call-function',
9596
'click',
9697
'css',
98+
'device-pixel-ratio',
9799
'drag-and-drop',
98100
'emulate',
99101
'focus',
@@ -102,6 +104,7 @@ const FATAL_ERROR_COMMANDS = [
102104
'move-cursor-to',
103105
'screenshot',
104106
'scroll-to',
107+
'size',
105108
'store-property',
106109
'store-value',
107110
'text',

src/commands/all.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ module.exports = {
5353
'parseCss': dom_modifiers.parseCss,
5454
'parseDebug': context_setters.parseDebug,
5555
'parseDefineFunction': functions.parseDefineFunction,
56+
'parseDevicePixelRatio': emulation.parseDevicePixelRatio,
5657
'parseDragAndDrop': input.parseDragAndDrop,
5758
'parseEmulate': emulation.parseEmulate,
5859
'parseFail': context_setters.parseFail,

src/commands/emulation.js

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ function parseSize(parser) {
1212
if (elems.length === 0) {
1313
return {'error': 'expected `([number], [number])`, found nothing'};
1414
} else if (elems.length !== 1 || elems[0].kind !== 'tuple') {
15-
return {'error': `expected \`([number], [number])\`, found \`${parser.getRawArgs()}\``};
15+
return {
16+
'error': `expected \`([number], [number])\`, found \`${parser.getRawArgs()}\``,
17+
};
1618
}
1719
const ret = checkIntegerTuple(elems[0], 'width', 'height', true);
1820
if (ret.error !== undefined) {
@@ -21,7 +23,36 @@ function parseSize(parser) {
2123
const [width, height] = ret.value;
2224
return {
2325
'instructions': [
24-
`await page.setViewport({width: ${width}, height: ${height}})`,
26+
`\
27+
const viewport = page.viewport();
28+
viewport.width = ${width};
29+
viewport.height = ${height};
30+
await page.setViewport(viewport);`,
31+
],
32+
};
33+
}
34+
35+
// Possible inputs:
36+
//
37+
// * number
38+
function parseDevicePixelRatio(parser) {
39+
const elems = parser.elems;
40+
41+
if (elems.length === 0) {
42+
return {'error': 'expected a number, found nothing'};
43+
} else if (elems.length !== 1 || elems[0].kind !== 'number') {
44+
return {'error': `expected a number, found \`${parser.getRawArgs()}\``};
45+
}
46+
const ratio = elems[0].getRaw();
47+
if (Math.ceil(ratio) <= 0) {
48+
return {'error': 'device pixel ratio cannot be less than or equal to 0'};
49+
}
50+
return {
51+
'instructions': [
52+
`\
53+
const viewport = page.viewport();
54+
viewport.deviceScaleFactor = ${ratio};
55+
await page.setViewport(viewport);`,
2556
],
2657
};
2758
}
@@ -158,6 +189,7 @@ function parseFontSize(parser) {
158189
}
159190

160191
module.exports = {
192+
'parseDevicePixelRatio': parseDevicePixelRatio,
161193
'parseEmulate': parseEmulate,
162194
'parseFontSize': parseFontSize,
163195
'parseGeolocation': parseGeolocation,

tests/test-js/api.js

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5844,6 +5844,24 @@ local-storage: "ab"`,
58445844
});
58455845
}
58465846

5847+
function checkDevicePixelRatio(x, func) {
5848+
x.assert(func(''), {'error': 'expected a number, found nothing'});
5849+
x.assert(func('hello'), {'error': 'expected a number, found `hello`'});
5850+
x.assert(func('0.'), {'error': 'device pixel ratio cannot be less than or equal to 0'});
5851+
x.assert(func('-1.2'), {'error': 'device pixel ratio cannot be less than or equal to 0'});
5852+
5853+
x.assert(func('1.2'), {'instructions': [`\
5854+
const viewport = page.viewport();
5855+
viewport.deviceScaleFactor = 1.2;
5856+
await page.setViewport(viewport);`,
5857+
]});
5858+
x.assert(func('0.2'), {'instructions': [`\
5859+
const viewport = page.viewport();
5860+
viewport.deviceScaleFactor = 0.2;
5861+
await page.setViewport(viewport);`,
5862+
]});
5863+
}
5864+
58475865
function checkDragAndDrop(x, func) {
58485866
// check tuple argument
58495867
x.assert(func('true'), {
@@ -6860,12 +6878,27 @@ function checkSize(x, func) {
68606878
x.assert(func('(-1.0,2)'), {'error': 'expected integer for width, found float: `-1.0`'});
68616879
x.assert(func('(1,2.0)'), {'error': 'expected integer for height, found float: `2.0`'});
68626880
x.assert(func('(1,-2.0)'), {'error': 'expected integer for height, found float: `-2.0`'});
6863-
x.assert(func('(1,2)'), {'instructions': ['await page.setViewport({width: 1, height: 2})']});
68646881

6865-
x.assert(func('(1,2,)'), {'instructions': ['await page.setViewport({width: 1, height: 2})']});
6882+
x.assert(func('(1,2)'), {'instructions': [`\
6883+
const viewport = page.viewport();
6884+
viewport.width = 1;
6885+
viewport.height = 2;
6886+
await page.setViewport(viewport);`,
6887+
]});
6888+
x.assert(func('(1,2,)'), {'instructions': [`\
6889+
const viewport = page.viewport();
6890+
viewport.width = 1;
6891+
viewport.height = 2;
6892+
await page.setViewport(viewport);`,
6893+
]});
68666894
// Multiline
68676895
x.assert(func('(1,\n-2.0)'), {'error': 'expected integer for height, found float: `-2.0`'});
6868-
x.assert(func('(1\n,2)'), {'instructions': ['await page.setViewport({width: 1, height: 2})']});
6896+
x.assert(func('(1\n,2)'), {'instructions': [`\
6897+
const viewport = page.viewport();
6898+
viewport.width = 1;
6899+
viewport.height = 2;
6900+
await page.setViewport(viewport);`,
6901+
]});
68696902
}
68706903

68716904
function checkStoreAttribute(x, func) {
@@ -8792,6 +8825,11 @@ const TO_CHECK = [
87928825
'func': checkDefineFunction,
87938826
'toCall': (e, o) => wrapperDefineFunction(parserFuncs.parseDefineFunction, e, o),
87948827
},
8828+
{
8829+
'name': 'device-pixel-ratio',
8830+
'func': checkDevicePixelRatio,
8831+
'toCall': (e, o) => wrapper(parserFuncs.parseDevicePixelRatio, e, o),
8832+
},
87958833
{
87968834
'name': 'drag-and-drop',
87978835
'func': checkDragAndDrop,

tests/test-js/ui.js

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const fs = require('fs');
22
const path = require('path');
3+
const os = require('os');
34
const process = require('process');
45

56
const utils = require('../../src/utils.js');
@@ -15,6 +16,30 @@ async function wrapRunTests(options = new Options()) {
1516
return ret[0];
1617
}
1718

19+
function runAsyncUiTest(x, file, output, tests_queue) {
20+
const options = new Options();
21+
options.parseArguments(['--variable', 'DOC_PATH', 'tests/html_files',
22+
'--test-files', file]);
23+
let testOutput = '';
24+
25+
const callback = x.assertTryUi(
26+
wrapRunTests,
27+
[options],
28+
output.replaceAll('$CURRENT_DIR', utils.getCurrentDir()),
29+
file,
30+
false,
31+
s => testOutput += s,
32+
).finally(() => {
33+
print(`Finished testing "${file}"`);
34+
if (testOutput.length > 0) {
35+
print(testOutput);
36+
}
37+
// We now remove the promise from the tests_queue.
38+
tests_queue.splice(tests_queue.indexOf(callback), 1);
39+
});
40+
tests_queue.push(callback);
41+
}
42+
1843
// This test ensures that the outputs looks as expected.
1944
async function compareOutput(x) {
2045
const filesToTest = [];
@@ -26,6 +51,11 @@ async function compareOutput(x) {
2651
}
2752
filesToTest.push(curPath.toString());
2853
});
54+
55+
const cpuCount = os.cpus().length / 2 + 1;
56+
process.setMaxListeners(cpuCount);
57+
const tests_queue = [];
58+
2959
for (let i = 0; i < filesToTest.length; ++i) {
3060
const file = filesToTest[i];
3161
const outputFile = file.replace('.goml', '.output');
@@ -38,17 +68,13 @@ async function compareOutput(x) {
3868
continue;
3969
}
4070

41-
const options = new Options();
42-
options.parseArguments(['--variable', 'DOC_PATH', 'tests/html_files',
43-
'--test-files', file]);
44-
45-
await x.assertTryUi(
46-
wrapRunTests,
47-
[options],
48-
output.replaceAll('$CURRENT_DIR', utils.getCurrentDir()),
49-
file,
50-
false,
51-
);
71+
runAsyncUiTest(x, file, output, tests_queue);
72+
if (tests_queue.length >= cpuCount) {
73+
await Promise.race(tests_queue);
74+
}
75+
}
76+
if (tests_queue.length > 0) {
77+
await Promise.all(tests_queue);
5278
}
5379
}
5480

tests/test-js/utils.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ function plural(x, nb) {
3333
return x;
3434
}
3535

36-
function printDiff(i, value) {
36+
function printDiff(i, value, out) {
3737
let s = '=> ';
3838
for (let count = 0; count < 34 && i < value.length; ++count) {
3939
s += value[i];
4040
i += 1;
4141
}
42-
print(s);
42+
print(s, out);
4343
}
4444

4545
class Assert {
@@ -48,7 +48,7 @@ class Assert {
4848
}
4949

5050
// `extraInfo` is used as an additional message in case the test fails.
51-
assert(value1, value2, pos, extraInfo, toJson = true) {
51+
assert(value1, value2, pos, extraInfo, toJson = true, out = undefined) {
5252
this._addTest();
5353
if (typeof value2 !== 'undefined') {
5454
if (toJson === true) {
@@ -60,20 +60,20 @@ class Assert {
6060
pos = getStackInfo(new Error().stack);
6161
}
6262
if (typeof extraInfo === 'undefined') {
63-
print(`[${pos.file}:${pos.line}] failed:`);
63+
print(`[${pos.file}:${pos.line}] failed:`, out);
6464
} else {
65-
print(`[${pos.file}:${pos.line}] failed (in ${extraInfo}):`);
65+
print(`[${pos.file}:${pos.line}] failed (in ${extraInfo}):`, out);
6666
}
67-
print(`EXPECTED: \`${value2}\`\n===============\n FOUND: \`${value1}\``);
67+
print(`EXPECTED: \`${value2}\`\n===============\n FOUND: \`${value1}\``, out);
6868
for (let i = 0; i < value1.length && i < value2.length; ++i) {
6969
if (value1[i] !== value2[i]) {
7070
i -= 8;
7171
if (i < 0) {
7272
i = 0;
7373
}
74-
print('|||||> Error happened around there:');
75-
printDiff(i, value2);
76-
printDiff(i, value1);
74+
print('|||||> Error happened around there:', out);
75+
printDiff(i, value2, out);
76+
printDiff(i, value1, out);
7777
break;
7878
}
7979
}
@@ -84,7 +84,7 @@ class Assert {
8484
if (typeof pos === 'undefined') {
8585
pos = getStackInfo(new Error().stack);
8686
}
87-
print(`[${pos.file}:${pos.line}] failed: \`${value1}\` is evalued to false`);
87+
print(`[${pos.file}:${pos.line}] failed: \`${value1}\` is evalued to false`, out);
8888
this._incrError();
8989
return false;
9090
}
@@ -133,7 +133,7 @@ class Assert {
133133
}
134134

135135
// Same as `assertTry` but handle some corner cases linked to UI tests.
136-
async assertTryUi(callback, args, expectedValue, extraInfo, toJson = true) {
136+
async assertTryUi(callback, args, expectedValue, extraInfo, toJson = true, out = undefined) {
137137
const pos = getStackInfo(new Error().stack, 2);
138138
try {
139139
const ret = await callback(...args);
@@ -153,9 +153,9 @@ class Assert {
153153
}
154154
return true;
155155
}
156-
return this.assert(ret, expectedValue, pos, extraInfo, toJson);
156+
return this.assert(ret, expectedValue, pos, extraInfo, toJson, out);
157157
} catch (err) {
158-
return this.assert(err.message, expectedValue, pos, extraInfo, toJson);
158+
return this.assert(err.message, expectedValue, pos, extraInfo, toJson, out);
159159
}
160160
}
161161

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Check that the `device-pixel-ratio` command is working as expected.
2+
goto: "file://" + |CURRENT_DIR| + "/" + |DOC_PATH| + "/elements.html"
3+
device-pixel-ratio: 1.2
4+
assert-window-property: ({"devicePixelRatio": "1.2"}, [STARTS_WITH])
5+
device-pixel-ratio: 1.5
6+
assert-window-property: ({"devicePixelRatio": "1.5"}, [STARTS_WITH])
7+
device-pixel-ratio: -2
8+
// It should not run the next command.
9+
assert: ".whatever"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
=> Starting doc-ui tests...
2+
3+
device-pixel-ratio... FAILED
4+
[ERROR] line 7: device pixel ratio cannot be less than or equal to 0 (from command `-2`)
5+
6+
<= doc-ui tests done: 0 succeeded, 1 failed

tests/ui-tests/size.goml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Check that the `size` command is working as expected.
2+
goto: "file://" + |CURRENT_DIR| + "/" + |DOC_PATH| + "/elements.html"
3+
size: (670, 650)
4+
assert-window-property: {"innerWidth": "670", "innerHeight": "650"}
5+
size: (610, 600)
6+
assert-window-property: {"innerWidth": "610", "innerHeight": "600"}
7+
size: (-10, 0.2)
8+
// It should not run the next command.
9+
assert: ".whatever"

0 commit comments

Comments
 (0)