dsh-plugin-toolkit 0.8.6 → 0.8.7

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/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.8.7
2
+
3
+ - `panel.aria(selector)` and `panel.expectAria(selector, expected)`: assert what a
4
+ screen reader reads, and get the attribute that differs named in the failure.
5
+ A missing attribute reports `nothing` rather than `""`.
6
+
1
7
  ## 0.8.6
2
8
 
3
9
  - `release --publish`: run `npm publish` locally instead of waiting for a
package/README.md CHANGED
@@ -135,10 +135,22 @@ First run writes nothing: it tells you to re-run with `UPDATE_SNAPSHOTS=1`, so a
135
135
  ### Check what assistive tech sees
136
136
 
137
137
  ```js
138
- assert.equal(panel.attributes('[role="tab"][aria-selected="true"]').id, 'tab-protection');
138
+ panel.expectAria('[role="tab"][aria-selected="true"]', { label: 'Protection', selected: 'true' });
139
139
  assert.match(panel.must('[role="status"]').textContent, /Score moved 71 → 77/);
140
140
  ```
141
141
 
142
+ `expectAria()` compares the attributes a screen reader actually reads — `role`,
143
+ `label`, `live`, `selected`, `expanded`, `checked`, `pressed`, `disabled` — and
144
+ names the one that differs:
145
+
146
+ ```
147
+ [aria-live="polite"]: expected aria text to be "9", but it is "0"
148
+ ```
149
+
150
+ A missing attribute is reported as `nothing`, not as an empty string, because
151
+ those are different bugs. `panel.aria(selector)` returns the same object when you
152
+ want to assert on it yourself.
153
+
142
154
  `must()` throws with the rendered markup when the selector misses, which is the difference between "the assertion failed" and "here is what the user actually got".
143
155
 
144
156
  Every example below is a file in this repository, run by CI, and the output shown is the output it prints:
@@ -177,6 +177,35 @@ export async function mountClient(options) {
177
177
  const element = must(selector);
178
178
  return Object.fromEntries([...element.attributes].map((attribute) => [attribute.name, attribute.value]));
179
179
  },
180
+ // What a screen reader would report, in the same blunt vocabulary as the
181
+ // rest: the attributes, not a re-implementation of the accessibility tree.
182
+ aria: (selector) => {
183
+ const element = must(selector);
184
+ const read = (name) => element.getAttribute(name) ?? undefined;
185
+ return {
186
+ role: read('role'),
187
+ label: read('aria-label'),
188
+ labelledBy: read('aria-labelledby'),
189
+ describedBy: read('aria-describedby'),
190
+ live: read('aria-live'),
191
+ selected: read('aria-selected'),
192
+ expanded: read('aria-expanded'),
193
+ checked: read('aria-checked'),
194
+ pressed: read('aria-pressed'),
195
+ disabled: read('aria-disabled') ?? (element.disabled === true ? 'true' : undefined),
196
+ hidden: read('aria-hidden'),
197
+ text: element.textContent.replace(/\s+/g, ' ').trim(),
198
+ };
199
+ },
200
+ expectAria: (selector, expected) => {
201
+ const actual = helpers.aria(selector);
202
+ for (const [key, value] of Object.entries(expected)) {
203
+ if (actual[key] === value) continue;
204
+ const shown = actual[key] === undefined ? 'nothing' : `"${actual[key]}"`;
205
+ throw new Error(`${selector}: expected aria ${key} to be "${value}", but it is ${shown}`);
206
+ }
207
+ return actual;
208
+ },
180
209
  snapshot: (dir, name) => {
181
210
  const result = compare(dir, name, root.innerHTML);
182
211
  if (result.status === 'changed') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-toolkit",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "description": "Preflight, release and test DeepSeek Harness plugins: checks what the host needs, waits for npm to actually serve the version, and keeps the market index honest.",
5
5
  "type": "module",
6
6
  "bin": {