pagean 9.0.0 → 10.0.0
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 +1 -1
- package/README.md +228 -77
- package/docs/upgrade-guide.md +14 -5
- package/index.js +2 -0
- package/lib/config.js +15 -4
- package/lib/external-file-utils.js +8 -2
- package/lib/link-utils.js +1 -1
- package/lib/report-template.handlebars +54 -35
- package/lib/reporter.js +4 -2
- package/lib/sitemap.js +5 -2
- package/package.json +26 -26
package/LICENSE
CHANGED
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
|
|
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
|
|
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
|
|
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
|
|
41
|
+
## Test cases
|
|
33
42
|
|
|
34
|
-
The tests use [Puppeteer](https://github.com/GoogleChrome/puppeteer) to launch
|
|
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
|
|
50
|
+
### Horizontal scrollbar test
|
|
37
51
|
|
|
38
|
-
The horizontal scrollbar test fails if the rendered page has a horizontal
|
|
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
|
|
56
|
+
### Console output test
|
|
41
57
|
|
|
42
|
-
The console output test fails if any output is written to the browser console.
|
|
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
|
|
73
|
+
### Console error test
|
|
57
74
|
|
|
58
|
-
The console error test fails if any error is written to the browser console,
|
|
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
|
|
79
|
+
### Rendered HTML test
|
|
61
80
|
|
|
62
|
-
The rendered HTML test is intended for cases where content is dynamically
|
|
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
|
|
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:
|
|
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
|
|
114
|
+
### Page load time test
|
|
87
115
|
|
|
88
|
-
The page load time test fails if the page load time (from start through the
|
|
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
|
|
121
|
+
### External script test
|
|
91
122
|
|
|
92
|
-
The external script test is intended to identify any externally loaded
|
|
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
|
-
|
|
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
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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:
|
|
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
|
|
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
|
|
153
|
-
|
|
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
|
|
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
|
|
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
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
- `
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
- `
|
|
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
|
-
##
|
|
382
|
+
## Container images
|
|
260
383
|
|
|
261
|
-
Provided with the Pagean project are
|
|
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:**
|
|
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
|
|
393
|
+
### Puppeteer cache location
|
|
266
394
|
|
|
267
|
-
In [Puppeteer v19](https://github.com/puppeteer/puppeteer/releases/tag/v19.0.0)
|
|
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
|
|
403
|
+
## GitLab CI configuration
|
|
270
404
|
|
|
271
|
-
The following is an example job from a .gitlab-ci.yml file to use this image to
|
|
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
|
|
422
|
+
### Testing with static HTTP server
|
|
288
423
|
|
|
289
|
-
The
|
|
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
|
|
452
|
+
## Linting pageanrc files
|
|
310
453
|
|
|
311
|
-
A command line tool is also available to lint pageanrc files, which is executed
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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/docs/upgrade-guide.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
# Version
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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
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
|
|
115
|
-
|
|
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
|
@@ -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:
|
|
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-
|
|
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-
|
|
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-
|
|
58
|
-
max-
|
|
71
|
+
margin-block-end: 2rem;
|
|
72
|
+
max-inline-size: 50%;
|
|
59
73
|
}
|
|
60
74
|
|
|
61
75
|
.summary {
|
|
62
|
-
background-color:
|
|
63
|
-
border: 1px solid
|
|
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
|
|
67
|
-
|
|
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-
|
|
87
|
+
margin-inline-start: 0;
|
|
72
88
|
}
|
|
73
89
|
|
|
74
90
|
.summary:last-of-type {
|
|
75
|
-
margin-
|
|
91
|
+
margin-inline-end: 0;
|
|
76
92
|
}
|
|
77
93
|
|
|
78
94
|
.passed {
|
|
79
|
-
background-color:
|
|
80
|
-
border: 1px solid
|
|
81
|
-
color:
|
|
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:
|
|
86
|
-
border: 1px solid
|
|
87
|
-
color:
|
|
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:
|
|
92
|
-
border: 1px solid
|
|
93
|
-
color:
|
|
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
|
|
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-
|
|
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
|
|
125
|
-
|
|
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:
|
|
156
|
+
text-align: end;
|
|
140
157
|
}
|
|
141
158
|
|
|
142
159
|
.test .data,
|
|
143
160
|
.test .time,
|
|
144
161
|
.test .error {
|
|
145
|
-
padding-
|
|
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:
|
|
179
|
+
background-color: var(--color-background-data-hover);
|
|
163
180
|
border: 1px dotted;
|
|
164
|
-
border-
|
|
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
|
|
186
|
+
margin-block: 0 0.25rem;
|
|
187
|
+
margin-inline: 0;
|
|
170
188
|
}
|
|
171
189
|
|
|
172
190
|
.test .time {
|
|
173
|
-
margin: 0.25rem 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": "
|
|
3
|
+
"version": "10.0.0",
|
|
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
|
|
11
|
-
"hooks
|
|
12
|
-
"lint": "npm run lint
|
|
13
|
-
"lint
|
|
14
|
-
"lint
|
|
15
|
-
"lint
|
|
16
|
-
"lint
|
|
17
|
-
"prettier
|
|
18
|
-
"prettier
|
|
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
|
|
21
|
-
"start
|
|
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": "^
|
|
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": "^
|
|
55
|
-
"@aarongoldenthal/stylelint-config-standard": "^
|
|
56
|
-
"bin-tester": "^
|
|
57
|
-
"eslint": "^8.
|
|
58
|
-
"jest": "^29.
|
|
54
|
+
"@aarongoldenthal/eslint-config-standard": "^25.0.0",
|
|
55
|
+
"@aarongoldenthal/stylelint-config-standard": "^17.0.0",
|
|
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.
|
|
61
|
-
"prettier": "^2.
|
|
60
|
+
"markdownlint-cli2": "^0.12.1",
|
|
61
|
+
"prettier": "^3.2.4",
|
|
62
62
|
"strip-ansi": "^6.0.1",
|
|
63
|
-
"stylelint": "^
|
|
63
|
+
"stylelint": "^16.2.0"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"ajv": "^8.12.0",
|
|
67
67
|
"ajv-errors": "^3.0.0",
|
|
68
|
-
"axios": "^1.
|
|
68
|
+
"axios": "^1.6.7",
|
|
69
69
|
"ci-logger": "^6.0.0",
|
|
70
|
-
"commander": "^11.
|
|
70
|
+
"commander": "^11.1.0",
|
|
71
71
|
"cssesc": "^3.0.0",
|
|
72
|
-
"handlebars": "^4.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": "^
|
|
78
|
-
"xml2js": "^0.6.
|
|
77
|
+
"puppeteer": "^21.9.0",
|
|
78
|
+
"xml2js": "^0.6.2"
|
|
79
79
|
}
|
|
80
80
|
}
|