pagean 6.0.6 → 6.0.9

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.
@@ -32,12 +32,6 @@
32
32
  "ignoreDuplicates": true
33
33
  }
34
34
  },
35
- "reporters": [
36
- "cli",
37
- "html",
38
- "json"
39
- ],
40
- "urls": [
41
- "ignored, required to validate schema"
42
- ]
35
+ "reporters": ["cli", "html", "json"],
36
+ "urls": ["ignored, required to validate schema"]
43
37
  }
@@ -39,7 +39,11 @@ const saveExternalScript = async (script) => {
39
39
  const result = { url: script };
40
40
  try {
41
41
  const scriptUrl = new URL(script);
42
- const pathName = path.join(externalFilePath, scriptUrl.hostname, scriptUrl.pathname);
42
+ const pathName = path.join(
43
+ externalFilePath,
44
+ scriptUrl.hostname,
45
+ scriptUrl.pathname
46
+ );
43
47
  if (!fs.existsSync(pathName)) {
44
48
  // Axios will throw for any error response
45
49
  const response = await axios.get(script);
@@ -47,9 +51,8 @@ const saveExternalScript = async (script) => {
47
51
  fs.writeFileSync(pathName, response.data);
48
52
  }
49
53
  result.localFile = pathName;
50
- }
51
- catch (err) {
52
- result.error = err.message;
54
+ } catch (error) {
55
+ result.error = error.message;
53
56
  }
54
57
  return result;
55
58
  };
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * Utilities for checking page links.
5
5
  *
6
- * @module linkUtils
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
  /**
@@ -45,15 +45,14 @@ const noRetryResponses = [httpResponse.tooManyRequests];
45
45
  * @param {string} url The URL to normalize.
46
46
  * @returns {string} The normalized URL.
47
47
  */
48
- const normalizeLink = url => normalizeUrl(url,
49
- {
48
+ const normalizeLink = (url) =>
49
+ normalizeUrl(url, {
50
50
  defaultProtocol: 'https:',
51
51
  removeQueryParameters: [],
52
52
  stripHash: true,
53
53
  stripWWW: false
54
54
  });
55
55
 
56
-
57
56
  /**
58
57
  * Checks settings to determine if the provided link should be ignored.
59
58
  *
@@ -64,8 +63,8 @@ const normalizeLink = url => normalizeUrl(url,
64
63
  * @param {string} link The link to check against the ignore list.
65
64
  * @returns {boolean} True if the link should be ignored, otherwise false.
66
65
  */
67
- const ignoreLink = (settings, link) => settings.ignoredLinks && settings.ignoredLinks.includes(link);
68
-
66
+ const ignoreLink = (settings, link) =>
67
+ settings.ignoredLinks && settings.ignoredLinks.includes(link);
69
68
 
70
69
  /**
71
70
  * Checks a response to an HTTP request, either a response code or explicit error,
@@ -76,8 +75,9 @@ const ignoreLink = (settings, link) => settings.ignoredLinks && settings.ignored
76
75
  * @param {(string|number)} response The response to an HTTP request to check for failure.
77
76
  * @returns {boolean} True if failed, otherwise false.
78
77
  */
79
- const isFailedResponse = response => isNaN(response.status) || response.status >= httpResponse.badRequest;
80
-
78
+ const isFailedResponse = (response) =>
79
+ Number.isNaN(Number(response.status)) ||
80
+ response.status >= httpResponse.badRequest;
81
81
 
82
82
  /**
83
83
  * Checks a Puppeteer page for the element specified in the hash of the provided link.
@@ -98,7 +98,6 @@ const checkSamePageLink = async (page, link) => {
98
98
  return element ? httpResponse.ok : `${selector} Not Found`;
99
99
  };
100
100
 
101
-
102
101
  /**
103
102
  * Checks the provided link for validity by loading in a Puppeteer page.
104
103
  *
@@ -115,16 +114,14 @@ const checkExternalPageLinkBrowser = async (page, link) => {
115
114
  const response = await testPage.goto(link);
116
115
  status = response.status();
117
116
  await testPage.close();
118
- }
119
- catch (err) {
117
+ } catch (error) {
120
118
  // Errors are returned in the format: "ENOTFOUND at https://this.url.does.not.exist/",
121
119
  // so extract error only and remove URL
122
- status = err.message.replace(/^(.*) at .*$/, '$1');
120
+ status = error.message.replace(/^(.*) at .*$/, '$1');
123
121
  }
124
122
  return status;
125
123
  };
126
124
 
127
-
128
125
  /**
129
126
  * Checks the provided link for validity by requesting with axios. If useGet if false,
130
127
  * a HEAD request is made for efficiency. If useGet is true, a full GET request is made.
@@ -142,7 +139,10 @@ const checkExternalPageLink = async (page, link, useGet = false) => {
142
139
  const userAgent = await page.evaluate('navigator.userAgent');
143
140
 
144
141
  try {
145
- const options = { headers: { 'User-Agent': userAgent }, timeout: timeoutSeconds * msPerSec };
142
+ const options = {
143
+ headers: { 'User-Agent': userAgent },
144
+ timeout: timeoutSeconds * msPerSec
145
+ };
146
146
  // Using internal browser property since not exposed
147
147
  // eslint-disable-next-line no-underscore-dangle
148
148
  if (page.browser()._ignoreHTTPSErrors) {
@@ -152,22 +152,24 @@ const checkExternalPageLink = async (page, link, useGet = false) => {
152
152
  const httpMethod = useGet ? axios.get : axios.head;
153
153
  const response = await httpMethod(link, options);
154
154
  return response.status;
155
- }
156
- catch (err) {
155
+ } catch (error) {
157
156
  // Some servers respond invalid for head request (e.g. a lot of 405 Method
158
157
  // Not Allowed), so if a response was returned, is not a response that should
159
158
  // skip a retry (e.g. 429), and the request was head then retry with get.
160
- if (err.response && !noRetryResponses.includes(err.response.status) && !useGet) {
159
+ if (
160
+ error.response &&
161
+ !noRetryResponses.has(error.response.status) &&
162
+ !useGet
163
+ ) {
161
164
  return checkExternalPageLink(page, link, true);
162
165
  }
163
166
 
164
167
  // Axios will throw for failed response (code >= 400), so return
165
168
  // that response code or the error code if execution error
166
- return err.response ? err.response.status : err.code;
169
+ return error.response ? error.response.status : error.code;
167
170
  }
168
171
  };
169
172
 
170
-
171
173
  /**
172
174
  * Factory function returning a linkChecker object with a {@link checkLink}
173
175
  * function that caches checked link results.
@@ -176,7 +178,6 @@ const checkExternalPageLink = async (page, link, useGet = false) => {
176
178
  * @static
177
179
  * @returns {object} Link checker object.
178
180
  */
179
- // eslint-disable-next-line max-lines-per-function
180
181
  const createLinkChecker = () => {
181
182
  const checkedLinks = new Map();
182
183
 
@@ -206,18 +207,17 @@ const createLinkChecker = () => {
206
207
  return httpResponse.continue;
207
208
  }
208
209
 
209
- if (context.testSettings.ignoreDuplicates && checkedLinks.has(link)) {
210
+ if (
211
+ context.testSettings.ignoreDuplicates &&
212
+ checkedLinks.has(link)
213
+ ) {
210
214
  return checkedLinks.get(link);
211
215
  }
212
216
 
213
- if (context.testSettings.checkWithBrowser) {
214
- status = await checkExternalPageLinkBrowser(context.page, normalizedLink);
215
- }
216
- else {
217
- status = await checkExternalPageLink(context.page, normalizedLink);
218
- }
219
- }
220
- catch {
217
+ status = await (context.testSettings.checkWithBrowser
218
+ ? checkExternalPageLinkBrowser(context.page, normalizedLink)
219
+ : checkExternalPageLink(context.page, normalizedLink));
220
+ } catch {
221
221
  status = httpResponse.unknownError;
222
222
  }
223
223
 
package/lib/logger.js CHANGED
@@ -15,7 +15,7 @@ const testResultSymbols = Object.freeze({
15
15
  warning: ' ‼'
16
16
  });
17
17
 
18
- const nullFunction = () => { };
18
+ const nullFunction = () => {};
19
19
 
20
20
  /**
21
21
  * Factory function that creates an instance of a
@@ -29,7 +29,9 @@ const nullFunction = () => { };
29
29
  module.exports = (config) => {
30
30
  const cliReporter = {
31
31
  // If cli reporter is enabled, set console log function, otherwise null function
32
- log: config.reporters.includes(reporterTypes.cli) ? consoleLogger.log : nullFunction,
32
+ log: config.reporters.includes(reporterTypes.cli)
33
+ ? consoleLogger.log
34
+ : nullFunction,
33
35
  // The logAlways function provides a mechanism to log to the console even
34
36
  // when the cli reporter is disabled (e.g. returning the final results)
35
37
  logAlways: consoleLogger.log
@@ -87,7 +89,9 @@ module.exports = (config) => {
87
89
  };
88
90
 
89
91
  const outputTestSummary = () => {
90
- cliReporter.logAlways({ message: `\n Tests: ${testResults.summary.tests}\n Passed: ${testResults.summary.passed}\n Warning: ${testResults.summary.warning}\n Failed: ${testResults.summary.failed}\n` });
92
+ cliReporter.logAlways({
93
+ message: `\n Tests: ${testResults.summary.tests}\n Passed: ${testResults.summary.passed}\n Warning: ${testResults.summary.warning}\n Failed: ${testResults.summary.failed}\n`
94
+ });
91
95
  };
92
96
 
93
97
  /**
package/lib/reporter.js CHANGED
@@ -19,8 +19,10 @@ handlebars.registerHelper('json', (context) => {
19
19
  });
20
20
 
21
21
  const saveHtmlReport = (results) => {
22
- const templateFile = path.resolve(path.join(__dirname, htmlReportTemplateName));
23
- const htmlReportTemplate = fs.readFileSync(templateFile, 'utf-8');
22
+ const templateFile = path.resolve(
23
+ path.join(__dirname, htmlReportTemplateName)
24
+ );
25
+ const htmlReportTemplate = fs.readFileSync(templateFile, 'utf8');
24
26
  const template = handlebars.compile(htmlReportTemplate);
25
27
  const htmlReport = template(results);
26
28
  fs.writeFileSync(htmlReportFileName, htmlReport);
@@ -16,14 +16,25 @@ 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
- return baseKey + instancePath.split('/').slice(1).reduce((accumulator, currentValue) => {
20
- const unencodedValue = currentValue.replace(/~0/g, '~').replace(/~1/g, '/');
21
- // eslint-disable-next-line sonarjs/no-nested-template-literals -- less intuitive
22
- return `${accumulator}${isNaN(unencodedValue) ? `.${unencodedValue}` : `[${unencodedValue}]`}`;
23
- }, '');
19
+ return (
20
+ baseKey +
21
+ instancePath
22
+ .split('/')
23
+ .slice(1)
24
+ // eslint-disable-next-line unicorn/no-array-reduce -- reduce for string concatenation
25
+ .reduce((accumulator, currentValue) => {
26
+ const unencodedValue = currentValue
27
+ .replace(/~0/g, '~')
28
+ .replace(/~1/g, '/');
29
+ const encodedValue = Number.isNaN(Number(unencodedValue))
30
+ ? `.${unencodedValue}`
31
+ : `[${unencodedValue}]`;
32
+ return `${accumulator}${encodedValue}`;
33
+ }, '')
34
+ );
24
35
  };
25
36
 
26
- const processErrorParams = (error) => {
37
+ const processErrorParameters = (error) => {
27
38
  let formattedMessage = error.message;
28
39
  // Ajv includes all allowed values in params.allowedValues,
29
40
  // so add to message if available.
@@ -44,15 +55,20 @@ const processErrorParams = (error) => {
44
55
  const formatErrors = (errors) => {
45
56
  const margin = 2;
46
57
  let maxLength = 0;
47
- errors.forEach(error => {
58
+ for (const error of errors) {
48
59
  error.dataKey = getDataKey(error.instancePath);
49
- error.formattedMessage = processErrorParams(error);
60
+ error.formattedMessage = processErrorParameters(error);
50
61
  // Get max dataKey length for all errors to line up column in final output
51
62
  if (error.dataKey.length > maxLength) {
52
63
  maxLength = error.dataKey.length;
53
64
  }
54
- });
55
- return errors.map(error => ` ${error.dataKey.padEnd(maxLength + margin)}${red(error.formattedMessage)}`);
65
+ }
66
+ return errors.map(
67
+ (error) =>
68
+ ` ${error.dataKey.padEnd(maxLength + margin)}${red(
69
+ error.formattedMessage
70
+ )}`
71
+ );
56
72
  };
57
73
 
58
74
  module.exports.formatErrors = formatErrors;
@@ -14,7 +14,9 @@ const testResultStates = Object.freeze({
14
14
 
15
15
  const getTestSettings = (testSettingProperty, urlSettings) => {
16
16
  if (urlSettings[testSettingProperty] === undefined) {
17
- throw new Error(`Property '${testSettingProperty}' could not be found in test settings`);
17
+ throw new Error(
18
+ `Property '${testSettingProperty}' could not be found in test settings`
19
+ );
18
20
  }
19
21
  return urlSettings[testSettingProperty];
20
22
  };
@@ -31,19 +33,29 @@ const getTestSettings = (testSettingProperty, urlSettings) => {
31
33
  * @param {string} testSettingProperty The name of the config property
32
34
  * with settings for the current test.
33
35
  */
34
- // eslint-disable-next-line sonarjs/cognitive-complexity -- Allow < 10
35
- const pageanTest = async (name, testFunction, testContext, testSettingProperty) => {
36
- const testSettings = getTestSettings(testSettingProperty, testContext.urlSettings);
36
+ const pageanTest = async (
37
+ name,
38
+ testFunction,
39
+ testContext,
40
+ testSettingProperty
41
+ // eslint-disable-next-line sonarjs/cognitive-complexity -- Allow < 10
42
+ ) => {
43
+ const testSettings = getTestSettings(
44
+ testSettingProperty,
45
+ testContext.urlSettings
46
+ );
37
47
  testContext.testSettings = testSettings;
38
48
  if (testSettings.enabled) {
39
49
  let results;
40
50
  try {
41
51
  results = await testFunction(testContext);
52
+ } catch (error) {
53
+ results = { result: testResultStates.failed, data: { error } };
42
54
  }
43
- catch (err) {
44
- results = { result: testResultStates.failed, data: { error: err } };
45
- }
46
- if (results.result === testResultStates.failed && testSettings.failWarn) {
55
+ if (
56
+ results.result === testResultStates.failed &&
57
+ testSettings.failWarn
58
+ ) {
47
59
  results.result = testResultStates.warning;
48
60
  }
49
61
  testContext.logger.logTestResults({