pagean 4.4.2 → 6.0.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.
Files changed (96) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +9 -9
  3. package/docs/upgrade-guide.md +16 -0
  4. package/index.js +7 -4
  5. package/lib/config.js +2 -2
  6. package/lib/default-config.json +41 -39
  7. package/lib/externalFileUtils.js +1 -1
  8. package/lib/linkUtils.js +162 -25
  9. package/lib/logger.js +1 -1
  10. package/lib/report-template.handlebars +224 -209
  11. package/lib/schemaErrors.js +5 -4
  12. package/lib/testUtils.js +1 -1
  13. package/lib/tests.js +14 -14
  14. package/package.json +28 -30
  15. package/schemas/pageanrc.schema.json +199 -191
  16. package/.codeclimate.json +0 -8
  17. package/.depcheckrc.json +0 -3
  18. package/.dockerignore +0 -12
  19. package/.eslintrc.json +0 -19
  20. package/.gitattributes +0 -4
  21. package/.gitlab/gitlab-releaser.json +0 -16
  22. package/.htmlhintrc +0 -25
  23. package/.markdownlint.json +0 -13
  24. package/.pa11yci.json +0 -5
  25. package/.pageanrc.json +0 -55
  26. package/.stylelintrc.json +0 -7
  27. package/CHANGELOG.md +0 -204
  28. package/gitlab.pageanrc.json +0 -16
  29. package/jest.config.json +0 -22
  30. package/static-server.pageanrc.json +0 -50
  31. package/tests/__snapshots__/config.test.js.snap +0 -591
  32. package/tests/__snapshots__/externalFileUtils.test.js.snap +0 -7
  33. package/tests/__snapshots__/index.test.js.snap +0 -30
  34. package/tests/__snapshots__/pagean.test.js.snap +0 -82
  35. package/tests/__snapshots__/pageanrc.test.js.snap +0 -759
  36. package/tests/__snapshots__/reporter.test.js.snap +0 -509
  37. package/tests/config.test.js +0 -264
  38. package/tests/externalFileUtils.test.js +0 -184
  39. package/tests/index.test.js +0 -181
  40. package/tests/linkUtils.test.js +0 -290
  41. package/tests/logger.test.js +0 -324
  42. package/tests/pagean.test.js +0 -85
  43. package/tests/pageanrc.test.js +0 -96
  44. package/tests/reporter.test.js +0 -82
  45. package/tests/schemaErrors.test.js +0 -88
  46. package/tests/test-cases/.htmlhintrc +0 -25
  47. package/tests/test-cases/brokenLinks.html +0 -22
  48. package/tests/test-cases/consoleLog.html +0 -11
  49. package/tests/test-cases/duplicateLinks.html +0 -22
  50. package/tests/test-cases/dynamicContent.html +0 -13
  51. package/tests/test-cases/externalScripts.html +0 -21
  52. package/tests/test-cases/horizontalScrollbar.html +0 -13
  53. package/tests/test-cases/htmlError.html +0 -11
  54. package/tests/test-cases/noExternalScripts.html +0 -12
  55. package/tests/test-cases/notDocumentLinks.html +0 -18
  56. package/tests/test-cases/pagean-results.json +0 -1
  57. package/tests/test-cases/scriptError404.html +0 -9
  58. package/tests/test-cases/slowLoad.html +0 -9
  59. package/tests/test-configs/cli-tests/.pageanrc.json +0 -28
  60. package/tests/test-configs/cli-tests/all-empty.pageanrc.json +0 -10
  61. package/tests/test-configs/cli-tests/all-errors.pageanrc.json +0 -69
  62. package/tests/test-configs/cli-tests/all-fail-cli.pageanrc.json +0 -9
  63. package/tests/test-configs/cli-tests/no-urls.pageanrc.json +0 -7
  64. package/tests/test-configs/cli-tests/pass-fail-cli.pageanrc.json +0 -14
  65. package/tests/test-configs/integration-tests/all-passing-tests.pageanrc.json +0 -63
  66. package/tests/test-configs/integration-tests/broken-links-error.pageanrc.json +0 -22
  67. package/tests/test-configs/integration-tests/console-error-reporter-cli-json.pageanrc.json +0 -20
  68. package/tests/test-configs/integration-tests/console-error-reporter-html.pageanrc.json +0 -19
  69. package/tests/test-configs/integration-tests/console-error.pageanrc.json +0 -16
  70. package/tests/test-configs/integration-tests/console-output.pageanrc.json +0 -16
  71. package/tests/test-configs/integration-tests/external-scripts-error.pageanrc.json +0 -19
  72. package/tests/test-configs/integration-tests/horizontal-scrollbar.pageanrc.json +0 -16
  73. package/tests/test-configs/integration-tests/html-error.pageanrc.json +0 -16
  74. package/tests/test-configs/integration-tests/page-load-time.pageanrc.json +0 -16
  75. package/tests/test-configs/unit-tests/empty-url-values.pageanrc.json +0 -9
  76. package/tests/test-configs/unit-tests/empty-urls.pageanrc.json +0 -3
  77. package/tests/test-configs/unit-tests/empty.pageanrc.json +0 -2
  78. package/tests/test-configs/unit-tests/global-and-test-specific-settings-shorthand.pageanrc.json +0 -30
  79. package/tests/test-configs/unit-tests/global-and-test-specific-settings-test-props.pageanrc.json +0 -42
  80. package/tests/test-configs/unit-tests/global-and-test-specific-settings.pageanrc.json +0 -34
  81. package/tests/test-configs/unit-tests/global-test-settings.pageanrc.json +0 -15
  82. package/tests/test-configs/unit-tests/htmlhintrc-invalid.pageanrc.json +0 -7
  83. package/tests/test-configs/unit-tests/htmlhintrc-valid.pageanrc.json +0 -7
  84. package/tests/test-configs/unit-tests/ignored-links-denormalized.pageanrc.json +0 -18
  85. package/tests/test-configs/unit-tests/invalid.pageanrc.json +0 -0
  86. package/tests/test-configs/unit-tests/no-test-settings.pageanrc.json +0 -6
  87. package/tests/test-configs/unit-tests/project-no-test-settings.pageanrc.json +0 -7
  88. package/tests/test-configs/unit-tests/puppeteer-no-test-settings.pageanrc.json +0 -9
  89. package/tests/test-configs/unit-tests/reporters-empty.pageanrc.json +0 -7
  90. package/tests/test-configs/unit-tests/reporters-invalid-type.pageanrc.json +0 -9
  91. package/tests/test-configs/unit-tests/reporters-not-array.pageanrc.json +0 -6
  92. package/tests/test-configs/unit-tests/reporters-valid.pageanrc.json +0 -9
  93. package/tests/test-configs/unit-tests/test-specific-settings.pageanrc.json +0 -26
  94. package/tests/test-configs/unit-tests/url-types.pageanrc.json +0 -10
  95. package/tests/testUtils.test.js +0 -244
  96. package/tests/tests.test.js +0 -533
@@ -1,264 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const config = require('../lib/config');
5
- const defaultConfig = require('../lib/default-config.json');
6
-
7
- const nonExistentConfigFileName = 'not-a-file.json';
8
- const invalidConfigFileName = './tests/test-configs/unit-tests/invalid.pageanrc.json';
9
- const emptyConfigFileName = './tests/test-configs/unit-tests/empty.pageanrc.json';
10
- const emptyUrlsConfigFileName = './tests/test-configs/unit-tests/empty-urls.pageanrc.json';
11
- const emptyUrlValuesConfigFileName = './tests/test-configs/unit-tests/empty-url-values.pageanrc.json';
12
- const noTestSettingsConfigFileName = './tests/test-configs/unit-tests/no-test-settings.pageanrc.json';
13
- const globalTestSettingsConfigFileName = './tests/test-configs/unit-tests/global-test-settings.pageanrc.json';
14
- const testSpecificSettingsConfigFileName = './tests/test-configs/unit-tests/test-specific-settings.pageanrc.json';
15
- const globalAndTestSpecificSettingsConfigFileName = './tests/test-configs/unit-tests/global-and-test-specific-settings.pageanrc.json';
16
- const projectNoTestSettingsConfigFileName = './tests/test-configs/unit-tests/project-no-test-settings.pageanrc.json';
17
- const puppeteerNoTestSettingsConfigFileName = './tests/test-configs/unit-tests/puppeteer-no-test-settings.pageanrc.json';
18
- const urlTypesConfigFileName = './tests/test-configs/unit-tests/url-types.pageanrc.json';
19
- const allTestPropsConfigFileName = './tests/test-configs/unit-tests/global-and-test-specific-settings-test-props.pageanrc.json';
20
- const allShorthandConfigFileName = './tests/test-configs/unit-tests/global-and-test-specific-settings-shorthand.pageanrc.json';
21
- const reportersEmptyArrayConfigFileName = './tests/test-configs/unit-tests/reporters-empty.pageanrc.json';
22
- const reportersInvalidTypeConfigFileName = './tests/test-configs/unit-tests/reporters-invalid-type.pageanrc.json';
23
- const reportersNotArrayConfigFileName = './tests/test-configs/unit-tests/reporters-not-array.pageanrc.json';
24
- const reportersValidConfigFileName = './tests/test-configs/unit-tests/reporters-valid.pageanrc.json';
25
- const htmlhintrcInvalidConfigFileName = './tests/test-configs/unit-tests/htmlhintrc-invalid.pageanrc.json';
26
- const ignoredLinksDenormalizedConfigFileName = './tests/test-configs/unit-tests/ignored-links-denormalized.pageanrc.json';
27
- const htmlhintrcValidConfigFileName = './tests/test-configs/unit-tests/htmlhintrc-valid.pageanrc.json';
28
- const cliDefaultConfigFileName = './tests/test-configs/cli-tests/.pageanrc.json';
29
-
30
- // eslint-disable-next-line max-lines-per-function
31
- describe('process config', () => {
32
- // eslint-disable-next-line max-lines-per-function
33
- describe('invalid config', () => {
34
- const invalidConfigMessage = 'invalid pageanrc schema';
35
-
36
- it('should throw if config file not found', () => {
37
- expect.assertions(1);
38
- expect(() => config(nonExistentConfigFileName)).toThrow('ENOENT');
39
- });
40
-
41
- it('should throw if config file is not JSON', () => {
42
- expect.assertions(1);
43
- expect(() => config(invalidConfigFileName)).toThrow('Unexpected end of JSON input');
44
- });
45
-
46
- it('should throw if no URLs specified in config file', () => {
47
- expect.assertions(1);
48
- expect(() => config(emptyConfigFileName)).toThrow(invalidConfigMessage);
49
- });
50
-
51
- it('should throw if empty URL array specified in config file', () => {
52
- expect.assertions(1);
53
- expect(() => config(emptyUrlsConfigFileName)).toThrow(invalidConfigMessage);
54
- });
55
-
56
- it('should throw if URL object with no url property specified in config file', () => {
57
- expect.assertions(1);
58
- expect(() => config(emptyUrlValuesConfigFileName)).toThrow(invalidConfigMessage);
59
- });
60
-
61
- it('should throw if reporters specified in config are not array', () => {
62
- expect.assertions(1);
63
- expect(() => config(reportersNotArrayConfigFileName)).toThrow(invalidConfigMessage);
64
- });
65
-
66
- it('should throw if reporters specified in config are empty array', () => {
67
- expect.assertions(1);
68
- expect(() => config(reportersEmptyArrayConfigFileName)).toThrow(invalidConfigMessage);
69
- });
70
-
71
- it('should throw if reporters array specified in config has invalid values', () => {
72
- expect.assertions(1);
73
- expect(() => config(reportersInvalidTypeConfigFileName)).toThrow(invalidConfigMessage);
74
- });
75
- });
76
-
77
- const checkConfigAgainstSnapshot = (configFileName, property) => {
78
- expect.assertions(1);
79
- const processedConfig = config(configFileName);
80
- expect(processedConfig[property]).toMatchSnapshot();
81
- };
82
-
83
- describe('project name', () => {
84
- it('should return config with project name if provided', () => {
85
- expect.assertions(1);
86
- const processedConfig = config(projectNoTestSettingsConfigFileName);
87
- expect(processedConfig.project).toStrictEqual('This is a test project');
88
- });
89
-
90
- it('should return config with empty project name if none provided', () => {
91
- expect.assertions(1);
92
- const processedConfig = config(puppeteerNoTestSettingsConfigFileName);
93
- expect(processedConfig.project).toStrictEqual('');
94
- });
95
- });
96
-
97
- describe('puppeteer launch options', () => {
98
- it('should return config with puppeteer launch settings', () => {
99
- expect.hasAssertions();
100
- checkConfigAgainstSnapshot(puppeteerNoTestSettingsConfigFileName, 'puppeteerLaunchOptions');
101
- });
102
-
103
- it('should return config with undefined puppeteer launch settings', () => {
104
- expect.hasAssertions();
105
- checkConfigAgainstSnapshot(noTestSettingsConfigFileName, 'puppeteerLaunchOptions');
106
- });
107
- });
108
-
109
- // eslint-disable-next-line max-lines-per-function
110
- describe('test settings', () => {
111
- it('should return config with default test settings', () => {
112
- expect.hasAssertions();
113
- checkConfigAgainstSnapshot(noTestSettingsConfigFileName, 'urls');
114
- });
115
-
116
- it('should return config with global test settings', () => {
117
- expect.hasAssertions();
118
- checkConfigAgainstSnapshot(globalTestSettingsConfigFileName, 'urls');
119
- });
120
-
121
- it('should return config with default and test-specific settings', () => {
122
- expect.hasAssertions();
123
- checkConfigAgainstSnapshot(testSpecificSettingsConfigFileName, 'urls');
124
- });
125
-
126
- it('should return config with default, global, and test-specific settings', () => {
127
- expect.hasAssertions();
128
- checkConfigAgainstSnapshot(globalAndTestSpecificSettingsConfigFileName, 'urls');
129
- });
130
-
131
- it('should return config with all url types properly parsed', () => {
132
- expect.assertions(6); // eslint-disable-line no-magic-numbers
133
- const processedConfig = config(urlTypesConfigFileName);
134
- // Case 1: Local file that exists. Use regex since path change in different environments.
135
- expect(processedConfig.urls[0].url).toMatch(/file:\/\/\/.*\/tests\/test-cases\/consoleLog.html/);
136
- // Case 2: Local file that does not exist, so assume URL (add https://)
137
- expect(processedConfig.urls[1].url).toStrictEqual('https://tests/test-cases/bar.html');
138
- // Case 3: URL with no protocol (add https://)
139
- expect(processedConfig.urls[2].url).toStrictEqual('https://localhost/foo.html'); // eslint-disable-line no-magic-numbers
140
- // Case 4: URL with port and no protocol (add https://)
141
- expect(processedConfig.urls[3].url).toStrictEqual('https://localhost:3000/foo.html'); // eslint-disable-line no-magic-numbers
142
- // Case 5: URL with http protocol (unchanged)
143
- expect(processedConfig.urls[4].url).toStrictEqual('http://localhost/foo.html'); // eslint-disable-line no-magic-numbers
144
- // Case 6: URL with https protocol (unchanged)
145
- expect(processedConfig.urls[5].url).toStrictEqual('https://localhost/foo.html'); // eslint-disable-line no-magic-numbers
146
- });
147
-
148
- it('should return the same config with test shorthand and property declaration', () => {
149
- expect.assertions(1);
150
- const shorthandConfig = config(allShorthandConfigFileName);
151
- const testPropsConfig = config(allTestPropsConfigFileName);
152
- expect(shorthandConfig).toStrictEqual(testPropsConfig);
153
- });
154
-
155
- it('should normalize ignored links in brokenLinkTest settings', () => {
156
- expect.assertions(2); // eslint-disable-line no-magic-numbers
157
- // Original link: https://this.url.is.ignored/
158
- const normalizedLinks = ['https://this.url.is.ignored'];
159
- const globalSettingUrl = 0; // URL inherits global settings
160
- const testSettingUrl = 1; // URL has test-specific settings
161
- const normalizedLinksConfig = config(ignoredLinksDenormalizedConfigFileName);
162
- expect(normalizedLinksConfig.urls[globalSettingUrl].settings.brokenLinkTest.ignoredLinks).toStrictEqual(normalizedLinks);
163
- expect(normalizedLinksConfig.urls[testSettingUrl].settings.brokenLinkTest.ignoredLinks).toStrictEqual(normalizedLinks);
164
- });
165
- });
166
-
167
- // eslint-disable-next-line max-lines-per-function
168
- describe('htmlhint settings', () => {
169
- const defaultHtmlHintConfigFilename = './.htmlhintrc';
170
- const invalidHtmlHintConfigFilename = './nonexistent/.htmlhintrc';
171
-
172
- beforeEach(() => {
173
- jest.restoreAllMocks();
174
- });
175
-
176
- it('should check for default htmlhintrc file if none specified in config', () => {
177
- expect.assertions(1);
178
- const fsExistsSpy = jest.spyOn(fs, 'existsSync').mockImplementation(() => false);
179
- config(globalAndTestSpecificSettingsConfigFileName);
180
- expect(fsExistsSpy).toHaveBeenCalledWith(defaultHtmlHintConfigFilename);
181
- });
182
-
183
- it('should check for htmlhintrc file from config if specified', () => {
184
- expect.assertions(1);
185
- const fsExistsSpy = jest.spyOn(fs, 'existsSync').mockImplementation(() => false);
186
- config(htmlhintrcInvalidConfigFileName);
187
- expect(fsExistsSpy).toHaveBeenCalledWith(invalidHtmlHintConfigFilename);
188
- });
189
-
190
- it('should return valid htmlhint settings from file specified in config if file exists', () => {
191
- expect.hasAssertions();
192
- checkConfigAgainstSnapshot(htmlhintrcValidConfigFileName, 'htmlHintConfig');
193
- });
194
-
195
- it('should return valid default htmlhint settings if .htmlhintrc file exists and none specified in config', () => {
196
- expect.hasAssertions();
197
- checkConfigAgainstSnapshot(globalAndTestSpecificSettingsConfigFileName, 'htmlHintConfig');
198
- });
199
-
200
- it('should return no htmlhint config if htmlhintrc file does not exist', () => {
201
- expect.assertions(1);
202
- const result = config(htmlhintrcInvalidConfigFileName);
203
- expect(result.htmlHintConfig).toBeUndefined();
204
- });
205
- });
206
-
207
- describe('reporter settings', () => {
208
- it('should return default reporters if none specified in config', () => {
209
- expect.assertions(1);
210
- const processedConfig = config(globalTestSettingsConfigFileName);
211
- expect(processedConfig).toStrictEqual(expect.objectContaining({ reporters: defaultConfig.reporters }));
212
- });
213
-
214
- it('should return reporters from config if valid', () => {
215
- expect.assertions(1);
216
- const expectedReporters = ['cli', 'html'];
217
- const processedConfig = config(reportersValidConfigFileName);
218
- expect(processedConfig).toStrictEqual(expect.objectContaining({ reporters: expectedReporters }));
219
- });
220
- });
221
- });
222
-
223
- // eslint-disable-next-line max-lines-per-function
224
- describe('lint config', () => {
225
- it('should throw if config file not found', () => {
226
- expect.assertions(1);
227
- expect(() => config.lintConfigFile(nonExistentConfigFileName)).toThrow('ENOENT');
228
- });
229
-
230
- it('should throw if config file is not JSON', () => {
231
- expect.assertions(1);
232
- expect(() => config.lintConfigFile(invalidConfigFileName)).toThrow('Unexpected end of JSON input');
233
- });
234
-
235
- it('should return an object with a boolean isValid property', () => {
236
- expect.assertions(1);
237
- const results = config.lintConfigFile(cliDefaultConfigFileName);
238
- expect(results).toStrictEqual(expect.objectContaining({ isValid: expect.any(Boolean) }));
239
- });
240
-
241
- it('should return an object with an errors array', () => {
242
- expect.assertions(1);
243
- const results = config.lintConfigFile(cliDefaultConfigFileName);
244
- expect(results).toStrictEqual(expect.objectContaining({ errors: expect.any(Array) }));
245
- });
246
-
247
- it('should return an object with isValid true if schema is valid', () => {
248
- expect.assertions(1);
249
- const results = config.lintConfigFile(cliDefaultConfigFileName);
250
- expect(results.isValid).toStrictEqual(true);
251
- });
252
-
253
- it('should return an object with isValid false if schema is invalid', () => {
254
- expect.assertions(1);
255
- const results = config.lintConfigFile(emptyUrlsConfigFileName);
256
- expect(results.isValid).toStrictEqual(false);
257
- });
258
-
259
- it('should return an object with errors array populated if schema is invalid', () => {
260
- expect.assertions(1);
261
- const results = config.lintConfigFile(emptyUrlsConfigFileName);
262
- expect(results.errors).toMatchSnapshot();
263
- });
264
- });
@@ -1,184 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
-
6
- const axios = require('axios');
7
-
8
- const { shouldSaveFile, saveExternalScript } = require('../lib/externalFileUtils');
9
-
10
- // eslint-disable-next-line max-lines-per-function
11
- describe('shouldSaveFile', () => {
12
- const urlBaseWithHost = 'https://foo.com/';
13
- const urlBaseWithoutHost = 'file:///E:/this/is/a/test/';
14
- const scriptFileName = 'jquery-3.5.1.min.js';
15
- const pageFileName = 'index.html';
16
- const invalidUrl = 'foo';
17
-
18
- afterEach(() => {
19
- jest.restoreAllMocks();
20
- });
21
-
22
- it('should return false for script and page with same host', () => {
23
- expect.assertions(1);
24
- const script = `${urlBaseWithHost}${scriptFileName}`;
25
- const page = urlBaseWithHost;
26
- expect(shouldSaveFile(script, page)).toStrictEqual(false);
27
- });
28
-
29
- it('should return false for script and page with same host and different protocols', () => {
30
- expect.assertions(1);
31
- const script = `${urlBaseWithHost}${scriptFileName}`;
32
- const page = 'file://foo.com/';
33
- expect(shouldSaveFile(script, page)).toStrictEqual(false);
34
- });
35
-
36
- it('should return true for script and page with different hosts', () => {
37
- expect.assertions(1);
38
- const script = `${urlBaseWithHost}${scriptFileName}`;
39
- const page = `https://bar.com/${pageFileName}`;
40
- expect(shouldSaveFile(script, page)).toStrictEqual(true);
41
- });
42
-
43
- it('should return true for script with no host and page with host', () => {
44
- expect.assertions(1);
45
- const script = `${urlBaseWithoutHost}${scriptFileName}`;
46
- const page = urlBaseWithHost;
47
- expect(shouldSaveFile(script, page)).toStrictEqual(true);
48
- });
49
-
50
- it('should return true for script with host and page with no host', () => {
51
- expect.assertions(1);
52
- const script = `${urlBaseWithHost}${scriptFileName}`;
53
- const page = `${urlBaseWithoutHost}${pageFileName}`;
54
- expect(shouldSaveFile(script, page)).toStrictEqual(true);
55
- });
56
-
57
- it('should return false for script and page with no host', () => {
58
- expect.assertions(1);
59
- const script = `${urlBaseWithoutHost}${scriptFileName}`;
60
- const page = `${urlBaseWithoutHost}${pageFileName}`;
61
- expect(shouldSaveFile(script, page)).toStrictEqual(false);
62
- });
63
-
64
- it('should throw for invalid script URL', () => {
65
- expect.assertions(1);
66
- const script = invalidUrl;
67
- const page = urlBaseWithHost;
68
- expect(() => shouldSaveFile(script, page)).toThrow('Invalid URL');
69
- });
70
-
71
- it('should throw for invalid page URL', () => {
72
- expect.assertions(1);
73
- const script = `${urlBaseWithoutHost}${scriptFileName}`;
74
- const page = invalidUrl;
75
- expect(() => shouldSaveFile(script, page)).toThrow('Invalid URL');
76
- });
77
- });
78
-
79
- // eslint-disable-next-line max-lines-per-function
80
- describe('saveExternalScript', () => {
81
- const jqueryUrl = 'https://code.jquery.com/jquery-3.5.1.slim.min.js';
82
- const jqueryPath = path.join('pagean-external-scripts', 'code.jquery.com', 'jquery-3.5.1.slim.min.js');
83
- const scriptText = 'this is a script';
84
- const httpResponseOk = 200;
85
- const httpResponseNotFound = 404;
86
-
87
- afterEach(() => {
88
- jest.restoreAllMocks();
89
- });
90
-
91
- const saveExternalScriptWithSpies = async(url, status = httpResponseOk, data = scriptText, fileExists = false) => {
92
- const axiosSpy = jest.spyOn(axios, 'get').mockImplementation(() => {
93
- if (status === httpResponseOk) {
94
- return { status, data };
95
- }
96
- throw new Error(`Request failed with status code ${status}`);
97
- });
98
- const existsSpy = jest.spyOn(fs, 'existsSync').mockImplementation(() => fileExists);
99
- const mkdirSpy = jest.spyOn(fs, 'mkdirSync').mockImplementation(() => {});
100
- const writeFileSpy = jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {});
101
- const result = await saveExternalScript(url);
102
- return {
103
- result,
104
- axiosSpy,
105
- existsSpy,
106
- mkdirSpy,
107
- writeFileSpy
108
- };
109
- };
110
-
111
- it('should try to get script if file does not exist', async() => {
112
- expect.assertions(1);
113
- const { axiosSpy } = await saveExternalScriptWithSpies(jqueryUrl);
114
- expect(axiosSpy).toHaveBeenCalledWith(jqueryUrl);
115
- });
116
-
117
- it('should not try to get script, or make dir, or save file if file exists', async() => {
118
- expect.assertions(3); // eslint-disable-line no-magic-numbers
119
- const { axiosSpy, mkdirSpy, writeFileSpy } = await saveExternalScriptWithSpies(jqueryUrl, httpResponseOk, scriptText, true);
120
- expect(axiosSpy).not.toHaveBeenCalled();
121
- expect(mkdirSpy).not.toHaveBeenCalled();
122
- expect(writeFileSpy).not.toHaveBeenCalled();
123
- });
124
-
125
- it('should create output directory if script is retrieved successfully', async() => {
126
- expect.assertions(1);
127
- const { mkdirSpy } = await saveExternalScriptWithSpies(jqueryUrl);
128
- expect(mkdirSpy).toHaveBeenCalledWith(path.dirname(jqueryPath), expect.objectContaining({ recursive: true }));
129
- });
130
-
131
- it('should save file if script is retrieved successfully', async() => {
132
- expect.assertions(1);
133
- const { writeFileSpy } = await saveExternalScriptWithSpies(jqueryUrl, httpResponseOk, scriptText);
134
- expect(writeFileSpy).toHaveBeenCalledWith(jqueryPath, scriptText);
135
- });
136
-
137
- it('should return script URL and saved file name if script is retrieved successfully', async() => {
138
- expect.assertions(1);
139
- const { result } = await saveExternalScriptWithSpies(jqueryUrl, httpResponseOk, scriptText);
140
- expect(result).toStrictEqual(expect.objectContaining({
141
- url: jqueryUrl,
142
- localFile: jqueryPath
143
- }));
144
- });
145
-
146
- it('should return script URL and saved file name if script already existed', async() => {
147
- expect.assertions(1);
148
- const { result } = await saveExternalScriptWithSpies(jqueryUrl, httpResponseOk, scriptText, true);
149
- expect(result).toStrictEqual(expect.objectContaining({
150
- url: jqueryUrl,
151
- localFile: jqueryPath
152
- }));
153
- });
154
-
155
- it('should not create output directory if script is not retrieved successfully', async() => {
156
- expect.assertions(1);
157
- const { mkdirSpy } = await saveExternalScriptWithSpies(jqueryUrl, httpResponseNotFound);
158
- expect(mkdirSpy).not.toHaveBeenCalledWith();
159
- });
160
-
161
- it('should not save file if script is not retrieved successfully', async() => {
162
- expect.assertions(1);
163
- const { writeFileSpy } = await saveExternalScriptWithSpies(jqueryUrl, httpResponseNotFound);
164
- expect(writeFileSpy).not.toHaveBeenCalledWith();
165
- });
166
-
167
- it('should return script URL and error message if script is is retrieved successfully', async() => {
168
- expect.assertions(1);
169
- const { result } = await saveExternalScriptWithSpies(jqueryUrl, httpResponseNotFound, scriptText);
170
- expect(result).toStrictEqual(expect.objectContaining({
171
- url: jqueryUrl,
172
- error: expect.stringContaining(String(httpResponseNotFound))
173
- }));
174
- });
175
-
176
- it('should retrieve script that matches snapshot', async() => {
177
- expect.assertions(1);
178
- // Add fs spies to avoid actually writing the file
179
- jest.spyOn(fs, 'mkdirSync').mockImplementation(() => {});
180
- const writeFileSpy = jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {});
181
- await saveExternalScript(jqueryUrl);
182
- expect(writeFileSpy.mock.calls[0][1]).toMatchSnapshot();
183
- });
184
- });
@@ -1,181 +0,0 @@
1
- 'use strict';
2
-
3
- const pagean = require('../index');
4
- const configParser = require('../lib/config');
5
- const reporter = require('../lib/reporter');
6
- const { testResultStates } = require('../lib/testUtils');
7
- const fileUtils = require('../lib/externalFileUtils');
8
- const linkUtils = require('../lib/linkUtils');
9
-
10
- // eslint-disable-next-line max-lines-per-function
11
- describe('integration tests', () => {
12
- const allPassConfigFileName = './tests/test-configs/integration-tests/all-passing-tests.pageanrc.json';
13
- const horizontalScrollbarTestFailConfigFileName = './tests/test-configs/integration-tests/horizontal-scrollbar.pageanrc.json';
14
- const consoleOutputTestFailConfigFileName = './tests/test-configs/integration-tests/console-output.pageanrc.json';
15
- const consoleErrorTestFailConfigFileName = './tests/test-configs/integration-tests/console-error.pageanrc.json';
16
- const consoleErrorTestFailReporterHtmlConfigFileName = './tests/test-configs/integration-tests/console-error-reporter-html.pageanrc.json';
17
- const consoleErrorTestFailReporterCliJsonConfigFileName = './tests/test-configs/integration-tests/console-error-reporter-cli-json.pageanrc.json';
18
- const renderedHtmlTestFailConfigFileName = './tests/test-configs/integration-tests/html-error.pageanrc.json';
19
- const pageLoadTimeTestFailConfigFileName = './tests/test-configs/integration-tests/page-load-time.pageanrc.json';
20
- const externalScriptTestFailConfigFileName = './tests/test-configs/integration-tests/external-scripts-error.pageanrc.json';
21
- const brokenLinksTestFailConfigFileName = './tests/test-configs/integration-tests/broken-links-error.pageanrc.json';
22
-
23
- const horizontalScrollbarTestName = 'should not have a horizontal scrollbar';
24
- const consoleOutputTestName = 'should not have console output';
25
- const consoleErrorTestName = 'should not have console errors';
26
- const renderedHtmlTestName = 'should have valid rendered HTML';
27
- const pageLoadTimeTestName = 'should load page within 2 sec';
28
- const externalScriptTestName = 'should not have external scripts';
29
- const brokenLinksTestName = 'should not have broken links';
30
-
31
- const executeTests = async(configFileName) => {
32
- const config = configParser(configFileName);
33
-
34
- const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
35
- const processSpy = jest.spyOn(process, 'exit').mockImplementation(() => { });
36
- const reporterSpy = jest.spyOn(reporter, 'saveReports').mockImplementation(() => { });
37
- const saveScriptSpy = jest.spyOn(fileUtils, 'saveExternalScript').mockImplementation(() => { });
38
- const checkLinkSpy = jest.spyOn(linkUtils, 'checkLink');
39
-
40
- await pagean.executeAllTests(config);
41
- return {
42
- consoleLogSpy,
43
- processSpy,
44
- reporterSpy,
45
- saveScriptSpy,
46
- checkLinkSpy
47
- };
48
- };
49
-
50
- const executeFailedIntegrationTest = async(config, testName) => {
51
- expect.assertions(6); // eslint-disable-line no-magic-numbers
52
- const { processSpy, reporterSpy } = await executeTests(config);
53
-
54
- // Expect test suite to fail and exit with code 1
55
- expect(processSpy).toHaveBeenCalledWith(1);
56
- expect(reporterSpy).toHaveBeenCalledTimes(1);
57
-
58
- const testResults = reporterSpy.mock.calls[0][0]; // eslint-disable-line prefer-destructuring -- less intuitive
59
- // Expect only one URL to be tested
60
- expect(testResults.results).toHaveLength(1);
61
- const failedTests = testResults.results[0].tests;
62
- // Expect only one test to be run
63
- expect(failedTests).toHaveLength(1);
64
- const failedTest = failedTests[0]; // eslint-disable-line prefer-destructuring -- less intuitive
65
- // Verify the correct test was run and failed
66
- expect(failedTest.name).toStrictEqual(testName);
67
- expect(failedTest.result).toStrictEqual(testResultStates.failed);
68
- };
69
-
70
- afterEach(() => {
71
- jest.restoreAllMocks();
72
- });
73
-
74
- it('should execute all tests and all should pass', async() => {
75
- expect.assertions(3); // eslint-disable-line no-magic-numbers
76
- const { processSpy, reporterSpy, saveScriptSpy } = await executeTests(allPassConfigFileName);
77
- // This passes when npm test is called, but fails in other cases like watch
78
- // expect(processSpy).not.toHaveBeenCalled();
79
- expect(processSpy).not.toHaveBeenCalled();
80
- expect(reporterSpy).toHaveBeenCalledTimes(1);
81
- expect(saveScriptSpy).not.toHaveBeenCalled();
82
- });
83
-
84
- it('should execute tests and horizontal scrollbar test should fail', async() => {
85
- expect.hasAssertions();
86
- await executeFailedIntegrationTest(horizontalScrollbarTestFailConfigFileName, horizontalScrollbarTestName);
87
- });
88
-
89
- it('should execute tests and console output test should fail', async() => {
90
- expect.hasAssertions();
91
- await executeFailedIntegrationTest(consoleOutputTestFailConfigFileName, consoleOutputTestName);
92
- });
93
-
94
- it('should execute tests and console error test should fail', async() => {
95
- expect.hasAssertions();
96
- await executeFailedIntegrationTest(consoleErrorTestFailConfigFileName, consoleErrorTestName);
97
- });
98
-
99
- it('should execute tests and rendered HTML test should fail', async() => {
100
- expect.hasAssertions();
101
- await executeFailedIntegrationTest(renderedHtmlTestFailConfigFileName, renderedHtmlTestName);
102
- });
103
-
104
- it('should execute tests and page load time test should fail', async() => {
105
- expect.hasAssertions();
106
- await executeFailedIntegrationTest(pageLoadTimeTestFailConfigFileName, pageLoadTimeTestName);
107
- });
108
-
109
- it('should execute tests and external script test should fail', async() => {
110
- expect.hasAssertions();
111
- await executeFailedIntegrationTest(externalScriptTestFailConfigFileName, externalScriptTestName);
112
- });
113
-
114
- it('should execute tests and broken links test should fail', async() => {
115
- expect.hasAssertions();
116
- await executeFailedIntegrationTest(brokenLinksTestFailConfigFileName, brokenLinksTestName);
117
- });
118
-
119
- // eslint-disable-next-line max-lines-per-function
120
- it('should execute all tests and report failure with the correct tests failed', async() => {
121
- expect.assertions(7); // eslint-disable-line no-magic-numbers
122
- const configFileName = './.pageanrc.json';
123
- const totalTests = 51;
124
- const externalScriptCount = 4;
125
- const linkCount = 7;
126
-
127
- const { processSpy, reporterSpy, saveScriptSpy, checkLinkSpy } = await executeTests(configFileName);
128
-
129
- expect(processSpy).toHaveBeenCalledWith(1);
130
- expect(reporterSpy).toHaveBeenCalledTimes(1);
131
- expect(saveScriptSpy).toHaveBeenCalledTimes(externalScriptCount);
132
- expect(checkLinkSpy).toHaveBeenCalledTimes(linkCount);
133
-
134
- // eslint-disable-next-line prefer-destructuring -- less intuitive
135
- const testResults = reporterSpy.mock.calls[0][0];
136
- // Verify number of expected tests were run
137
- expect(testResults.summary.tests).toStrictEqual(totalTests);
138
- // Verify appropriate tests failed. Some tests have log data with times and paths that
139
- // will fail if just checking snapshot of results, so filter down to URL and failed tests.
140
- const failedTests = testResults.results.reduce((accumulator, currentTestUrl) => {
141
- const failed = currentTestUrl.tests
142
- .filter(test => test.result === testResultStates.failed)
143
- .map(test => ({ url: currentTestUrl.url, name: test.name }));
144
- accumulator.push(...failed);
145
- return accumulator;
146
- }, []);
147
- expect(failedTests).toMatchSnapshot();
148
-
149
- // Check that console message field names are correct and returning data from puppeteer.
150
- // These contain environment-specific data, so exact test isn't checked, but the fields
151
- // will be empty if they are no longer reported by Chromium (see #85, #86).
152
- // eslint-disable-next-line prefer-destructuring
153
- const consoleLogTestFailResult = testResults.results[0].tests[1];
154
- expect(consoleLogTestFailResult.data[0]).toStrictEqual(expect.objectContaining({
155
- _type: expect.any(String),
156
- _text: expect.any(String),
157
- _stackTraceLocations: expect.any(Array)
158
- }));
159
- });
160
-
161
- it('should pass reporter config when saving reports', async() => {
162
- expect.assertions(1);
163
- const { reporterSpy } = await executeTests(consoleErrorTestFailReporterCliJsonConfigFileName);
164
- expect(reporterSpy.mock.calls[0][1]).toStrictEqual(['cli', 'json']);
165
- });
166
-
167
- it('should write all results to console if CLI reporter enabled', async() => {
168
- expect.assertions(1);
169
- const { consoleLogSpy } = await executeTests(consoleErrorTestFailReporterCliJsonConfigFileName);
170
- // Console should be called 3 times: url, test result, and final results
171
- // eslint-disable-next-line no-magic-numbers
172
- expect(consoleLogSpy).toHaveBeenCalledTimes(3);
173
- });
174
-
175
- it('should only summary results to console if CLI reporter disabled', async() => {
176
- expect.assertions(1);
177
- const { consoleLogSpy } = await executeTests(consoleErrorTestFailReporterHtmlConfigFileName);
178
- // Console should only be called once for final results
179
- expect(consoleLogSpy).toHaveBeenCalledTimes(1);
180
- });
181
- });