pagean 6.0.4 → 6.0.5

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2019 - 2021 Aaron Goldenthal
3
+ Copyright (c) 2019 - 2022 Aaron Goldenthal
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/index.js CHANGED
@@ -1,5 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ * Pagean test framework.
5
+ *
6
+ * @module pagean
7
+ */
3
8
  const puppeteer = require('puppeteer');
4
9
 
5
10
  const testLogger = require('./lib/logger');
@@ -7,7 +12,12 @@ const testReporter = require('./lib/reporter');
7
12
  const { ...testFunctions } = require('./lib/tests');
8
13
  const { createLinkChecker } = require('./lib/linkUtils');
9
14
 
10
- // eslint-disable-next-line max-lines-per-function
15
+ /**
16
+ * Executes Pagean tests as specified in config and reports results.
17
+ *
18
+ * @static
19
+ * @param {object} config The Pagean test configuration.
20
+ */
11
21
  const executeAllTests = async (config) => {
12
22
  const logger = testLogger(config);
13
23
  const linkChecker = createLinkChecker();
@@ -23,8 +33,10 @@ const executeAllTests = async (config) => {
23
33
  page.on('console', msg => consoleLog.push({ _type: msg._type, _text: msg._text, _stackTraceLocations: msg._stackTraceLocations }));
24
34
  await page.goto(testUrl.url, { waitUntil: 'load' });
25
35
 
26
- const testContext = { page, consoleLog,
27
- urlSettings: { ...testUrl.settings, htmlHintConfig: config.htmlHintConfig }, logger, linkChecker };
36
+ const testContext = {
37
+ page, consoleLog,
38
+ urlSettings: { ...testUrl.settings, htmlHintConfig: config.htmlHintConfig }, logger, linkChecker
39
+ };
28
40
  for (const test of Object.keys(testFunctions)) {
29
41
  await testFunctions[test](testContext);
30
42
  }
package/lib/config.js CHANGED
@@ -1,5 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ * Functions for managing Pagean config files.
5
+ *
6
+ * @module config
7
+ */
8
+
3
9
  const fs = require('fs');
4
10
  const path = require('path');
5
11
  const Ajv = require('ajv').default;
@@ -86,6 +92,14 @@ const getConfigFromFile = (configFileName) => {
86
92
  return JSON.parse(fs.readFileSync(configFileName, 'utf-8'));
87
93
  };
88
94
 
95
+ /**
96
+ * Loads config from file and returns consolidated config with
97
+ * defaults where values are not specified.
98
+ *
99
+ * @static
100
+ * @param {string} configFileName Pagean configuration file name.
101
+ * @returns {object} Consolidated Pagean configuration.
102
+ */
89
103
  const processConfig = (configFileName) => {
90
104
  const config = getConfigFromFile(configFileName);
91
105
  const { isValid } = validateConfigSchema(config);
@@ -101,6 +115,13 @@ const processConfig = (configFileName) => {
101
115
  };
102
116
  };
103
117
 
118
+ /**
119
+ * Lints the configuration file schema.
120
+ *
121
+ * @static
122
+ * @param {string} configFileName Pagean configuration file name.
123
+ * @returns {boolean} True if file has valid Pagean config schema.
124
+ */
104
125
  const lintConfigFile = (configFileName) => {
105
126
  const config = getConfigFromFile(configFileName);
106
127
  return validateConfigSchema(config);
@@ -1,5 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ * Utilities for checking external JavaScript files.
5
+ *
6
+ * @module external-file-utils
7
+ */
3
8
  const fs = require('fs');
4
9
  const path = require('path');
5
10
 
@@ -7,12 +12,29 @@ const axios = require('axios');
7
12
 
8
13
  const externalFilePath = 'pagean-external-scripts';
9
14
 
15
+ /**
16
+ * Checks if the JavaScript is external to the page and should be saved.
17
+ *
18
+ * @static
19
+ * @param {string} script The URL of the JavaScript file.
20
+ * @param {string} page The URL of the current page.
21
+ * @returns {boolean} True if the script is external to the page.
22
+ */
10
23
  const shouldSaveFile = (script, page) => {
11
24
  const scriptUrl = new URL(script);
12
25
  const pageUrl = new URL(page);
13
26
  return scriptUrl.host !== pageUrl.host;
14
27
  };
15
28
 
29
+ /**
30
+ * Loads the JavaScript file from the specified URL and
31
+ * saves it to disc.
32
+ *
33
+ * @static
34
+ * @param {string} script The URL of the JavaScript file.
35
+ * @returns {object} An object with original script
36
+ * URL and local file name.
37
+ */
16
38
  const saveExternalScript = async (script) => {
17
39
  const result = { url: script };
18
40
  try {
package/lib/linkUtils.js CHANGED
@@ -1,6 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  /**
4
+ * Utilities for checking page links.
5
+ *
4
6
  * @module linkUtils
5
7
  */
6
8
 
@@ -12,7 +14,7 @@ const msPerSec = 1000;
12
14
  const timeoutSeconds = 120;
13
15
 
14
16
  /**
15
- * Enum for HTTP responses
17
+ * Enum for HTTP responses.
16
18
  *
17
19
  * @public
18
20
  * @readonly
@@ -29,6 +31,7 @@ const httpResponse = Object.freeze({
29
31
 
30
32
  const noRetryResponses = [httpResponse.tooManyRequests];
31
33
 
34
+ // eslint-disable-next-line jsdoc/require-description-complete-sentence
32
35
  /**
33
36
  * Normalizes a URL with https://www.npmjs.com/package/normalize-url
34
37
  * using defaults plus the following overrides:
@@ -38,8 +41,9 @@ const noRetryResponses = [httpResponse.tooManyRequests];
38
41
  * 4. Do not strip "www." from the URL
39
42
  *
40
43
  * @public
41
- * @param {string} url The URL to normalize
42
- * @returns {string} The normalized URL
44
+ * @static
45
+ * @param {string} url The URL to normalize.
46
+ * @returns {string} The normalized URL.
43
47
  */
44
48
  const normalizeLink = url => normalizeUrl(url,
45
49
  {
@@ -51,13 +55,14 @@ const normalizeLink = url => normalizeUrl(url,
51
55
 
52
56
 
53
57
  /**
54
- * Checks settings to determine if the provided link should be ignored
58
+ * Checks settings to determine if the provided link should be ignored.
55
59
  *
56
60
  * @private
57
- * @param {Object} settings Test settings object, which may contain an
58
- * ignoredLinks array
59
- * @param {string} link The link to check against the ignore list
60
- * @returns {boolean} True if the link should be ignored, otherwise false
61
+ * @static
62
+ * @param {object} settings Test settings object, which may contain an
63
+ * ignoredLinks array.
64
+ * @param {string} link The link to check against the ignore list.
65
+ * @returns {boolean} True if the link should be ignored, otherwise false.
61
66
  */
62
67
  const ignoreLink = (settings, link) => settings.ignoredLinks && settings.ignoredLinks.includes(link);
63
68
 
@@ -67,8 +72,9 @@ const ignoreLink = (settings, link) => settings.ignoredLinks && settings.ignored
67
72
  * to identify any failed responses.
68
73
  *
69
74
  * @public
70
- * @param {(string|number)} response The response to an HTTP request to check for failure.
71
- * @returns {boolean} True if failed, otherwise false
75
+ * @static
76
+ * @param {(string|number)} response The response to an HTTP request to check for failure.
77
+ * @returns {boolean} True if failed, otherwise false.
72
78
  */
73
79
  const isFailedResponse = response => isNaN(response.status) || response.status >= httpResponse.badRequest;
74
80
 
@@ -77,9 +83,10 @@ const isFailedResponse = response => isNaN(response.status) || response.status >
77
83
  * Checks a Puppeteer page for the element specified in the hash of the provided link.
78
84
  *
79
85
  * @private
80
- * @param {Object} page A Puppeteer page object
81
- * @param {string} link The link to check
82
- * @returns {(string|number)} The link status (HTTP response code or error)
86
+ * @static
87
+ * @param {object} page A Puppeteer page object.
88
+ * @param {string} link The link to check.
89
+ * @returns {(string|number)} The link status (HTTP response code or error).
83
90
  */
84
91
  const checkSamePageLink = async (page, link) => {
85
92
  const selector = link.slice(page.url().length);
@@ -96,9 +103,10 @@ const checkSamePageLink = async (page, link) => {
96
103
  * Checks the provided link for validity by loading in a Puppeteer page.
97
104
  *
98
105
  * @private
99
- * @param {Object} page A Puppeteer page object
100
- * @param {string} link The link to check
101
- * @returns {(string|number)} The link status (HTTP response code or error)
106
+ * @static
107
+ * @param {object} page A Puppeteer page object.
108
+ * @param {string} link The link to check.
109
+ * @returns {(string|number)} The link status (HTTP response code or error).
102
110
  */
103
111
  const checkExternalPageLinkBrowser = async (page, link) => {
104
112
  let status;
@@ -122,10 +130,11 @@ const checkExternalPageLinkBrowser = async (page, link) => {
122
130
  * a HEAD request is made for efficiency. If useGet is true, a full GET request is made.
123
131
  *
124
132
  * @private
125
- * @param {Object} page A Puppeteer page object
126
- * @param {string} link The link to check
127
- * @param {boolean} [useGet=false] Used to identify the request method to use (HEAD or GET)
128
- * @returns {(string|number)} The link status (HTTP response code or error)
133
+ * @static
134
+ * @param {object} page A Puppeteer page object.
135
+ * @param {string} link The link to check.
136
+ * @param {boolean} [useGet] Used to identify the request method to use (HEAD or GET).
137
+ * @returns {(string|number)} The link status (HTTP response code or error).
129
138
  */
130
139
  // eslint-disable-next-line sonarjs/cognitive-complexity -- Allow less than 10
131
140
  const checkExternalPageLink = async (page, link, useGet = false) => {
@@ -164,7 +173,8 @@ const checkExternalPageLink = async (page, link, useGet = false) => {
164
173
  * function that caches checked link results.
165
174
  *
166
175
  * @public
167
- * @returns {Object}
176
+ * @static
177
+ * @returns {object} Link checker object.
168
178
  */
169
179
  // eslint-disable-next-line max-lines-per-function
170
180
  const createLinkChecker = () => {
@@ -176,11 +186,12 @@ const createLinkChecker = () => {
176
186
  * reference to the Puppeteer page and applicable settings.
177
187
  *
178
188
  * @public
179
- * @param {Object} context A Pagean test context object
180
- * @param {string} link The link to check
181
- * @returns {(string|number)} The link status (HTTP response code or error)
189
+ * @instance
190
+ * @param {object} context A Pagean test context object.
191
+ * @param {string} link The link to check.
192
+ * @returns {(string|number)} The link status (HTTP response code or error).
182
193
  */
183
- // eslint-disable-next-line sonarjs/cognitive-complexity, max-lines-per-function
194
+ // eslint-disable-next-line sonarjs/cognitive-complexity
184
195
  checkLink: async (context, link) => {
185
196
  let status = httpResponse.unknownError;
186
197
  try {
package/lib/logger.js CHANGED
@@ -1,5 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ * Creates an instance of a logger object to manage logging functions.
5
+ *
6
+ * @module logger
7
+ */
8
+
3
9
  const consoleLogger = require('ci-logger');
4
10
  const { reporterTypes } = require('../lib/reporter');
5
11
 
@@ -11,6 +17,14 @@ const testResultSymbols = Object.freeze({
11
17
 
12
18
  const nullFunction = () => { };
13
19
 
20
+ /**
21
+ * Factory function that creates an instance of a
22
+ * logger object to manage logging functions.
23
+ *
24
+ * @static
25
+ * @param {object} config Pagean configuration.
26
+ * @returns {object} A logger object.
27
+ */
14
28
  // eslint-disable-next-line max-lines-per-function
15
29
  module.exports = (config) => {
16
30
  const cliReporter = {
@@ -34,6 +48,13 @@ module.exports = (config) => {
34
48
  };
35
49
 
36
50
  let currentUrlTests;
51
+ /**
52
+ * Indicates the start of testing the specified URL. Subsequent
53
+ * calls to logTestResults will be logged with this URL.
54
+ *
55
+ * @instance
56
+ * @param {string} url The URL being tested.
57
+ */
37
58
  const startUrlTests = (url) => {
38
59
  const urlTestResults = {
39
60
  url,
@@ -44,6 +65,13 @@ module.exports = (config) => {
44
65
  cliReporter.log({ message: `\nTesting URL: ${url}` });
45
66
  };
46
67
 
68
+ /**
69
+ * Logs test results for the current URL (indicated
70
+ * by the last call to StartUrlTests).
71
+ *
72
+ * @instance
73
+ * @param {object} testResult The test results.
74
+ */
47
75
  const logTestResults = (testResult) => {
48
76
  if (testResult) {
49
77
  currentUrlTests.tests.push(testResult);
@@ -62,6 +90,13 @@ module.exports = (config) => {
62
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` });
63
91
  };
64
92
 
93
+ /**
94
+ * Outputs the test results summary to stdout and returns
95
+ * the consolidated results for all tests.
96
+ *
97
+ * @instance
98
+ * @returns {object} The consolidated results for all tests.
99
+ */
65
100
  const getTestResults = () => {
66
101
  outputTestSummary();
67
102
  return testResults;
package/lib/reporter.js CHANGED
@@ -1,5 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ * Manages Pagean reporting.
5
+ *
6
+ * @module reporter
7
+ */
3
8
  const fs = require('fs');
4
9
  const path = require('path');
5
10
  const handlebars = require('handlebars');
@@ -31,6 +36,13 @@ const reporterTypes = Object.freeze({
31
36
  json: 'json'
32
37
  });
33
38
 
39
+ /**
40
+ * Outputs the given results with specified reporters.
41
+ *
42
+ * @static
43
+ * @param {object} results Consolidated Pagean results for a all tests.
44
+ * @param {string[]} reporters The configured reporters.
45
+ */
34
46
  const saveReports = (results, reporters) => {
35
47
  if (reporters.includes(reporterTypes.json)) {
36
48
  saveJsonReport(results);
@@ -1,5 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ * Generates formatted Pagean config schema errors for output to stdout.
5
+ *
6
+ * @module schema-errors
7
+ */
3
8
  const { red } = require('kleur');
4
9
 
5
10
  const getDataKey = (instancePath) => {
@@ -28,6 +33,14 @@ const processErrorParams = (error) => {
28
33
  return formattedMessage;
29
34
  };
30
35
 
36
+ /**
37
+ * Generates formatted schema strings for output to stdout for all
38
+ * schema errors.
39
+ *
40
+ * @static
41
+ * @param {object[]} errors Array of Pagean config schema errors.
42
+ * @returns {string[]} Array of formatted schema error strings.
43
+ */
31
44
  const formatErrors = (errors) => {
32
45
  const margin = 2;
33
46
  let maxLength = 0;
package/lib/testUtils.js CHANGED
@@ -1,5 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ * Miscellaneous test utilities.
5
+ *
6
+ * @module test-utils
7
+ */
8
+
3
9
  const testResultStates = Object.freeze({
4
10
  passed: 'passed',
5
11
  warning: 'warning',
@@ -13,8 +19,19 @@ const getTestSettings = (testSettingProperty, urlSettings) => {
13
19
  return urlSettings[testSettingProperty];
14
20
  };
15
21
 
16
- // Allow cognitive complexity les than 10
17
- // eslint-disable-next-line sonarjs/cognitive-complexity
22
+ /**
23
+ * Wrapper function for executing all Pagean tests that manages getting
24
+ * test-specific settings from configuration, passing the test context,
25
+ * and logging results.
26
+ *
27
+ * @static
28
+ * @param {string} name The name of the test.
29
+ * @param {Function} testFunction The test function to be executed.
30
+ * @param {object} testContext The test execution context.
31
+ * @param {string} testSettingProperty The name of the config property
32
+ * with settings for the current test.
33
+ */
34
+ // eslint-disable-next-line sonarjs/cognitive-complexity -- Allow < 10
18
35
  const pageanTest = async (name, testFunction, testContext, testSettingProperty) => {
19
36
  const testSettings = getTestSettings(testSettingProperty, testContext.urlSettings);
20
37
  testContext.testSettings = testSettings;
package/lib/tests.js CHANGED
@@ -1,5 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ * Pagean tests.
5
+ *
6
+ * @module tests
7
+ */
3
8
  const { HTMLHint } = require('htmlhint');
4
9
 
5
10
  const { testResultStates, pageanTest } = require('./testUtils');
@@ -8,6 +13,12 @@ const { isFailedResponse } = require('./linkUtils');
8
13
 
9
14
  const msPerSec = 1000;
10
15
 
16
+ /**
17
+ * Tests the current page for the existence of a horizontal scroll bar.
18
+ *
19
+ * @static
20
+ * @param {object} context Test execution context.
21
+ */
11
22
  const horizontalScrollbarTest = async (context) => {
12
23
  // eslint-disable-next-line no-shadow -- less intuitive
13
24
  await pageanTest('should not have a horizontal scrollbar', async (context) => {
@@ -20,6 +31,12 @@ const horizontalScrollbarTest = async (context) => {
20
31
  }, context, 'horizontalScrollbarTest');
21
32
  };
22
33
 
34
+ /**
35
+ * Tests the current page for any console output.
36
+ *
37
+ * @static
38
+ * @param {object} context Test execution context.
39
+ */
23
40
  const consoleOutputTest = (context) => {
24
41
  // eslint-disable-next-line no-shadow -- less intuitive
25
42
  pageanTest('should not have console output', (context) => {
@@ -31,6 +48,12 @@ const consoleOutputTest = (context) => {
31
48
  }, context, 'consoleOutputTest');
32
49
  };
33
50
 
51
+ /**
52
+ * Tests the current page for any console errors.
53
+ *
54
+ * @static
55
+ * @param {object} context Test execution context.
56
+ */
34
57
  const consoleErrorTest = (context) => {
35
58
  // eslint-disable-next-line no-shadow -- less intuitive
36
59
  pageanTest('should not have console errors', (context) => {
@@ -45,6 +68,12 @@ const consoleErrorTest = (context) => {
45
68
  }, context, 'consoleErrorTest');
46
69
  };
47
70
 
71
+ /**
72
+ * Tests the current page for any HTML lint issues.
73
+ *
74
+ * @static
75
+ * @param {object} context Test execution context.
76
+ */
48
77
  const renderedHtmlTest = async (context) => {
49
78
  // eslint-disable-next-line no-shadow -- less intuitive
50
79
  await pageanTest('should have valid rendered HTML', async (context) => {
@@ -58,6 +87,12 @@ const renderedHtmlTest = async (context) => {
58
87
  }, context, 'renderedHtmlTest');
59
88
  };
60
89
 
90
+ /**
91
+ * Tests the current page for load time.
92
+ *
93
+ * @static
94
+ * @param {object} context Test execution context.
95
+ */
61
96
  const pageLoadTimeTest = async (context) => {
62
97
  const testSettingName = 'pageLoadTimeTest';
63
98
  // eslint-disable-next-line no-shadow -- less intuitive
@@ -77,6 +112,13 @@ const pageLoadTimeTest = async (context) => {
77
112
  }, context, testSettingName);
78
113
  };
79
114
 
115
+ /**
116
+ * Tests the current page for any external JavaScript files and
117
+ * downloads the files for further analysis.
118
+ *
119
+ * @static
120
+ * @param {object} context Test execution context.
121
+ */
80
122
  const externalScriptTest = async (context) => {
81
123
  // eslint-disable-next-line no-shadow -- less intuitive
82
124
  await pageanTest('should not have external scripts', async (context) => {
@@ -96,6 +138,12 @@ const externalScriptTest = async (context) => {
96
138
  }, context, 'externalScriptTest');
97
139
  };
98
140
 
141
+ /**
142
+ * Tests the current page for any broken links (external or within the page).
143
+ *
144
+ * @static
145
+ * @param {object} context Test execution context.
146
+ */
99
147
  const brokenLinkTest = async (context) => {
100
148
  // eslint-disable-next-line no-shadow -- less intuitive
101
149
  await pageanTest('should not have broken links', async (context) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pagean",
3
- "version": "6.0.4",
3
+ "version": "6.0.5",
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",
@@ -48,27 +48,27 @@
48
48
  },
49
49
  "homepage": "https://gitlab.com/gitlab-ci-utils/pagean#readme",
50
50
  "devDependencies": {
51
- "@aarongoldenthal/eslint-config-standard": "^10.0.2",
51
+ "@aarongoldenthal/eslint-config-standard": "^11.0.0",
52
52
  "@aarongoldenthal/stylelint-config-standard": "^6.0.0",
53
53
  "bin-tester": "^2.0.1",
54
- "eslint": "^8.5.0",
55
- "jest": "^27.4.5",
54
+ "eslint": "^8.7.0",
55
+ "jest": "^27.4.7",
56
56
  "jest-junit": "^13.0.0",
57
57
  "markdownlint-cli": "^0.30.0",
58
58
  "strip-ansi": "^6.0.1",
59
- "stylelint": "^14.1.0"
59
+ "stylelint": "^14.2.0"
60
60
  },
61
61
  "dependencies": {
62
- "ajv": "^8.8.2",
62
+ "ajv": "^8.9.0",
63
63
  "ajv-errors": "^3.0.0",
64
- "axios": "^0.24.0",
64
+ "axios": "^0.25.0",
65
65
  "ci-logger": "^4.0.1",
66
66
  "commander": "^8.3.0",
67
67
  "handlebars": "^4.7.7",
68
- "htmlhint": "^1.0.0",
68
+ "htmlhint": "^1.1.0",
69
69
  "kleur": "^4.1.4",
70
70
  "normalize-url": "^6.1.0",
71
71
  "protocolify": "^3.0.0",
72
- "puppeteer": "^13.0.0"
72
+ "puppeteer": "^13.1.1"
73
73
  }
74
74
  }