pagean 10.2.0 → 11.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.
package/README.md CHANGED
@@ -45,79 +45,96 @@ a headless Chrome browser. The URLs defined in the configuration file are each
45
45
  loaded once, and after page load the applicable tests are executed. Test
46
46
  results are `passed` or `failed`, but can be configured to report `warning`
47
47
  instead of failure. Only a `failed` test causes the test process to fail and
48
- exit with an error code (a `warning` doesn't).
48
+ exit with an error code (a `warning` does not). If a page URL fails to load,
49
+ it is retried up to two additional times and if unsuccessful the URL is
50
+ logged as a `page error` with the error message.
49
51
 
50
- ### Horizontal scrollbar test
52
+ ### Broken link test
51
53
 
52
- The horizontal scrollbar test fails if the rendered page has a horizontal
53
- scrollbar. If a specific browser viewport size is desired for this test, that
54
- can be configured in the `puppeteerLaunchOptions`.
54
+ The broken link test checks for broken links on the page. It checks any `<a>`
55
+ tag on the page with `href` pointing to another location on the current page or
56
+ another page (that is, only `http(s)` or `file` protocols).
55
57
 
56
- ### Console output test
58
+ - For links within the page, this test checks for existence of the element on
59
+ the page, passing if the element exists and failing otherwise (and passing
60
+ for cases that are always valid, for example `#` or `#top` for the current
61
+ page). It doesn't check the visibility of the element. Failing tests return a
62
+ response of "#element Not Found" (where `#element` identifies the specific
63
+ element).
64
+ - For links to other pages, the test tries to most efficiently confirm whether
65
+ the target link is valid. It first makes a `HEAD` request for that URL and
66
+ checks the response. If an erroneous response is returned (>= 400 with no
67
+ execution error) and not code 429 (Too Many Requests), the request is retried
68
+ with a `GET` request. The test passes for HTTP responses < 400 and fails
69
+ otherwise (if HTTP response is >= 400 or another error occurs).
70
+ - This can result in false failure indications, specifically for `file:`
71
+ links (`404` or `ECONNREFUSED`) or where the browser passes a domain
72
+ identity with the request (page loads when tested, but `401` response for
73
+ links to that page). For these cases, or other false failures, the test
74
+ configuration allows a Boolean `checkWithBrowser` option that instead
75
+ checks links by loading the target in the browser (via `puppeteer`). Note
76
+ this can increase test execution time, in some cases substantially, due to
77
+ the time to open a new browser tab and plus load the page and all assets.
78
+ - Note that `file:` links can only be tested with the `checkWithBrowser`
79
+ option.
80
+ - If the link to another page includes a hash it's removed prior to checking.
81
+ The test in this case is confirming a valid link, not that the element
82
+ exists, which is only done for the current page.
83
+ - The test configuration allows an `ignoredLinks` array listing link URLs to
84
+ ignore for this test. Note this only applies to links to other pages, not
85
+ links within the page, which are always checked.
86
+ - To optimize performance, link test results are cached and those links aren't
87
+ re-tested for the entire test run (across all tested URLs). The test
88
+ configuration allows a Boolean `ignoreDuplicates` option that can be set to
89
+ `false` to bypass this behavior and re-test all links. The results for any
90
+ failed links are included in the reports in any case.
57
91
 
58
- The console output test fails if any output is written to the browser console.
59
- An array is included in the report with all entries, as shown below:
92
+ For any failing test, the `data` array in the test report includes the original
93
+ URL and the response code or error as shown below.
60
94
 
61
95
  ```json
62
96
  [
63
97
  {
64
- "type": "error",
65
- "text": "Failed to load resource: net::ERR_NAME_NOT_RESOLVED",
66
- "location": {
67
- "url": "https://this.url.does.not.exist/file.js"
68
- }
98
+ "href": "https://about.gitlab.com/not-found",
99
+ "status": 404
100
+ },
101
+ {
102
+ "href": "http://localhost:3000/brokenLinks.html#notlinked",
103
+ "status": "#notlinked Not Found"
104
+ },
105
+ {
106
+ "href": "https://this.url.does.not.exist/",
107
+ "status": "ENOTFOUND"
69
108
  }
70
109
  ]
71
110
  ```
72
111
 
112
+ Note: this test checks all links on the page, and doesn't respect mechanisms
113
+ intended to limit web crawlers such as `robots.txt` or `noindex` tags.
114
+
73
115
  ### Console error test
74
116
 
75
117
  The console error test fails if any error is written to the browser console,
76
- but is otherwise the same as the console output test. This separation allows
77
- for testing for console errors, but allowing any other console output.
118
+ but is otherwise simply a subset of the console output test. This separation
119
+ allows for testing for console errors, but allowing any other console output.
78
120
 
79
- ### Rendered HTML test
121
+ ### Console output test
80
122
 
81
- The rendered HTML test is intended for cases where content is dynamically
82
- created prior to page load (that is, the `load` event firing). The rendered
83
- HTML is returned and checked with
84
- [HTML Hint](https://www.npmjs.com/package/htmlhint) and the test fails if any
85
- issues are found. An array is included in the report with all HTML Hint issues,
86
- as shown below:
123
+ The console output test fails if any output is written to the browser console.
124
+ An array is included in the report with all entries, as shown below:
87
125
 
88
126
  ```json
89
127
  [
90
128
  {
91
- "col": 9,
92
- "evidence": " <div id=\"div1\"></div>",
93
- "line": 6,
94
- "message": "The id value [ div1 ] must be unique.",
95
- "raw": " id=\"div1\"",
96
- "rule": {
97
- "description": "The value of id attributes must be unique.",
98
- "id": "id-unique",
99
- "link": "https://github.com/thedaviddias/HTMLHint/wiki/id-unique"
100
- },
101
- "type": "error"
129
+ "type": "error",
130
+ "text": "Failed to load resource: net::ERR_NAME_NOT_RESOLVED",
131
+ "location": {
132
+ "url": "https://this.url.does.not.exist/file.js"
133
+ }
102
134
  }
103
135
  ]
104
136
  ```
105
137
 
106
- An htmlhintrc file can be specified in the configuration file, otherwise the
107
- default "./.htmlhintrc" file is used (if it exists). See the Configuration
108
- section below.
109
-
110
- Note: this test may not find some errors in the original HTML that are
111
- removed/resolved as the page is parsed (for example closing tags with no
112
- opening tags).
113
-
114
- ### Page load time test
115
-
116
- The page load time test fails if the page load time (from start through the
117
- `load` event) exceeds the defined threshold in the configuration file (or the
118
- default of 2 seconds). The actual load time is included in the report. Tests
119
- time out at twice the page load time threshold.
120
-
121
138
  ### External script test
122
139
 
123
140
  The external script test is intended to identify any externally loaded
@@ -157,68 +174,53 @@ saved filename or applicable error, as shown below.
157
174
  Each external script is saved only once, but is reported on any page where it's
158
175
  referenced.
159
176
 
160
- ### Broken link test
177
+ ### Horizontal scrollbar test
161
178
 
162
- The broken link test checks for broken links on the page. It checks any `<a>`
163
- tag on the page with `href` pointing to another location on the current page or
164
- another page (that is, only `http(s)` or `file` protocols).
179
+ The horizontal scrollbar test fails if the rendered page has a horizontal
180
+ scrollbar. If a specific browser viewport size is desired for this test, that
181
+ can be configured in the `puppeteerLaunchOptions`.
165
182
 
166
- - For links within the page, this test checks for existence of the element on
167
- the page, passing if the element exists and failing otherwise (and passing
168
- for cases that are always valid, for example `#` or `#top` for the current
169
- page). It doesn't check the visibility of the element. Failing tests return a
170
- response of "#element Not Found" (where `#element` identifies the specific
171
- element).
172
- - For links to other pages, the test tries to most efficiently confirm whether
173
- the target link is valid. It first makes a `HEAD` request for that URL and
174
- checks the response. If an erroneous response is returned (>= 400 with no
175
- execution error) and not code 429 (Too Many Requests), the request is retried
176
- with a `GET` request. The test passes for HTTP responses < 400 and fails
177
- otherwise (if HTTP response is >= 400 or another error occurs).
178
- - This can result in false failure indications, specifically for `file:`
179
- links (`404` or `ECONNREFUSED`) or where the browser passes a domain
180
- identity with the request (page loads when tested, but `401` response for
181
- links to that page). For these cases, or other false failures, the test
182
- configuration allows a Boolean `checkWithBrowser` option that instead
183
- checks links by loading the target in the browser (via `puppeteer`). Note
184
- this can increase test execution time, in some cases substantially, due to
185
- the time to open a new browser tab and plus load the page and all assets.
186
- - Note that `file:` links can only be tested with the `checkWithBrowser`
187
- option.
188
- - If the link to another page includes a hash it's removed prior to checking.
189
- The test in this case is confirming a valid link, not that the element
190
- exists, which is only done for the current page.
191
- - The test configuration allows an `ignoredLinks` array listing link URLs to
192
- ignore for this test. Note this only applies to links to other pages, not
193
- links within the page, which are always checked.
194
- - To optimize performance, link test results are cached and those links aren't
195
- re-tested for the entire test run (across all tested URLs). The test
196
- configuration allows a Boolean `ignoreDuplicates` option that can be set to
197
- `false` to bypass this behavior and re-test all links. The results for any
198
- failed links are included in the reports in any case.
183
+ ### Page load time test
199
184
 
200
- For any failing test, the `data` array in the test report includes the original
201
- URL and the response code or error as shown below.
185
+ The page load time test fails if the page load time (from start through the
186
+ `load` event) exceeds the defined threshold in the configuration file (or the
187
+ default of 2 seconds). The actual load time is included in the report. Tests
188
+ time out at twice the page load time threshold.
189
+
190
+ ### Rendered HTML test
191
+
192
+ The rendered HTML test is intended for cases where content is dynamically
193
+ created prior to page load (that is, the `load` event firing). The rendered
194
+ HTML is returned and checked with
195
+ [HTML Hint](https://www.npmjs.com/package/htmlhint) and the test fails if any
196
+ issues are found. An array is included in the report with all HTML Hint issues,
197
+ as shown below:
202
198
 
203
199
  ```json
204
200
  [
205
201
  {
206
- "href": "https://about.gitlab.com/not-found",
207
- "status": 404
208
- },
209
- {
210
- "href": "http://localhost:3000/brokenLinks.html#notlinked",
211
- "status": "#notlinked Not Found"
212
- },
213
- {
214
- "href": "https://this.url.does.not.exist/",
215
- "status": "ENOTFOUND"
202
+ "col": 9,
203
+ "evidence": " <div id=\"div1\"></div>",
204
+ "line": 6,
205
+ "message": "The id value [ div1 ] must be unique.",
206
+ "raw": " id=\"div1\"",
207
+ "rule": {
208
+ "description": "The value of id attributes must be unique.",
209
+ "id": "id-unique",
210
+ "link": "https://github.com/thedaviddias/HTMLHint/wiki/id-unique"
211
+ },
212
+ "type": "error"
216
213
  }
217
214
  ]
218
215
  ```
219
216
 
220
- Note: this test checks all links on the page, and doesn't respect mechanisms
221
- intended to limit web crawlers such as `robots.txt` or `noindex` tags.
217
+ An htmlhintrc file can be specified in the configuration file, otherwise the
218
+ default "./.htmlhintrc" file is used (if it exists). See the Configuration
219
+ section below.
220
+
221
+ Note: this test may not find some errors in the original HTML that are
222
+ removed/resolved as the page is parsed (for example closing tags with no
223
+ opening tags).
222
224
 
223
225
  ## Reports
224
226
 
@@ -227,14 +229,15 @@ console and saved in two reports in the project root directory (any or all of
227
229
  the three):
228
230
 
229
231
  - A JSON report named
230
- [`pagean-results.json`](https://gitlab-ci-utils.gitlab.io/pagean/pagean-results.json)
232
+ [`pagean-results.json`](https://gitlab-ci-utils.gitlab.io/pagean/pagean-results.json).
231
233
  - An HTML report named
232
- [`pagean-results.html`](https://gitlab-ci-utils.gitlab.io/pagean/pagean-results.html)
234
+ [`pagean-results.html`](https://gitlab-ci-utils.gitlab.io/pagean/pagean-results.html).
233
235
 
234
236
  Both reports contain:
235
237
 
236
- - The time of test execution
237
- - A summary of the total tests and results (passed, warning, failed)
238
+ - The time of test execution.
239
+ - A summary of the total tests and results (passed, warning, failed, and page
240
+ errors).
238
241
  - The detailed test results, including the URL tested, list of tests performed
239
242
  on that URL with results, and, if applicable, any relevant data associated
240
243
  with the test failure (for example the console errors if the console error
@@ -256,12 +259,11 @@ Below is an example `.pageanrc.json` file, which is broken into seven major
256
259
  properties:
257
260
 
258
261
  - `htmlhintrc`: An optional path to an htmlhintrc file to be used in the
259
- rendered HTML test
262
+ rendered HTML test.
260
263
  - `project`: An optional name of the project, which is included in HTML and
261
264
  JSON reports.
262
265
  - `puppeteerLaunchOptions`: An optional set of options to pass to Puppeteer on
263
- launch. There are no default options. The complete list of available options
264
- can be found at
266
+ launch. The complete list of available options can be found at
265
267
  https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions.
266
268
  - `reporters`: An optional array of reporters indicating the test reports that
267
269
  should be provided. There are three possible options - `cli`, `html`, and
@@ -302,8 +304,6 @@ is equivalent to the longhand:
302
304
  }
303
305
  ```
304
306
 
305
- All available settings with the default values are shown below.
306
-
307
307
  - `sitemap`: Specify a sitemap with URLs to test. If a sitemap is specified,
308
308
  the URLs from the sitemap are added to the `urls` array. If a URL is in the
309
309
  `urls` array with `settings`, those settings are retained. Note that
@@ -327,14 +327,23 @@ All available settings with the default values are shown below.
327
327
  testing that URL. The `url` string can be either an actual URL or a local
328
328
  file, as shown in the example below.
329
329
 
330
+ The following shows all available settings, except `sitemap`, with the default
331
+ values.
332
+
330
333
  ```json
331
334
  {
332
335
  "puppeteerLaunchOptions": {
333
- "args": ["--no-sandbox"]
336
+ "headless": "new"
334
337
  },
335
338
  "reporters": ["cli", "html", "json"],
336
339
  "settings": {
337
- "horizontalScrollbarTest": {
340
+ "brokenLinkTest": {
341
+ "enabled": true,
342
+ "failWarn": false,
343
+ "checkWithBrowser": false,
344
+ "ignoreDuplicates": true
345
+ },
346
+ "consoleErrorTest": {
338
347
  "enabled": true,
339
348
  "failWarn": false
340
349
  },
@@ -342,11 +351,11 @@ All available settings with the default values are shown below.
342
351
  "enabled": true,
343
352
  "failWarn": false
344
353
  },
345
- "consoleErrorTest": {
354
+ "externalScriptTest": {
346
355
  "enabled": true,
347
- "failWarn": false
356
+ "failWarn": true
348
357
  },
349
- "renderedHtmlTest": {
358
+ "horizontalScrollbarTest": {
350
359
  "enabled": true,
351
360
  "failWarn": false
352
361
  },
@@ -355,35 +364,23 @@ All available settings with the default values are shown below.
355
364
  "failWarn": false,
356
365
  "pageLoadTimeThreshold": 2
357
366
  },
358
- "externalScriptTest": {
359
- "enabled": true,
360
- "failWarn": true
361
- },
362
- "brokenLinkTest": {
367
+ "renderedHtmlTest": {
363
368
  "enabled": true,
364
- "failWarn": false,
365
- "checkWithBrowser": false,
366
- "ignoreDuplicates": true,
367
- "ignoredLinks": []
368
- }
369
- },
370
- "urls": [
371
- "https://gitlab.com/gitlab-ci-utils/pagean/",
372
- {
373
- "url": "./tests/fixtures/site/consoleLog.html",
374
- "settings": {
375
- "consoleOutputTest": false
376
- }
369
+ "failWarn": false
377
370
  }
378
- ]
371
+ }
379
372
  }
380
373
  ```
381
374
 
375
+ Numerous example config files used in the tests can be found
376
+ [here](tests/fixtures/configs/).
377
+
382
378
  ## Container images
383
379
 
384
380
  Provided with the Pagean project are container images configured to run the
385
- tests. All available image tags can be found in the `gitlab-ci-utils/pagean`
386
- repository at https://gitlab.com/gitlab-ci-utils/pagean/container_registry.
381
+ tests. All available image tags can be found in the
382
+ `registry.gitlab.com/gitlab-ci-utils/pagean` repository
383
+ [here](https://gitlab.com/gitlab-ci-utils/pagean/container_registry).
387
384
  Details on each release can be found on the
388
385
  [Releases](https://gitlab.com/gitlab-ci-utils/pagean/releases) page.
389
386
 
@@ -419,7 +416,7 @@ pagean:
419
416
  - pagean-external-scripts/
420
417
  ```
421
418
 
422
- ### Testing with static HTTP server
419
+ ### Testing with a static HTTP server
423
420
 
424
421
  The container image shown previously includes
425
422
  [`serve`](https://www.npmjs.com/package/serve) and
package/bin/pagean.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';
3
2
 
4
- const { log, Levels } = require('ci-logger');
5
- const { program } = require('commander');
6
- const pagean = require('../index');
7
- const getConfig = require('../lib/config');
8
- const pkg = require('../package.json');
3
+ import { Levels, log } from 'ci-logger';
4
+ import { program } from 'commander';
5
+
6
+ import { executeAllTests } from '../index.js';
7
+ import getConfig from '../lib/config.js';
8
+ import { pkg } from '../lib/utils.js';
9
9
 
10
10
  const defaultConfigFileName = './.pageanrc.json';
11
11
 
@@ -19,19 +19,14 @@ program
19
19
  .parse(process.argv);
20
20
  const options = program.opts();
21
21
 
22
- getConfig(options.config)
23
- /* eslint-disable-next-line promise/always-return -- required instead
24
- of top level await */
25
- .then((config) => {
26
- pagean.executeAllTests(config);
27
- })
28
- /* eslint-disable-next-line promise/prefer-await-to-callbacks --
29
- required instead of top level await */
30
- .catch((error) => {
31
- log({
32
- errorCode: 1,
33
- exitOnError: true,
34
- level: Levels.Error,
35
- message: `Error executing pagean tests\n${error.message}`
36
- });
22
+ try {
23
+ const config = await getConfig(options.config);
24
+ executeAllTests(config);
25
+ } catch (error) {
26
+ log({
27
+ errorCode: 1,
28
+ exitOnError: true,
29
+ level: Levels.Error,
30
+ message: `Error executing pagean tests\n${error.message}`
37
31
  });
32
+ }
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';
3
2
 
4
- const { log, Levels } = require('ci-logger');
5
- const { program } = require('commander');
6
- const { green, underline } = require('kleur');
7
- const { lintConfigFile } = require('../lib/config');
8
- const { formatErrors } = require('../lib/schema-errors');
9
- const pkg = require('../package.json');
3
+ import { Levels, log } from 'ci-logger';
4
+ import kleur from 'kleur';
5
+ import { program } from 'commander';
6
+
7
+ import { formatErrors } from '../lib/schema-errors.js';
8
+ import { lintConfigFile } from '../lib/config.js';
9
+ import { pkg } from '../lib/utils.js';
10
10
 
11
11
  const defaultConfigFileName = './.pageanrc.json';
12
12
 
@@ -34,9 +34,9 @@ const outputJsonResults = (configFileName, lintResults) => {
34
34
 
35
35
  const outputConsoleResults = (configFileName, lintResults) => {
36
36
  if (lintResults.isValid) {
37
- log({ message: `\n${configFileName}: ${green('valid')}\n` });
37
+ log({ message: `\n${configFileName}: ${kleur.green('valid')}\n` });
38
38
  } else {
39
- logError(`\n${underline(configFileName)}`, false);
39
+ logError(`\n${kleur.underline(configFileName)}`, false);
40
40
  for (const error of formatErrors(lintResults.errors)) {
41
41
  logError(error, false);
42
42
  }
package/index.js CHANGED
@@ -1,38 +1,43 @@
1
- 'use strict';
2
-
3
1
  /**
4
2
  * Pagean test framework.
5
3
  *
6
4
  * @module pagean
7
5
  */
8
- const puppeteer = require('puppeteer');
9
6
 
10
- const testLogger = require('./lib/logger');
11
- const testReporter = require('./lib/reporter');
12
- const { ...testFunctions } = require('./lib/tests');
13
- const { createLinkChecker } = require('./lib/link-utils');
7
+ import puppeteer from 'puppeteer';
8
+
9
+ import * as testFunctions from './lib/tests.js';
10
+ import { createLinkChecker } from './lib/link-utils.js';
11
+ import { saveReports } from './lib/reporter.js';
12
+ import testLogger from './lib/logger.js';
14
13
 
15
14
  /**
16
15
  * @typedef {object} PageOptions
17
16
  * @property {number} retryCount - The number of times to retry navigation.
18
17
  * @property {number} timeout - The timeout for navigation.
19
18
  */
19
+
20
+ /** @type {PageOptions} */
20
21
  const defaultPageOptions = {
21
22
  retryCount: 2,
22
23
  timeout: 60_000
23
24
  };
24
25
 
26
+ /** @typedef {import('puppeteer').Page} Page */
27
+
25
28
  /**
26
29
  * Opens the specified URL in the given page, with retry logic.
27
30
  *
28
- * @param {string} page The puppeteer page object.
29
- * @param {string} url The URL to navigate to.
30
- * @param {PageOptions} options The options for navigating to the URL.
31
+ * @param {Page} page The puppeteer page object.
32
+ * @param {string} url The URL to navigate to.
33
+ * @param {PageOptions} options The options for navigating to the URL.
34
+ * @throws {Error} If the navigation fails.
31
35
  * @static
32
36
  * @private
33
37
  */
34
38
  const gotoPage = async (page, url, options) => {
35
39
  let retryCount = 0;
40
+ let lastError;
36
41
  while (retryCount < options.retryCount) {
37
42
  try {
38
43
  /* eslint-disable no-await-in-loop -- loop for retry only */
@@ -44,24 +49,33 @@ const gotoPage = async (page, url, options) => {
44
49
  });
45
50
  /* eslint-enable no-await-in-loop -- loop for retry only */
46
51
  break;
47
- } catch {
52
+ } catch (error) {
53
+ lastError = error;
48
54
  retryCount++;
49
- console.error(
50
- `Failed to navigate to ${url}. Retrying (${retryCount}/${options.retryCount})...`
51
- );
52
55
  }
53
56
  }
57
+
58
+ // Normalize URLs for comparison, prevents cases like trailing slashes
59
+ // from causing false negatives.
60
+ const desiredUrl = new URL(url);
61
+ const currentUrl = new URL(page.url());
62
+ if (currentUrl.href !== desiredUrl.href) {
63
+ throw lastError;
64
+ }
54
65
  };
55
66
 
67
+ /** @typedef {import('./lib/config.js').PageanConfig} PageanConfig */
68
+
56
69
  /* eslint-disable no-await-in-loop, max-lines-per-function --
57
70
  no-await-in-loop - tests are deliberately performed synchronously,
58
71
  max-lines-per-function - allowed to test executor */
59
72
  /**
60
73
  * Executes Pagean tests as specified in config and reports results.
61
74
  *
62
- * @param {object} config The Pagean test configuration.
75
+ * @param {PageanConfig} config The Pagean test configuration.
63
76
  * @static
64
77
  */
78
+ // eslint-disable-next-line sonarjs/cognitive-complexity -- Allow < 10
65
79
  const executeAllTests = async (config) => {
66
80
  const logger = testLogger(config);
67
81
  const linkChecker = createLinkChecker();
@@ -79,7 +93,15 @@ const executeAllTests = async (config) => {
79
93
  type: message.type()
80
94
  })
81
95
  );
82
- await gotoPage(page, testUrl.url, defaultPageOptions);
96
+
97
+ try {
98
+ await gotoPage(page, testUrl.url, defaultPageOptions);
99
+ } catch (error) {
100
+ logger.logPageError(error.message);
101
+ /* eslint-disable-next-line no-continue -- tests should not be
102
+ executed if navigation fails */
103
+ continue;
104
+ }
83
105
 
84
106
  const testContext = {
85
107
  consoleLog,
@@ -99,9 +121,9 @@ const executeAllTests = async (config) => {
99
121
  }
100
122
  await browser.close();
101
123
  const testResults = logger.getTestResults();
102
- testReporter.saveReports(testResults, config.reporters);
124
+ saveReports(testResults, config.reporters);
103
125
 
104
- if (testResults.summary.failed > 0) {
126
+ if (testResults.summary.failed > 0 || testResults.summary.pageError > 0) {
105
127
  // For test harness want process to exit with error code
106
128
  // eslint-disable-next-line unicorn/no-process-exit, no-magic-numbers -- exit code
107
129
  process.exit(2);
@@ -109,4 +131,4 @@ const executeAllTests = async (config) => {
109
131
  };
110
132
  /* eslint-enable no-await-in-loop, max-lines-per-function -- enable */
111
133
 
112
- module.exports.executeAllTests = executeAllTests;
134
+ export { executeAllTests };