pagean 9.0.0 → 10.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2019 - 2023 Aaron Goldenthal
3
+ Copyright (c) 2019 - 2024 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/README.md CHANGED
@@ -1,10 +1,15 @@
1
1
  # Pagean
2
2
 
3
- Pagean is a web page analysis tool designed to automate tests requiring web pages to be loaded in a browser window (e.g. 404 error loading an external resource, page renders with horizontal scrollbars). The specific tests are outlined below, but are all general tests that do not include any page-specific logic.
3
+ Pagean is a web page analysis tool designed to automate tests requiring web
4
+ pages to be loaded in a browser window (for example 404 error loading an
5
+ external resource, page renders with horizontal scrollbars). The specific tests
6
+ are outlined below, but are all general tests that do not include any
7
+ page-specific logic.
4
8
 
5
9
  ## Installation
6
10
 
7
- Install Pagean globally (as shown below), or locally, via [npm](https://www.npmjs.com/).
11
+ Install Pagean globally (as shown below), or locally, via
12
+ [npm](https://www.npmjs.com/).
8
13
 
9
14
  ```
10
15
  npm install -g pagean
@@ -27,19 +32,31 @@ Options:
27
32
  -h, --help display help for command
28
33
  ```
29
34
 
30
- Pagean requires a configuration file named, which can be specified via the CLI as detailed above, or use the default file `.pageanrc.json` in the project root. This file provides the URLs to be tested and options to configure the tests and reports. Details on the available tests and the configuration file format are provided below.
35
+ Pagean requires a configuration file named, which can be specified via the CLI
36
+ as detailed previously, or use the default file `.pageanrc.json` in the project
37
+ root. This file provides the URLs to be tested and options to configure the
38
+ tests and reports. Details on the available tests and the configuration file
39
+ format are provided below.
31
40
 
32
- ## Test Cases
41
+ ## Test cases
33
42
 
34
- The tests use [Puppeteer](https://github.com/GoogleChrome/puppeteer) to launch a headless Chrome browser. The URLs defined in the configuration file are each loaded once, and after page load the applicable tests are executed. Test results are `passed` or `failed`, but can be configured to report `warning` instead of failure. Only a `failed` test will cause the test process to fail and exit with an error code (a `warning` will not).
43
+ The tests use [Puppeteer](https://github.com/GoogleChrome/puppeteer) to launch
44
+ a headless Chrome browser. The URLs defined in the configuration file are each
45
+ loaded once, and after page load the applicable tests are executed. Test
46
+ results are `passed` or `failed`, but can be configured to report `warning`
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).
35
49
 
36
- ### Horizontal Scrollbar Test
50
+ ### Horizontal scrollbar test
37
51
 
38
- The horizontal scrollbar test fails if the rendered page has a horizontal scrollbar. If a specific browser viewport size is desired for this test, that can be configured in the `puppeteerLaunchOptions`.
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`.
39
55
 
40
- ### Console Output Test
56
+ ### Console output test
41
57
 
42
- The console output test fails if any output is written to the browser console. An array is included in the report with all entries, as shown below:
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:
43
60
 
44
61
  ```json
45
62
  [
@@ -53,13 +70,20 @@ The console output test fails if any output is written to the browser console. A
53
70
  ]
54
71
  ```
55
72
 
56
- ### Console Error Test
73
+ ### Console error test
57
74
 
58
- The console error test fails if any error is written to the browser console, but is otherwise the same as the console output test. This separation allows for testing for console errors, but allowing any other console output.
75
+ 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.
59
78
 
60
- ### Rendered HTML Test
79
+ ### Rendered HTML test
61
80
 
62
- The rendered HTML test is intended for cases where content is dynamically created prior to page load (i.e. the `load` event firing). The rendered HTML is returned and checked with [HTML Hint](https://www.npmjs.com/package/htmlhint) and the test fails if any issues are found. An array is included in the report with all HTML Hint issues, as shown below:
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:
63
87
 
64
88
  ```json
65
89
  [
@@ -79,23 +103,43 @@ The rendered HTML test is intended for cases where content is dynamically create
79
103
  ]
80
104
  ```
81
105
 
82
- An htmlhintrc file can be specified in the configuration file, otherwise the default "./.htmlhintrc" file will be used (if it exists). See the Configuration section below.
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.
83
109
 
84
- Note: This test may not find some errors in the original HTML that are removed/resolved as the page is parsed (e.g. closing tags with no opening tags).
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).
85
113
 
86
- ### Page Load Time Test
114
+ ### Page load time test
87
115
 
88
- The page load time test fails if the page load time (from start through the `load` event) exceeds the defined threshold in the configuration file (or the default of 2 seconds). The actual load time is included in the report. Tests will time out at twice the page load time threshold.
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.
89
120
 
90
- ### External Script Test
121
+ ### External script test
91
122
 
92
- The external script test is intended to identify any externally loaded javascript files (e.g. loaded from a CDN) and aggregate those files so they can undergo further analysis (e.g. dependency vulnerability scanning). The test is included here since these tests load fully rendered pages, therefore allowing the aggregation of this data for pages generated using any language or framework. By default the test returns a warning if the page includes any javascript files loaded from a different domain than the page (although this could be overridden to fail instead via setting `failWarn: false`, see the Configuration section below). These files are then downloaded and saved in the "pagean-external-files" directory in the project root. Subdirectories are created for each domain, then following the URL path. For example, the following script...
123
+ The external script test is intended to identify any externally loaded
124
+ JavaScript files (for example loaded from a CDN) and aggregate those files so
125
+ they can undergo further analysis (for example dependency vulnerability
126
+ scanning). The test is included here since these tests load fully rendered
127
+ pages, therefore allowing the aggregation of this data for pages generated
128
+ using any language or framework. By default the test returns a warning if the
129
+ page includes any JavaScript files loaded from a different domain than the page
130
+ (although this could be overridden to fail instead via setting
131
+ `failWarn: false`, see the Configuration section below). These files are then
132
+ downloaded and saved in the "pagean-external-files" directory in the project
133
+ root. Subdirectories are created for each domain, then following the URL path.
134
+ For example, the following script…
93
135
 
94
136
  ```html
95
137
  <script src="https://bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
96
138
  ```
97
139
 
98
- ...will be saved as `./bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js`. The `data` array in the test report includes the original file URL and the local saved filename or applicable error, as shown below.
140
+ …is saved as `./bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js`. The
141
+ `data` array in the test report includes the original file URL and the local
142
+ saved filename or applicable error, as shown below.
99
143
 
100
144
  ```json
101
145
  [
@@ -110,21 +154,51 @@ The external script test is intended to identify any externally loaded javascrip
110
154
  ]
111
155
  ```
112
156
 
113
- Each external script is saved only once, but will be reported on any page where it is referenced.
114
-
115
- ### Broken Link Test
116
-
117
- The broken link test checks for broken links on the page. It checks any `<a>` tag on the page with `href` pointing to another location on the current page or another page (i.e. only `http(s)` or `file` protocols).
118
-
119
- - For links within the page, this test checks for existence of the element on the page, passing if the element exists and failing otherwise (and passing for cases that are always valid, e.g. `#` or `#top` for the current page). It does not check the visibility of the element. Failing tests return a response of "#element Not Found" (where `#element` identifies the specific element).
120
- - For links to other pages, the test tries to most efficiently confirm whether the target link is valid. It first makes a `HEAD` request for that URL and checks the response. If an erroneous response is returned (>= 400 with no execution error) and not code 429 (Too Many Requests), the request is retried with a `GET` request. The test passes for HTTP responses < 400 and fails otherwise (if HTTP response is >= 400 or another error occurs).
121
- - This can result in false failure indications, specifically for `file:` links (`404` or `ECONNREFUSED`) or where the browser passes a domain identity with the request (page loads when tested, but `401` response for links to that page). For these cases, or other false failures, the test configuration allows a boolean `checkWithBrowser` option that will instead check links by loading the target in the browser (via `puppeteer`). Note this can increase test execution time, in some cases substantially, due to the time to open a new browser tab and plus load the page and all assets.
122
- - Note that `file:` links can only be tested with the `checkWithBrowser` option.
123
- - If the link to another page includes a hash it is removed prior to checking. The test in this case is confirming a valid link, not that the element exists, which is only done for the current page.
124
- - The test configuration allows an `ignoredLinks` array listing link URLs to ignore for this test. Note this only applies to links to other pages, not links within the page, which are always checked.
125
- - To optimize performance, link test results are cached and those links are not re-tested for the entire test run (across all tested URLs). The test configuration allows a boolean `ignoreDuplicates` option that can be set to `false` to bypass this behavior and re-test all links. The results for any failed links are included in the reports in any case.
126
-
127
- For any failing test, the `data` array in the test report includes the original URL and the response code or error as shown below.
157
+ Each external script is saved only once, but is reported on any page where it's
158
+ referenced.
159
+
160
+ ### Broken link test
161
+
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).
165
+
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.
199
+
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.
128
202
 
129
203
  ```json
130
204
  [
@@ -143,38 +217,71 @@ For any failing test, the `data` array in the test report includes the original
143
217
  ]
144
218
  ```
145
219
 
146
- Note: This test will check all links on the page, and does not respect mechanisms inteded to limit web crawlers such as `robots.txt` or `noindex` tags.
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.
147
222
 
148
223
  ## Reports
149
224
 
150
- Based on the `reporters` configuration, Pagean results may be displayed in the console and saved in two reports in the project root directory (any or all of the three):
225
+ Based on the `reporters` configuration, Pagean results may be displayed in the
226
+ console and saved in two reports in the project root directory (any or all of
227
+ the three):
151
228
 
152
- - A JSON report named [`pagean-results.json`](https://gitlab-ci-utils.gitlab.io/pagean/pagean-results.json)
153
- - An HTML report named [`pagean-results.html`](https://gitlab-ci-utils.gitlab.io/pagean/pagean-results.html)
229
+ - A JSON report named
230
+ [`pagean-results.json`](https://gitlab-ci-utils.gitlab.io/pagean/pagean-results.json)
231
+ - An HTML report named
232
+ [`pagean-results.html`](https://gitlab-ci-utils.gitlab.io/pagean/pagean-results.html)
154
233
 
155
234
  Both reports contain:
156
235
 
157
236
  - The time of test execution
158
237
  - A summary of the total tests and results (passed, warning, failed)
159
- - The detailed test results, including the URL tested, list of tests performed on that URL with results, and, if applicable, any relevant data associated with the test failure (e.g. the console errors if the console error test fails).
238
+ - The detailed test results, including the URL tested, list of tests performed
239
+ on that URL with results, and, if applicable, any relevant data associated
240
+ with the test failure (for example the console errors if the console error
241
+ test fails).
160
242
 
161
- Complete reports for the example case in this project (the tests as specified in the project [`.pageanrc.json`](https://gitlab.com/gitlab-ci-utils/pagean/-/blob/master/.pageanrc.json) file) can be found at the links above.
243
+ Complete reports for the example case in this project (the tests as specified
244
+ in the project
245
+ [`.pageanrc.json`](https://gitlab.com/gitlab-ci-utils/pagean/-/blob/master/.pageanrc.json)
246
+ file) can be found at the preceding links.
162
247
 
163
248
  ## Configuration
164
249
 
165
- Pagean looks for a configuration file as specified via the CLI, or defaults to a file named `.pageanrc.json` in the project root. If the configuration file is not found, is not valid JSON, or does not contain any URLs to check the job will fail.
166
-
167
- Below is an example `.pageanrc.json` file, which is broken into seven major properties:
168
-
169
- - `htmlhintrc`: An optional path to an htmlhintrc file to be used in the rendered HTML test
170
- - `project`: An optional name of the project, which is included in HTML and JSON reports.
171
- - `puppeteerLaunchOptions`: An optional set of options to pass to Puppeteer on launch. There are no default options. The complete list of available options can be found at https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions.
172
- - `reporters`: An optional array of reporters indicating the test reports that should be provided. There are three possible options - `cli`, `html`, and `json`. The `cli` option reports all test details to the console, but the final results summary is always output (even with `cli` disabled). If `reporters` is specified, at least one reporter must be included. The default value, as specified below, is all three reporters enabled.
173
- - `settings`: These settings enable/disable or configure tests, and are applied to all tests overriding the default values.
174
- - The shorthand notation allows easy enabling/disabling of tests. In this format the test name is given with a boolean value to enable or disable the test. In this case any other test-specific settings use the default values.
175
- - The longhand version includes an object for each test. Every test includes two possible properties (some tests include additional settings):
176
- - `enabled`: A boolean value to enable/disable the test, and some tests include additional settings (default `true` for all tests).
177
- - `failWarn`: A boolean value causing a failed test to report a warning instead of failure. A warning result will not cause the test process to fail (exit with an error code). The default value for all tests is `false` except the `externalScriptTest`, as shown below.
250
+ Pagean looks for a configuration file as specified via the CLI, or defaults to
251
+ a file named `.pageanrc.json` in the project root. If the configuration file is
252
+ not found, is not valid JSON, or doesn't contain any URLs to check the job
253
+ fails.
254
+
255
+ Below is an example `.pageanrc.json` file, which is broken into seven major
256
+ properties:
257
+
258
+ - `htmlhintrc`: An optional path to an htmlhintrc file to be used in the
259
+ rendered HTML test
260
+ - `project`: An optional name of the project, which is included in HTML and
261
+ JSON reports.
262
+ - `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
265
+ https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions.
266
+ - `reporters`: An optional array of reporters indicating the test reports that
267
+ should be provided. There are three possible options - `cli`, `html`, and
268
+ `json`. The `cli` option reports all test details to the console, but the
269
+ final results summary is always output (even with `cli` disabled). If
270
+ `reporters` is specified, at least one reporter must be included. The default
271
+ value, as specified below, is all three reporters enabled.
272
+ - `settings`: These settings enable/disable or configure tests, and are applied
273
+ to all tests overriding the default values.
274
+ - The shorthand notation allows easy enabling/disabling of tests. In this
275
+ format the test name is given with a Boolean value to enable or disable the
276
+ test. In this case any other test-specific settings use the default values.
277
+ - The longhand version includes an object for each test. Every test includes
278
+ two possible properties (some tests include additional settings):
279
+ - `enabled`: A Boolean value to enable/disable the test, and some tests
280
+ include additional settings (default `true` for all tests).
281
+ - `failWarn`: A Boolean value causing a failed test to report a warning
282
+ instead of failure. A warning result doesn't cause the test process to
283
+ fail (exit with an error code). The default value for all tests is
284
+ `false` except the `externalScriptTest`, as shown below.
178
285
 
179
286
  The shorthand:
180
287
 
@@ -197,12 +304,28 @@ is equivalent to the longhand:
197
304
 
198
305
  All available settings with the default values are shown below.
199
306
 
200
- - `sitemap`: Specify a sitemap with URLs to test. If a sitemap is specified, the URLs from the sitemap are added to the `urls` array. If a URL is in the `urls` array with `settings`, those settings are retained. Note that `<sitemapindex>` is currently not supported. The `sitemap` object can have the following properties:
201
- - `url`: The URL of the sitemap (required if `sitemap` is included). This can be either an actual URL or a local file.
202
- - `find`: A string to search for in sitemap URLs (e.g. `https://somehere.test`) (required if `replace` is specified).
203
- - `replace`: The string to replace the `find` string with (e.g. `http://localhost:3000`) (required if `find` is specified).
204
- - `exclude`: An array of strings with regular expressions to exclude URLs from the sitemap (e.g. `['\.pdf$']` to exclude any PDF files). Since these are string representations of regular expressions, the backslash must be escaped (e.g. `\\.`). Exclude is performed before find/replace, so uses the original URLs from the sitemap.
205
- - `urls`: An array of URLs to be tested, which must contain at least one value. Each array entry can either be a URL string, or an object that contains a `url` string and an optional `settings` object. This object can contain any of the `settings` values identified above and will override that setting for testing that URL. The `url` string can be either an actual URL or a local file, as shown in the example below.
307
+ - `sitemap`: Specify a sitemap with URLs to test. If a sitemap is specified,
308
+ the URLs from the sitemap are added to the `urls` array. If a URL is in the
309
+ `urls` array with `settings`, those settings are retained. Note that
310
+ `<sitemapindex>` is currently not supported. The `sitemap` object can have
311
+ the following properties:
312
+ - `url`: The URL of the sitemap (required if `sitemap` is included). This can
313
+ be either an actual URL or a local file.
314
+ - `find`: A string to search for in sitemap URLs (for example
315
+ `https://somehere.test`) (required if `replace` is specified).
316
+ - `replace`: The string to replace the `find` string with (for example
317
+ `http://localhost:3000`) (required if `find` is specified).
318
+ - `exclude`: An array of strings with regular expressions to exclude URLs
319
+ from the sitemap (for example `['\.pdf$']` to exclude any PDF files). Since
320
+ these are string representations of regular expressions, the backslash must
321
+ be escaped (for example `\\.`). Exclude is performed before find/replace,
322
+ so uses the original URLs from the sitemap.
323
+ - `urls`: An array of URLs to be tested, which must contain at least one value.
324
+ Each array entry can either be a URL string, or an object that contains a
325
+ `url` string and an optional `settings` object. This object can contain any
326
+ of the `settings` values identified previously and overrides that setting for
327
+ testing that URL. The `url` string can be either an actual URL or a local
328
+ file, as shown in the example below.
206
329
 
207
330
  ```json
208
331
  {
@@ -256,19 +379,31 @@ All available settings with the default values are shown below.
256
379
  }
257
380
  ```
258
381
 
259
- ## Docker Images
382
+ ## Container images
260
383
 
261
- Provided with the Pagean project are Docker images configured to run the tests. All available image tags can be found in the `gitlab-ci-utils/pagean` repository at https://gitlab.com/gitlab-ci-utils/pagean/container_registry. Details on each release can be found on the [Releases](https://gitlab.com/gitlab-ci-utils/pagean/releases) page.
384
+ 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.
387
+ Details on each release can be found on the
388
+ [Releases](https://gitlab.com/gitlab-ci-utils/pagean/releases) page.
262
389
 
263
- **Note:** Any images in the `gitlab-ci-utils/pagean/tmp` repository are temporary images used during the build process and may be deleted at any point.
390
+ **Note:** any images in the `gitlab-ci-utils/pagean/tmp` repository are
391
+ temporary images used during the build process and may be deleted at any point.
264
392
 
265
- ### Puppeteer Cache Location
393
+ ### Puppeteer cache location
266
394
 
267
- In [Puppeteer v19](https://github.com/puppeteer/puppeteer/releases/tag/v19.0.0) the default cache location for installing the Chrome binary was changed from within the project's `node_modules` folder to `~/.cache/puppeteer`. To simplify execution in a container, the `PUPPETEER_CACHE_DIR` environment variable is set to install the Chrome binaries in `/home/pptruser/.cache/puppeteer` during container build, so setting to another value before execution can cause errors where Puppeteer cannot find the Chrome binary.
395
+ In [Puppeteer v19](https://github.com/puppeteer/puppeteer/releases/tag/v19.0.0)
396
+ the default cache location for installing the Chrome binary was changed from
397
+ within the project's `node_modules` folder to `~/.cache/puppeteer`. To simplify
398
+ execution in a container, the `PUPPETEER_CACHE_DIR` environment variable is set
399
+ to install the Chrome binaries in `/home/pptruser/.cache/puppeteer` during
400
+ container build, so setting to another value before execution can cause errors
401
+ where Puppeteer can't find the Chrome binary.
268
402
 
269
- ## GitLab CI Configuration
403
+ ## GitLab CI configuration
270
404
 
271
- The following is an example job from a .gitlab-ci.yml file to use this image to run Pagean against another project in GitLab CI:
405
+ The following is an example job from a .gitlab-ci.yml file to use this image to
406
+ run Pagean against another project in GitLab CI:
272
407
 
273
408
  ```yaml
274
409
  pagean:
@@ -284,9 +419,17 @@ pagean:
284
419
  - pagean-external-scripts/
285
420
  ```
286
421
 
287
- ### Testing With Static HTTP Server
422
+ ### Testing with static HTTP server
288
423
 
289
- The Docker image shown above includes [`serve`](https://www.npmjs.com/package/serve) and [`wait-on`](https://www.npmjs.com/package/wait-on) installed globally to run a local HTTP server for testing static content. The example job below illustrates how to use this for Pagean tests. The script starts the server in this project's `./tests/fixtures/site` directory and uses `wait-on` to hold the script until the server is running and returns a valid response. The referenced `pageanrc` file is the same as the project default `pageanrc`, but references all test URLs from the local server.
424
+ The container image shown previously includes
425
+ [`serve`](https://www.npmjs.com/package/serve) and
426
+ [`wait-on`](https://www.npmjs.com/package/wait-on) installed globally to run a
427
+ local HTTP server for testing static content. The example job below illustrates
428
+ how to use this for Pagean tests. The script starts the server in this
429
+ project's `./tests/fixtures/site` directory and uses `wait-on` to hold the
430
+ script until the server is running and returns a valid response. The referenced
431
+ `pageanrc` file is the same as the project default `pageanrc`, but references
432
+ all test URLs from the local server.
290
433
 
291
434
  ```yaml
292
435
  pagean:
@@ -306,9 +449,10 @@ pagean:
306
449
  - pagean-external-scripts/
307
450
  ```
308
451
 
309
- ## Linting Pageanrc Files
452
+ ## Linting pageanrc files
310
453
 
311
- A command line tool is also available to lint pageanrc files, which is executed as follows:
454
+ A command line tool is also available to lint pageanrc files, which is executed
455
+ as follows:
312
456
 
313
457
  ```
314
458
  Installed globally:
@@ -325,21 +469,28 @@ Options:
325
469
  -h, --help display help for command
326
470
  ```
327
471
 
328
- The `--json` option outputs the JSON results to stdout in all cases for consistency (`[]` if no errors found, so that it always outputs valid JSON). Otherwise errors are output to stderr, for example:
472
+ The `--json` option outputs the JSON results to stdout in all cases for
473
+ consistency (`[]` if no errors found, so that it always outputs valid
474
+ JSON). Otherwise errors are output to stderr, for example:
329
475
 
330
476
  ```sh
331
477
  .\tests\test-configs\cli-tests\some-test.pageanrc.json
332
478
  <pageanrc>.puppeteerLaunchOptions must NOT have fewer than 1 properties
333
479
  <pageanrc>.reporters[0] must be equal to one of the allowed values (cli, html, json)
334
- <pageanrc>.settings.consoleOutputTest must be either boolean or object with the appropriate properties
480
+ <pageanrc>.settings.consoleOutputTest must be either Boolean or object with the appropriate properties
335
481
  <pageanrc>.settings.pageLoadTimeTest.foo must NOT contain additional properties: "foo"
336
- <pageanrc>.settings.pageLoadTimeTest must be either boolean or object with the appropriate properties
482
+ <pageanrc>.settings.pageLoadTimeTest must be either Boolean or object with the appropriate properties
337
483
  <pageanrc>.sitemap must use 'find' and 'replace' together
338
- <pageanrc>.urls[2].settings.consoleOutputTest must be either boolean or object with the appropriate properties
484
+ <pageanrc>.urls[2].settings.consoleOutputTest must be either Boolean or object with the appropriate properties
339
485
  <pageanrc>.urls[3] must be either URL string or object with the appropriate properties
340
486
  <pageanrc>.urls[5] must have required property 'url'
341
487
  ```
342
488
 
343
- In some cases, a single error might result in multiple messages based on the options in the schema definition, especially for cases that can be either a single value or an object with specific properties (e.g. the errors for `<pageanrc>.settings.pageLoadTimeTest` in the example above).
489
+ In some cases, a single error might result in multiple messages based on the
490
+ options in the schema definition, especially for cases that can be either a
491
+ single value or an object with specific properties (for example the errors for
492
+ `<pageanrc>.settings.pageLoadTimeTest` in the preceding example).
344
493
 
345
- Note that because of the large number of options, which are dependent on an external project, the linting of `puppeteerLaunchOptions` only checks that at least one property is provided, it does not check the detailed settings.
494
+ Note that because of the large number of options, which are dependent on an
495
+ external project, the linting of `puppeteerLaunchOptions` only checks that at
496
+ least one property is provided, it doesn't check the detailed settings.
package/bin/pagean.js CHANGED
@@ -2,7 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  const { log, Levels } = require('ci-logger');
5
- const program = require('commander');
5
+ const { program } = require('commander');
6
6
  const pagean = require('../index');
7
7
  const getConfig = require('../lib/config');
8
8
  const pkg = require('../package.json');
@@ -2,7 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  const { log, Levels } = require('ci-logger');
5
- const program = require('commander');
5
+ const { program } = require('commander');
6
6
  const { green, underline } = require('kleur');
7
7
  const { lintConfigFile } = require('../lib/config');
8
8
  const { formatErrors } = require('../lib/schema-errors');
@@ -1,10 +1,15 @@
1
- # Version Upgrade Guide
1
+ # Version upgrade guide
2
2
 
3
3
  ## Upgrading from v4.x to v5.0
4
4
 
5
- 1. Update to a Node.js current or LTS release (`^12.20.0 || ^14.15.0 || >=16.0.0`). Pagean may still work in other releases, but is not specifically tested or supported.
5
+ 1. Update to a Node.js current or LTS release
6
+ (`^12.20.0 || ^14.15.0 || >=16.0.0`). Pagean may still work in other
7
+ releases, but is not specifically tested or supported.
6
8
 
7
- 2. The Broken Link Test default setting was originally to fail with warning, but this was updated to fail (without warning) to be consistent with the other tests. To return to the previous behavior, update your configuration settings with:
9
+ 2. The Broken Link Test default setting was originally to fail with warning,
10
+ but this was updated to fail (without warning) to be consistent with the
11
+ other tests. To return to the previous behavior, update your configuration
12
+ settings with:
8
13
 
9
14
  ```json
10
15
  {
@@ -18,9 +23,13 @@
18
23
 
19
24
  ## Upgrading from v3.x (`page-load-tests`) to v4.0 (`pagean`)
20
25
 
21
- 1. Change the configurations file name from `.pltconfig.json` to `.pageanrc.json`
26
+ 1. Change the configurations filename from `.pltconfig.json` to
27
+ `.pageanrc.json`
22
28
 
23
- 2. Pagean v4.0.0 updated the configuration file format to allow test-specific settings. With this change, `pageLoadTimeThreshold` must now appears as a setting of the `pageLoadTimeTest` test, rather than at the same level as the other tests. See the example from/to below:
29
+ 2. Pagean v4.0.0 updated the configuration file format to allow test-specific
30
+ settings. With this change, `pageLoadTimeThreshold` must now appears as a
31
+ setting of the `pageLoadTimeTest` test, rather than at the same level as the
32
+ other tests. See the example from/to below:
24
33
 
25
34
  **From:**
26
35
 
package/index.js CHANGED
@@ -38,6 +38,8 @@ const executeAllTests = async (config) => {
38
38
  type: message.type()
39
39
  })
40
40
  );
41
+ // User provided test input required.
42
+ // nosemgrep: puppeteer-goto-injection
41
43
  await page.goto(testUrl.url, { waitUntil: 'load' });
42
44
 
43
45
  const testContext = {
package/lib/config.js CHANGED
@@ -6,8 +6,8 @@
6
6
  * @module config
7
7
  */
8
8
 
9
- const fs = require('fs');
10
- const path = require('path');
9
+ const fs = require('node:fs');
10
+ const path = require('node:path');
11
11
  const Ajv = require('ajv/dist/2019');
12
12
  const draft7MetaSchema = require('ajv/dist/refs/json-schema-draft-07.json');
13
13
  const ajvErrors = require('ajv-errors');
@@ -108,20 +108,29 @@ const processUrls = async (config) => {
108
108
  };
109
109
 
110
110
  const getHtmlHintConfig = (htmlHintConfigFilename) => {
111
+ // Allow users to specify a custom htmlhintrc file.
112
+ // nosemgrep: eslint.detect-non-literal-fs-filename
111
113
  if (!fs.existsSync(htmlHintConfigFilename)) {
112
114
  return;
113
115
  }
114
- /* eslint-disable-next-line consistent-return -- return undefined
115
- if no settings */
116
+ /* eslint-disable consistent-return -- return undefined if no settings */
117
+ // Allow users to specify a custom htmlhintrc file.
118
+ // nosemgrep: eslint.detect-non-literal-fs-filename
116
119
  return JSON.parse(fs.readFileSync(htmlHintConfigFilename, 'utf8'));
120
+ /* eslint-enable consistent-return -- return undefined if no settings */
117
121
  };
118
122
 
119
123
  const validateConfigSchema = (config) => {
120
124
  const schema = JSON.parse(
125
+ // All values hardcoded.
126
+ // nosemgrep: eslint.detect-non-literal-fs-filename
121
127
  fs.readFileSync(
122
128
  path.join(__dirname, '../', 'schemas', 'pageanrc.schema.json')
123
129
  )
124
130
  );
131
+ // Allow allErrors to lint the entire config file, although users could
132
+ // ReDoS themselves.
133
+ // nosemgrep: ajv-allerrors-true
125
134
  const ajv = new Ajv({ allErrors: true });
126
135
  ajv.addMetaSchema(draft7MetaSchema);
127
136
  ajvErrors(ajv);
@@ -131,6 +140,8 @@ const validateConfigSchema = (config) => {
131
140
  };
132
141
 
133
142
  const getConfigFromFile = (configFileName) =>
143
+ // Allow users to specify config filename.
144
+ // nosemgrep: eslint.detect-non-literal-fs-filename
134
145
  JSON.parse(fs.readFileSync(configFileName, 'utf8'));
135
146
 
136
147
  /**
@@ -5,8 +5,8 @@
5
5
  *
6
6
  * @module external-file-utils
7
7
  */
8
- const fs = require('fs');
9
- const path = require('path');
8
+ const fs = require('node:fs');
9
+ const path = require('node:path');
10
10
 
11
11
  const axios = require('axios');
12
12
 
@@ -48,10 +48,16 @@ const saveExternalScript = async (script) => {
48
48
  scriptUrl.hostname,
49
49
  scriptUrl.pathname
50
50
  );
51
+ // Path generated above from URL, not from user input.
52
+ // nosemgrep: eslint.detect-non-literal-fs-filename
51
53
  if (!fs.existsSync(pathName)) {
52
54
  // Axios will throw for any error response
53
55
  const response = await axios.get(script);
56
+ // Path generated above from URL, not from user input.
57
+ // nosemgrep: eslint.detect-non-literal-fs-filename
54
58
  fs.mkdirSync(path.dirname(pathName), { recursive: true });
59
+ // Path generated above from URL, not from user input.
60
+ // nosemgrep: eslint.detect-non-literal-fs-filename
55
61
  fs.writeFileSync(pathName, response.data);
56
62
  }
57
63
  result.localFile = pathName;
package/lib/link-utils.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * @module link-utils
7
7
  */
8
8
 
9
- const https = require('https');
9
+ const https = require('node:https');
10
10
  const axios = require('axios');
11
11
  const normalizeUrl = require('normalize-url');
12
12
  const cssesc = require('cssesc');
@@ -4,25 +4,40 @@
4
4
  <head>
5
5
  <title>Pagean Results</title>
6
6
  <style>
7
+ :root {
8
+ /* Default colors */
9
+ --color-text-default: #333333;
10
+ --color-background-data-hover: rgba(255 255 255 / 10%);
11
+ --color-background-summary: #f4f4f4;
12
+ --color-border-summary: #333333;
13
+
14
+ /* Test result colors */
15
+ --color-background-passed: #dff2bf;
16
+ --color-text-passed: #44760f;
17
+ --color-background-failed: #ffbaba;
18
+ --color-text-failed: #ad000c;
19
+ --color-background-warning: #fdec96;
20
+ --color-text-warning: #7e6902;
21
+ }
22
+
7
23
  html {
8
24
  margin: 0;
9
25
  padding: 0;
10
26
  }
11
27
 
12
28
  body {
13
- color: #333333;
29
+ color: var(--color-text-default);
14
30
  font-family: system-ui, sans-serif;
15
31
  font-size: 0.85rem;
16
32
  margin: auto;
17
- max-width: 1000px;
33
+ max-inline-size: 1000px;
18
34
  padding: 1rem;
19
35
  }
20
36
 
21
37
  ul {
22
- margin: 0;
23
38
  margin-block: 0;
24
39
  margin-inline: 0;
25
- padding: 0;
40
+ padding-block: 0;
26
41
  padding-inline: 0;
27
42
  }
28
43
 
@@ -31,7 +46,6 @@
31
46
  }
32
47
 
33
48
  h1 {
34
- margin: 1rem 0 0.75rem;
35
49
  margin-block: 0;
36
50
  margin-inline: 0;
37
51
  }
@@ -48,54 +62,55 @@
48
62
  .project,
49
63
  .started {
50
64
  margin: 0;
51
- padding-bottom: 0.5rem;
65
+ padding-block-end: 0.5rem;
52
66
  }
53
67
 
54
68
  .test-summary {
55
69
  display: flex;
56
70
  flex-direction: row;
57
- margin-bottom: 2rem;
58
- max-width: 50%;
71
+ margin-block-end: 2rem;
72
+ max-inline-size: 50%;
59
73
  }
60
74
 
61
75
  .summary {
62
- background-color: #f4f4f4;
63
- border: 1px solid #333333;
76
+ background-color: var(--color-background-summary);
77
+ border: 1px solid var(--color-border-summary);
64
78
  display: inline-block;
65
79
  flex: 1 1 10%;
66
- margin: 0 0.25rem;
67
- padding: 0.25rem 0.5rem;
80
+ margin-block: 0;
81
+ margin-inline: 0.25rem;
82
+ padding-block: 0.25rem;
83
+ padding-inline: 0.5rem;
68
84
  }
69
85
 
70
86
  .summary:first-of-type {
71
- margin-left: 0;
87
+ margin-inline-start: 0;
72
88
  }
73
89
 
74
90
  .summary:last-of-type {
75
- margin-right: 0;
91
+ margin-inline-end: 0;
76
92
  }
77
93
 
78
94
  .passed {
79
- background-color: #dff2bf;
80
- border: 1px solid #44760f;
81
- color: #44760f;
95
+ background-color: var(--color-background-passed);
96
+ border: 1px solid var(--color-text-passed);
97
+ color: var(--color-text-passed);
82
98
  }
83
99
 
84
100
  .failed {
85
- background-color: #ffbaba;
86
- border: 1px solid #ad000c;
87
- color: #ad000c;
101
+ background-color: var(--color-background-failed);
102
+ border: 1px solid var(--color-text-failed);
103
+ color: var(--color-text-failed);
88
104
  }
89
105
 
90
106
  .warning {
91
- background-color: #fdec96;
92
- border: 1px solid #7e6902;
93
- color: #7e6902;
107
+ background-color: var(--color-background-warning);
108
+ border: 1px solid var(--color-text-warning);
109
+ color: var(--color-text-warning);
94
110
  }
95
111
 
96
112
  .test-results h2 {
97
- margin-block-end: 0;
98
- margin-block-start: 1rem;
113
+ margin-block: 1rem 0;
99
114
  }
100
115
 
101
116
  details summary .name::after,
@@ -104,7 +119,7 @@
104
119
  font-family: monospace;
105
120
  font-weight: bold;
106
121
  opacity: 0.8;
107
- padding-left: 0.5rem;
122
+ padding-inline-start: 0.5rem;
108
123
  }
109
124
 
110
125
  details[open] summary .name::after {
@@ -121,8 +136,10 @@
121
136
  }
122
137
 
123
138
  li.test {
124
- margin: 0.25rem 0;
125
- padding: 0.5rem 1rem;
139
+ margin-block: 0.25rem;
140
+ margin-inline: 0;
141
+ padding-block: 0.5rem;
142
+ padding-inline: 1rem;
126
143
  }
127
144
 
128
145
  .test .header {
@@ -136,20 +153,20 @@
136
153
 
137
154
  .test .header .result {
138
155
  flex: 1 1 25%;
139
- text-align: right;
156
+ text-align: end;
140
157
  }
141
158
 
142
159
  .test .data,
143
160
  .test .time,
144
161
  .test .error {
145
- padding-left: 10px;
162
+ padding-inline-start: 0.75rem;
146
163
  }
147
164
 
148
165
  .test .data h3 {
149
166
  font-size: inherit;
150
167
  font-weight: normal;
151
- margin: 0.25rem 0 0;
152
168
  margin-block: 0;
169
+ margin-inline: 0;
153
170
  }
154
171
 
155
172
  .test .data li {
@@ -159,18 +176,20 @@
159
176
  }
160
177
 
161
178
  .test .data li:hover {
162
- background-color: rgba(255 255 255 / 10%);
179
+ background-color: var(--color-background-data-hover);
163
180
  border: 1px dotted;
164
- border-right: 4px solid;
181
+ border-inline-end: 4px solid;
165
182
  padding: calc(0.25rem - 1px);
166
183
  }
167
184
 
168
185
  .test .data .pre {
169
- margin: 0 0 0.25rem;
186
+ margin-block: 0 0.25rem;
187
+ margin-inline: 0;
170
188
  }
171
189
 
172
190
  .test .time {
173
- margin: 0.25rem 0 0;
191
+ margin-block: 0.25rem 0;
192
+ margin-inline: 0;
174
193
  }
175
194
  </style>
176
195
  </head>
package/lib/reporter.js CHANGED
@@ -5,8 +5,8 @@
5
5
  *
6
6
  * @module reporter
7
7
  */
8
- const fs = require('fs');
9
- const path = require('path');
8
+ const fs = require('node:fs');
9
+ const path = require('node:path');
10
10
  const handlebars = require('handlebars');
11
11
 
12
12
  const htmlReportTemplateName = 'report-template.handlebars';
@@ -22,6 +22,8 @@ const saveHtmlReport = (results) => {
22
22
  const templateFile = path.resolve(
23
23
  path.join(__dirname, htmlReportTemplateName)
24
24
  );
25
+ // Path hardcoded above, not from user input.
26
+ // nosemgrep: eslint.detect-non-literal-fs-filename
25
27
  const htmlReportTemplate = fs.readFileSync(templateFile, 'utf8');
26
28
  const template = handlebars.compile(htmlReportTemplate);
27
29
  const htmlReport = template(results);
package/lib/sitemap.js CHANGED
@@ -1,10 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ const fs = require('node:fs');
3
4
  const axios = require('axios');
4
5
  const { parseStringPromise } = require('xml2js');
5
6
 
6
- const fs = require('fs');
7
-
8
7
  /**
9
8
  * Gets a sitemap, via file path or URL, and returns the string contents.
10
9
  *
@@ -21,6 +20,8 @@ const getSitemap = async (url) => {
21
20
  const response = await axios.get(url);
22
21
  return response.data;
23
22
  }
23
+ // Allow users to specify a local sitemap filename.
24
+ // nosemgrep: eslint.detect-non-literal-fs-filename
24
25
  return fs.readFileSync(url, 'utf8');
25
26
  } catch {
26
27
  throw new Error(`Error retrieving sitemap "${url}"`);
@@ -54,6 +55,8 @@ const parseSitemap = async (sitemapXml) => {
54
55
  * @private
55
56
  */
56
57
  const removeExcludedUrls = (urls, exclude = []) => {
58
+ // Allow URLs to be excluded by regular expression.
59
+ // nosemgrep: eslint.detect-non-literal-regexp
57
60
  const excludeRegex = exclude.map((url) => new RegExp(url));
58
61
  return urls.filter((url) => {
59
62
  for (const excludeUrlRegex of excludeRegex) {
package/package.json CHANGED
@@ -1,24 +1,24 @@
1
1
  {
2
2
  "name": "pagean",
3
- "version": "9.0.0",
3
+ "version": "10.0.1",
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
- "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",
13
- "lint-css": "stylelint ./lib/report-template.handlebars",
14
- "lint-html": "htmlhint ./lib/report-template.handlebars",
15
- "lint-js": "eslint .",
16
- "lint-md": "markdownlint-cli2 \"**/*.md\" \"#node_modules\" \"#Archive\"",
17
- "prettier-check": "prettier --check .",
18
- "prettier-fix": "prettier --write .",
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",
13
+ "lint:css": "stylelint ./lib/report-template.handlebars",
14
+ "lint:html": "htmlhint ./lib/report-template.handlebars",
15
+ "lint:js": "eslint .",
16
+ "lint:md": "markdownlint-cli2 \"**/*.md\" \"#node_modules\" \"#Archive\"",
17
+ "prettier:check": "prettier --check .",
18
+ "prettier:fix": "prettier --write .",
19
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 static-server.pageanrc.json && npm run start-lint ./lib/default-config.json",
20
+ "start:lint": "node ./bin/pageanrc-lint.js",
21
+ "start:lint-all": "npm run start:lint && npm run start:lint static-server.pageanrc.json && npm run start:lint ./lib/default-config.json",
22
22
  "test": "jest --ci --config jest.config.json"
23
23
  },
24
24
  "repository": {
@@ -37,7 +37,7 @@
37
37
  "author": "Aaron Goldenthal <npm@aarongoldenthal.com>",
38
38
  "license": "MIT",
39
39
  "engines": {
40
- "node": "^16.13.0 || ^18.12.0 || >=20.0.0"
40
+ "node": "^18.12.0 || >=20.0.0"
41
41
  },
42
42
  "files": [
43
43
  "index.js",
@@ -51,30 +51,30 @@
51
51
  },
52
52
  "homepage": "https://gitlab.com/gitlab-ci-utils/pagean",
53
53
  "devDependencies": {
54
- "@aarongoldenthal/eslint-config-standard": "^22.1.0",
55
- "@aarongoldenthal/stylelint-config-standard": "^14.0.0",
56
- "bin-tester": "^4.0.1",
57
- "eslint": "^8.44.0",
58
- "jest": "^29.6.0",
54
+ "@aarongoldenthal/eslint-config-standard": "^26.0.0",
55
+ "@aarongoldenthal/stylelint-config-standard": "^17.0.1",
56
+ "bin-tester": "^5.0.0",
57
+ "eslint": "^8.56.0",
58
+ "jest": "^29.7.0",
59
59
  "jest-junit": "^16.0.0",
60
- "markdownlint-cli2": "^0.8.1",
61
- "prettier": "^2.8.8",
60
+ "markdownlint-cli2": "^0.12.1",
61
+ "prettier": "^3.2.5",
62
62
  "strip-ansi": "^6.0.1",
63
- "stylelint": "^15.10.0"
63
+ "stylelint": "^16.2.1"
64
64
  },
65
65
  "dependencies": {
66
66
  "ajv": "^8.12.0",
67
67
  "ajv-errors": "^3.0.0",
68
- "axios": "^1.4.0",
68
+ "axios": "^1.6.7",
69
69
  "ci-logger": "^6.0.0",
70
- "commander": "^11.0.0",
70
+ "commander": "^12.0.0",
71
71
  "cssesc": "^3.0.0",
72
- "handlebars": "^4.7.7",
72
+ "handlebars": "^4.7.8",
73
73
  "htmlhint": "^1.1.4",
74
74
  "kleur": "^4.1.5",
75
75
  "normalize-url": "^6.1.0",
76
76
  "protocolify": "^3.0.0",
77
- "puppeteer": "^20.7.4",
78
- "xml2js": "^0.6.0"
77
+ "puppeteer": "^22.1.0",
78
+ "xml2js": "^0.6.2"
79
79
  }
80
80
  }