@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.
@@ -78,6 +78,7 @@ type AllIssues = {
78
78
  htmlETL: any;
79
79
  rules: string[];
80
80
  };
81
+ siteName: string;
81
82
  startTime: Date;
82
83
  endTime: Date;
83
84
  urlScanned: string;
@@ -130,7 +131,6 @@ const extractFileNames = async (directory: string): Promise<string[]> => {
130
131
  .then(allFiles => allFiles.filter(file => path.extname(file).toLowerCase() === '.json'))
131
132
  .catch(readdirError => {
132
133
  consoleLogger.info('An error has occurred when retrieving files, please try again.');
133
- silentLogger.error(`(extractFileNames) - ${readdirError}`);
134
134
  throw readdirError;
135
135
  });
136
136
  };
@@ -140,7 +140,6 @@ const parseContentToJson = async rPath =>
140
140
  .then(content => JSON.parse(content))
141
141
  .catch(parseError => {
142
142
  consoleLogger.info('An error has occurred when parsing the content, please try again.');
143
- silentLogger.error(`(parseContentToJson) - ${parseError}`);
144
143
  });
145
144
 
146
145
  const writeCsv = async (allIssues, storagePath) => {
@@ -684,7 +683,7 @@ async function compressJsonFileStreaming(inputPath: string, outputPath: string)
684
683
  // Pipe the streams:
685
684
  // read -> gzip -> base64 -> write
686
685
  await pipeline(readStream, gzip, base64Encode, writeStream);
687
- console.log(`File successfully compressed and saved to ${outputPath}`);
686
+ consoleLogger.info(`File successfully compressed and saved to ${outputPath}`);
688
687
  }
689
688
 
690
689
  const writeJsonFileAndCompressedJsonFile = async (
@@ -1559,7 +1558,7 @@ const sendWcagBreakdownToSentry = async (
1559
1558
  const wcagCriteriaBreakdown: Record<string, any> = {};
1560
1559
 
1561
1560
  // Tag app version
1562
- tags['version'] = appVersion;
1561
+ tags.version = appVersion;
1563
1562
 
1564
1563
  // Get dynamic WCAG criteria map once
1565
1564
  const wcagCriteriaMap = await getWcagCriteriaMap();
@@ -1638,7 +1637,7 @@ const sendWcagBreakdownToSentry = async (
1638
1637
  tags['WCAG-MustFix-Occurrences'] = String(allIssues.items.mustFix.totalItems);
1639
1638
  tags['WCAG-GoodToFix-Occurrences'] = String(allIssues.items.goodToFix.totalItems);
1640
1639
  tags['WCAG-NeedsReview-Occurrences'] = String(allIssues.items.needsReview.totalItems);
1641
-
1640
+
1642
1641
  // Add number of pages scanned tag
1643
1642
  tags['Pages-Scanned-Count'] = String(allIssues.totalPagesScanned);
1644
1643
  } else if (pagesScannedCount > 0) {
@@ -1667,7 +1666,7 @@ const sendWcagBreakdownToSentry = async (
1667
1666
  ...(userData && userData.userId ? { id: userData.userId } : {}),
1668
1667
  },
1669
1668
  extra: {
1670
- additionalScanMetadata: ruleIdJson != null ? JSON.stringify(ruleIdJson) : "{}",
1669
+ additionalScanMetadata: ruleIdJson != null ? JSON.stringify(ruleIdJson) : '{}',
1671
1670
  wcagBreakdown: wcagCriteriaBreakdown,
1672
1671
  reportCounts: allIssues
1673
1672
  ? {
@@ -1766,6 +1765,7 @@ const generateArtifacts = async (
1766
1765
  htmlETL: oobeeAiHtmlETL,
1767
1766
  rules: oobeeAiRules,
1768
1767
  },
1768
+ siteName: (pagesScanned[0]?.pageTitle ?? '').replace(/^\d+\s*:\s*/, '').trim(),
1769
1769
  startTime: scanDetails.startTime ? scanDetails.startTime : new Date(),
1770
1770
  endTime: scanDetails.endTime ? scanDetails.endTime : new Date(),
1771
1771
  urlScanned,
@@ -1845,7 +1845,6 @@ const generateArtifacts = async (
1845
1845
  }),
1846
1846
  ).catch(flattenIssuesError => {
1847
1847
  consoleLogger.info('An error has occurred when flattening the issues, please try again.');
1848
- silentLogger.error(flattenIssuesError.stack);
1849
1848
  });
1850
1849
 
1851
1850
  flattenAndSortResults(allIssues, isCustomFlow);
@@ -1853,6 +1852,10 @@ const generateArtifacts = async (
1853
1852
  printMessage([
1854
1853
  'Scan Summary',
1855
1854
  '',
1855
+ `Site Name: ${allIssues.siteName}`,
1856
+ `URL: ${allIssues.urlScanned}`,
1857
+ `Pages Scanned: ${allIssues.totalPagesScanned}`,
1858
+ '',
1856
1859
  `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'}`,
1857
1860
  `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'}`,
1858
1861
  `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'}`,
@@ -1882,8 +1885,13 @@ const generateArtifacts = async (
1882
1885
  allIssues.advancedScanOptionsSummaryItems.disableOobee,
1883
1886
  );
1884
1887
 
1885
- // console.log(allIssues.progressPercentage);
1886
- // console.log(allIssues.issuesPercentage);
1888
+ consoleLogger.info(`Site Name: ${allIssues.siteName}`);
1889
+ consoleLogger.info(`URL: ${allIssues.urlScanned}`);
1890
+ consoleLogger.info(`Pages Scanned: ${allIssues.totalPagesScanned}`);
1891
+ consoleLogger.info(`Start Time: ${allIssues.startTime}`);
1892
+ consoleLogger.info(`End Time: ${allIssues.endTime}`);
1893
+ const elapsedSeconds = (new Date(allIssues.endTime).getTime() - new Date(allIssues.startTime).getTime()) / 1000;
1894
+ consoleLogger.info(`Elapsed Time: ${elapsedSeconds}s`);
1887
1895
 
1888
1896
  const getAxeImpactCount = (allIssues: AllIssues) => {
1889
1897
  const impactCount = {
@@ -2044,6 +2052,9 @@ const generateArtifacts = async (
2044
2052
  console.error('Error sending WCAG data to Sentry:', error);
2045
2053
  }
2046
2054
 
2055
+ if (process.env.RUNNING_FROM_PH_GUI || process.env.OOBEE_VERBOSE)
2056
+ console.log('Report generated successfully');
2057
+
2047
2058
  return ruleIdJson;
2048
2059
  };
2049
2060
 
package/src/npmIndex.ts CHANGED
@@ -219,7 +219,7 @@ export const init = async ({
219
219
  try {
220
220
  await page.locator(elem).click();
221
221
  } catch (e) {
222
- silentLogger.info(e);
222
+ // do nothing if element is not found or not clickable
223
223
  }
224
224
  });
225
225
 
@@ -2,7 +2,7 @@
2
2
  import { createHash } from 'crypto';
3
3
  import fs from 'fs';
4
4
  import path from 'path';
5
- import { consoleLogger } from '../logs.js';
5
+ // import { silentLogger } from '../logs.js';
6
6
  import { Result } from 'axe-core';
7
7
  import { Page } from 'playwright';
8
8
  import { NodeResultWithScreenshot, ResultWithScreenshot } from '../crawlers/commonCrawlerFunc.js';
@@ -21,9 +21,11 @@ export const takeScreenshotForHTMLElements = async (
21
21
 
22
22
  for (const violation of violations) {
23
23
  if (screenshotCount >= maxScreenshots) {
24
- consoleLogger.warn(
24
+ /*
25
+ silentLogger.warn(
25
26
  `Skipping screenshots for ${violation.id} as maxScreenshots (${maxScreenshots}) exceeded. You can increase it by specifying a higher value when calling takeScreenshotForHTMLElements.`,
26
27
  );
28
+ */
27
29
  newViolations.push(violation);
28
30
  continue;
29
31
  }
@@ -32,7 +34,7 @@ export const takeScreenshotForHTMLElements = async (
32
34
 
33
35
  // Check if rule ID is 'oobee-grading-text-contents' and skip screenshot logic
34
36
  if (rule === 'oobee-grading-text-contents') {
35
- // consoleLogger.info('Skipping screenshot for rule oobee-grading-text-contents');
37
+ // silentLogger.info('Skipping screenshot for rule oobee-grading-text-contents');
36
38
  newViolations.push(violation); // Make sure it gets added
37
39
  continue;
38
40
  }
@@ -57,13 +59,13 @@ export const takeScreenshotForHTMLElements = async (
57
59
  nodeWithScreenshotPath.screenshotPath = screenshotPath;
58
60
  screenshotCount++;
59
61
  } else {
60
- consoleLogger.info(`Element at ${currLocator} is not visible`);
62
+ // silentLogger.info(`Element at ${currLocator} is not visible`);
61
63
  }
62
64
 
63
65
  break; // Stop looping after finding the first visible locator
64
66
  }
65
67
  } catch (e) {
66
- consoleLogger.info(`Unable to take element screenshot at ${selector}`);
68
+ // silentLogger.info(`Unable to take element screenshot at ${selector}`);
67
69
  }
68
70
  }
69
71
  newViolationNodes.push(nodeWithScreenshotPath);
@@ -12,7 +12,7 @@ import { Canvas, createCanvas, SKRSContext2D } from '@napi-rs/canvas';
12
12
  import assert from 'assert';
13
13
  import path from 'path';
14
14
  import { fileURLToPath } from 'url';
15
- import { silentLogger } from '../logs.js';
15
+ import { consoleLogger, silentLogger } from '../logs.js';
16
16
  import { TransformedRuleObject } from '../crawlers/pdfScanFunc.js';
17
17
  import { IBboxLocation, StructureTree, ViewportSize } from '../types/types.js';
18
18
 
@@ -213,7 +213,7 @@ const annotateAndSave = (origCanvas: Canvas, screenshotPath: string, viewport: V
213
213
  try {
214
214
  fs.writeFileSync(indexedScreenshotPath, croppedImage);
215
215
  } catch (e) {
216
- silentLogger.error('Error in writing screenshot:', e);
216
+ consoleLogger.error('Error in writing screenshot:', e);
217
217
  }
218
218
 
219
219
  canvasFactory.destroy({ canvas: croppedCanvas, context: croppedCtx });
@@ -29,7 +29,7 @@
29
29
  <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
30
30
  data-bs-target="#wcagLinksAccordionContent" aria-expanded="false"
31
31
  aria-controls="wcagLinksAccordionContent">
32
- 20 (A & AA) and 5 (AAA) WCAG Success Criteria
32
+ 20 (A & AA) and 6 (AAA) WCAG Success Criteria
33
33
  </button>
34
34
  </div>
35
35
  <div id="wcagLinksAccordionContent" class="accordion-collapse collapse"
@@ -22,6 +22,7 @@ category summary is clicked %>
22
22
  // wcag1410: 'https://www.w3.org/TR/WCAG22/#reflow',
23
23
  wcag1412: 'https://www.w3.org/TR/WCAG22/#text-spacing',
24
24
  wcag211: 'https://www.w3.org/TR/WCAG22/#keyboard',
25
+ wcag213: 'https://www.w3.org/WAI/WCAG22/Understanding/keyboard-no-exception.html', // AAA
25
26
  wcag221: 'https://www.w3.org/TR/WCAG22/#timing-adjustable',
26
27
  wcag222: 'https://www.w3.org/TR/WCAG22/#pause-stop-hide',
27
28
  wcag224: 'https://www.w3.org/TR/WCAG22/#interruptions', // AAA
@@ -668,6 +668,17 @@
668
668
  #pagesScannedModal .not-scanned-url {
669
669
  word-wrap: break-word;
670
670
  }
671
+ #pagesScannedModal .metadata-text {
672
+ word-wrap: break-word;
673
+ font-size: 0.875rem;
674
+ color: var(--coral-red-100);
675
+ }
676
+ #pagesScannedModal .metadata-inline {
677
+ display: flex;
678
+ align-items: center;
679
+ gap: 0.5rem;
680
+ height: 16px;
681
+ }
671
682
  #pagesScannedModal p {
672
683
  overflow: hidden;
673
684
  white-space: nowrap;
@@ -298,7 +298,20 @@
298
298
 
299
299
  pagesNotScanned.forEach((page, index) => {
300
300
  var listItem = document.createElement('li');
301
- listItem.innerHTML = `<a class="not-scanned-url" href="${page.url || page }" target="_blank">${page.url || page }</a>`;
301
+ const url = page.url || page;
302
+ const metadata = page.metadata || page;
303
+
304
+ const linkHTML = `<a class="not-scanned-url" href="${url}" target="_blank">${url}</a>`;
305
+ const metadataHTML = `
306
+ <div class="metadata-inline">
307
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none">
308
+ <path d="M12 19.875C9.91142 19.875 7.90838 19.0453 6.43153 17.5685C4.95468 16.0916 4.125 14.0886 4.125 12C4.125 9.91142 4.95468 7.90838 6.43153 6.43153C7.90838 4.95468 9.91142 4.125 12 4.125C14.0886 4.125 16.0916 4.95468 17.5685 6.43153C19.0453 7.90838 19.875 9.91142 19.875 12C19.875 14.0886 19.0453 16.0916 17.5685 17.5685C16.0916 19.0453 14.0886 19.875 12 19.875ZM12 21C14.3869 21 16.6761 20.0518 18.364 18.364C20.0518 16.6761 21 14.3869 21 12C21 9.61305 20.0518 7.32387 18.364 5.63604C16.6761 3.94821 14.3869 3 12 3C9.61305 3 7.32387 3.94821 5.63604 5.63604C3.94821 7.32387 3 9.61305 3 12C3 14.3869 3.94821 16.6761 5.63604 18.364C7.32387 20.0518 9.61305 21 12 21Z" fill="#f26949"/>
309
+ <path d="M10.8772 15.3751C10.8772 15.2274 10.9063 15.0811 10.9628 14.9446C11.0194 14.8081 11.1022 14.6841 11.2067 14.5796C11.3112 14.4752 11.4352 14.3923 11.5717 14.3357C11.7082 14.2792 11.8545 14.2501 12.0022 14.2501C12.1499 14.2501 12.2962 14.2792 12.4327 14.3357C12.5692 14.3923 12.6932 14.4752 12.7977 14.5796C12.9022 14.6841 12.985 14.8081 13.0416 14.9446C13.0981 15.0811 13.1272 15.2274 13.1272 15.3751C13.1272 15.6735 13.0087 15.9596 12.7977 16.1706C12.5867 16.3816 12.3006 16.5001 12.0022 16.5001C11.7038 16.5001 11.4177 16.3816 11.2067 16.1706C10.9957 15.9596 10.8772 15.6735 10.8772 15.3751ZM10.9874 8.61949C10.9725 8.47756 10.9875 8.33407 11.0315 8.19832C11.0756 8.06257 11.1477 7.9376 11.2432 7.83152C11.3387 7.72544 11.4554 7.64062 11.5857 7.58256C11.7161 7.52449 11.8572 7.49449 11.9999 7.49449C12.1427 7.49449 12.2838 7.52449 12.4142 7.58256C12.5445 7.64062 12.6612 7.72544 12.7567 7.83152C12.8522 7.9376 12.9243 8.06257 12.9683 8.19832C13.0124 8.33407 13.0274 8.47756 13.0124 8.61949L12.6187 12.5649C12.6055 12.7199 12.5346 12.8642 12.42 12.9695C12.3054 13.0747 12.1555 13.133 11.9999 13.133C11.8444 13.133 11.6945 13.0747 11.5799 12.9695C11.4653 12.8642 11.3944 12.7199 11.3812 12.5649L10.9874 8.61949Z" fill="#f26949"/>
310
+ </svg>
311
+ <span class="metadata-text">${metadata}</span>
312
+ </div>`;
313
+
314
+ listItem.innerHTML = `${linkHTML}${metadataHTML}`;
302
315
  pagesNotScannedList.appendChild(listItem);
303
316
  });
304
317
  }
package/src/utils.ts CHANGED
@@ -209,8 +209,8 @@ export const getWcagPassPercentage = (
209
209
  totalWcagViolationsAAandAAA: number;
210
210
  } => {
211
211
  // These AAA rules should not be counted as WCAG Pass Percentage only contains A and AA
212
- const wcagAAALinks = ['WCAG 1.4.6', 'WCAG 2.2.4', 'WCAG 2.4.9', 'WCAG 3.1.5', 'WCAG 3.2.5'];
213
- const wcagAAA = ['wcag146', 'wcag224', 'wcag249', 'wcag315', 'wcag325'];
212
+ const wcagAAALinks = ['WCAG 1.4.6', 'WCAG 2.2.4', 'WCAG 2.4.9', 'WCAG 3.1.5', 'WCAG 3.2.5', 'WCAG 2.1.3'];
213
+ const wcagAAA = ['wcag146', 'wcag224', 'wcag249', 'wcag315', 'wcag325', 'wcag213'];
214
214
 
215
215
  const wcagLinksAAandAAA = constants.wcagLinks;
216
216
 
@@ -783,7 +783,7 @@ export const retryFunction = async <T>(func: () => Promise<T>, maxAttempt: numbe
783
783
  const result = await func();
784
784
  return result;
785
785
  } catch (error) {
786
- silentLogger.error(`(Attempt count: ${attemptCount} of ${maxAttempt}) ${error}`);
786
+ // do nothing, just retry
787
787
  }
788
788
  }
789
789
  throw new Error('Maximum number of attempts reached');