@govtechsg/oobee 0.10.34 → 0.10.36
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/.vscode/settings.json +1 -1
- package/DETAILS.md +58 -42
- package/__mocks__/mock-report.html +1 -1
- package/package.json +1 -1
- package/src/constants/itemTypeDescription.ts +3 -3
- package/src/crawlers/commonCrawlerFunc.ts +7 -1
- package/src/mergeAxeResults.ts +38 -5
- package/src/static/ejs/partials/components/summaryScanResults.ejs +1 -1
- package/src/static/ejs/partials/components/wcagCompliance.ejs +3 -2
- package/src/static/ejs/partials/footer.ejs +13 -7
- package/src/static/ejs/partials/scripts/utils.ejs +1 -1
- package/src/static/ejs/partials/summaryMain.ejs +5 -5
- package/src/static/ejs/report.ejs +2 -2
- package/src/utils.ts +29 -10
package/.vscode/settings.json
CHANGED
package/DETAILS.md
CHANGED
@@ -14,37 +14,53 @@ Details of each issue and severity rating provided by the current scan engine.
|
|
14
14
|
|
15
15
|
## Conformance Covered
|
16
16
|
|
17
|
+
#### Definitions of Conformance Level, Must Fix, Good To Fix, Manual Review Required Required
|
18
|
+
|
19
|
+
In Oobee, issues are grouped into one of three categories:
|
20
|
+
- **Must Fix** issues includes WCAG A & AA success criteria (excluding those requiring review).
|
21
|
+
- **Good To Fix** issues includes WCAG Level AAA success criteria issues and all best practice rules that do not necessarily conform to WCAG success criterion but are industry accepted practices that improve the user experience.
|
22
|
+
- **Manual Review Required Required** occurrences could potentially be false positive, requiring human validation for accuracy.
|
23
|
+
|
17
24
|
Note: Level AAA are disabled by default. Please specify `enable-wcag-aaa` in ruleset flag to enable AAA rules.
|
18
25
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
|
28
|
-
|
29
|
-
| WCAG 1.
|
30
|
-
| WCAG 1.
|
31
|
-
| WCAG
|
32
|
-
| WCAG
|
33
|
-
| WCAG
|
34
|
-
| WCAG
|
35
|
-
| WCAG
|
36
|
-
| WCAG
|
37
|
-
| WCAG
|
38
|
-
| WCAG
|
39
|
-
| WCAG 2.
|
40
|
-
| WCAG
|
41
|
-
| WCAG
|
42
|
-
| WCAG
|
43
|
-
| WCAG
|
44
|
-
| WCAG
|
45
|
-
| WCAG 4.
|
46
|
-
|
47
|
-
|
26
|
+
#### WCAG Level of Conformance
|
27
|
+
|
28
|
+
- **Level A**: The minimum level of accessibility, addressing the most critical issues.
|
29
|
+
- **Level AA**: Builds on Level A, adding more accessibility features. This is the standard most organizations aim for, as it provides reasonable accessibility for most users.
|
30
|
+
- **Level AAA**: The highest level of accessibility, encompassing all Level A and AA criteria plus additional stringent requirements. While ideal, it's often not practical or possible for all content. Examples include providing sign language interpretation for all pre-recorded videos.
|
31
|
+
|
32
|
+
#### Breakdown of WCAG Clauses and Best Practice
|
33
|
+
|
34
|
+
| Conformance | Level | Must Fix | Good to Fix | Exclusive to Manual Review Required |
|
35
|
+
|-------------|-------|----------|-------------|--------------|
|
36
|
+
| WCAG 1.1.1 | A | Yes | | |
|
37
|
+
| WCAG 1.2.2 | A | Yes | | |
|
38
|
+
| WCAG 1.3.1 | A | Yes | | |
|
39
|
+
| WCAG 1.3.5 | AA | Yes | | |
|
40
|
+
| WCAG 1.4.1 | A | Yes | | |
|
41
|
+
| WCAG 1.4.2 | A | Yes | | |
|
42
|
+
| WCAG 1.4.3 | AA | Yes | | |
|
43
|
+
| WCAG 1.4.4 | AA | Yes | | |
|
44
|
+
| WCAG 1.4.6 | AAA | Yes | | |
|
45
|
+
| WCAG 1.4.12 | AA | Yes | | |
|
46
|
+
| WCAG 2.1.1 | A | Yes | | |
|
47
|
+
| WCAG 2.2.1 | A | Yes | | |
|
48
|
+
| WCAG 2.2.2 | A | Yes | | |
|
49
|
+
| WCAG 2.2.4 | AAA | | Yes | |
|
50
|
+
| WCAG 2.4.1 | A | Yes | | |
|
51
|
+
| WCAG 2.4.2 | A | Yes | | |
|
52
|
+
| WCAG 2.4.4 | A | Yes | | |
|
53
|
+
| WCAG 2.4.9 | AAA | | Yes | |
|
54
|
+
| WCAG 2.5.8 | AA | Yes | | |
|
55
|
+
| WCAG 3.1.1 | A | Yes | | |
|
56
|
+
| WCAG 3.1.2 | AA | Yes | | |
|
57
|
+
| WCAG 3.1.5 | AAA | | | Yes |
|
58
|
+
| WCAG 3.2.5 | AAA | | Yes | |
|
59
|
+
| WCAG 3.3.2 | A | Yes | | |
|
60
|
+
| WCAG 4.1.2 | A | Yes | | |
|
61
|
+
| Best Practice| | | Yes | |
|
62
|
+
|
63
|
+
### Summary of WCAG Clauses Supported
|
48
64
|
| Level | Count |
|
49
65
|
|-------|-------|
|
50
66
|
| A | 15 |
|
@@ -61,7 +77,7 @@ Note: Level AAA are disabled by default. Please specify `enable-wcag-aaa` in ru
|
|
61
77
|
| aria-braille-equivalent | Ensure aria-braillelabel and aria-brailleroledescription have a non-braille equivalent | Must Fix | WCAG 4.1.2 |
|
62
78
|
| aria-command-name | Ensures every ARIA button, link and menuitem has an accessible name | Must Fix | WCAG 4.1.2 |
|
63
79
|
| aria-conditional-attr | Ensures ARIA attributes are used as described in the specification of the element's role | Must Fix | WCAG 4.1.2 |
|
64
|
-
| aria-deprecated-role | Ensures elements do not use deprecated roles |
|
80
|
+
| aria-deprecated-role | Ensures elements do not use deprecated roles | Must Fix | WCAG 4.1.2 |
|
65
81
|
| aria-hidden-body | Ensures aria-hidden="true" is not present on the document body. | Must Fix | WCAG 4.1.2 |
|
66
82
|
| aria-hidden-focus | Ensures aria-hidden elements are not focusable nor contain focusable elements | Must Fix | WCAG 4.1.2 |
|
67
83
|
| aria-input-field-name | Ensures every ARIA input field has an accessible name | Must Fix | WCAG 4.1.2 |
|
@@ -89,7 +105,7 @@ Note: Level AAA are disabled by default. Please specify `enable-wcag-aaa` in ru
|
|
89
105
|
| frame-title | Ensures `<iframe>` and `<frame>` elements have an accessible name | Must Fix | WCAG 4.1.2 |
|
90
106
|
| html-has-lang | Ensures every HTML document has a lang attribute | Must Fix | WCAG 3.1.1 |
|
91
107
|
| html-lang-valid | Ensures the lang attribute of the `<html>` element has a valid value | Must Fix | WCAG 3.1.1 |
|
92
|
-
| html-xml-lang-mismatch | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page |
|
108
|
+
| html-xml-lang-mismatch | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Must Fix | WCAG 3.1.1 |
|
93
109
|
| image-alt | Ensures `<img>` elements have alternate text or a role of none or presentation | Must Fix | WCAG 1.1.1 |
|
94
110
|
| input-button-name | Ensures input buttons have discernible text | Must Fix | WCAG 4.1.2 |
|
95
111
|
| input-image-alt | Ensures `<input type="image">` elements have alternate text | Must Fix | WCAG 1.1.1, WCAG 4.1.2 |
|
@@ -101,12 +117,12 @@ Note: Level AAA are disabled by default. Please specify `enable-wcag-aaa` in ru
|
|
101
117
|
| marquee | Ensures `<marquee>` elements are not used | Must Fix | WCAG 2.2.2 |
|
102
118
|
| meta-refresh | Ensures `<meta http-equiv="refresh">` is not used for delayed refresh | Must Fix | WCAG 2.2.1 |
|
103
119
|
| nested-interactive | Ensures interactive controls are not nested as they are not always announced by screen readers or can cause focus problems for assistive technologies | Must Fix | WCAG 4.1.2 |
|
104
|
-
| 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 |
|
120
|
+
| 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 |
|
105
121
|
| object-alt | Ensures `<object>` elements have alternate text | Must Fix | WCAG 1.1.1 |
|
106
122
|
| role-img-alt | Ensures [role="img"] elements have alternate text | Must Fix | WCAG 1.1.1 |
|
107
123
|
| scrollable-region-focusable | Ensure elements that have scrollable content are accessible by keyboard | Must Fix | WCAG 2.1.1 |
|
108
124
|
| select-name | Ensures select element has an accessible name | Must Fix | WCAG 4.1.2 |
|
109
|
-
| server-side-image-map | Ensures that server-side image maps are not used |
|
125
|
+
| server-side-image-map | Ensures that server-side image maps are not used | Must Fix | WCAG 2.1.1 |
|
110
126
|
| 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 |
|
111
127
|
| td-headers-attr | Ensure that each cell in a table that uses the headers attribute refers only to other cells in that table | Must Fix | WCAG 1.3.1 |
|
112
128
|
| th-has-data-cells | Ensure that `<th>` elements and elements with role=columnheader/rowheader have data cells they describe | Must Fix | WCAG 1.3.1 |
|
@@ -139,26 +155,26 @@ Note: Level AAA are disabled by default. Please specify `enable-wcag-aaa` in ru
|
|
139
155
|
|
140
156
|
| Issue ID | Issue Description | Severity | Conformance |
|
141
157
|
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | ----------- | ---------------------- |
|
142
|
-
| color-contrast-enhanced | Ensure the contrast between foreground and background colors meets WCAG 2 AAA enhanced contrast ratio thresholds |
|
158
|
+
| color-contrast-enhanced | Ensure the contrast between foreground and background colors meets WCAG 2 AAA enhanced contrast ratio thresholds | Good to Fix | WCAG 1.4.6 |
|
143
159
|
| identical-links-same-purpose | Ensure that links with the same accessible name serve a similar purpose | Good to Fix | WCAG 2.4.9 |
|
144
160
|
| meta-refresh-no-exceptions | Ensure <meta http-equiv="refresh"> is not used for delayed refresh | Good to Fix | WCAG 2.2.4, WCAG 3.2.5 |
|
145
|
-
| oobee-grading-text-contents | Text content should be clear and plain to ensure that it is easily understood. |
|
161
|
+
| oobee-grading-text-contents | Text content should be clear and plain to ensure that it is easily understood. | Manual Review Required Required | WCAG 3.1.5 |
|
146
162
|
|
147
163
|
## Best Practice
|
148
164
|
|
149
165
|
| Issue ID | Issue Description | Severity |
|
150
166
|
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
|
151
|
-
| accesskeys | Ensures every accesskey attribute value is unique |
|
167
|
+
| accesskeys | Ensures every accesskey attribute value is unique | Good to Fix |
|
152
168
|
| aria-allowed-role | Ensures role attribute has an appropriate value for the element | Good to Fix |
|
153
|
-
| aria-dialog-name | Ensures every ARIA dialog and alertdialog node has an accessible name |
|
154
|
-
| aria-text | Ensures role="text" is used on elements with no focusable descendants |
|
155
|
-
| aria-treeitem-name | Ensures every ARIA treeitem node has an accessible name |
|
169
|
+
| aria-dialog-name | Ensures every ARIA dialog and alertdialog node has an accessible name | Good to Fix |
|
170
|
+
| aria-text | Ensures role="text" is used on elements with no focusable descendants | Good to Fix |
|
171
|
+
| aria-treeitem-name | Ensures every ARIA treeitem node has an accessible name | Good to Fix |
|
156
172
|
| empty-heading | Ensures headings have discernible text | Good to Fix |
|
157
173
|
| empty-table-header | Ensures table headers have discernible text | Good to Fix |
|
158
|
-
| frame-tested | Ensures `<iframe>` and `<frame>` elements contain the axe-core script |
|
174
|
+
| frame-tested | Ensures `<iframe>` and `<frame>` elements contain the axe-core script | Good to Fix |
|
159
175
|
| heading-order | Ensures the order of headings is semantically correct | Good to Fix |
|
160
176
|
| image-redundant-alt | Ensure image alternative is not repeated as text | Good to Fix |
|
161
|
-
| label-title-only | Ensures that every form element has a visible label and is not solely labeled using hidden labels, or the title or aria-describedby attributes |
|
177
|
+
| label-title-only | Ensures that every form element has a visible label and is not solely labeled using hidden labels, or the title or aria-describedby attributes | Good to Fix |
|
162
178
|
| landmark-banner-is-top-level | Ensures the banner landmark is at top level | Good to Fix |
|
163
179
|
| landmark-complementary-is-top-level | Ensures the complementary landmark or aside is at top level | Good to Fix |
|
164
180
|
| landmark-contentinfo-is-top-level | Ensures the contentinfo landmark is at top level | Good to Fix |
|
@@ -174,5 +190,5 @@ Note: Level AAA are disabled by default. Please specify `enable-wcag-aaa` in ru
|
|
174
190
|
| region | Ensures all page content is contained by landmarks | Good to Fix |
|
175
191
|
| scope-attr-valid | Ensures the scope attribute is used correctly on tables | Good to Fix |
|
176
192
|
| skip-link | Ensure all skip links have a focusable target | Good to Fix |
|
177
|
-
| tabindex | Ensures tabindex attribute values are not greater than 0 |
|
193
|
+
| tabindex | Ensures tabindex attribute values are not greater than 0 | Good to Fix |
|
178
194
|
| table-duplicate-name | Ensure the `<caption>` element does not contain the same text as the summary attribute | Good to Fix |
|
@@ -1493,7 +1493,7 @@
|
|
1493
1493
|
<div class="container-fluid">
|
1494
1494
|
<div class="row text-center pt-2 pb-2">
|
1495
1495
|
<div class="col-sm-6 text-sm-left">
|
1496
|
-
<a href="mailto:
|
1496
|
+
<a href="mailto:oobee@wogaa.gov.sg">Help us improve</a>
|
1497
1497
|
<hr class="d-sm-none" />
|
1498
1498
|
</div>
|
1499
1499
|
<div class="col-sm-6 text-sm-right">
|
package/package.json
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
const itemTypeDescription = {
|
2
2
|
mustFix:
|
3
|
-
'
|
3
|
+
'Must Fix issues includes WCAG A & AA success criteria (excluding those requiring review).',
|
4
4
|
goodToFix:
|
5
|
-
'
|
5
|
+
'Good to Fix issues includes WCAG Level AAA success criteria issues and all best practice rules that do not necessarily conform to WCAG success criterion but are industry accepted practices that improve the user experience.',
|
6
6
|
needsReview:
|
7
|
-
'
|
7
|
+
'Manual Review Required occurrences could potentially be false positive, requiring human validation for accuracy.',
|
8
8
|
passed: 'Occurrences that passed the automated checks.',
|
9
9
|
};
|
10
10
|
|
@@ -138,9 +138,15 @@ export const filterAxeResults = (
|
|
138
138
|
|
139
139
|
nodes.forEach(node => {
|
140
140
|
const { impact } = node;
|
141
|
+
const hasWcag2a = conformance.includes('wcag2a');
|
142
|
+
const hasWcag2aa = conformance.includes('wcag2aa');
|
143
|
+
const hasWcag2aaa = conformance.includes('wcag2aaa');
|
144
|
+
|
141
145
|
if (displayNeedsReview) {
|
142
146
|
addTo(needsReview, node);
|
143
|
-
} else if (
|
147
|
+
} else if (hasWcag2aaa) {
|
148
|
+
addTo(goodToFix, node);
|
149
|
+
} else if (hasWcag2a || hasWcag2aa) {
|
144
150
|
addTo(mustFix, node);
|
145
151
|
} else {
|
146
152
|
addTo(goodToFix, node);
|
package/src/mergeAxeResults.ts
CHANGED
@@ -725,6 +725,8 @@ const writeJsonAndBase64Files = async (
|
|
725
725
|
scanItemsBase64FilePath: string;
|
726
726
|
scanItemsSummaryJsonFilePath: string;
|
727
727
|
scanItemsSummaryBase64FilePath: string;
|
728
|
+
scanItemsMiniReportJsonFilePath: string;
|
729
|
+
scanItemsMiniReportBase64FilePath: string;
|
728
730
|
scanDataJsonFileSize: number;
|
729
731
|
scanItemsJsonFileSize: number;
|
730
732
|
}> => {
|
@@ -777,7 +779,7 @@ const writeJsonAndBase64Files = async (
|
|
777
779
|
topTenIssues,
|
778
780
|
} = rest;
|
779
781
|
|
780
|
-
const
|
782
|
+
const summaryItemsMini = {
|
781
783
|
...items,
|
782
784
|
pagesScanned,
|
783
785
|
topTenPagesWithMostIssues,
|
@@ -789,6 +791,32 @@ const writeJsonAndBase64Files = async (
|
|
789
791
|
topTenIssues,
|
790
792
|
};
|
791
793
|
|
794
|
+
const {
|
795
|
+
jsonFilePath: scanItemsMiniReportJsonFilePath,
|
796
|
+
base64FilePath: scanItemsMiniReportBase64FilePath,
|
797
|
+
} = await writeJsonFileAndCompressedJsonFile(summaryItemsMini, storagePath, 'scanItemsSummaryMiniReport');
|
798
|
+
|
799
|
+
const summaryItems = {
|
800
|
+
mustFix: {
|
801
|
+
totalItems: items.mustFix?.totalItems || 0,
|
802
|
+
totalRuleIssues: items.mustFix?.totalRuleIssues || 0,
|
803
|
+
},
|
804
|
+
goodToFix: {
|
805
|
+
totalItems: items.goodToFix?.totalItems || 0,
|
806
|
+
totalRuleIssues: items.goodToFix?.totalRuleIssues || 0,
|
807
|
+
},
|
808
|
+
needsReview: {
|
809
|
+
totalItems: items.needsReview?.totalItems || 0,
|
810
|
+
totalRuleIssues: items.needsReview?.totalRuleIssues || 0,
|
811
|
+
},
|
812
|
+
topTenPagesWithMostIssues,
|
813
|
+
wcagLinks,
|
814
|
+
wcagPassPercentage,
|
815
|
+
totalPagesScanned,
|
816
|
+
totalPagesNotScanned,
|
817
|
+
topTenIssues,
|
818
|
+
};
|
819
|
+
|
792
820
|
const {
|
793
821
|
jsonFilePath: scanItemsSummaryJsonFilePath,
|
794
822
|
base64FilePath: scanItemsSummaryBase64FilePath,
|
@@ -801,6 +829,8 @@ const writeJsonAndBase64Files = async (
|
|
801
829
|
scanItemsBase64FilePath,
|
802
830
|
scanItemsSummaryJsonFilePath,
|
803
831
|
scanItemsSummaryBase64FilePath,
|
832
|
+
scanItemsMiniReportJsonFilePath,
|
833
|
+
scanItemsMiniReportBase64FilePath,
|
804
834
|
scanDataJsonFileSize: fs.statSync(scanDataJsonFilePath).size,
|
805
835
|
scanItemsJsonFileSize: fs.statSync(scanItemsJsonFilePath).size,
|
806
836
|
};
|
@@ -1052,8 +1082,8 @@ const flattenAndSortResults = (allIssues: AllIssues, isCustomFlow: boolean) => {
|
|
1052
1082
|
};
|
1053
1083
|
|
1054
1084
|
allIssues.topFiveMostIssues.sort((page1, page2) => page2.totalIssues - page1.totalIssues);
|
1055
|
-
allIssues.topFiveMostIssues = allIssues.topFiveMostIssues.slice(0, 5);
|
1056
1085
|
allIssues.topTenPagesWithMostIssues = allIssues.topFiveMostIssues.slice(0, 10);
|
1086
|
+
allIssues.topFiveMostIssues = allIssues.topFiveMostIssues.slice(0, 5);
|
1057
1087
|
updateIssuesWithOccurrences(allIssues.topTenPagesWithMostIssues);
|
1058
1088
|
const topTenIssues = getTopTenIssues(allIssues);
|
1059
1089
|
allIssues.topTenIssues = topTenIssues;
|
@@ -1234,7 +1264,7 @@ const generateArtifacts = async (
|
|
1234
1264
|
'',
|
1235
1265
|
`Must Fix: ${allIssues.items.mustFix.rules.length} ${Object.keys(allIssues.items.mustFix.rules).length === 1 ? 'issue' : 'issues'} / ${allIssues.items.mustFix.totalItems} ${allIssues.items.mustFix.totalItems === 1 ? 'occurrence' : 'occurrences'}`,
|
1236
1266
|
`Good to Fix: ${allIssues.items.goodToFix.rules.length} ${Object.keys(allIssues.items.goodToFix.rules).length === 1 ? 'issue' : 'issues'} / ${allIssues.items.goodToFix.totalItems} ${allIssues.items.goodToFix.totalItems === 1 ? 'occurrence' : 'occurrences'}`,
|
1237
|
-
`
|
1267
|
+
`Manual Review Required: ${allIssues.items.needsReview.rules.length} ${Object.keys(allIssues.items.needsReview.rules).length === 1 ? 'issue' : 'issues'} / ${allIssues.items.needsReview.totalItems} ${allIssues.items.needsReview.totalItems === 1 ? 'occurrence' : 'occurrences'}`,
|
1238
1268
|
`Passed: ${allIssues.items.passed.totalItems} ${allIssues.items.passed.totalItems === 1 ? 'occurrence' : 'occurrences'}`,
|
1239
1269
|
]);
|
1240
1270
|
|
@@ -1244,7 +1274,7 @@ const generateArtifacts = async (
|
|
1244
1274
|
createScreenshotsFolder(randomToken);
|
1245
1275
|
}
|
1246
1276
|
|
1247
|
-
allIssues.wcagPassPercentage = getWcagPassPercentage(allIssues.wcagViolations);
|
1277
|
+
allIssues.wcagPassPercentage = getWcagPassPercentage(allIssues.wcagViolations, allIssues.advancedScanOptionsSummaryItems.showEnableWcagAaa);
|
1248
1278
|
consoleLogger.info(
|
1249
1279
|
`advancedScanOptionsSummaryItems is ${allIssues.advancedScanOptionsSummaryItems}`,
|
1250
1280
|
);
|
@@ -1293,6 +1323,8 @@ const generateArtifacts = async (
|
|
1293
1323
|
scanItemsBase64FilePath,
|
1294
1324
|
scanItemsSummaryJsonFilePath,
|
1295
1325
|
scanItemsSummaryBase64FilePath,
|
1326
|
+
scanItemsMiniReportJsonFilePath,
|
1327
|
+
scanItemsMiniReportBase64FilePath,
|
1296
1328
|
scanDataJsonFileSize,
|
1297
1329
|
scanItemsJsonFileSize,
|
1298
1330
|
} = await writeJsonAndBase64Files(allIssues, storagePath);
|
@@ -1306,12 +1338,13 @@ const generateArtifacts = async (
|
|
1306
1338
|
storagePath,
|
1307
1339
|
);
|
1308
1340
|
await writeSummaryHTML(allIssues, storagePath);
|
1341
|
+
|
1309
1342
|
await writeHTML(
|
1310
1343
|
allIssues,
|
1311
1344
|
storagePath,
|
1312
1345
|
'report',
|
1313
1346
|
scanDataBase64FilePath,
|
1314
|
-
resultsTooBig ?
|
1347
|
+
resultsTooBig ? scanItemsMiniReportBase64FilePath : scanItemsBase64FilePath,
|
1315
1348
|
);
|
1316
1349
|
|
1317
1350
|
if (!generateJsonFiles) {
|
@@ -21,7 +21,7 @@
|
|
21
21
|
</div>
|
22
22
|
<div class="modal-body">
|
23
23
|
<div>
|
24
|
-
Only 20 WCAG 2.2 Success Criteria (A & AA) can be checked reasonably through automated testing:
|
24
|
+
Only <a href="https://go.gov.sg/oobee-details" target="_blank">20 WCAG 2.2</a> Success Criteria (A & AA) can be checked reasonably through automated testing:
|
25
25
|
</div>
|
26
26
|
<div class="accordion my-3" id="wcagLinksAccordion">
|
27
27
|
<div class="accordion-item">
|
@@ -41,7 +41,8 @@
|
|
41
41
|
</div>
|
42
42
|
</div>
|
43
43
|
<div>
|
44
|
-
<strong
|
44
|
+
<strong><a aria-label="Manual testing guide" href="https://go.gov.sg/a11y-manual-testing" target="_blank">Manual
|
45
|
+
testing</a> is still recommended</strong> as they involve subjective judgements
|
45
46
|
and human interpretation, which cannot be fully automated.
|
46
47
|
</div>
|
47
48
|
</div>
|
@@ -1,17 +1,23 @@
|
|
1
1
|
<footer aria-label="Report footer" id="footer" class="card">
|
2
2
|
<div class="row mx-0">
|
3
3
|
<div class="col-sm-6 text-sm-start">
|
4
|
-
<%
|
5
|
-
const
|
6
|
-
encodedVersionNumber=encodeURIComponent(phAppVersion);
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
<%
|
5
|
+
const encodedUrlScanned = encodeURIComponent(urlScanned);
|
6
|
+
const encodedVersionNumber = encodeURIComponent(phAppVersion);
|
7
|
+
|
8
|
+
// Use %0A for line breaks in the body
|
9
|
+
const mailtoAddress = `oobee@wogaa.gov.sg`;
|
10
|
+
const mailtoSubject = encodeURIComponent(`Support Request - Oobee Version ${phAppVersion}`);
|
11
|
+
const mailtoBody = encodeURIComponent(`URL Scanned: ${urlScanned}\nVersion: ${phAppVersion}`);
|
12
|
+
const feedbackEmail = `mailto:${mailtoAddress}?subject=${mailtoSubject}&body=${mailtoBody}`;
|
13
|
+
%>
|
14
|
+
|
15
|
+
<a href="<%=feedbackEmail%>" aria-label="Send feedback to <%=mailtoAddress%>" target="_blank">Help us improve</a>
|
10
16
|
<hr class="d-sm-none" />
|
11
17
|
</div>
|
12
18
|
<div class="col-sm-6 text-sm-end">
|
13
19
|
Created by
|
14
|
-
<a href="https://
|
20
|
+
<a href="https://go.gov.sg/a11y" target="_blank">GovTech Accessibility Enabling Team</a> |
|
15
21
|
<a href="https://go.gov.sg/oobee-report-third-party-licenses" target="_blank">Third-Party Licenses</a>
|
16
22
|
</div>
|
17
23
|
</div>
|
@@ -13,7 +13,7 @@
|
|
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.
|
16
|
+
<%= wcagPassPercentage.totalWcagChecksAA - wcagPassPercentage.totalWcagViolationsAA %> / <%= wcagPassPercentage.totalWcagChecksAA %> of automated checks
|
17
17
|
</span>
|
18
18
|
</div>
|
19
19
|
<div class="wcag-compliance-passes-bar mb-5 d-flex">
|
@@ -36,10 +36,10 @@
|
|
36
36
|
<div class="mx-3">
|
37
37
|
<h2 class="mb-2">Summary of issues:</h2>
|
38
38
|
<p>
|
39
|
-
Only
|
40
|
-
<a href="https://
|
41
|
-
|
42
|
-
<a aria-label="Manual testing guide" href="
|
39
|
+
Only
|
40
|
+
<a href="https://go.gov.sg/oobee-details" target=" _blank">20 WCAG 2.2</a>
|
41
|
+
Success Criteria (A & AA) can be automatically checked so
|
42
|
+
<a aria-label="Manual testing guide" href="https://go.gov.sg/a11y-manual-testing" target="_blank">manual
|
43
43
|
testing</a>
|
44
44
|
is still required. For more details, please refer to the HTML report.
|
45
45
|
</p>
|
@@ -47,7 +47,7 @@
|
|
47
47
|
// Scan DATA FUNCTION TO REPLACE NA
|
48
48
|
const scanDataWCAGCompliance = () => {
|
49
49
|
const passPecentage = document.getElementById('passPercentage');
|
50
|
-
passPecentage.innerHTML = scanData.wcagPassPercentage.
|
50
|
+
passPecentage.innerHTML = (scanData.wcagPassPercentage.totalWcagChecksAA - scanData.wcagPassPercentage.totalWcagViolationsAA) + ' / ' + scanData.wcagPassPercentage.totalWcagChecksAA + ' of automated checks';
|
51
51
|
const wcagBarProgess = document.getElementById('wcag-compliance-passes-bar-progress');
|
52
52
|
wcagBarProgess.style.width = `${scanData.wcagPassPercentage.passPercentageAA}%`; // Set this to your desired width
|
53
53
|
|
@@ -94,7 +94,7 @@
|
|
94
94
|
const formattedCategoryTitles = {
|
95
95
|
mustFix: 'Must Fix',
|
96
96
|
goodToFix: 'Good to Fix',
|
97
|
-
needsReview: '
|
97
|
+
needsReview: 'Manual Review Required',
|
98
98
|
passed: 'Passed',
|
99
99
|
};
|
100
100
|
|
package/src/utils.ts
CHANGED
@@ -190,22 +190,41 @@ export const cleanUp = async pathToDelete => {
|
|
190
190
|
// timeZoneName: "longGeneric",
|
191
191
|
// });
|
192
192
|
|
193
|
-
export const getWcagPassPercentage = (
|
193
|
+
export const getWcagPassPercentage = (
|
194
|
+
wcagViolations: string[],
|
195
|
+
showEnableWcagAaa: boolean
|
196
|
+
): {
|
197
|
+
passPercentageAA: string;
|
198
|
+
totalWcagChecksAA: number;
|
199
|
+
totalWcagViolationsAA: number;
|
200
|
+
passPercentageAAandAAA: string;
|
201
|
+
totalWcagChecksAAandAAA: number;
|
202
|
+
totalWcagViolationsAAandAAA: number;
|
203
|
+
} => {
|
194
204
|
|
195
205
|
// These AAA rules should not be counted as WCAG Pass Percentage only contains A and AA
|
196
|
-
const
|
197
|
-
|
198
|
-
|
199
|
-
const
|
200
|
-
|
201
|
-
|
202
|
-
const
|
203
|
-
const
|
206
|
+
const wcagAAALinks = ['WCAG 1.4.6', 'WCAG 2.2.4', 'WCAG 2.4.9', 'WCAG 3.1.5', 'WCAG 3.2.5'];
|
207
|
+
const wcagAAA = ['wcag146', 'wcag224', 'wcag249', 'wcag315', 'wcag325'];
|
208
|
+
|
209
|
+
const wcagLinksAAandAAA = constants.wcagLinks;
|
210
|
+
|
211
|
+
const wcagViolationsAAandAAA = showEnableWcagAaa ? wcagViolations.length : null;
|
212
|
+
const totalChecksAAandAAA = showEnableWcagAaa ? Object.keys(wcagLinksAAandAAA).length : null;
|
213
|
+
const passedChecksAAandAAA = showEnableWcagAaa ? totalChecksAAandAAA - wcagViolationsAAandAAA : null;
|
214
|
+
const passPercentageAAandAAA = showEnableWcagAaa ? (totalChecksAAandAAA === 0 ? 0 : (passedChecksAAandAAA / totalChecksAAandAAA) * 100) : null;
|
215
|
+
|
216
|
+
const wcagViolationsAA = wcagViolations.filter(violation => !wcagAAA.includes(violation)).length;
|
217
|
+
const totalChecksAA = Object.keys(wcagLinksAAandAAA).filter(key => !wcagAAALinks.includes(key)).length;
|
218
|
+
const passedChecksAA = totalChecksAA - wcagViolationsAA;
|
219
|
+
const passPercentageAA = totalChecksAA === 0 ? 0 : (passedChecksAA / totalChecksAA) * 100;
|
204
220
|
|
205
221
|
return {
|
206
222
|
passPercentageAA: passPercentageAA.toFixed(2), // toFixed returns a string, which is correct here
|
207
223
|
totalWcagChecksAA: totalChecksAA,
|
208
|
-
totalWcagViolationsAA:
|
224
|
+
totalWcagViolationsAA: wcagViolationsAA,
|
225
|
+
passPercentageAAandAAA: passPercentageAAandAAA ? passPercentageAAandAAA.toFixed(2) : null, // toFixed returns a string, which is correct here
|
226
|
+
totalWcagChecksAAandAAA: totalChecksAAandAAA,
|
227
|
+
totalWcagViolationsAAandAAA: wcagViolationsAAandAAA,
|
209
228
|
};
|
210
229
|
};
|
211
230
|
|