@jrpool/kilotest 46.0.3 → 46.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jrpool/kilotest",
3
- "version": "46.0.3",
3
+ "version": "46.0.4",
4
4
  "description": "Ensemble testing for front-end web quality",
5
5
  "main": "index.js",
6
6
  "engines": {
@@ -2,14 +2,9 @@
2
2
  buildFixtures.js
3
3
  Builds the fixture corpus for Kilotest tests.
4
4
 
5
- Each fixture is a minimal Testaro report in the current format, crafted so
6
- that the expected API response can be hand-computed and hard-coded into
7
- tests. The fixtures collectively cover the `outcome` property values
8
- (`failed`, `cantTell`, and missing/undefined), superseded reports, empty
9
- reports, and prevented rule engines.
5
+ Each fixture is a minimal Testaro report in the current format, crafted so that the expected API response can be hand-computed and hard-coded into tests. The fixtures collectively cover the `outcome` property values (`failed`, `cantTell`, and missing/undefined), superseded reports, empty reports, and prevented rule engines.
10
6
 
11
7
  Run with: node test/fixtures/buildFixtures.js [targetDir]
12
- Defaults to test/fixtures/db under the project root.
13
8
  */
14
9
 
15
10
  // IMPORTS
@@ -20,14 +15,17 @@ const path = require('path');
20
15
  // CONSTANTS
21
16
 
22
17
  // Issue IDs with known specs in testaro-issues, chosen for different weights.
23
- const ISSUE_LINK_NO_TEXT = 'linkNoText'; // weight 4 (highest)
24
- const ISSUE_FOCUS_INDICATION = 'focusIndicationBad'; // weight 4
25
- const ISSUE_ALL_CAPS = 'allCaps'; // weight 1 (lowest)
18
+ // weight 4 (highest)
19
+ const issueLinkNoText = 'linkNoText';
20
+ // weight 4
21
+ const issueFocusIndication = 'focusIndicationBad';
22
+ // weight 1 (lowest)
23
+ const issueAllCaps = 'allCaps';
26
24
 
27
25
  // Rule engine IDs that exist in util.js ruleEngines.
28
- const ENGINE_AXE = 'axe';
29
- const ENGINE_ALFA = 'alfa';
30
- const ENGINE_IBM = 'ibm';
26
+ const engineAxe = 'axe';
27
+ const engineAlfa = 'alfa';
28
+ const engineIbm = 'ibm';
31
29
 
32
30
  // FUNCTIONS
33
31
 
@@ -116,27 +114,23 @@ const main = async () => {
116
114
  await fs.mkdir(path.join(targetDir, 'jobs', 'failed'), {recursive: true});
117
115
  await fs.mkdir(path.join(targetDir, 'hiddenReports'), {recursive: true});
118
116
 
119
- // Fixture 1: mixedOutcomes
120
- // Two rule engines, three instances: one failed, one cantTell, one failed.
121
- // The cantTell instance must be excluded from issue/violator counts.
122
- // Two distinct issues (linkNoText weight 4, allCaps weight 1) and two
123
- // distinct violator catalog indexes (0 and 1).
117
+ // Fixture 1: mixedOutcomes. Two rule engines, four instances: two failed (same issue, same violator, two engines), one cantTell (excluded from counts), one failed (different issue, different violator). Two distinct issues (linkNoText weight 4, allCaps weight 1) and two distinct violator catalog indexes (0 and 1).
124
118
  const mixedCatalog = {
125
119
  '0': catalogItem('A', 'About Us', '/html/body/a[1]', '10:20:80:30'),
126
120
  '1': catalogItem('P', 'ALL ABOUT US', '/html/body/p[1]', '10:60:80:20')
127
121
  };
128
122
  const mixedActs = [
129
- testAct(ENGINE_AXE, [
123
+ testAct(engineAxe, [
130
124
  instance('r11', 'The link does not have an accessible name', 'failed',
131
- ISSUE_LINK_NO_TEXT, 0, 2, 1),
125
+ issueLinkNoText, 0, 2, 1),
132
126
  instance('r65', 'Focus Visible', 'cantTell',
133
- ISSUE_FOCUS_INDICATION, 0, 0, 1)
127
+ issueFocusIndication, 0, 0, 1)
134
128
  ]),
135
- testAct(ENGINE_ALFA, [
129
+ testAct(engineAlfa, [
136
130
  instance('r11', 'The link does not have an accessible name', 'failed',
137
- ISSUE_LINK_NO_TEXT, 0, 2, 1),
131
+ issueLinkNoText, 0, 2, 1),
138
132
  instance('r3', 'Text is all-capital', 'failed',
139
- ISSUE_ALL_CAPS, 1, 1, 1)
133
+ issueAllCaps, 1, 1, 1)
140
134
  ])
141
135
  ];
142
136
  await writeJSON(
@@ -145,16 +139,14 @@ const main = async () => {
145
139
  'https://example.com/mixed', mixedActs, mixedCatalog)
146
140
  );
147
141
 
148
- // Fixture 2: allCantTell
149
- // All instances have outcome cantTell, so no issues or violators should be
150
- // reported by listIssues, listViolators, or listDiagnoses.
142
+ // Fixture 2: allCantTell. All instances have outcome cantTell, so no issues or violators should be reported by listIssues, listViolators, or listDiagnoses.
151
143
  const cantTellCatalog = {
152
144
  '0': catalogItem('A', 'Click here', '/html/body/a[1]', '5:10:60:20')
153
145
  };
154
146
  const cantTellActs = [
155
- testAct(ENGINE_AXE, [
147
+ testAct(engineAxe, [
156
148
  instance('r65', 'Focus Visible', 'cantTell',
157
- ISSUE_FOCUS_INDICATION, 0, 0, 1)
149
+ issueFocusIndication, 0, 0, 1)
158
150
  ])
159
151
  ];
160
152
  await writeJSON(
@@ -163,15 +155,12 @@ const main = async () => {
163
155
  'https://example.com/canttell', cantTellActs, cantTellCatalog)
164
156
  );
165
157
 
166
- // Fixture 3: noOutcomes
167
- // Instances with no outcome property. Testaro defaults to 'failed', but
168
- // Kilotest code checks `outcome !== 'cantTell'`, so missing outcome (undefined)
169
- // is treated as a violation. This verifies that behavior.
158
+ // Fixture 3: noOutcomes. Instances with no outcome property. Testaro defaults to 'failed', but Kilotest code checks `outcome !== 'cantTell'`, so missing outcome (undefined) is treated as a violation. This verifies that behavior.
170
159
  const noOutcomeCatalog = {
171
160
  '0': catalogItem('BUTTON', 'Submit', '/html/body/button[1]', '15:25:70:30')
172
161
  };
173
162
  const noOutcomeActs = [
174
- testAct(ENGINE_IBM, [
163
+ testAct(engineIbm, [
175
164
  {
176
165
  ruleID: 'r1',
177
166
  what: 'Button has no accessible name',
@@ -179,7 +168,7 @@ const main = async () => {
179
168
  count: 1,
180
169
  catalogIndex: '0',
181
170
  checkpoint: 0,
182
- issueID: ISSUE_LINK_NO_TEXT
171
+ issueID: issueLinkNoText
183
172
  }
184
173
  ])
185
174
  ];
@@ -189,13 +178,11 @@ const main = async () => {
189
178
  'https://example.com/nooutcomes', noOutcomeActs, noOutcomeCatalog)
190
179
  );
191
180
 
192
- // Fixture 4: superseded
193
- // A report about the same page as mixedOutcomes but with a later timestamp,
194
- // so mixedOutcomes is superseded by this one.
181
+ // Fixture 4: superseded. A report about the same page as mixedOutcomes but with a later timestamp, so mixedOutcomes is superseded by this one.
195
182
  const newerActs = [
196
- testAct(ENGINE_AXE, [
183
+ testAct(engineAxe, [
197
184
  instance('r11', 'The link does not have an accessible name', 'failed',
198
- ISSUE_LINK_NO_TEXT, 0, 2, 1)
185
+ issueLinkNoText, 0, 2, 1)
199
186
  ])
200
187
  ];
201
188
  await writeJSON(
@@ -204,24 +191,21 @@ const main = async () => {
204
191
  'https://example.com/mixed', newerActs, mixedCatalog, '26-02-02T00:10')
205
192
  );
206
193
 
207
- // Fixture 5: empty
208
- // A valid report with no test acts that have instances, so listIssues
209
- // returns zero issues.
194
+ // Fixture 5: empty. A valid report with no test acts that have instances, so listIssues returns zero issues.
210
195
  await writeJSON(
211
196
  path.join(reportsDir, '260101T0005-emp.json'),
212
197
  report('260101T0005-emp', 'Empty Results Page',
213
- 'https://example.com/empty', [testAct(ENGINE_AXE, [])], {})
198
+ 'https://example.com/empty', [testAct(engineAxe, [])], {})
214
199
  );
215
200
 
216
- // Fixture 6: prevented
217
- // A report where one rule engine was prevented from testing.
201
+ // Fixture 6: prevented. A report where one rule engine was prevented from testing.
218
202
  const preventedCatalog = {
219
203
  '0': catalogItem('IMG', 'An image', '/html/body/img[1]', '0:0:200:100')
220
204
  };
221
205
  const preventedActs = [
222
- testAct(ENGINE_AXE, [
206
+ testAct(engineAxe, [
223
207
  instance('r11', 'The image has no alt text', 'failed',
224
- ISSUE_LINK_NO_TEXT, 0, 2, 1)
208
+ issueLinkNoText, 0, 2, 1)
225
209
  ])
226
210
  ];
227
211
  const preventedReport = report('260101T0006-prv', 'Prevented Page',
@@ -232,6 +216,23 @@ const main = async () => {
232
216
  preventedReport
233
217
  );
234
218
 
219
+ // Fixture 7: hidden. A report placed in hiddenReports/ instead of reports/, so it must not appear in listReports, listIssues, listViolators, listDiagnoses, or getReport API responses. The reportsExtract must not include it.
220
+ const hiddenCatalog = {
221
+ '0': catalogItem('A', 'Secret link', '/html/body/a[1]', '5:10:60:20')
222
+ };
223
+ const hiddenActs = [
224
+ testAct(engineAxe, [
225
+ instance('r11', 'The link does not have an accessible name', 'failed',
226
+ issueLinkNoText, 0, 2, 1)
227
+ ])
228
+ ];
229
+ const hiddenReport = report('260101T0007-hid', 'Hidden Page',
230
+ 'https://example.com/hidden', hiddenActs, hiddenCatalog);
231
+ await writeJSON(
232
+ path.join(targetDir, 'hiddenReports', '260101T0007-hid.json'),
233
+ hiddenReport
234
+ );
235
+
235
236
  // Write an empty recs.json so getRecs does not try to create one.
236
237
  await writeJSON(path.join(targetDir, 'jobs', 'recs.json'), {});
237
238
 
@@ -0,0 +1,69 @@
1
+ {
2
+ "id": "260101T0007-hid",
3
+ "what": "Hidden Page",
4
+ "strict": false,
5
+ "standard": "only",
6
+ "device": {
7
+ "id": "default"
8
+ },
9
+ "browserID": "chromium",
10
+ "creationTimeStamp": "260101T0007",
11
+ "executionTimeStamp": "260101T0007",
12
+ "target": {
13
+ "what": "Hidden Page",
14
+ "url": "https://example.com/hidden"
15
+ },
16
+ "sources": {
17
+ "worker": "test-worker"
18
+ },
19
+ "acts": [
20
+ {
21
+ "type": "test",
22
+ "which": "axe",
23
+ "startTime": "26-01-01T00:00",
24
+ "endTime": "26-01-01T00:01",
25
+ "result": {
26
+ "standardResult": {
27
+ "instances": [
28
+ {
29
+ "ruleID": "r11",
30
+ "what": "The link does not have an accessible name",
31
+ "ordinalSeverity": 2,
32
+ "outcome": "failed",
33
+ "count": 1,
34
+ "catalogIndex": "0",
35
+ "checkpoint": 0,
36
+ "issueID": "linkNoText"
37
+ }
38
+ ],
39
+ "outcomeTotals": {
40
+ "failed": 1,
41
+ "cantTell": 0
42
+ }
43
+ }
44
+ }
45
+ }
46
+ ],
47
+ "jobData": {
48
+ "startTime": "26-01-01T00:00",
49
+ "endTime": "26-01-01T00:10",
50
+ "elapsedSeconds": 600,
51
+ "preventions": {},
52
+ "issuelessRules": []
53
+ },
54
+ "catalog": {
55
+ "0": {
56
+ "tagName": "A",
57
+ "id": "",
58
+ "startTag": "<a>",
59
+ "text": "Secret link",
60
+ "textLinkable": false,
61
+ "boxID": "5:10:60:20",
62
+ "pathID": "/html/body/a[1]",
63
+ "headingIndex": "",
64
+ "checkpoint": 0
65
+ }
66
+ },
67
+ "images": {},
68
+ "checkpoints": []
69
+ }
package/util.js CHANGED
@@ -14,8 +14,7 @@ const wcagMap = require('./wcagMap.json');
14
14
 
15
15
  // CONSTANTS
16
16
 
17
- // Path of the data directory. Read afresh on every call (rather than cached at module load) so
18
- // that tests can point Kilotest at a fixture directory via the DB_DIR environment variable.
17
+ // Path of the data directory. Read afresh on every call (rather than cached at module load) so that tests can point Kilotest at a fixture directory via the DB_DIR environment variable.
19
18
  const dbPath = exports.dbPath = () => process.env.DB_DIR || path.join(__dirname, 'db');
20
19
  // Path of the jobs directory.
21
20
  const jobsPath = exports.jobsPath = () => path.join(dbPath(), 'jobs');