snap-ally 1.0.2 → 1.0.3

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.
@@ -140,22 +140,31 @@ class SnapAllyReporter {
140
140
  const videoPath = this.assetsManager.copyVideos(result, testFolder);
141
141
  const screenshotPaths = this.assetsManager.copyScreenshots(result, testFolder);
142
142
  const attachments = this.assetsManager.copyAllOtherAttachments(result, testFolder);
143
- const a11yAttachment = result.attachments.find((a) => a.name === 'A11y');
144
- if (!a11yAttachment && this.options.verbose) {
143
+ // A single test may call scanA11y/checkAccessibility multiple times (e.g.
144
+ // before and after login), producing one 'A11y' attachment per scan. Read
145
+ // every 'A11y' attachment and merge their violations so findings from all
146
+ // scans are reported — not just the first.
147
+ const a11yAttachments = result.attachments.filter((a) => a.name === 'A11y' && a.body);
148
+ if (a11yAttachments.length === 0 && this.options.verbose) {
145
149
  console.warn(`[SnapAlly] A11y attachment missing for test: ${test.title}. Available: ${result.attachments.map(a => a.name).join(', ')}`);
146
150
  }
147
- let a11yData = null;
148
- if (a11yAttachment && a11yAttachment.body) {
151
+ const parsedData = [];
152
+ for (const att of a11yAttachments) {
149
153
  try {
150
- a11yData = JSON.parse(a11yAttachment.body.toString());
154
+ const raw = JSON.parse(att.body.toString());
155
+ // Handle cases where the payload is the direct ReportData or wrapped in a data property
156
+ const data = (raw && typeof raw === 'object' && 'data' in raw ? raw.data : raw);
157
+ if (data)
158
+ parsedData.push(data);
151
159
  }
152
160
  catch (err) {
153
- console.error(`[SnapAlly] Failed to parse A11y attachment: ${err}. Body was: ${a11yAttachment.body.toString().substring(0, 100)}`);
161
+ console.error(`[SnapAlly] Failed to parse A11y attachment: ${err}. Body was: ${att.body.toString().substring(0, 100)}`);
154
162
  }
155
163
  }
156
- // Handle cases where a11yData might be the direct ReportData or wrapped in a data property
157
- const actualData = (a11yData && typeof a11yData === 'object' && 'data' in a11yData ? a11yData.data : a11yData);
158
- const violations = (actualData === null || actualData === void 0 ? void 0 : actualData.a11yErrors) || (actualData === null || actualData === void 0 ? void 0 : actualData.violations) || [];
164
+ // Use the first scan for page-level metadata (pageUrl, ADO settings, ...),
165
+ // but aggregate violations across every scan in the test.
166
+ const actualData = parsedData[0] || null;
167
+ const violations = parsedData.flatMap((d) => d.a11yErrors || d.violations || []);
159
168
  const a11yErrorCount = violations.reduce((acc, curr) => { var _a, _b; return acc + (curr.total || ((_a = curr.target) === null || _a === void 0 ? void 0 : _a.length) || ((_b = curr.nodes) === null || _b === void 0 ? void 0 : _b.length) || 0); }, 0);
160
169
  const filteredSteps = (() => {
161
170
  const blocklist = ['Evaluate', 'Create page', 'Close page', 'Before Hooks', 'After Hooks', 'Worker Teardown', 'Worker Cleanup', 'Attach', 'Wait for timeout', 'Capture A11y screenshot', 'Scroll into view', 'Bounding box'];
@@ -109,14 +109,22 @@ function renderTestExecutionReport(data) {
109
109
  }
110
110
 
111
111
  // Helper method for array elements
112
- const renderList = (array, listId, cardId) => {
112
+ const renderList = (array, listId, cardId, asHtml = false) => {
113
113
  if (array && array.length > 0) {
114
114
  document.getElementById(cardId).classList.remove('hidden');
115
115
  const list = document.getElementById(listId);
116
116
  const tpl = document.getElementById('string-item-template');
117
117
  array.forEach((item) => {
118
118
  const clone = tpl.content.cloneNode(true);
119
- clone.querySelector('li').textContent = item;
119
+ const li = clone.querySelector('li');
120
+ // Exceptions arrive as pre-sanitized HTML from ansiToHtml (entities
121
+ // already escaped, only known <span> color tags injected), so render
122
+ // them as HTML to show the colors. Everything else is plain text.
123
+ if (asHtml) {
124
+ li.innerHTML = item;
125
+ } else {
126
+ li.textContent = item;
127
+ }
120
128
  list.appendChild(clone);
121
129
  });
122
130
  }
@@ -130,7 +138,7 @@ function renderTestExecutionReport(data) {
130
138
  const filteredErrs = (data.errors || []).filter(
131
139
  (err) => !err.includes('Accessibility audit failed')
132
140
  );
133
- renderList(filteredErrs, 'list-exceptions', 'card-exceptions');
141
+ renderList(filteredErrs, 'list-exceptions', 'card-exceptions', true);
134
142
 
135
143
  // Normalize to an array of videos
136
144
  const videos = Array.isArray(data.videoPath)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snap-ally",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "A custom Playwright reporter for Accessibility testing using Axe, with HTML reporting and Azure DevOps integration.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",