@govtechsg/oobee 0.10.33 → 0.10.34
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/Dockerfile +1 -1
- package/package.json +1 -1
- package/src/constants/constants.ts +3 -3
- package/src/crawlers/crawlDomain.ts +36 -6
- package/src/crawlers/crawlSitemap.ts +12 -2
- package/src/crawlers/custom/flagUnlabelledClickableElements.ts +0 -2
- package/src/crawlers/pdfScanFunc.ts +5 -1
- package/src/static/ejs/partials/summaryMain.ejs +3 -2
- package/src/static/ejs/report.ejs +2 -2
- package/src/utils.ts +9 -5
package/Dockerfile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Use Microsoft Playwright image as base image
|
2
2
|
# Node version is v22
|
3
|
-
FROM mcr.microsoft.com/playwright:v1.50.
|
3
|
+
FROM mcr.microsoft.com/playwright:v1.50.1-noble
|
4
4
|
|
5
5
|
# Installation of packages for oobee and runner
|
6
6
|
RUN apt-get update && apt-get install -y zip git
|
package/package.json
CHANGED
@@ -178,14 +178,14 @@ export const axeScript = path.join(dirname, '../../node_modules/axe-core/axe.min
|
|
178
178
|
export class UrlsCrawled {
|
179
179
|
toScan: string[] = [];
|
180
180
|
scanned: { url: string; actualUrl: string; pageTitle: string }[] = [];
|
181
|
-
invalid: string[] = [];
|
181
|
+
invalid: { url: string; actualUrl: string; pageTitle: string }[] = [];
|
182
182
|
scannedRedirects: { fromUrl: string; toUrl: string }[] = [];
|
183
183
|
notScannedRedirects: { fromUrl: string; toUrl: string }[] = [];
|
184
184
|
outOfDomain: string[] = [];
|
185
|
-
blacklisted: string[] = [];
|
185
|
+
blacklisted: { url: string; actualUrl: string; pageTitle: string }[] = [];
|
186
186
|
error: { url: string }[] = [];
|
187
187
|
exceededRequests: string[] = [];
|
188
|
-
forbidden: string[] = [];
|
188
|
+
forbidden: { url: string; actualUrl: string; pageTitle: string }[] = [];
|
189
189
|
userExcluded: { url: string; actualUrl: string; pageTitle: string }[] = [];
|
190
190
|
everything: string[] = [];
|
191
191
|
|
@@ -638,7 +638,12 @@ const crawlDomain = async ({
|
|
638
638
|
numScanned: urlsCrawled.scanned.length,
|
639
639
|
urlScanned: request.url,
|
640
640
|
});
|
641
|
-
urlsCrawled.blacklisted.push(
|
641
|
+
urlsCrawled.blacklisted.push({
|
642
|
+
url: request.url,
|
643
|
+
pageTitle: request.url,
|
644
|
+
actualUrl: actualUrl, // i.e. actualUrl
|
645
|
+
});
|
646
|
+
|
642
647
|
return;
|
643
648
|
}
|
644
649
|
const { pdfFileName, url } = handlePdfDownload(
|
@@ -662,7 +667,12 @@ const crawlDomain = async ({
|
|
662
667
|
numScanned: urlsCrawled.scanned.length,
|
663
668
|
urlScanned: request.url,
|
664
669
|
});
|
665
|
-
urlsCrawled.blacklisted.push(
|
670
|
+
urlsCrawled.blacklisted.push({
|
671
|
+
url: request.url,
|
672
|
+
pageTitle: request.url,
|
673
|
+
actualUrl: actualUrl, // i.e. actualUrl
|
674
|
+
});
|
675
|
+
|
666
676
|
return;
|
667
677
|
}
|
668
678
|
|
@@ -671,7 +681,12 @@ const crawlDomain = async ({
|
|
671
681
|
numScanned: urlsCrawled.scanned.length,
|
672
682
|
urlScanned: request.url,
|
673
683
|
});
|
674
|
-
urlsCrawled.blacklisted.push(
|
684
|
+
urlsCrawled.blacklisted.push({
|
685
|
+
url: request.url,
|
686
|
+
pageTitle: request.url,
|
687
|
+
actualUrl: actualUrl, // i.e. actualUrl
|
688
|
+
});
|
689
|
+
|
675
690
|
return;
|
676
691
|
}
|
677
692
|
|
@@ -691,7 +706,12 @@ const crawlDomain = async ({
|
|
691
706
|
numScanned: urlsCrawled.scanned.length,
|
692
707
|
urlScanned: request.url,
|
693
708
|
});
|
694
|
-
urlsCrawled.forbidden.push(
|
709
|
+
urlsCrawled.forbidden.push({
|
710
|
+
url: request.url,
|
711
|
+
pageTitle: request.url,
|
712
|
+
actualUrl: actualUrl, // i.e. actualUrl
|
713
|
+
});
|
714
|
+
|
695
715
|
return;
|
696
716
|
}
|
697
717
|
|
@@ -700,7 +720,12 @@ const crawlDomain = async ({
|
|
700
720
|
numScanned: urlsCrawled.scanned.length,
|
701
721
|
urlScanned: request.url,
|
702
722
|
});
|
703
|
-
urlsCrawled.invalid.push(
|
723
|
+
urlsCrawled.invalid.push({
|
724
|
+
url: request.url,
|
725
|
+
pageTitle: request.url,
|
726
|
+
actualUrl: actualUrl, // i.e. actualUrl
|
727
|
+
});
|
728
|
+
|
704
729
|
return;
|
705
730
|
}
|
706
731
|
|
@@ -779,7 +804,12 @@ const crawlDomain = async ({
|
|
779
804
|
numScanned: urlsCrawled.scanned.length,
|
780
805
|
urlScanned: request.url,
|
781
806
|
});
|
782
|
-
urlsCrawled.blacklisted.push(
|
807
|
+
urlsCrawled.blacklisted.push({
|
808
|
+
url: request.url,
|
809
|
+
pageTitle: request.url,
|
810
|
+
actualUrl: actualUrl, // i.e. actualUrl
|
811
|
+
});
|
812
|
+
|
783
813
|
}
|
784
814
|
|
785
815
|
if (followRobots) await getUrlsFromRobotsTxt(request.url, browser);
|
@@ -250,7 +250,12 @@ const crawlSitemap = async (
|
|
250
250
|
numScanned: urlsCrawled.scanned.length,
|
251
251
|
urlScanned: request.url,
|
252
252
|
});
|
253
|
-
urlsCrawled.blacklisted.push(
|
253
|
+
urlsCrawled.blacklisted.push({
|
254
|
+
url: request.url,
|
255
|
+
pageTitle: request.url,
|
256
|
+
actualUrl: actualUrl, // i.e. actualUrl
|
257
|
+
});
|
258
|
+
|
254
259
|
return;
|
255
260
|
}
|
256
261
|
// pushes download promise into pdfDownloads
|
@@ -297,7 +302,12 @@ const crawlSitemap = async (
|
|
297
302
|
numScanned: urlsCrawled.scanned.length,
|
298
303
|
urlScanned: request.url,
|
299
304
|
});
|
300
|
-
urlsCrawled.invalid.push(
|
305
|
+
urlsCrawled.invalid.push({
|
306
|
+
url: request.url,
|
307
|
+
pageTitle: request.url,
|
308
|
+
actualUrl: actualUrl, // i.e. actualUrl
|
309
|
+
});
|
310
|
+
|
301
311
|
return;
|
302
312
|
}
|
303
313
|
|
@@ -874,7 +874,6 @@ export const flagUnlabelledClickableElements = async (page: Page) => {
|
|
874
874
|
}
|
875
875
|
|
876
876
|
function flagElements() {
|
877
|
-
console.time('Accessibility Check Time');
|
878
877
|
|
879
878
|
const currentFlaggedElementsByDocument: Record<string, HTMLElement[]> = {}; // Temporary object to hold current flagged elements
|
880
879
|
|
@@ -1014,7 +1013,6 @@ export const flagUnlabelledClickableElements = async (page: Page) => {
|
|
1014
1013
|
previousFlaggedXPathsByDocument = { ...flaggedXPathsByDocument };
|
1015
1014
|
|
1016
1015
|
cleanupFlaggedElements();
|
1017
|
-
console.timeEnd('Accessibility Check Time');
|
1018
1016
|
return previousAllFlaggedElementsXPaths;
|
1019
1017
|
}
|
1020
1018
|
|
@@ -295,7 +295,11 @@ export const handlePdfDownload = (
|
|
295
295
|
numScanned: urlsCrawled.scanned.length,
|
296
296
|
urlScanned: request.url,
|
297
297
|
});
|
298
|
-
urlsCrawled.invalid.push(
|
298
|
+
urlsCrawled.invalid.push({
|
299
|
+
url: request.url,
|
300
|
+
pageTitle: url,
|
301
|
+
actualUrl: url, // i.e. actualUrl
|
302
|
+
});
|
299
303
|
}
|
300
304
|
resolve();
|
301
305
|
});
|
@@ -13,14 +13,15 @@
|
|
13
13
|
<div class="d-flex justify-content-between align-items-center">
|
14
14
|
<span class="fw-bold"> WCAG (A & AA) Passes </span>
|
15
15
|
<span aria-label="Pass percentage" class="ms-2">
|
16
|
-
<%= wcagPassPercentage %>% of automated checks
|
16
|
+
<%= wcagPassPercentage.passPercentageAA %>% of automated checks
|
17
17
|
</span>
|
18
18
|
</div>
|
19
19
|
<div class="wcag-compliance-passes-bar mb-5 d-flex">
|
20
20
|
<svg width="500" role="none" height="6" fill="none" xmlns="http://www.w3.org/2000/svg"
|
21
21
|
style="display: flex; width: 100%; position: absolute">
|
22
22
|
<rect width="100%" height="10" rx="3" fill="#E7ECEE" style="justify-content: left"></rect>
|
23
|
-
<rect width="<%= wcagPassPercentage %>%" height="6" rx="3" fill="#9021a6" style=""
|
23
|
+
<rect width="<%= wcagPassPercentage.passPercentageAA %>%" height="6" rx="3" fill="#9021a6" style="">
|
24
|
+
</rect>
|
24
25
|
</svg>
|
25
26
|
</div>
|
26
27
|
<ul class="unbulleted-list">
|
@@ -47,9 +47,9 @@
|
|
47
47
|
// Scan DATA FUNCTION TO REPLACE NA
|
48
48
|
const scanDataWCAGCompliance = () => {
|
49
49
|
const passPecentage = document.getElementById('passPercentage');
|
50
|
-
passPecentage.innerHTML = scanData.wcagPassPercentage + '% of automated checks';
|
50
|
+
passPecentage.innerHTML = scanData.wcagPassPercentage.passPercentageAA + '% of automated checks';
|
51
51
|
const wcagBarProgess = document.getElementById('wcag-compliance-passes-bar-progress');
|
52
|
-
wcagBarProgess.style.width = `${scanData.wcagPassPercentage}%`; // Set this to your desired width
|
52
|
+
wcagBarProgess.style.width = `${scanData.wcagPassPercentage.passPercentageAA}%`; // Set this to your desired width
|
53
53
|
|
54
54
|
const wcagLinksList = document.getElementById('wcagLinksList');
|
55
55
|
|
package/src/utils.ts
CHANGED
@@ -190,19 +190,23 @@ export const cleanUp = async pathToDelete => {
|
|
190
190
|
// timeZoneName: "longGeneric",
|
191
191
|
// });
|
192
192
|
|
193
|
-
export const getWcagPassPercentage = (wcagViolations: string[]): string => {
|
193
|
+
export const getWcagPassPercentage = (wcagViolations: string[]): { passPercentageAA: string; totalWcagChecksAA: number; totalWcagViolationsAA: number } => {
|
194
194
|
|
195
195
|
// These AAA rules should not be counted as WCAG Pass Percentage only contains A and AA
|
196
196
|
const wcagAAA = ['WCAG 1.4.6', 'WCAG 2.2.4', 'WCAG 2.4.9', 'WCAG 3.1.5', 'WCAG 3.2.5'];
|
197
197
|
|
198
198
|
const filteredWcagLinks = Object.keys(constants.wcagLinks).filter(key => !wcagAAA.includes(key));
|
199
199
|
const filteredWcagViolations = wcagViolations.filter(violation => !wcagAAA.includes(violation));
|
200
|
-
const
|
200
|
+
const totalChecksAA = filteredWcagLinks.length;
|
201
201
|
|
202
|
-
const passedChecks =
|
203
|
-
const
|
202
|
+
const passedChecks = totalChecksAA - filteredWcagViolations.length;
|
203
|
+
const passPercentageAA = (passedChecks / totalChecksAA) * 100;
|
204
204
|
|
205
|
-
return
|
205
|
+
return {
|
206
|
+
passPercentageAA: passPercentageAA.toFixed(2), // toFixed returns a string, which is correct here
|
207
|
+
totalWcagChecksAA: totalChecksAA,
|
208
|
+
totalWcagViolationsAA: filteredWcagViolations.length,
|
209
|
+
};
|
206
210
|
};
|
207
211
|
|
208
212
|
export const getFormattedTime = inputDate => {
|