pagean 6.0.7 → 6.0.8
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/bin/pagean.js +2 -2
- package/bin/pageanrc-lint.js +6 -4
- package/index.js +3 -3
- package/lib/config.js +1 -1
- package/lib/{externalFileUtils.js → external-file-utils.js} +2 -2
- package/lib/{linkUtils.js → link-utils.js} +11 -15
- package/lib/{schemaErrors.js → schema-errors.js} +8 -6
- package/lib/{testUtils.js → test-utils.js} +2 -2
- package/lib/tests.js +3 -3
- package/package.json +10 -10
package/bin/pagean.js
CHANGED
|
@@ -20,6 +20,6 @@ try {
|
|
|
20
20
|
const config = getConfig(options.config);
|
|
21
21
|
pagean.executeAllTests(config);
|
|
22
22
|
}
|
|
23
|
-
catch (
|
|
24
|
-
log({ message: `Error executing pagean tests\n${
|
|
23
|
+
catch (error) {
|
|
24
|
+
log({ message: `Error executing pagean tests\n${error.message}`, level: levels.error, exitOnError: true, errorCode: 1 });
|
|
25
25
|
}
|
package/bin/pageanrc-lint.js
CHANGED
|
@@ -5,7 +5,7 @@ const { log, levels } = require('ci-logger');
|
|
|
5
5
|
const program = require('commander');
|
|
6
6
|
const { green, underline } = require('kleur');
|
|
7
7
|
const { lintConfigFile } = require('../lib/config');
|
|
8
|
-
const { formatErrors } = require('../lib/
|
|
8
|
+
const { formatErrors } = require('../lib/schema-errors');
|
|
9
9
|
const pkg = require('../package.json');
|
|
10
10
|
|
|
11
11
|
const defaultConfigFileName = './.pageanrc.json';
|
|
@@ -37,7 +37,9 @@ const outputConsoleResults = (configFileName, lintResults) => {
|
|
|
37
37
|
}
|
|
38
38
|
else {
|
|
39
39
|
logError(`\n${underline(configFileName)}`, false);
|
|
40
|
-
formatErrors(lintResults.errors)
|
|
40
|
+
for (const error of formatErrors(lintResults.errors)) {
|
|
41
|
+
logError(error, false);
|
|
42
|
+
}
|
|
41
43
|
// Add line for spacing and error exits process
|
|
42
44
|
logError('');
|
|
43
45
|
}
|
|
@@ -54,6 +56,6 @@ try {
|
|
|
54
56
|
outputConsoleResults(configFileName, lintResults);
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
|
-
catch (
|
|
58
|
-
logError(`Error linting pageanrc file\n${
|
|
59
|
+
catch (error) {
|
|
60
|
+
logError(`Error linting pageanrc file\n${error.message}`);
|
|
59
61
|
}
|
package/index.js
CHANGED
|
@@ -10,7 +10,7 @@ const puppeteer = require('puppeteer');
|
|
|
10
10
|
const testLogger = require('./lib/logger');
|
|
11
11
|
const testReporter = require('./lib/reporter');
|
|
12
12
|
const { ...testFunctions } = require('./lib/tests');
|
|
13
|
-
const { createLinkChecker } = require('./lib/
|
|
13
|
+
const { createLinkChecker } = require('./lib/link-utils');
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Executes Pagean tests as specified in config and reports results.
|
|
@@ -30,7 +30,7 @@ const executeAllTests = async (config) => {
|
|
|
30
30
|
const page = await browser.newPage();
|
|
31
31
|
// Object property names defined by puppeteer API
|
|
32
32
|
// eslint-disable-next-line no-underscore-dangle
|
|
33
|
-
page.on('console',
|
|
33
|
+
page.on('console', message => consoleLog.push({ _type: message._type, _text: message._text, _stackTraceLocations: message._stackTraceLocations }));
|
|
34
34
|
await page.goto(testUrl.url, { waitUntil: 'load' });
|
|
35
35
|
|
|
36
36
|
const testContext = {
|
|
@@ -49,7 +49,7 @@ const executeAllTests = async (config) => {
|
|
|
49
49
|
|
|
50
50
|
if (testResults.summary.failed > 0) {
|
|
51
51
|
// For test harness want process to exit with error code
|
|
52
|
-
// eslint-disable-next-line no-process-exit, no-magic-numbers
|
|
52
|
+
// eslint-disable-next-line unicorn/no-process-exit, no-process-exit, no-magic-numbers
|
|
53
53
|
process.exit(2);
|
|
54
54
|
}
|
|
55
55
|
};
|
package/lib/config.js
CHANGED
|
@@ -12,7 +12,7 @@ const Ajv = require('ajv').default;
|
|
|
12
12
|
const ajvErrors = require('ajv-errors');
|
|
13
13
|
const protocolify = require('protocolify');
|
|
14
14
|
|
|
15
|
-
const { normalizeLink } = require('./
|
|
15
|
+
const { normalizeLink } = require('./link-utils');
|
|
16
16
|
|
|
17
17
|
const defaultConfig = require('./default-config.json');
|
|
18
18
|
const defaultHtmlHintConfigFilename = './.htmlhintrc';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Utilities for checking page links.
|
|
5
5
|
*
|
|
6
|
-
* @module
|
|
6
|
+
* @module link-utils
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const https = require('https');
|
|
@@ -29,7 +29,7 @@ const httpResponse = Object.freeze({
|
|
|
29
29
|
unknownError: 999
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
const noRetryResponses = [httpResponse.tooManyRequests];
|
|
32
|
+
const noRetryResponses = new Set([httpResponse.tooManyRequests]);
|
|
33
33
|
|
|
34
34
|
// eslint-disable-next-line jsdoc/require-description-complete-sentence
|
|
35
35
|
/**
|
|
@@ -76,7 +76,7 @@ const ignoreLink = (settings, link) => settings.ignoredLinks && settings.ignored
|
|
|
76
76
|
* @param {(string|number)} response The response to an HTTP request to check for failure.
|
|
77
77
|
* @returns {boolean} True if failed, otherwise false.
|
|
78
78
|
*/
|
|
79
|
-
const isFailedResponse = response => isNaN(response.status) || response.status >= httpResponse.badRequest;
|
|
79
|
+
const isFailedResponse = response => Number.isNaN(Number(response.status)) || response.status >= httpResponse.badRequest;
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
/**
|
|
@@ -116,10 +116,10 @@ const checkExternalPageLinkBrowser = async (page, link) => {
|
|
|
116
116
|
status = response.status();
|
|
117
117
|
await testPage.close();
|
|
118
118
|
}
|
|
119
|
-
catch (
|
|
119
|
+
catch (error) {
|
|
120
120
|
// Errors are returned in the format: "ENOTFOUND at https://this.url.does.not.exist/",
|
|
121
121
|
// so extract error only and remove URL
|
|
122
|
-
status =
|
|
122
|
+
status = error.message.replace(/^(.*) at .*$/, '$1');
|
|
123
123
|
}
|
|
124
124
|
return status;
|
|
125
125
|
};
|
|
@@ -153,17 +153,17 @@ const checkExternalPageLink = async (page, link, useGet = false) => {
|
|
|
153
153
|
const response = await httpMethod(link, options);
|
|
154
154
|
return response.status;
|
|
155
155
|
}
|
|
156
|
-
catch (
|
|
156
|
+
catch (error) {
|
|
157
157
|
// Some servers respond invalid for head request (e.g. a lot of 405 Method
|
|
158
158
|
// Not Allowed), so if a response was returned, is not a response that should
|
|
159
159
|
// skip a retry (e.g. 429), and the request was head then retry with get.
|
|
160
|
-
if (
|
|
160
|
+
if (error.response && !noRetryResponses.has(error.response.status) && !useGet) {
|
|
161
161
|
return checkExternalPageLink(page, link, true);
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
// Axios will throw for failed response (code >= 400), so return
|
|
165
165
|
// that response code or the error code if execution error
|
|
166
|
-
return
|
|
166
|
+
return error.response ? error.response.status : error.code;
|
|
167
167
|
}
|
|
168
168
|
};
|
|
169
169
|
|
|
@@ -176,7 +176,6 @@ const checkExternalPageLink = async (page, link, useGet = false) => {
|
|
|
176
176
|
* @static
|
|
177
177
|
* @returns {object} Link checker object.
|
|
178
178
|
*/
|
|
179
|
-
// eslint-disable-next-line max-lines-per-function
|
|
180
179
|
const createLinkChecker = () => {
|
|
181
180
|
const checkedLinks = new Map();
|
|
182
181
|
|
|
@@ -210,12 +209,9 @@ const createLinkChecker = () => {
|
|
|
210
209
|
return checkedLinks.get(link);
|
|
211
210
|
}
|
|
212
211
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
else {
|
|
217
|
-
status = await checkExternalPageLink(context.page, normalizedLink);
|
|
218
|
-
}
|
|
212
|
+
status = await (context.testSettings.checkWithBrowser
|
|
213
|
+
? checkExternalPageLinkBrowser(context.page, normalizedLink)
|
|
214
|
+
: checkExternalPageLink(context.page, normalizedLink));
|
|
219
215
|
}
|
|
220
216
|
catch {
|
|
221
217
|
status = httpResponse.unknownError;
|
|
@@ -16,14 +16,16 @@ const getDataKey = (instancePath) => {
|
|
|
16
16
|
// Convert pointer to key be splitting by /, removing first value (since pointer
|
|
17
17
|
// starts with /, so empty), unencoding values, and the re-assembling with different
|
|
18
18
|
// formatting for numeric array indices versus properties.
|
|
19
|
+
// eslint-disable-next-line unicorn/no-array-reduce -- reduce for string concatenation
|
|
19
20
|
return baseKey + instancePath.split('/').slice(1).reduce((accumulator, currentValue) => {
|
|
21
|
+
// eslint-disable-next-line unicorn/prefer-string-replace-all -- requires Node 15
|
|
20
22
|
const unencodedValue = currentValue.replace(/~0/g, '~').replace(/~1/g, '/');
|
|
21
|
-
|
|
22
|
-
return `${accumulator}${
|
|
23
|
+
const encodedValue = Number.isNaN(Number(unencodedValue)) ? `.${unencodedValue}` : `[${unencodedValue}]`;
|
|
24
|
+
return `${accumulator}${encodedValue}`;
|
|
23
25
|
}, '');
|
|
24
26
|
};
|
|
25
27
|
|
|
26
|
-
const
|
|
28
|
+
const processErrorParameters = (error) => {
|
|
27
29
|
let formattedMessage = error.message;
|
|
28
30
|
// Ajv includes all allowed values in params.allowedValues,
|
|
29
31
|
// so add to message if available.
|
|
@@ -44,14 +46,14 @@ const processErrorParams = (error) => {
|
|
|
44
46
|
const formatErrors = (errors) => {
|
|
45
47
|
const margin = 2;
|
|
46
48
|
let maxLength = 0;
|
|
47
|
-
|
|
49
|
+
for (const error of errors) {
|
|
48
50
|
error.dataKey = getDataKey(error.instancePath);
|
|
49
|
-
error.formattedMessage =
|
|
51
|
+
error.formattedMessage = processErrorParameters(error);
|
|
50
52
|
// Get max dataKey length for all errors to line up column in final output
|
|
51
53
|
if (error.dataKey.length > maxLength) {
|
|
52
54
|
maxLength = error.dataKey.length;
|
|
53
55
|
}
|
|
54
|
-
}
|
|
56
|
+
}
|
|
55
57
|
return errors.map(error => ` ${error.dataKey.padEnd(maxLength + margin)}${red(error.formattedMessage)}`);
|
|
56
58
|
};
|
|
57
59
|
|
|
@@ -40,8 +40,8 @@ const pageanTest = async (name, testFunction, testContext, testSettingProperty)
|
|
|
40
40
|
try {
|
|
41
41
|
results = await testFunction(testContext);
|
|
42
42
|
}
|
|
43
|
-
catch (
|
|
44
|
-
results = { result: testResultStates.failed, data: { error
|
|
43
|
+
catch (error) {
|
|
44
|
+
results = { result: testResultStates.failed, data: { error } };
|
|
45
45
|
}
|
|
46
46
|
if (results.result === testResultStates.failed && testSettings.failWarn) {
|
|
47
47
|
results.result = testResultStates.warning;
|
package/lib/tests.js
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
const { HTMLHint } = require('htmlhint');
|
|
9
9
|
|
|
10
|
-
const { testResultStates, pageanTest } = require('./
|
|
11
|
-
const fileUtils = require('./
|
|
12
|
-
const { isFailedResponse } = require('./
|
|
10
|
+
const { testResultStates, pageanTest } = require('./test-utils');
|
|
11
|
+
const fileUtils = require('./external-file-utils');
|
|
12
|
+
const { isFailedResponse } = require('./link-utils');
|
|
13
13
|
|
|
14
14
|
const msPerSec = 1000;
|
|
15
15
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pagean",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.8",
|
|
4
4
|
"description": "Pagean is a web page analysis tool designed to automate tests requiring web pages to be loaded in a browser window (e.g. horizontal scrollbar, console errors)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"pagean": "./bin/pagean.js",
|
|
@@ -46,29 +46,29 @@
|
|
|
46
46
|
"bugs": {
|
|
47
47
|
"url": "https://gitlab.com/gitlab-ci-utils/pagean/issues"
|
|
48
48
|
},
|
|
49
|
-
"homepage": "https://gitlab.com/gitlab-ci-utils/pagean
|
|
49
|
+
"homepage": "https://gitlab.com/gitlab-ci-utils/pagean",
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@aarongoldenthal/eslint-config-standard": "^
|
|
51
|
+
"@aarongoldenthal/eslint-config-standard": "^12.0.2",
|
|
52
52
|
"@aarongoldenthal/stylelint-config-standard": "^7.0.0",
|
|
53
53
|
"bin-tester": "^2.0.1",
|
|
54
|
-
"eslint": "^8.
|
|
54
|
+
"eslint": "^8.12.0",
|
|
55
55
|
"jest": "^27.5.1",
|
|
56
56
|
"jest-junit": "^13.0.0",
|
|
57
57
|
"markdownlint-cli": "^0.31.1",
|
|
58
58
|
"strip-ansi": "^6.0.1",
|
|
59
|
-
"stylelint": "^14.
|
|
59
|
+
"stylelint": "^14.6.1"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"ajv": "^8.
|
|
62
|
+
"ajv": "^8.11.0",
|
|
63
63
|
"ajv-errors": "^3.0.0",
|
|
64
|
-
"axios": "^0.
|
|
64
|
+
"axios": "^0.26.1",
|
|
65
65
|
"ci-logger": "^4.0.1",
|
|
66
|
-
"commander": "^9.
|
|
66
|
+
"commander": "^9.1.0",
|
|
67
67
|
"handlebars": "^4.7.7",
|
|
68
|
-
"htmlhint": "^1.1.
|
|
68
|
+
"htmlhint": "^1.1.3",
|
|
69
69
|
"kleur": "^4.1.4",
|
|
70
70
|
"normalize-url": "^6.1.0",
|
|
71
71
|
"protocolify": "^3.0.0",
|
|
72
|
-
"puppeteer": "^13.
|
|
72
|
+
"puppeteer": "^13.5.1"
|
|
73
73
|
}
|
|
74
74
|
}
|