@govtechsg/oobee 0.10.51 → 0.10.58
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/.github/workflows/bump-package-version.yml +58 -0
- package/.github/workflows/image.yml +38 -17
- package/DETAILS.md +5 -2
- package/INTEGRATION.md +57 -53
- package/README.md +4 -1
- package/__tests__/test-sitemap-url-patterns.xml +105 -0
- package/exclusions.txt +1 -0
- package/package.json +7 -6
- package/src/cli.ts +35 -2
- package/src/combine.ts +10 -7
- package/src/constants/cliFunctions.ts +9 -0
- package/src/constants/common.ts +95 -105
- package/src/constants/constants.ts +47 -2
- package/src/crawlers/commonCrawlerFunc.ts +84 -5
- package/src/crawlers/crawlDomain.ts +93 -160
- package/src/crawlers/crawlIntelligentSitemap.ts +40 -36
- package/src/crawlers/crawlLocalFile.ts +77 -35
- package/src/crawlers/crawlSitemap.ts +156 -89
- package/src/crawlers/pdfScanFunc.ts +2 -0
- package/src/index.ts +2 -0
- package/src/logs.ts +4 -2
- package/src/mergeAxeResults.ts +20 -9
- package/src/npmIndex.ts +1 -1
- package/src/screenshotFunc/htmlScreenshotFunc.ts +7 -5
- package/src/screenshotFunc/pdfScreenshotFunc.ts +2 -2
- package/src/static/ejs/partials/components/wcagCompliance.ejs +1 -1
- package/src/static/ejs/partials/scripts/ruleOffcanvas.ejs +1 -0
- package/src/static/ejs/partials/styles/styles.ejs +11 -0
- package/src/static/ejs/report.ejs +14 -1
- package/src/utils.ts +3 -3
@@ -0,0 +1,58 @@
|
|
1
|
+
name: Bump Package Version
|
2
|
+
|
3
|
+
on:
|
4
|
+
workflow_dispatch: # Trigger manually from GitHub UI
|
5
|
+
|
6
|
+
permissions:
|
7
|
+
contents: write
|
8
|
+
pull-requests: write
|
9
|
+
|
10
|
+
jobs:
|
11
|
+
bump-version:
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
|
14
|
+
steps:
|
15
|
+
- name: Checkout repository
|
16
|
+
uses: actions/checkout@v4
|
17
|
+
with:
|
18
|
+
fetch-depth: 0 # Required for creating new branches
|
19
|
+
|
20
|
+
- name: Set up Node.js 22
|
21
|
+
uses: actions/setup-node@v4
|
22
|
+
with:
|
23
|
+
node-version: '22'
|
24
|
+
|
25
|
+
- name: Get current version
|
26
|
+
id: current
|
27
|
+
run: |
|
28
|
+
current_version=$(node -p "require('./package.json').version")
|
29
|
+
echo "version=$current_version" >> "$GITHUB_OUTPUT"
|
30
|
+
|
31
|
+
- name: Bump patch version
|
32
|
+
id: bump
|
33
|
+
run: |
|
34
|
+
new_version=$(npm version patch --no-git-tag-version)
|
35
|
+
echo "version=$new_version" >> "$GITHUB_OUTPUT"
|
36
|
+
|
37
|
+
- name: Create branch and commit changes
|
38
|
+
run: |
|
39
|
+
BRANCH="bump/version-${{ steps.bump.outputs.version }}"
|
40
|
+
git config user.name "github-actions[bot]"
|
41
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
42
|
+
git checkout -b "$BRANCH"
|
43
|
+
git add package.json package-lock.json
|
44
|
+
git commit -m "chore: bump version ${{ steps.current.outputs.version }} → ${{ steps.bump.outputs.version }}"
|
45
|
+
git push origin "$BRANCH"
|
46
|
+
echo "BRANCH=$BRANCH" >> $GITHUB_ENV
|
47
|
+
|
48
|
+
- name: Authenticate GitHub CLI
|
49
|
+
run: |
|
50
|
+
echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token
|
51
|
+
|
52
|
+
- name: Create pull request
|
53
|
+
run: |
|
54
|
+
gh pr create \
|
55
|
+
--title "chore: bump version to ${{ steps.bump.outputs.version }}" \
|
56
|
+
--body "Automated version bump from ${{ steps.current.outputs.version }} to ${{ steps.bump.outputs.version }}." \
|
57
|
+
--head "$BRANCH" \
|
58
|
+
--base "${{ github.ref_name }}"
|
@@ -119,25 +119,46 @@ jobs:
|
|
119
119
|
| sed -E 's/^[[:space:]]*[0-9]+\) ([^"]+).*$/\1/')
|
120
120
|
echo "id=$ID" >> $GITHUB_OUTPUT
|
121
121
|
|
122
|
-
- name: Sign
|
122
|
+
- name: Sign all Mach-O binaries (deep)
|
123
|
+
shell: bash
|
123
124
|
run: |
|
124
|
-
|
125
|
-
CERTIFICATE=$(security find-identity -v -p codesigning -s - | tail -n +2 | grep -o '"Developer ID Application:[^"]*"' | sed 's/"//g')
|
126
|
-
|
127
|
-
# Paths to the binaries you want to sign only ending with .node
|
128
|
-
BINARIES=($(find . -type f \( -name "*.node" -o -name "*.sh" -o -name "*.command" \) ! -path "*.framework/*" ! -path "*.dSYM/*"))
|
129
|
-
|
130
|
-
# Loop through the binary paths and sign each one with a secure timestamp
|
131
|
-
for binary in "${BINARIES[@]}"; do
|
132
|
-
# Check if the binary is already signed
|
133
|
-
codesign --timestamp -f -s "$CERTIFICATE" "$binary"
|
134
|
-
if [ $? -eq 0 ]; then
|
135
|
-
echo "Successfully signed (with secure timestamp): $binary"
|
136
|
-
else
|
137
|
-
echo "Failed to sign: $binary"
|
138
|
-
fi
|
139
|
-
done
|
125
|
+
set -euo pipefail
|
140
126
|
|
127
|
+
# Ensure the build keychain is available & unlocked in THIS step
|
128
|
+
security list-keychains -d user -s build.keychain
|
129
|
+
security default-keychain -d user -s build.keychain
|
130
|
+
security unlock-keychain -p "" build.keychain
|
131
|
+
|
132
|
+
echo "Available signing identities in build.keychain:"
|
133
|
+
security find-identity -v -p codesigning build.keychain || true
|
134
|
+
|
135
|
+
# Extract the FULL identity name (between the quotes)
|
136
|
+
CERTIFICATE_NAME=$(security find-identity -v -p codesigning build.keychain \
|
137
|
+
| awk -F\" '/Developer ID Application:/{print $2; exit}')
|
138
|
+
|
139
|
+
if [[ -z "${CERTIFICATE_NAME}" ]]; then
|
140
|
+
echo "ERROR: No 'Developer ID Application' identity found in build.keychain."
|
141
|
+
exit 1
|
142
|
+
fi
|
143
|
+
echo "Using identity: ${CERTIFICATE_NAME}"
|
144
|
+
|
145
|
+
# Ensure we can re-sign files (node_modules sometimes read-only)
|
146
|
+
chmod -R u+w "$GITHUB_WORKSPACE/oobee"
|
147
|
+
|
148
|
+
# Sign all Mach-O (exec bits OR dylib OR node native addons)
|
149
|
+
while IFS= read -r f; do
|
150
|
+
echo "Signing $f"
|
151
|
+
codesign --force --options runtime --timestamp --sign "${CERTIFICATE_NAME}" "$f"
|
152
|
+
done < <(
|
153
|
+
find "$GITHUB_WORKSPACE/oobee" -type f \
|
154
|
+
\( -perm -111 -o -name "*.dylib" -o -name "*.node" \) \
|
155
|
+
! -path "*/.git/*"
|
156
|
+
)
|
157
|
+
|
158
|
+
echo "Verifying signatures of Mach-O files..."
|
159
|
+
find "$GITHUB_WORKSPACE/oobee" -type f \( -perm -111 -o -name "*.dylib" -o -name "*.node" \) \
|
160
|
+
-exec codesign --verify --strict --verbose=2 {} \; || true
|
161
|
+
|
141
162
|
- name: Cleanup keychain
|
142
163
|
if: always()
|
143
164
|
run: security delete-keychain build.keychain
|
package/DETAILS.md
CHANGED
@@ -44,6 +44,7 @@ Note: Level AAA are disabled by default. Please specify `enable-wcag-aaa` in ru
|
|
44
44
|
| WCAG 1.4.6 | AAA | Yes | | |
|
45
45
|
| WCAG 1.4.12 | AA | Yes | | |
|
46
46
|
| WCAG 2.1.1 | A | Yes | | |
|
47
|
+
| WCAG 2.1.3 | AAA | Yes * | | |
|
47
48
|
| WCAG 2.2.1 | A | Yes | | |
|
48
49
|
| WCAG 2.2.2 | A | Yes | | |
|
49
50
|
| WCAG 2.2.4 | AAA | | Yes | |
|
@@ -60,12 +61,14 @@ Note: Level AAA are disabled by default. Please specify `enable-wcag-aaa` in ru
|
|
60
61
|
| WCAG 4.1.2 | A | Yes | | |
|
61
62
|
| Best Practice| | | Yes | |
|
62
63
|
|
64
|
+
* The WCAG 2.1.3 check is done by 'Scrollable region must have keyboard access' which is a WCAG 2.1.1 (Must Fix) rule.
|
65
|
+
|
63
66
|
### Summary of WCAG Clauses Supported
|
64
67
|
| Level | Count |
|
65
68
|
|-------|-------|
|
66
69
|
| A | 15 |
|
67
70
|
| AA | 5 |
|
68
|
-
| AAA |
|
71
|
+
| AAA | 6 |
|
69
72
|
|
70
73
|
|
71
74
|
## WCAG 2.0 Level A
|
@@ -120,7 +123,7 @@ Note: Level AAA are disabled by default. Please specify `enable-wcag-aaa` in ru
|
|
120
123
|
| no-autoplay-audio | Ensures `<video>` or `<audio>` elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio | Must Fix | WCAG 1.4.2 |
|
121
124
|
| object-alt | Ensures `<object>` elements have alternate text | Must Fix | WCAG 1.1.1 |
|
122
125
|
| role-img-alt | Ensures [role="img"] elements have alternate text | Must Fix | WCAG 1.1.1 |
|
123
|
-
| scrollable-region-focusable | Ensure elements that have scrollable content are accessible by keyboard | Must Fix | WCAG 2.1.1
|
126
|
+
| scrollable-region-focusable | Ensure elements that have scrollable content are accessible by keyboard | Must Fix | WCAG 2.1.1, WCAG 2.1.3 |
|
124
127
|
| select-name | Ensures select element has an accessible name | Must Fix | WCAG 4.1.2 |
|
125
128
|
| server-side-image-map | Ensures that server-side image maps are not used | Must Fix | WCAG 2.1.1 |
|
126
129
|
| svg-img-alt | Ensures `<svg>` elements with an img, graphics-document or graphics-symbol role have an accessible text | Must Fix | WCAG 1.1.1 |
|
package/INTEGRATION.md
CHANGED
@@ -53,7 +53,7 @@ Returns an instance of Oobee
|
|
53
53
|
- `scanAboutMetadata` (optional)
|
54
54
|
- Include additional information in the Scan About section of the report by passing in a JSON object.
|
55
55
|
- `zip` (optional)
|
56
|
-
- Name of the generated zip of Oobee results at the end of scan. Defaults to "oobee-scan-results".
|
56
|
+
- Name of the generated zip of Oobee results at the end of scan. Defaults to "oobee-scan-results.zip".
|
57
57
|
- `deviceChosen` (optional)
|
58
58
|
- Name of the device to scan on. Example: `iPhone 13 Pro Max`
|
59
59
|
- `strategy` (optional)
|
@@ -185,7 +185,7 @@ Create <code>cypress.config.js</code> with the following contents, and change yo
|
|
185
185
|
// additional information to include in the "Scan About" section of the report
|
186
186
|
const scanAboutMetadata = { browser: 'Chrome (Desktop)' };
|
187
187
|
// name of the generated zip of the results at the end of scan
|
188
|
-
const resultsZipName = "oobee-scan-results"
|
188
|
+
const resultsZipName = "oobee-scan-results.zip";
|
189
189
|
|
190
190
|
const oobeeA11y = await oobeeA11yInit({
|
191
191
|
entryUrl: "https://govtechsg.github.io", // initial url to start scan
|
@@ -211,23 +211,23 @@ Create <code>cypress.config.js</code> with the following contents, and change yo
|
|
211
211
|
e2e: {
|
212
212
|
setupNodeEvents(on, _config) {
|
213
213
|
on("task", {
|
214
|
-
|
214
|
+
getOobeeA11yScripts() {
|
215
215
|
return oobeeA11y.getScripts();
|
216
216
|
},
|
217
217
|
gradeReadability(sentences) {
|
218
218
|
return oobeeA11y.gradeReadability(sentences);
|
219
219
|
},
|
220
|
-
async
|
220
|
+
async pushOobeeA11yScanResults({res, metadata, elementsToClick}) {
|
221
221
|
return await oobeeA11y.pushScanResults(res, metadata, elementsToClick);
|
222
222
|
},
|
223
223
|
returnResultsDir() {
|
224
224
|
return `results/${oobeeA11y.randomToken}_${oobeeA11y.scanDetails.urlsCrawled.scanned.length}pages/report.html`;
|
225
225
|
},
|
226
|
-
|
226
|
+
finishOobeeA11yTestCase() {
|
227
227
|
oobeeA11y.testThresholds();
|
228
228
|
return null;
|
229
229
|
},
|
230
|
-
async
|
230
|
+
async terminateOobeeA11y() {
|
231
231
|
return await oobeeA11y.terminate();
|
232
232
|
},
|
233
233
|
});
|
@@ -237,15 +237,15 @@ Create <code>cypress.config.js</code> with the following contents, and change yo
|
|
237
237
|
|
238
238
|
Create a sub-folder and file <code>cypress/support/e2e.js</code> with the following contents:
|
239
239
|
|
240
|
-
Cypress.Commands.add("
|
241
|
-
cy.task("
|
240
|
+
Cypress.Commands.add("injectOobeeA11yScripts", () => {
|
241
|
+
cy.task("getOobeeA11yScripts").then((s) => {
|
242
242
|
cy.window().then((win) => {
|
243
243
|
win.eval(s);
|
244
244
|
});
|
245
245
|
});
|
246
246
|
});
|
247
247
|
|
248
|
-
Cypress.Commands.add("
|
248
|
+
Cypress.Commands.add("runOobeeA11yScan", (items={}) => {
|
249
249
|
cy.window().then(async (win) => {
|
250
250
|
const { elementsToScan, elementsToClick, metadata } = items;
|
251
251
|
|
@@ -259,7 +259,7 @@ Create a sub-folder and file <code>cypress/support/e2e.js</code> with the follow
|
|
259
259
|
elementsToScan,
|
260
260
|
gradingReadabilityFlag,
|
261
261
|
);
|
262
|
-
cy.task("
|
262
|
+
cy.task("pushOobeeA11yScanResults", {
|
263
263
|
res,
|
264
264
|
metadata,
|
265
265
|
elementsToClick,
|
@@ -268,12 +268,12 @@ Create a sub-folder and file <code>cypress/support/e2e.js</code> with the follow
|
|
268
268
|
});
|
269
269
|
},
|
270
270
|
);
|
271
|
-
cy.task("
|
271
|
+
cy.task("finishOobeeA11yTestCase"); // test the accumulated number of issue occurrences against specified thresholds. If exceed, terminate oobeeA11y instance.
|
272
272
|
});
|
273
273
|
});
|
274
274
|
|
275
|
-
Cypress.Commands.add("
|
276
|
-
cy.task("
|
275
|
+
Cypress.Commands.add("terminateOobeeA11y", () => {
|
276
|
+
cy.task("terminateOobeeA11y");
|
277
277
|
});
|
278
278
|
|
279
279
|
Create <code>cypress/e2e/spec.cy.js</code> with the following contents:
|
@@ -283,17 +283,17 @@ Create <code>cypress/e2e/spec.cy.js</code> with the following contents:
|
|
283
283
|
cy.visit(
|
284
284
|
"https://govtechsg.github.io/purple-banner-embeds/purple-integrated-scan-example.htm"
|
285
285
|
);
|
286
|
-
cy.
|
287
|
-
cy.
|
286
|
+
cy.injectOobeeA11yScripts();
|
287
|
+
cy.runOobeeA11yScan();
|
288
288
|
cy.get("button[onclick=\"toggleSecondSection()\"]").click();
|
289
289
|
// Run a scan on <input> and <button> elements
|
290
|
-
cy.
|
290
|
+
cy.runOobeeA11yScan({
|
291
291
|
elementsToScan: ["input", "button"],
|
292
292
|
elementsToClick: ["button[onclick=\"toggleSecondSection()\"]"],
|
293
293
|
metadata: "Clicked button"
|
294
294
|
});
|
295
295
|
|
296
|
-
cy.
|
296
|
+
cy.terminateOobeeA11y();
|
297
297
|
});
|
298
298
|
});
|
299
299
|
|
@@ -373,7 +373,7 @@ Create <code>cypress.config.ts</code> with the following contents, and change yo
|
|
373
373
|
// additional information to include in the "Scan About" section of the report
|
374
374
|
const scanAboutMetadata: ScanAboutMetadata = { browser: 'Chrome (Desktop)' };
|
375
375
|
// name of the generated zip of the results at the end of scan
|
376
|
-
const resultsZipName: string = "oobee-scan-results"
|
376
|
+
const resultsZipName: string = "oobee-scan-results.zip"
|
377
377
|
|
378
378
|
const oobeeA11y = await oobeeA11yInit({
|
379
379
|
"https://govtechsg.github.io", // initial url to start scan
|
@@ -399,23 +399,23 @@ Create <code>cypress.config.ts</code> with the following contents, and change yo
|
|
399
399
|
e2e: {
|
400
400
|
setupNodeEvents(on, _config) {
|
401
401
|
on("task", {
|
402
|
-
|
402
|
+
getOobeeA11yScripts(): string {
|
403
403
|
return oobeeA11y.getScripts();
|
404
404
|
},
|
405
405
|
gradeReadability(sentences: string[]): string {
|
406
406
|
return oobeeA11y.gradeReadability(sentences);
|
407
407
|
},
|
408
|
-
async
|
408
|
+
async pushOobeeA11yScanResults({res, metadata, elementsToClick}: { res: any, metadata: any, elementsToClick: any[] }): Promise<{ mustFix: number, goodToFix: number }> {
|
409
409
|
return await oobeeA11y.pushScanResults(res, metadata, elementsToClick);
|
410
410
|
},
|
411
411
|
returnResultsDir(): string {
|
412
412
|
return `results/${oobeeA11y.randomToken}_${oobeeA11y.scanDetails.urlsCrawled.scanned.length}pages/reports/report.html`;
|
413
413
|
},
|
414
|
-
|
414
|
+
finishOobeeA11yTestCase(): null {
|
415
415
|
oobeeA11y.testThresholds();
|
416
416
|
return null;
|
417
417
|
},
|
418
|
-
async
|
418
|
+
async terminateOobeeA11y(): Promise<string> {
|
419
419
|
return await oobeeA11y.terminate();
|
420
420
|
},
|
421
421
|
});
|
@@ -427,15 +427,15 @@ Create <code>cypress.config.ts</code> with the following contents, and change yo
|
|
427
427
|
|
428
428
|
Create a sub-folder and file <code>src/cypress/support/e2e.ts</code> with the following contents:
|
429
429
|
|
430
|
-
Cypress.Commands.add("
|
431
|
-
cy.task("
|
430
|
+
Cypress.Commands.add("injectOobeeA11yScripts", () => {
|
431
|
+
cy.task("getOobeeA11yScripts").then((s: string) => {
|
432
432
|
cy.window().then((win) => {
|
433
433
|
win.eval(s);
|
434
434
|
});
|
435
435
|
});
|
436
436
|
});
|
437
437
|
|
438
|
-
Cypress.Commands.add("
|
438
|
+
Cypress.Commands.add("runOobeeA11yScan", (items={}) => {
|
439
439
|
cy.window().then(async (win) => {
|
440
440
|
const { elementsToScan, elementsToClick, metadata } = items;
|
441
441
|
|
@@ -449,7 +449,7 @@ Create a sub-folder and file <code>src/cypress/support/e2e.ts</code> with the fo
|
|
449
449
|
elementsToScan,
|
450
450
|
gradingReadabilityFlag,
|
451
451
|
);
|
452
|
-
cy.task("
|
452
|
+
cy.task("pushOobeeA11yScanResults", {
|
453
453
|
res,
|
454
454
|
metadata,
|
455
455
|
elementsToClick,
|
@@ -458,12 +458,12 @@ Create a sub-folder and file <code>src/cypress/support/e2e.ts</code> with the fo
|
|
458
458
|
});
|
459
459
|
},
|
460
460
|
);
|
461
|
-
cy.task("
|
461
|
+
cy.task("finishOobeeA11yTestCase"); // test the accumulated number of issue occurrences against specified thresholds. If exceed, terminate oobeeA11y instance.
|
462
462
|
});
|
463
463
|
});
|
464
464
|
|
465
|
-
Cypress.Commands.add("
|
466
|
-
cy.task("
|
465
|
+
Cypress.Commands.add("terminateOobeeA11y", () => {
|
466
|
+
cy.task("terminateOobeeA11y");
|
467
467
|
});
|
468
468
|
|
469
469
|
Create <code>src/cypress/e2e/spec.cy.ts</code> with the following contents:
|
@@ -473,17 +473,17 @@ Create <code>src/cypress/e2e/spec.cy.ts</code> with the following contents:
|
|
473
473
|
cy.visit(
|
474
474
|
"https://govtechsg.github.io/purple-banner-embeds/oobee-integrated-scan-example.htm"
|
475
475
|
);
|
476
|
-
cy.
|
477
|
-
cy.
|
476
|
+
cy.injectOobeeA11yScripts();
|
477
|
+
cy.runOobeeA11yScan();
|
478
478
|
cy.get("button[onclick=\"toggleSecondSection()\"]").click();
|
479
479
|
// Run a scan on <input> and <button> elements
|
480
|
-
cy.
|
480
|
+
cy.runOobeeA11yScan({
|
481
481
|
elementsToScan: ["input", "button"],
|
482
482
|
elementsToClick: ["button[onclick=\"toggleSecondSection()\"]"],
|
483
483
|
metadata: "Clicked button"
|
484
484
|
});
|
485
485
|
|
486
|
-
cy.
|
486
|
+
cy.terminateOobeeA11y();
|
487
487
|
});
|
488
488
|
});
|
489
489
|
|
@@ -492,12 +492,12 @@ Create <code>cypress.d.ts</code> in the root directory with the following conten
|
|
492
492
|
```
|
493
493
|
declare namespace Cypress {
|
494
494
|
interface Chainable<Subject> {
|
495
|
-
|
496
|
-
|
497
|
-
|
495
|
+
injectOobeeA11yScripts(): Chainable<void>;
|
496
|
+
runOobeeA11yScan(options?: OobeeScanOptions): Chainable<void>;
|
497
|
+
terminateOobeeA11y(): Chainable<any>;
|
498
498
|
}
|
499
499
|
|
500
|
-
interface
|
500
|
+
interface OobeeScanOptions {
|
501
501
|
elementsToScan?: string[];
|
502
502
|
elementsToClick?: string[];
|
503
503
|
metadata?: string;
|
@@ -535,7 +535,7 @@ Navigate to <code>node_modules/@govtechsg/oobee</code> and run <code>npm install
|
|
535
535
|
npm run build
|
536
536
|
cd ../../..
|
537
537
|
|
538
|
-
On your project's root folder, create a Playwright test file <code>
|
538
|
+
On your project's root folder, create a Playwright test file <code>oobee-playwright-demo.js</code>:
|
539
539
|
|
540
540
|
import { chromium } from "playwright";
|
541
541
|
import oobeeA11yInit from "@govtechsg/oobee";
|
@@ -547,6 +547,8 @@ On your project's root folder, create a Playwright test file <code>oobeeA11y-pla
|
|
547
547
|
const thresholds = { mustFix: 20, goodToFix: 25 };
|
548
548
|
// additional information to include in the "Scan About" section of the report
|
549
549
|
const scanAboutMetadata = { browser: 'Chrome (Desktop)' };
|
550
|
+
// name of the generated zip of the results at the end of scan
|
551
|
+
const resultsZipName = "oobee-scan-results.zip";
|
550
552
|
|
551
553
|
const oobeeA11y = await oobeeA11yInit({
|
552
554
|
entryUrl: "https://govtechsg.github.io", // initial url to start scan
|
@@ -572,7 +574,7 @@ On your project's root folder, create a Playwright test file <code>oobeeA11y-pla
|
|
572
574
|
const context = await browser.newContext();
|
573
575
|
const page = await context.newPage();
|
574
576
|
|
575
|
-
const
|
577
|
+
const runOobeeA11yScan = async (elementsToScan, gradingReadabilityFlag) => {
|
576
578
|
const scanRes = await page.evaluate(
|
577
579
|
async ({ elementsToScan, gradingReadabilityFlag }) => await runA11yScan(elementsToScan, gradingReadabilityFlag),
|
578
580
|
{ elementsToScan, gradingReadabilityFlag },
|
@@ -587,11 +589,11 @@ On your project's root folder, create a Playwright test file <code>oobeeA11y-pla
|
|
587
589
|
const sentences = await page.evaluate(() => extractText());
|
588
590
|
const gradingReadabilityFlag = await oobeeA11y.gradeReadability(sentences);
|
589
591
|
|
590
|
-
await
|
592
|
+
await runOobeeA11yScan([], gradingReadabilityFlag);
|
591
593
|
|
592
594
|
await page.getByRole('button', { name: 'Click Me' }).click();
|
593
595
|
// Run a scan on <input> and <button> elements
|
594
|
-
await
|
596
|
+
await runOobeeA11yScan(['input', 'button'])
|
595
597
|
|
596
598
|
|
597
599
|
// ---------------------
|
@@ -600,7 +602,7 @@ On your project's root folder, create a Playwright test file <code>oobeeA11y-pla
|
|
600
602
|
await oobeeA11y.terminate();
|
601
603
|
})();
|
602
604
|
|
603
|
-
Run your test with <code>node
|
605
|
+
Run your test with <code>node oobee-playwright-demo.js</code> .
|
604
606
|
|
605
607
|
You will see Oobee results generated in <code>results</code> folder.
|
606
608
|
|
@@ -637,7 +639,7 @@ Navigate to <code>node_modules/@govtechsg/oobee</code> and run <code>npm install
|
|
637
639
|
npm run build
|
638
640
|
cd ../../..
|
639
641
|
|
640
|
-
Create a sub-folder and Playwright test file <code>src/
|
642
|
+
Create a sub-folder and Playwright test file <code>src/oobee-playwright-demo.ts</code> with the following contents:
|
641
643
|
|
642
644
|
import { Browser, BrowserContext, Page, chromium } from "playwright";
|
643
645
|
import oobeeA11yInit from "@govtechsg/oobee";
|
@@ -668,6 +670,8 @@ Create a sub-folder and Playwright test file <code>src/oobeeA11y-playwright-demo
|
|
668
670
|
const thresholds: Thresholds = { mustFix: 20, goodToFix: 25 };
|
669
671
|
// additional information to include in the "Scan About" section of the report
|
670
672
|
const scanAboutMetadata: ScanAboutMetadata = { browser: 'Chrome (Desktop)' };
|
673
|
+
// name of the generated zip of the results at the end of scan
|
674
|
+
const resultsZipName: string = "oobee-scan-results.zip";
|
671
675
|
|
672
676
|
const oobeeA11y = await oobeeA11yInit({
|
673
677
|
entryUrl: "https://govtechsg.github.io", // initial url to start scan
|
@@ -693,7 +697,7 @@ Create a sub-folder and Playwright test file <code>src/oobeeA11y-playwright-demo
|
|
693
697
|
const context: BrowserContext = await browser.newContext();
|
694
698
|
const page: Page = await context.newPage();
|
695
699
|
|
696
|
-
const
|
700
|
+
const runOobeeA11yScan = async (elementsToScan?: string[], gradingReadabilityFlag?: string) => {
|
697
701
|
const scanRes = await page.evaluate(
|
698
702
|
async ({ elementsToScan, gradingReadabilityFlag }) => await runA11yScan(elementsToScan, gradingReadabilityFlag),
|
699
703
|
{ elementsToScan, gradingReadabilityFlag },
|
@@ -708,11 +712,11 @@ Create a sub-folder and Playwright test file <code>src/oobeeA11y-playwright-demo
|
|
708
712
|
const sentences = await page.evaluate(() => extractText());
|
709
713
|
const gradingReadabilityFlag = await oobeeA11y.gradeReadability(sentences);
|
710
714
|
|
711
|
-
await
|
715
|
+
await runOobeeA11yScan([], gradingReadabilityFlag);
|
712
716
|
|
713
717
|
await page.getByRole('button', { name: 'Click Me' }).click();
|
714
718
|
// Run a scan on <input> and <button> elements
|
715
|
-
await
|
719
|
+
await runOobeeA11yScan(['input', 'button'])
|
716
720
|
|
717
721
|
|
718
722
|
// ---------------------
|
@@ -722,7 +726,7 @@ Create a sub-folder and Playwright test file <code>src/oobeeA11y-playwright-demo
|
|
722
726
|
})();
|
723
727
|
|
724
728
|
Compile your typescript code with <code>npx tsc</code>.
|
725
|
-
Run your test with <code>node dist/
|
729
|
+
Run your test with <code>node dist/oobee-playwright-demo.js</code>.
|
726
730
|
|
727
731
|
You will see Oobee results generated in <code>results</code> folder.
|
728
732
|
|
@@ -765,7 +769,7 @@ You will see Oobee results generated in <code>results</code> folder.
|
|
765
769
|
return formattedCookies;
|
766
770
|
};
|
767
771
|
|
768
|
-
const
|
772
|
+
const runOobeeA11yScan = command => {
|
769
773
|
exec(command, (error, stdout, stderr) => {
|
770
774
|
if (error) {
|
771
775
|
console.error(`Error: ${error.message}`);
|
@@ -790,8 +794,8 @@ You will see Oobee results generated in <code>results</code> folder.
|
|
790
794
|
// where -m "..." are the headers needed in the format "header1 value1, header2 value2" etc
|
791
795
|
// where -u ".../loginSuccess/" is the destination page after login
|
792
796
|
const command = `npm run cli -- -c website -u "https://authenticationtest.com/loginSuccess/" -p 1 -k "Your Name:email@domain.com" -m "${formattedCookies}"`;
|
793
|
-
console.log(`Executing
|
794
|
-
|
797
|
+
console.log(`Executing OobeeA11y scan command:\n> ${command}\n`);
|
798
|
+
runOobeeA11yScan(command);
|
795
799
|
})
|
796
800
|
.catch(err => {
|
797
801
|
console.error('Error:', err);
|
@@ -836,7 +840,7 @@ You will see Oobee results generated in <code>results</code> folder.
|
|
836
840
|
return formattedCookies;
|
837
841
|
};
|
838
842
|
|
839
|
-
const
|
843
|
+
const runOobeeA11yScan = (command: string): void => {
|
840
844
|
exec(command, (error, stdout, stderr) => {
|
841
845
|
if (error) {
|
842
846
|
console.error(`Error: ${error.message}`);
|
@@ -861,8 +865,8 @@ You will see Oobee results generated in <code>results</code> folder.
|
|
861
865
|
// where -m "..." are the headers needed in the format "header1 value1, header2 value2" etc
|
862
866
|
// where -u ".../loginSuccess/" is the destination page after login
|
863
867
|
const command: string = `npm run cli -- -c website -u "https://authenticationtest.com/loginSuccess/" -p 1 -k "Your Name:email@domain.com" -m "${formattedCookies}"`;
|
864
|
-
console.log(`Executing
|
865
|
-
|
868
|
+
console.log(`Executing OobeeA11y scan command:\n> ${command}\n`);
|
869
|
+
runOobeeA11yScan(command);
|
866
870
|
})
|
867
871
|
.catch((err: Error) => {
|
868
872
|
console.error('Error:', err);
|
package/README.md
CHANGED
@@ -84,7 +84,8 @@ verapdf --version
|
|
84
84
|
| Variable Name | Description | Default |
|
85
85
|
| ------------- | ----------- | ------- |
|
86
86
|
| OOBEE_VERBOSE | When set to `true`, log output goes to console | `false` |
|
87
|
-
|
|
87
|
+
| OOBEE_FAST_CRAWLER| When set to `true`, increases scan concurrency at a rapid rate. Experimental, may cause system stability issues on low-powered devices. | `false`|
|
88
|
+
| OOBEE_VALIDATE_URL| When set to `true`, validates if URLs are valid and exits. | `false` |
|
88
89
|
| WARN_LEVEL | Only used in tests. | |
|
89
90
|
|
90
91
|
#### Environment variables used internally (Do not set)
|
@@ -387,6 +388,8 @@ Options:
|
|
387
388
|
(linux) base64 -d scanData.json.gz.b64 |
|
388
389
|
gunzip > scanData.json\n
|
389
390
|
[string] [choices: "yes", "no"] [default: "no"]
|
391
|
+
-l, --scanDuration Maximum scan duration in seconds (0 means u
|
392
|
+
nlimited) [number] [default: 0]
|
390
393
|
|
391
394
|
Examples:
|
392
395
|
To scan sitemap of website:', 'npm run cli -- -c [ 1 | sitemap ] -u <url_lin
|
@@ -0,0 +1,105 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
3
|
+
<!-- Valid HTTP(S) URLs -->
|
4
|
+
<url>
|
5
|
+
<loc>https://example.com/</loc>
|
6
|
+
</url>
|
7
|
+
<url>
|
8
|
+
<loc>https://example.com/about</loc>
|
9
|
+
</url>
|
10
|
+
|
11
|
+
<!-- Disallowed Schemes -->
|
12
|
+
<url>
|
13
|
+
<loc>mailto:hello@example.com</loc>
|
14
|
+
</url>
|
15
|
+
<url>
|
16
|
+
<loc>tel:+1234567890</loc>
|
17
|
+
</url>
|
18
|
+
<url>
|
19
|
+
<loc>sms:+1234567890</loc>
|
20
|
+
</url>
|
21
|
+
<url>
|
22
|
+
<loc>skype:live:username</loc>
|
23
|
+
</url>
|
24
|
+
<url>
|
25
|
+
<loc>zoommtg://zoom.us/join?confno=123456789</loc>
|
26
|
+
</url>
|
27
|
+
<url>
|
28
|
+
<loc>msteams://teams.microsoft.com/l/meetup-join/abc</loc>
|
29
|
+
</url>
|
30
|
+
<url>
|
31
|
+
<loc>whatsapp://send?text=Hello</loc>
|
32
|
+
</url>
|
33
|
+
<url>
|
34
|
+
<loc>slack://channel?id=xyz</loc>
|
35
|
+
</url>
|
36
|
+
<url>
|
37
|
+
<loc>tg://msg?text=hi</loc>
|
38
|
+
</url>
|
39
|
+
<url>
|
40
|
+
<loc>line://msg/text/hello</loc>
|
41
|
+
</url>
|
42
|
+
<url>
|
43
|
+
<loc>meet://conference/room</loc>
|
44
|
+
</url>
|
45
|
+
<url>
|
46
|
+
<loc>facetime://user@example.com</loc>
|
47
|
+
</url>
|
48
|
+
<url>
|
49
|
+
<loc>imessage://user@example.com</loc>
|
50
|
+
</url>
|
51
|
+
<url>
|
52
|
+
<loc>discord://channel/123</loc>
|
53
|
+
</url>
|
54
|
+
<url>
|
55
|
+
<loc>sgnl://invite/abc</loc>
|
56
|
+
</url>
|
57
|
+
<url>
|
58
|
+
<loc>webex://meeting/123</loc>
|
59
|
+
</url>
|
60
|
+
<url>
|
61
|
+
<loc>intent://some-intent</loc>
|
62
|
+
</url>
|
63
|
+
<url>
|
64
|
+
<loc>ms-outlook://calendar</loc>
|
65
|
+
</url>
|
66
|
+
<url>
|
67
|
+
<loc>ms-word://doc</loc>
|
68
|
+
</url>
|
69
|
+
<url>
|
70
|
+
<loc>ms-excel://sheet</loc>
|
71
|
+
</url>
|
72
|
+
<url>
|
73
|
+
<loc>ms-powerpoint://presentation</loc>
|
74
|
+
</url>
|
75
|
+
<url>
|
76
|
+
<loc>ms-office://open</loc>
|
77
|
+
</url>
|
78
|
+
<url>
|
79
|
+
<loc>onenote://note</loc>
|
80
|
+
</url>
|
81
|
+
<url>
|
82
|
+
<loc>vs://launch</loc>
|
83
|
+
</url>
|
84
|
+
<url>
|
85
|
+
<loc>chrome-extension://abc123/index.html</loc>
|
86
|
+
</url>
|
87
|
+
<url>
|
88
|
+
<loc>chrome-search://search?q=test</loc>
|
89
|
+
</url>
|
90
|
+
<url>
|
91
|
+
<loc>chrome://settings/</loc>
|
92
|
+
</url>
|
93
|
+
<url>
|
94
|
+
<loc>chrome-untrusted://example</loc>
|
95
|
+
</url>
|
96
|
+
<url>
|
97
|
+
<loc>devtools://devtools/bundled/inspector.html</loc>
|
98
|
+
</url>
|
99
|
+
<url>
|
100
|
+
<loc>isolated-app://app/index.html</loc>
|
101
|
+
</url>
|
102
|
+
<url>
|
103
|
+
<loc>#</loc>
|
104
|
+
</url>
|
105
|
+
</urlset>
|