@enact/ui-test-utils 0.5.4 → 0.7.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/config/wdio.conf.js +37 -2
- package/package.json +23 -24
- package/screenshot/TestChooser.js +0 -2
- package/screenshot/index.js +0 -1
- package/screenshot/utils/confHelpers.js +17 -23
- package/screenshot/wdio.conf.js +6 -7
- package/screenshot/wdio.tv.conf.js +13 -0
- package/ui/index.js +0 -1
- package/ui/wdio.docker.conf.js +1 -1
- package/ui/wdio.tv.conf.js +5 -1
- package/utils/runTest.js +17 -4
- package/utils/selector.js +5 -2
package/config/wdio.conf.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const parseArgs = require('minimist');
|
|
2
|
+
const {execSync} = require('child_process');
|
|
2
3
|
|
|
3
4
|
const args = parseArgs(process.argv);
|
|
4
5
|
|
|
@@ -14,6 +15,40 @@ module.exports.configure = (options) => {
|
|
|
14
15
|
delete opts.before;
|
|
15
16
|
delete opts.services;
|
|
16
17
|
|
|
18
|
+
if (!process.env.CHROME_DRIVER) {
|
|
19
|
+
if (process.env.TV_IP && process.argv.find(arg => arg.includes('tv.conf'))) {
|
|
20
|
+
process.env.CHROME_DRIVER = 2.44; // Currently, TV supports 83 and lower, but keep the previous version for safety.
|
|
21
|
+
} else {
|
|
22
|
+
let chromeVersionMajorNumber;
|
|
23
|
+
try {
|
|
24
|
+
if (process.platform === 'win32') {
|
|
25
|
+
// Windows
|
|
26
|
+
const chromeVersion = /\d+/.exec(execSync('wmic datafile where "name=\'C:\\\\Program Files (x86)\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe\'" get Version /value').toString());
|
|
27
|
+
chromeVersionMajorNumber = (chromeVersion && chromeVersion[0]);
|
|
28
|
+
} else if (process.platform === 'darwin') {
|
|
29
|
+
// Mac
|
|
30
|
+
const chromeVersion = /Chrome (\d+)/.exec(execSync('/Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome --version'));
|
|
31
|
+
chromeVersionMajorNumber = (chromeVersion && chromeVersion[1]);
|
|
32
|
+
} else {
|
|
33
|
+
const chromeVersion = /Chrome (\d+)/.exec(execSync('google-chrome -version'));
|
|
34
|
+
chromeVersionMajorNumber = (chromeVersion && chromeVersion[1]);
|
|
35
|
+
}
|
|
36
|
+
const chromeDriverVersion = execSync('curl https://chromedriver.storage.googleapis.com/LATEST_RELEASE' + (chromeVersionMajorNumber ? ('_' + chromeVersionMajorNumber) : ''));
|
|
37
|
+
|
|
38
|
+
if (chromeDriverVersion.includes('Error') || !/\d+.\d+.\d+.\d+/.exec(chromeDriverVersion)) {
|
|
39
|
+
throw new Error();
|
|
40
|
+
} else {
|
|
41
|
+
process.env.CHROME_DRIVER = chromeDriverVersion;
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.log('ERROR: Cannnot find Chrome driver from Chrome ' + chromeVersionMajorNumber);
|
|
45
|
+
process.env.CHROME_DRIVER = 2.44;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log('Chrome Driver Version : ' + process.env.CHROME_DRIVER);
|
|
50
|
+
}
|
|
51
|
+
|
|
17
52
|
return Object.assign(
|
|
18
53
|
opts,
|
|
19
54
|
{
|
|
@@ -138,7 +173,7 @@ module.exports.configure = (options) => {
|
|
|
138
173
|
args: {
|
|
139
174
|
drivers : {
|
|
140
175
|
chrome : {
|
|
141
|
-
version :
|
|
176
|
+
version : process.env.CHROME_DRIVER,
|
|
142
177
|
arch : process.arch
|
|
143
178
|
}
|
|
144
179
|
}
|
|
@@ -146,7 +181,7 @@ module.exports.configure = (options) => {
|
|
|
146
181
|
installArgs: {
|
|
147
182
|
drivers : {
|
|
148
183
|
chrome : {
|
|
149
|
-
version :
|
|
184
|
+
version : process.env.CHROME_DRIVER,
|
|
150
185
|
arch : process.arch,
|
|
151
186
|
baseURL : 'https://chromedriver.storage.googleapis.com'
|
|
152
187
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enact/ui-test-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "UI Testing for the Enact framework",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,40 +16,39 @@
|
|
|
16
16
|
"access": "public"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@wdio/cli": "^
|
|
20
|
-
"@wdio/dot-reporter": "^
|
|
21
|
-
"@wdio/local-runner": "^
|
|
22
|
-
"@wdio/mocha-framework": "^
|
|
23
|
-
"@wdio/selenium-standalone-service": "^
|
|
24
|
-
"@wdio/spec-reporter": "^
|
|
25
|
-
"@wdio/static-server-service": "^
|
|
26
|
-
"@wdio/sync": "^
|
|
27
|
-
"chai": "4.
|
|
28
|
-
"chalk": "^4.1.
|
|
19
|
+
"@wdio/cli": "^7.9.0",
|
|
20
|
+
"@wdio/dot-reporter": "^7.9.0",
|
|
21
|
+
"@wdio/local-runner": "^7.9.0",
|
|
22
|
+
"@wdio/mocha-framework": "^7.9.0",
|
|
23
|
+
"@wdio/selenium-standalone-service": "^7.8.0",
|
|
24
|
+
"@wdio/spec-reporter": "^7.9.0",
|
|
25
|
+
"@wdio/static-server-service": "^7.8.0",
|
|
26
|
+
"@wdio/sync": "^7.9.0",
|
|
27
|
+
"chai": "4.3.4",
|
|
28
|
+
"chalk": "^4.1.2",
|
|
29
29
|
"cross-spawn": "^7.0.3",
|
|
30
30
|
"dirty-chai": "2.0.1",
|
|
31
|
-
"expect-webdriverio": "^1.
|
|
32
|
-
"fs-extra": "^
|
|
31
|
+
"expect-webdriverio": "^3.1.0",
|
|
32
|
+
"fs-extra": "^10.0.0",
|
|
33
33
|
"minimist": "^1.2.5",
|
|
34
|
-
"query-string": "^
|
|
35
|
-
"ramda": "^0.27.
|
|
36
|
-
"readdirp": "^3.
|
|
37
|
-
"wdio-docker-service": "^
|
|
38
|
-
"wdio-
|
|
39
|
-
"webdriverio": "^
|
|
34
|
+
"query-string": "^7.0.1",
|
|
35
|
+
"ramda": "^0.27.1",
|
|
36
|
+
"readdirp": "^3.6.0",
|
|
37
|
+
"wdio-docker-service": "^3.1.2",
|
|
38
|
+
"wdio-image-comparison-service": "^3.0.0",
|
|
39
|
+
"webdriverio": "^7.9.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"babel-eslint": "^10.1.0",
|
|
43
|
-
"eslint": "^7.
|
|
44
|
-
"eslint-config-enact": "^
|
|
43
|
+
"eslint": "^7.11.0",
|
|
44
|
+
"eslint-config-enact": "^3.0.0",
|
|
45
45
|
"eslint-config-prettier": "^6.11.0",
|
|
46
46
|
"eslint-plugin-babel": "^5.3.1",
|
|
47
47
|
"eslint-plugin-enact": "^0.2.0",
|
|
48
48
|
"eslint-plugin-import": "^2.22.0",
|
|
49
49
|
"eslint-plugin-jsx-a11y": "^6.3.1",
|
|
50
50
|
"eslint-plugin-prettier": "^3.1.4",
|
|
51
|
-
"eslint-plugin-react": "^7.
|
|
52
|
-
"eslint-plugin-react-hooks": "^4.0
|
|
53
|
-
"react": "^16.8.6"
|
|
51
|
+
"eslint-plugin-react": "^7.21.5",
|
|
52
|
+
"eslint-plugin-react-hooks": "^4.2.0"
|
|
54
53
|
}
|
|
55
54
|
}
|
package/screenshot/index.js
CHANGED
|
@@ -2,7 +2,6 @@ const crypto = require('crypto'),
|
|
|
2
2
|
path = require('path'),
|
|
3
3
|
fs = require('fs');
|
|
4
4
|
|
|
5
|
-
const VisualRegressionCompare = require('wdio-novus-visual-regression-service/compare');
|
|
6
5
|
const buildApps = require('../../src/build-apps');
|
|
7
6
|
const makeHeader = require('./headerTemplate');
|
|
8
7
|
|
|
@@ -23,21 +22,18 @@ function getScreenshotName (basePath) {
|
|
|
23
22
|
|
|
24
23
|
// shorten the name with a little bit of leading context to help find the file manually if necessary
|
|
25
24
|
testName = testName.substring(0, 128) + '-' + crypto.createHash('md5').update(testName).digest('hex');
|
|
26
|
-
|
|
27
|
-
return
|
|
25
|
+
let screenshotFileName = path.join(basePath, ...testNameParts, `${testName}.png`);
|
|
26
|
+
return screenshotFileName.replace(/ /g, '_');
|
|
28
27
|
};
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
const distPath = path.join(process.cwd(), 'tests', 'screenshot', 'dist');
|
|
31
|
+
const baselineRelativePath = 'screenshots/reference';
|
|
32
|
+
const screenshotRelativePath = 'screenshots/screen';
|
|
33
|
+
const baselineFolder = path.join(distPath, baselineRelativePath);
|
|
34
|
+
const screenshotFolder = path.join(distPath, screenshotRelativePath);
|
|
34
35
|
|
|
35
|
-
const
|
|
36
|
-
referenceName: generateReferenceName,
|
|
37
|
-
screenshotName: generateScreenshotName,
|
|
38
|
-
diffName: generateDiffName,
|
|
39
|
-
misMatchTolerance: 0.005
|
|
40
|
-
});
|
|
36
|
+
const generateReferenceName = getScreenshotName(baselineFolder);
|
|
41
37
|
|
|
42
38
|
function initFile (name, content) {
|
|
43
39
|
const dir = path.dirname(name);
|
|
@@ -77,16 +73,16 @@ function beforeTest (testData) {
|
|
|
77
73
|
function afterTest (testData, _context, {passed}) {
|
|
78
74
|
// If this doesn't include context data, not a screenshot test
|
|
79
75
|
if (testData && testData.title && testData.context && testData.context.params) {
|
|
76
|
+
const fileName = testData.context.fileName.replace(/ /g, '_') + '.png';
|
|
77
|
+
const referencePath = path.join(baselineRelativePath, fileName);
|
|
78
|
+
|
|
80
79
|
if (_context.isNewScreenshot) {
|
|
81
|
-
const filename = generateReferenceName({test: testData});
|
|
82
80
|
fs.open(newScreenshotFilename, 'a', (err, fd) => {
|
|
83
|
-
const distPath = path.join(process.cwd(), 'tests', 'screenshot', 'dist'),
|
|
84
|
-
relativeName = path.relative(distPath, filename);
|
|
85
81
|
if (err) {
|
|
86
82
|
console.error('Unable to create log file!');
|
|
87
83
|
} else {
|
|
88
84
|
const {params, url} = testData.context;
|
|
89
|
-
const output = {title: testData.title.replace(/~\//g, '/'), path:
|
|
85
|
+
const output = {title: testData.title.replace(/~\//g, '/'), path: referencePath, params, url};
|
|
90
86
|
fs.appendFile(fd, `${JSON.stringify(output)},`, 'utf8', () => {
|
|
91
87
|
fs.close(fd);
|
|
92
88
|
});
|
|
@@ -95,11 +91,9 @@ function afterTest (testData, _context, {passed}) {
|
|
|
95
91
|
}
|
|
96
92
|
|
|
97
93
|
if (!passed) {
|
|
94
|
+
const screenPath = path.join(screenshotRelativePath, 'actual', fileName);
|
|
95
|
+
const diffPath = path.join(screenshotRelativePath, 'diff', fileName);
|
|
98
96
|
fs.open(failedScreenshotFilename, 'a', (err, fd) => {
|
|
99
|
-
const distPath = path.join(process.cwd(), 'tests', 'screenshot', 'dist'),
|
|
100
|
-
diffPath = path.relative(distPath, generateDiffName({test: testData})),
|
|
101
|
-
referencePath = path.relative(distPath, generateReferenceName({test: testData})),
|
|
102
|
-
screenPath = path.relative(distPath, generateScreenshotName({test: testData}));
|
|
103
97
|
if (err) {
|
|
104
98
|
console.error('Unable to create failed test log file!');
|
|
105
99
|
} else {
|
|
@@ -115,7 +109,6 @@ function afterTest (testData, _context, {passed}) {
|
|
|
115
109
|
}
|
|
116
110
|
}
|
|
117
111
|
|
|
118
|
-
|
|
119
112
|
function onComplete () {
|
|
120
113
|
const {size: newSize} = fs.statSync(newScreenshotFilename),
|
|
121
114
|
{size: failedSize} = fs.statSync(failedScreenshotFilename);
|
|
@@ -141,8 +134,9 @@ function onComplete () {
|
|
|
141
134
|
|
|
142
135
|
module.exports = {
|
|
143
136
|
afterTest,
|
|
137
|
+
baselineFolder,
|
|
144
138
|
beforeTest,
|
|
145
|
-
comparator,
|
|
146
139
|
onComplete,
|
|
147
|
-
onPrepare
|
|
140
|
+
onPrepare,
|
|
141
|
+
screenshotFolder
|
|
148
142
|
};
|
package/screenshot/wdio.conf.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
// const visualRegression = require('wdio-novus-visual-regression-service');
|
|
2
1
|
const {configure} = require('../config/wdio.conf.js');
|
|
3
|
-
const {afterTest,
|
|
2
|
+
const {afterTest, baselineFolder, beforeTest, onComplete, onPrepare, screenshotFolder} = require('./utils/confHelpers.js');
|
|
4
3
|
|
|
5
4
|
exports.config = configure({
|
|
6
5
|
base: 'screenshot',
|
|
7
6
|
services: [[
|
|
8
|
-
'
|
|
7
|
+
'image-comparison',
|
|
9
8
|
{
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
baselineFolder: baselineFolder,
|
|
10
|
+
formatImageName: '{tag}',
|
|
11
|
+
screenshotPath: screenshotFolder,
|
|
12
|
+
autoSaveBaseline: true
|
|
14
13
|
}
|
|
15
14
|
]],
|
|
16
15
|
//
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
const ipAddress = require('../utils/ipAddress.js');
|
|
2
2
|
const {config} = require('./wdio.conf.js');
|
|
3
3
|
|
|
4
|
+
const services = config.services.map(service => {
|
|
5
|
+
if (service[0] === 'novus-visual-regression') {
|
|
6
|
+
delete service[1].viewports;
|
|
7
|
+
}
|
|
8
|
+
return service;
|
|
9
|
+
});
|
|
10
|
+
|
|
4
11
|
exports.config = Object.assign(
|
|
5
12
|
{},
|
|
6
13
|
config,
|
|
7
14
|
{
|
|
15
|
+
services,
|
|
16
|
+
|
|
8
17
|
// ============
|
|
9
18
|
// Capabilities
|
|
10
19
|
// ============
|
|
@@ -25,6 +34,7 @@ exports.config = Object.assign(
|
|
|
25
34
|
//
|
|
26
35
|
browserName: 'chrome',
|
|
27
36
|
'goog:chromeOptions': {
|
|
37
|
+
w3c: false,
|
|
28
38
|
debuggerAddress: `${process.env.TV_IP}:9998`
|
|
29
39
|
}
|
|
30
40
|
}],
|
|
@@ -44,6 +54,9 @@ exports.config = Object.assign(
|
|
|
44
54
|
if (config.before) {
|
|
45
55
|
config.before();
|
|
46
56
|
}
|
|
57
|
+
|
|
58
|
+
browser._options = {remote: true};
|
|
59
|
+
|
|
47
60
|
// Have to stub out these methods to prevent exceptions when running against
|
|
48
61
|
// remote chrome session
|
|
49
62
|
browser.setViewportSize = () => Promise.resolve({height: 1080, width: 1920});
|
package/ui/index.js
CHANGED
package/ui/wdio.docker.conf.js
CHANGED
|
@@ -3,7 +3,7 @@ const {config} = require('./wdio.conf.js');
|
|
|
3
3
|
|
|
4
4
|
// Remove selenium-standalone and replace with docker service
|
|
5
5
|
const services = config.services
|
|
6
|
-
.filter(service => service !== 'selenium-standalone')
|
|
6
|
+
.filter(service => service[0] !== 'selenium-standalone')
|
|
7
7
|
.concat(['docker']);
|
|
8
8
|
|
|
9
9
|
exports.config = Object.assign(
|
package/ui/wdio.tv.conf.js
CHANGED
|
@@ -10,6 +10,7 @@ exports.config = Object.assign(
|
|
|
10
10
|
|
|
11
11
|
browserName: 'chrome',
|
|
12
12
|
'goog:chromeOptions': {
|
|
13
|
+
w3c: false,
|
|
13
14
|
debuggerAddress: `${process.env.TV_IP}:9998`
|
|
14
15
|
}
|
|
15
16
|
}],
|
|
@@ -17,7 +18,10 @@ exports.config = Object.assign(
|
|
|
17
18
|
baseUrl: `http://${ipAddress()}:4567`,
|
|
18
19
|
|
|
19
20
|
before: function () {
|
|
20
|
-
if (config.before)
|
|
21
|
+
if (config.before) {
|
|
22
|
+
config.before();
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
browser._options = {remote: true};
|
|
22
26
|
}
|
|
23
27
|
}
|
package/utils/runTest.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
const crypto = require('crypto');
|
|
2
3
|
const parseArgs = require('minimist');
|
|
3
4
|
|
|
4
5
|
const args = parseArgs(process.argv);
|
|
@@ -48,12 +49,24 @@ const runTest = ({concurrency, filter, Page, testName, ...rest}) => {
|
|
|
48
49
|
testId
|
|
49
50
|
}, rest));
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
const testNameParts = testCase.title.split('~/');
|
|
53
|
+
let testCaseName = testNameParts.pop();
|
|
54
|
+
// Replace problematic filenames. Windows is much more restrictive.
|
|
55
|
+
testCaseName = testCaseName.replace(/[/\\:?*"|<>]/g, '_');
|
|
56
|
+
// shorten the name with a little bit of leading context to help find the file manually if necessary
|
|
57
|
+
testCaseName = testCaseName.substring(0, 128) + '-' + crypto.createHash('md5').update(testCaseName).digest('hex');
|
|
58
|
+
const screenshotFileName = (component + '/' + testName + '/' + testCaseName);
|
|
52
59
|
|
|
53
|
-
const context = {params, component, testName, url: Page.url};
|
|
60
|
+
const context = {params, component, testName, url: Page.url, fileName: screenshotFileName};
|
|
54
61
|
this.test.context = context;
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
|
|
63
|
+
Page.open(`?${params}`);
|
|
64
|
+
|
|
65
|
+
expect(browser.checkScreen(screenshotFileName, {
|
|
66
|
+
disableCSSAnimation: true,
|
|
67
|
+
ignoreNothing: true,
|
|
68
|
+
rawMisMatchPercentage: true
|
|
69
|
+
})).to.equal(0);
|
|
57
70
|
});
|
|
58
71
|
});
|
|
59
72
|
});
|
package/utils/selector.js
CHANGED
|
@@ -47,8 +47,11 @@ function expectOrdering (firstElement, secondElement) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
const hasClass = curry((className, el) => {
|
|
50
|
-
if (className[0] === '.')
|
|
51
|
-
|
|
50
|
+
if (className[0] === '.') {
|
|
51
|
+
className = className.slice(1);
|
|
52
|
+
}
|
|
53
|
+
const elementClass = el.getAttribute('className') || el.getAttribute('class');
|
|
54
|
+
return elementClass.includes(className);
|
|
52
55
|
});
|
|
53
56
|
|
|
54
57
|
module.exports = {
|