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.
package/lib/tests.js CHANGED
@@ -7,9 +7,9 @@
7
7
  */
8
8
  const { HTMLHint } = require('htmlhint');
9
9
 
10
- const { testResultStates, pageanTest } = require('./testUtils');
11
- const fileUtils = require('./externalFileUtils');
12
- const { isFailedResponse } = require('./linkUtils');
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
 
@@ -20,15 +20,25 @@ const msPerSec = 1000;
20
20
  * @param {object} context Test execution context.
21
21
  */
22
22
  const horizontalScrollbarTest = async (context) => {
23
- // eslint-disable-next-line no-shadow -- less intuitive
24
- await pageanTest('should not have a horizontal scrollbar', async (context) => {
25
- // istanbul ignore next: injects script causing puppeteer error, see #48
26
- const scrollbar = await context.page.evaluate(() => {
27
- document.scrollingElement.scrollLeft = 1;
28
- return document.scrollingElement.scrollLeft === 1;
29
- });
30
- return { result: scrollbar === false ? testResultStates.passed : testResultStates.failed };
31
- }, context, 'horizontalScrollbarTest');
23
+ await pageanTest(
24
+ 'should not have a horizontal scrollbar',
25
+ // eslint-disable-next-line no-shadow -- less intuitive
26
+ async (context) => {
27
+ // istanbul ignore next: injects script causing puppeteer error, see #48
28
+ const scrollbar = await context.page.evaluate(() => {
29
+ document.scrollingElement.scrollLeft = 1;
30
+ return document.scrollingElement.scrollLeft === 1;
31
+ });
32
+ return {
33
+ result:
34
+ scrollbar === false
35
+ ? testResultStates.passed
36
+ : testResultStates.failed
37
+ };
38
+ },
39
+ context,
40
+ 'horizontalScrollbarTest'
41
+ );
32
42
  };
33
43
 
34
44
  /**
@@ -38,14 +48,24 @@ const horizontalScrollbarTest = async (context) => {
38
48
  * @param {object} context Test execution context.
39
49
  */
40
50
  const consoleOutputTest = (context) => {
41
- // eslint-disable-next-line no-shadow -- less intuitive
42
- pageanTest('should not have console output', (context) => {
43
- const testResult = { result: context.consoleLog.length === 0 ? testResultStates.passed : testResultStates.failed };
44
- if (testResult.result === testResultStates.failed) {
45
- testResult.data = context.consoleLog;
46
- }
47
- return testResult;
48
- }, context, 'consoleOutputTest');
51
+ pageanTest(
52
+ 'should not have console output',
53
+ // eslint-disable-next-line no-shadow -- less intuitive
54
+ (context) => {
55
+ const testResult = {
56
+ result:
57
+ context.consoleLog.length === 0
58
+ ? testResultStates.passed
59
+ : testResultStates.failed
60
+ };
61
+ if (testResult.result === testResultStates.failed) {
62
+ testResult.data = context.consoleLog;
63
+ }
64
+ return testResult;
65
+ },
66
+ context,
67
+ 'consoleOutputTest'
68
+ );
49
69
  };
50
70
 
51
71
  /**
@@ -55,17 +75,29 @@ const consoleOutputTest = (context) => {
55
75
  * @param {object} context Test execution context.
56
76
  */
57
77
  const consoleErrorTest = (context) => {
58
- // eslint-disable-next-line no-shadow -- less intuitive
59
- pageanTest('should not have console errors', (context) => {
60
- // Object property names defined by puppeteer API
61
- // eslint-disable-next-line no-underscore-dangle
62
- const browserErrorLog = context.consoleLog.filter(log => log._type === 'error');
63
- const testResult = { result: browserErrorLog.length === 0 ? testResultStates.passed : testResultStates.failed };
64
- if (testResult.result === testResultStates.failed) {
65
- testResult.data = browserErrorLog;
66
- }
67
- return testResult;
68
- }, context, 'consoleErrorTest');
78
+ pageanTest(
79
+ 'should not have console errors',
80
+ // eslint-disable-next-line no-shadow -- less intuitive
81
+ (context) => {
82
+ const browserErrorLog = context.consoleLog.filter(
83
+ // Object property names defined by puppeteer API
84
+ // eslint-disable-next-line no-underscore-dangle
85
+ (log) => log._type === 'error'
86
+ );
87
+ const testResult = {
88
+ result:
89
+ browserErrorLog.length === 0
90
+ ? testResultStates.passed
91
+ : testResultStates.failed
92
+ };
93
+ if (testResult.result === testResultStates.failed) {
94
+ testResult.data = browserErrorLog;
95
+ }
96
+ return testResult;
97
+ },
98
+ context,
99
+ 'consoleErrorTest'
100
+ );
69
101
  };
70
102
 
71
103
  /**
@@ -75,16 +107,29 @@ const consoleErrorTest = (context) => {
75
107
  * @param {object} context Test execution context.
76
108
  */
77
109
  const renderedHtmlTest = async (context) => {
78
- // eslint-disable-next-line no-shadow -- less intuitive
79
- await pageanTest('should have valid rendered HTML', async (context) => {
80
- const html = await context.page.content();
81
- const lintResults = HTMLHint.verify(html, context.urlSettings.htmlHintConfig);
82
- const testResult = { result: lintResults.length === 0 ? testResultStates.passed : testResultStates.failed };
83
- if (testResult.result === testResultStates.failed) {
84
- testResult.data = lintResults;
85
- }
86
- return testResult;
87
- }, context, 'renderedHtmlTest');
110
+ await pageanTest(
111
+ 'should have valid rendered HTML',
112
+ // eslint-disable-next-line no-shadow -- less intuitive
113
+ async (context) => {
114
+ const html = await context.page.content();
115
+ const lintResults = HTMLHint.verify(
116
+ html,
117
+ context.urlSettings.htmlHintConfig
118
+ );
119
+ const testResult = {
120
+ result:
121
+ lintResults.length === 0
122
+ ? testResultStates.passed
123
+ : testResultStates.failed
124
+ };
125
+ if (testResult.result === testResultStates.failed) {
126
+ testResult.data = lintResults;
127
+ }
128
+ return testResult;
129
+ },
130
+ context,
131
+ 'renderedHtmlTest'
132
+ );
88
133
  };
89
134
 
90
135
  /**
@@ -93,23 +138,40 @@ const renderedHtmlTest = async (context) => {
93
138
  * @static
94
139
  * @param {object} context Test execution context.
95
140
  */
141
+ // eslint-disable-next-line max-lines-per-function
96
142
  const pageLoadTimeTest = async (context) => {
97
143
  const testSettingName = 'pageLoadTimeTest';
98
- // eslint-disable-next-line no-shadow -- less intuitive
99
- await pageanTest('should load page within timeout', async (context) => {
100
- const { pageLoadTimeThreshold } = context.testSettings;
101
- const name = `should load page within ${pageLoadTimeThreshold} sec`;
102
- // istanbul ignore next: injects script causing puppeteer error, see #48
103
- const performanceTiming = JSON.parse(await context.page.evaluate(
104
- () => JSON.stringify(window.performance)
105
- ));
106
- const loadTimeSec = (performanceTiming.timing.loadEventEnd - performanceTiming.timing.navigationStart) / msPerSec;
107
- const testResult = { name, result: loadTimeSec < pageLoadTimeThreshold ? testResultStates.passed : testResultStates.failed };
108
- if (testResult.result === testResultStates.failed) {
109
- testResult.data = { pageLoadTime: loadTimeSec };
110
- }
111
- return testResult;
112
- }, context, testSettingName);
144
+ await pageanTest(
145
+ 'should load page within timeout',
146
+ // eslint-disable-next-line no-shadow -- less intuitive
147
+ async (context) => {
148
+ const { pageLoadTimeThreshold } = context.testSettings;
149
+ const name = `should load page within ${pageLoadTimeThreshold} sec`;
150
+ // istanbul ignore next: injects script causing puppeteer error, see #48
151
+ const performanceTiming = JSON.parse(
152
+ await context.page.evaluate(() =>
153
+ JSON.stringify(window.performance)
154
+ )
155
+ );
156
+ const loadTimeSec =
157
+ (performanceTiming.timing.loadEventEnd -
158
+ performanceTiming.timing.navigationStart) /
159
+ msPerSec;
160
+ const testResult = {
161
+ name,
162
+ result:
163
+ loadTimeSec < pageLoadTimeThreshold
164
+ ? testResultStates.passed
165
+ : testResultStates.failed
166
+ };
167
+ if (testResult.result === testResultStates.failed) {
168
+ testResult.data = { pageLoadTime: loadTimeSec };
169
+ }
170
+ return testResult;
171
+ },
172
+ context,
173
+ testSettingName
174
+ );
113
175
  };
114
176
 
115
177
  /**
@@ -119,23 +181,42 @@ const pageLoadTimeTest = async (context) => {
119
181
  * @static
120
182
  * @param {object} context Test execution context.
121
183
  */
184
+ // eslint-disable-next-line max-lines-per-function
122
185
  const externalScriptTest = async (context) => {
123
- // eslint-disable-next-line no-shadow -- less intuitive
124
- await pageanTest('should not have external scripts', async (context) => {
125
- // istanbul ignore next: injects script causing puppeteer error, see #48
126
- const scripts = await context.page.evaluate(() => {
127
- return [...document.querySelectorAll('script[src]')].map(s => s.src);
128
- });
186
+ await pageanTest(
187
+ 'should not have external scripts',
188
+ // eslint-disable-next-line no-shadow -- less intuitive
189
+ async (context) => {
190
+ // istanbul ignore next: injects script causing puppeteer error, see #48
191
+ const scripts = await context.page.evaluate(() => {
192
+ return [...document.querySelectorAll('script[src]')].map(
193
+ (s) => s.src
194
+ );
195
+ });
129
196
 
130
- const pageUrl = context.page.url();
131
- const externalScripts = scripts.filter(script => fileUtils.shouldSaveFile(script, pageUrl));
132
- const scriptResults = await Promise.all(externalScripts.map(script => fileUtils.saveExternalScript(script)));
133
- const testResult = { result: scriptResults.length > 0 ? testResultStates.failed : testResultStates.passed };
134
- if (testResult.result === testResultStates.failed) {
135
- testResult.data = scriptResults;
136
- }
137
- return testResult;
138
- }, context, 'externalScriptTest');
197
+ const pageUrl = context.page.url();
198
+ const externalScripts = scripts.filter((script) =>
199
+ fileUtils.shouldSaveFile(script, pageUrl)
200
+ );
201
+ const scriptResults = await Promise.all(
202
+ externalScripts.map((script) =>
203
+ fileUtils.saveExternalScript(script)
204
+ )
205
+ );
206
+ const testResult = {
207
+ result:
208
+ scriptResults.length > 0
209
+ ? testResultStates.failed
210
+ : testResultStates.passed
211
+ };
212
+ if (testResult.result === testResultStates.failed) {
213
+ testResult.data = scriptResults;
214
+ }
215
+ return testResult;
216
+ },
217
+ context,
218
+ 'externalScriptTest'
219
+ );
139
220
  };
140
221
 
141
222
  /**
@@ -144,33 +225,54 @@ const externalScriptTest = async (context) => {
144
225
  * @static
145
226
  * @param {object} context Test execution context.
146
227
  */
228
+ // eslint-disable-next-line max-lines-per-function
147
229
  const brokenLinkTest = async (context) => {
148
- // eslint-disable-next-line no-shadow -- less intuitive
149
- await pageanTest('should not have broken links', async (context) => {
150
- // istanbul ignore next: injects script causing puppeteer error, see #48
151
- const links = await context.page.evaluate(() => {
152
- return [...document.querySelectorAll('a[href]')].map(a => a.href);
153
- });
230
+ await pageanTest(
231
+ 'should not have broken links',
232
+ // eslint-disable-next-line no-shadow -- less intuitive
233
+ async (context) => {
234
+ // istanbul ignore next: injects script causing puppeteer error, see #48
235
+ const links = await context.page.evaluate(() => {
236
+ return [...document.querySelectorAll('a[href]')].map(
237
+ (a) => a.href
238
+ );
239
+ });
154
240
 
155
- // All links are returned from puppeteer as absolute links, so this filters out
156
- // javascript and other values and leaves only pages to request.
157
- const httpLinks = links.filter(link => link.match(/(http(s?)|file):\/\//));
158
- // Reduce to unique page links so only checked once
159
- const uniqueHttpLinks = [...new Set(httpLinks)];
241
+ // All links are returned from puppeteer as absolute links, so this filters out
242
+ // javascript and other values and leaves only pages to request.
243
+ const httpLinks = links.filter((link) =>
244
+ link.match(/(http(s?)|file):\/\//)
245
+ );
246
+ // Reduce to unique page links so only checked once
247
+ const uniqueHttpLinks = [...new Set(httpLinks)];
160
248
 
161
- // Check each link includes check against ignored list, and if not checks
162
- // both links within the page as well as to other pages
163
- const linkResponses = await Promise.all(uniqueHttpLinks.map(async (link) =>
164
- ({ href: link, status: await context.linkChecker.checkLink(context, link) })));
249
+ // Check each link includes check against ignored list, and if not checks
250
+ // both links within the page as well as to other pages
251
+ const linkResponses = await Promise.all(
252
+ uniqueHttpLinks.map(async (link) => ({
253
+ href: link,
254
+ status: await context.linkChecker.checkLink(context, link)
255
+ }))
256
+ );
165
257
 
166
- // Returned results includes status for all links, so filter down to only failed
167
- const failedLinkResponses = linkResponses.filter(result => isFailedResponse(result));
168
- const testResult = { result: failedLinkResponses.length > 0 ? testResultStates.failed : testResultStates.passed };
169
- if (testResult.result === testResultStates.failed) {
170
- testResult.data = failedLinkResponses;
171
- }
172
- return testResult;
173
- }, context, 'brokenLinkTest');
258
+ // Returned results includes status for all links, so filter down to only failed
259
+ const failedLinkResponses = linkResponses.filter((result) =>
260
+ isFailedResponse(result)
261
+ );
262
+ const testResult = {
263
+ result:
264
+ failedLinkResponses.length > 0
265
+ ? testResultStates.failed
266
+ : testResultStates.passed
267
+ };
268
+ if (testResult.result === testResultStates.failed) {
269
+ testResult.data = failedLinkResponses;
270
+ }
271
+ return testResult;
272
+ },
273
+ context,
274
+ 'brokenLinkTest'
275
+ );
174
276
  };
175
277
 
176
278
  module.exports.consoleErrorTest = consoleErrorTest;
package/package.json CHANGED
@@ -1,22 +1,25 @@
1
1
  {
2
2
  "name": "pagean",
3
- "version": "6.0.6",
3
+ "version": "6.0.9",
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",
7
7
  "pageanrc-lint": "./bin/pageanrc-lint.js"
8
8
  },
9
9
  "scripts": {
10
- "start": "node ./bin/pagean.js",
11
- "start-lint": "node ./bin/pageanrc-lint.js",
12
- "start-lint-all": "npm run start-lint && npm run start-lint -c static-server.pageanrc.json && npm run start-lint -c ./lib/default-config.json",
13
- "test": "jest --ci --config jest.config.json",
10
+ "hooks-pre-commit": "npm run lint && npm run prettier-check",
11
+ "hooks-pre-push": "npm audit --audit-level=high && npm test",
12
+ "lint": "npm run lint-css && npm run lint-html && npm run lint-js && npm run lint-md",
14
13
  "lint-css": "stylelint ./lib/report-template.handlebars",
15
14
  "lint-html": "htmlhint ./lib/report-template.handlebars",
16
15
  "lint-js": "eslint \"**/*.js\"",
17
16
  "lint-md": "markdownlint **/*.md --ignore node_modules",
18
- "lint": "npm run lint-css && npm run lint-html && npm run lint-js && npm run lint-md",
19
- "push": "npm run start-lint-all && npm audit --audit-level=critical"
17
+ "prettier-check": "prettier --check .",
18
+ "prettier-fix": "prettier --write .",
19
+ "start": "node ./bin/pagean.js",
20
+ "start-lint": "node ./bin/pageanrc-lint.js",
21
+ "start-lint-all": "npm run start-lint && npm run start-lint -c static-server.pageanrc.json && npm run start-lint -c ./lib/default-config.json",
22
+ "test": "jest --ci --config jest.config.json"
20
23
  },
21
24
  "repository": {
22
25
  "type": "git",
@@ -46,29 +49,30 @@
46
49
  "bugs": {
47
50
  "url": "https://gitlab.com/gitlab-ci-utils/pagean/issues"
48
51
  },
49
- "homepage": "https://gitlab.com/gitlab-ci-utils/pagean#readme",
52
+ "homepage": "https://gitlab.com/gitlab-ci-utils/pagean",
50
53
  "devDependencies": {
51
- "@aarongoldenthal/eslint-config-standard": "^11.0.0",
52
- "@aarongoldenthal/stylelint-config-standard": "^6.0.0",
54
+ "@aarongoldenthal/eslint-config-standard": "^14.0.0",
55
+ "@aarongoldenthal/stylelint-config-standard": "^8.0.0",
53
56
  "bin-tester": "^2.0.1",
54
- "eslint": "^8.7.0",
55
- "jest": "^27.4.7",
56
- "jest-junit": "^13.0.0",
57
- "markdownlint-cli": "^0.30.0",
57
+ "eslint": "^8.14.0",
58
+ "jest": "^28.0.2",
59
+ "jest-junit": "^13.2.0",
60
+ "markdownlint-cli": "^0.31.1",
61
+ "prettier": "^2.6.2",
58
62
  "strip-ansi": "^6.0.1",
59
- "stylelint": "^14.3.0"
63
+ "stylelint": "^14.8.0"
60
64
  },
61
65
  "dependencies": {
62
- "ajv": "^8.9.0",
66
+ "ajv": "^8.11.0",
63
67
  "ajv-errors": "^3.0.0",
64
- "axios": "^0.25.0",
65
- "ci-logger": "^4.0.1",
66
- "commander": "^8.3.0",
68
+ "axios": "^0.27.2",
69
+ "ci-logger": "^4.0.2",
70
+ "commander": "^9.2.0",
67
71
  "handlebars": "^4.7.7",
68
- "htmlhint": "^1.1.1",
72
+ "htmlhint": "^1.1.4",
69
73
  "kleur": "^4.1.4",
70
74
  "normalize-url": "^6.1.0",
71
75
  "protocolify": "^3.0.0",
72
- "puppeteer": "^13.1.2"
76
+ "puppeteer": "^13.6.0"
73
77
  }
74
78
  }
@@ -22,11 +22,7 @@
22
22
  "description": "Reporters to use when returning the results of the Pagean tests.",
23
23
  "type": "array",
24
24
  "items": {
25
- "enum": [
26
- "cli",
27
- "html",
28
- "json"
29
- ]
25
+ "enum": ["cli", "html", "json"]
30
26
  },
31
27
  "minItems": 1
32
28
  },
@@ -60,9 +56,7 @@
60
56
  "not": true,
61
57
  "errorMessage": "must NOT contain additional properties: ${0#}"
62
58
  },
63
- "required": [
64
- "url"
65
- ],
59
+ "required": ["url"],
66
60
  "errorMessage": {
67
61
  "required": "must have required property 'url'"
68
62
  }
@@ -77,9 +71,7 @@
77
71
  "not": true,
78
72
  "errorMessage": "must NOT contain additional properties: ${0#}"
79
73
  },
80
- "required": [
81
- "urls"
82
- ],
74
+ "required": ["urls"],
83
75
  "definitions": {
84
76
  "detailedSetting": {
85
77
  "description": "The complete set of test-specific settings for most tests.",