testaro 58.2.1 → 58.3.1
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/AGENTS.md +1 -0
- package/UPGRADES.md +97 -96
- package/VALIDATION_README.md +1 -0
- package/actSpecs.js +1 -0
- package/netWatch.js +1 -0
- package/package.json +1 -1
- package/procs/doTestAct.js +1 -0
- package/procs/isInlineLink.js +1 -0
- package/procs/target.js +1 -0
- package/pw-aslint-claude.js +12 -7
- package/run.js +2 -1
- package/scripts/dumpAlts.js +1 -0
- package/testaro/adbID.js +1 -0
- package/testaro/altScheme.js +1 -0
- package/testaro/captionLoc.js +1 -0
- package/testaro/datalistRef.js +1 -0
- package/testaro/focVis.js +1 -0
- package/testaro/hovInd.js +1 -0
- package/testaro/imageLink.js +1 -0
- package/testaro/legendLoc.js +1 -0
- package/testaro/linkAmb.js +1 -0
- package/testaro/optRoleSel.js +1 -0
- package/testaro/phOnly.js +1 -0
- package/testaro/role.js +1 -0
- package/testaro/secHeading.js +1 -0
- package/testaro/targetSmall.js +1 -0
- package/testaro/targetTiny.js +1 -0
- package/testaro/textSem.js +1 -0
- package/tests/aslint.js +1 -0
- package/tests/axe.js +1 -0
- package/tests/ed11y.js +1 -0
- package/tests/ibm.js +1 -0
- package/tests/testaro.js +2 -12
- package/tests/wax.js +1 -0
- package/validation/done/README.md +25 -0
- package/validation/tests/targets/focInd/bad.html +1 -0
- package/validation/tests/targets/hovInd/index.html +1 -0
- package/validation/tests/targets/linkAmb/index.html +1 -0
- package/validation/tests/targets/linkUl/bad.html +1 -0
- package/validation/tests/targets/linkUl/good.html +1 -0
- package/validation/tests/targets/linkUl/na.html +1 -0
- package/validation/tests/targets/role/bad.html +1 -0
- package/validation/tests/targets/targetSize/index.html +1 -0
- package/validation/validateTest.js +1 -0
package/AGENTS.md
CHANGED
package/UPGRADES.md
CHANGED
|
@@ -393,7 +393,7 @@ Based on my analysis of the codebase, I can now provide comprehensive answers to
|
|
|
393
393
|
|
|
394
394
|
### **Import/export syntax conversion**
|
|
395
395
|
- **134 `require()` calls** need conversion to `import` statements
|
|
396
|
-
- **91 `exports.` assignments** need conversion to `export` statements
|
|
396
|
+
- **91 `exports.` assignments** need conversion to `export` statements
|
|
397
397
|
- **2 `module.exports`** need conversion to `export default`
|
|
398
398
|
- **Dynamic requires**: The codebase has dynamic `require()` calls like `require(\`../tests/${which}\`)` that need special handling
|
|
399
399
|
|
|
@@ -470,7 +470,7 @@ Based on my analysis of the codebase, I can now provide comprehensive answers to
|
|
|
470
470
|
- Add TypeScript tooling and types
|
|
471
471
|
- Convert syntax to TypeScript
|
|
472
472
|
- Establish type safety
|
|
473
|
-
|
|
473
|
+
|
|
474
474
|
2. **Phase 2**: Convert to ES modules within TypeScript
|
|
475
475
|
- Use TypeScript's ES module support
|
|
476
476
|
- Convert `require`/`exports` to `import`/`export`
|
|
@@ -490,7 +490,7 @@ Based on my analysis of the codebase, I can now provide comprehensive answers to
|
|
|
490
490
|
### **Specific efficiencies for this codebase:**
|
|
491
491
|
|
|
492
492
|
#### **Dynamic loading patterns**
|
|
493
|
-
- **Current**: `require(\`../tests/${which}\`)`
|
|
493
|
+
- **Current**: `require(\`../tests/${which}\`)`
|
|
494
494
|
- **TypeScript + ESM**: `const module = await import(\`../tests/${which}.js\`)` with proper typing
|
|
495
495
|
|
|
496
496
|
#### **Child process handling**
|
|
@@ -802,10 +802,10 @@ import { AxeValidation } from '../packages/core/src/validations/axe';
|
|
|
802
802
|
test.describe('Axe Tool Validation', () => {
|
|
803
803
|
test('should detect basic accessibility violations', async ({ page }) => {
|
|
804
804
|
await page.goto('http://localhost:3000/test-pages/basic-violations.html');
|
|
805
|
-
|
|
805
|
+
|
|
806
806
|
const validation = new AxeValidation();
|
|
807
807
|
const result = await validation.run(page);
|
|
808
|
-
|
|
808
|
+
|
|
809
809
|
expect(result.violations).toHaveLength(2);
|
|
810
810
|
expect(result.violations[0].id).toBe('color-contrast');
|
|
811
811
|
});
|
|
@@ -822,7 +822,7 @@ test.describe('Cross-Tool Validation', () => {
|
|
|
822
822
|
waveValidation.run(page),
|
|
823
823
|
htmlcsValidation.run(page)
|
|
824
824
|
]);
|
|
825
|
-
|
|
825
|
+
|
|
826
826
|
const disagreements = findDisagreements(results);
|
|
827
827
|
expect(disagreements).toBeDefined();
|
|
828
828
|
expect(disagreements.length).toBeGreaterThan(0);
|
|
@@ -907,7 +907,7 @@ export class AxeTool implements TestingTool {
|
|
|
907
907
|
const results = await new AxeBuilder({ page })
|
|
908
908
|
.withTags(options.tags)
|
|
909
909
|
.analyze();
|
|
910
|
-
|
|
910
|
+
|
|
911
911
|
return this.standardizeResults(results);
|
|
912
912
|
}
|
|
913
913
|
}
|
|
@@ -994,10 +994,10 @@ import { AxeValidation } from '../packages/core/src/validations/axe';
|
|
|
994
994
|
test.describe('Axe Tool Validation', () => {
|
|
995
995
|
test('should detect basic accessibility violations', async ({ page }) => {
|
|
996
996
|
await page.goto('http://localhost:3000/test-pages/basic-violations.html');
|
|
997
|
-
|
|
997
|
+
|
|
998
998
|
const validation = new AxeValidation();
|
|
999
999
|
const result = await validation.run(page);
|
|
1000
|
-
|
|
1000
|
+
|
|
1001
1001
|
expect(result.violations).toHaveLength(2);
|
|
1002
1002
|
expect(result.violations[0].id).toBe('color-contrast');
|
|
1003
1003
|
});
|
|
@@ -1013,7 +1013,7 @@ test.describe('Cross-Tool Validation', () => {
|
|
|
1013
1013
|
waveValidation.run(page),
|
|
1014
1014
|
htmlcsValidation.run(page)
|
|
1015
1015
|
]);
|
|
1016
|
-
|
|
1016
|
+
|
|
1017
1017
|
const disagreements = findDisagreements(results);
|
|
1018
1018
|
expect(disagreements).toBeDefined();
|
|
1019
1019
|
expect(disagreements.length).toBeGreaterThan(0);
|
|
@@ -1081,7 +1081,7 @@ export class AxeTool implements TestingTool {
|
|
|
1081
1081
|
const results = await new AxeBuilder({ page })
|
|
1082
1082
|
.withTags(options.tags)
|
|
1083
1083
|
.analyze();
|
|
1084
|
-
|
|
1084
|
+
|
|
1085
1085
|
return this.standardizeResults(results);
|
|
1086
1086
|
}
|
|
1087
1087
|
}
|
|
@@ -1131,7 +1131,7 @@ Perfect! Now I can see the implementation details. You're absolutely correct abo
|
|
|
1131
1131
|
#### **1. HTML CodeSniffer (`htmlcs`) - RECOMMENDED**
|
|
1132
1132
|
- **Maintenance**: Squiz Labs, appears less actively maintained
|
|
1133
1133
|
- **Implementation**: Pure JavaScript, self-contained, reads from local file
|
|
1134
|
-
- **Upgrade challenges**:
|
|
1134
|
+
- **Upgrade challenges**:
|
|
1135
1135
|
- Uses `fs.readFile()` to load script from local file
|
|
1136
1136
|
- Injects script into page DOM
|
|
1137
1137
|
- Uses global `window.HTMLCS_RUNNER` API
|
|
@@ -1191,19 +1191,19 @@ Perfect! Now I can see the implementation details. You're absolutely correct abo
|
|
|
1191
1191
|
export class HTMLCodeSnifferTool implements TestingTool {
|
|
1192
1192
|
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
1193
1193
|
const scriptText = await fs.readFile(
|
|
1194
|
-
new URL('../htmlcs/HTMLCS.js', import.meta.url),
|
|
1194
|
+
new URL('../htmlcs/HTMLCS.js', import.meta.url),
|
|
1195
1195
|
'utf8'
|
|
1196
1196
|
);
|
|
1197
|
-
|
|
1197
|
+
|
|
1198
1198
|
const issues = await page.evaluate(
|
|
1199
1199
|
(scriptText, scriptNonce, rules) => {
|
|
1200
1200
|
// Modern ES module version of current logic
|
|
1201
1201
|
},
|
|
1202
|
-
scriptText,
|
|
1203
|
-
options.scriptNonce,
|
|
1202
|
+
scriptText,
|
|
1203
|
+
options.scriptNonce,
|
|
1204
1204
|
options.rules
|
|
1205
1205
|
);
|
|
1206
|
-
|
|
1206
|
+
|
|
1207
1207
|
return this.standardizeResults(issues);
|
|
1208
1208
|
}
|
|
1209
1209
|
}
|
|
@@ -1260,19 +1260,19 @@ This approach gives you the most antiquated tool (as requested) while providing
|
|
|
1260
1260
|
export class HTMLCodeSnifferTool implements TestingTool {
|
|
1261
1261
|
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
1262
1262
|
const scriptText = await fs.readFile(
|
|
1263
|
-
new URL('../htmlcs/HTMLCS.js', import.meta.url),
|
|
1263
|
+
new URL('../htmlcs/HTMLCS.js', import.meta.url),
|
|
1264
1264
|
'utf8'
|
|
1265
1265
|
);
|
|
1266
|
-
|
|
1266
|
+
|
|
1267
1267
|
const issues = await page.evaluate(
|
|
1268
1268
|
(scriptText, scriptNonce, rules) => {
|
|
1269
1269
|
// Modern ES module version of current logic
|
|
1270
1270
|
},
|
|
1271
|
-
scriptText,
|
|
1272
|
-
options.scriptNonce,
|
|
1271
|
+
scriptText,
|
|
1272
|
+
options.scriptNonce,
|
|
1273
1273
|
options.rules
|
|
1274
1274
|
);
|
|
1275
|
-
|
|
1275
|
+
|
|
1276
1276
|
return this.standardizeResults(issues);
|
|
1277
1277
|
}
|
|
1278
1278
|
}
|
|
@@ -1387,16 +1387,16 @@ export class ASLintTool implements TestingTool {
|
|
|
1387
1387
|
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
1388
1388
|
// Challenge 1: ES module file system access
|
|
1389
1389
|
const aslintRunner = await fs.readFile(
|
|
1390
|
-
new URL('../procs/aslint.js', import.meta.url),
|
|
1390
|
+
new URL('../procs/aslint.js', import.meta.url),
|
|
1391
1391
|
'utf8'
|
|
1392
1392
|
);
|
|
1393
|
-
|
|
1393
|
+
|
|
1394
1394
|
// Challenge 2: Monorepo package resolution
|
|
1395
1395
|
const aslintBundle = await fs.readFile(
|
|
1396
1396
|
new URL('../node_modules/aslint-testaro/aslint.bundle.js', import.meta.url),
|
|
1397
1397
|
'utf8'
|
|
1398
1398
|
);
|
|
1399
|
-
|
|
1399
|
+
|
|
1400
1400
|
// Challenge 3: Complex script injection with typing
|
|
1401
1401
|
await page.evaluate(
|
|
1402
1402
|
(args: ScriptInjectionArgs) => {
|
|
@@ -1404,18 +1404,18 @@ export class ASLintTool implements TestingTool {
|
|
|
1404
1404
|
},
|
|
1405
1405
|
{ scriptNonce: options.scriptNonce, aslintBundle, aslintRunner }
|
|
1406
1406
|
);
|
|
1407
|
-
|
|
1407
|
+
|
|
1408
1408
|
// Challenge 4: Async waiting with timeout
|
|
1409
1409
|
const reportLoc = page.locator('#aslintResult');
|
|
1410
|
-
await reportLoc.waitFor({
|
|
1411
|
-
state: 'attached',
|
|
1412
|
-
timeout: 1000 * options.timeLimit
|
|
1410
|
+
await reportLoc.waitFor({
|
|
1411
|
+
state: 'attached',
|
|
1412
|
+
timeout: 1000 * options.timeLimit
|
|
1413
1413
|
});
|
|
1414
|
-
|
|
1414
|
+
|
|
1415
1415
|
// Challenge 5: Complex result parsing
|
|
1416
1416
|
const actReport = await reportLoc.textContent();
|
|
1417
1417
|
const result = JSON.parse(actReport);
|
|
1418
|
-
|
|
1418
|
+
|
|
1419
1419
|
return this.standardizeResults(result);
|
|
1420
1420
|
}
|
|
1421
1421
|
}
|
|
@@ -1456,16 +1456,16 @@ export class ASLintTool implements TestingTool {
|
|
|
1456
1456
|
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
1457
1457
|
// Challenge 1: ES module file system access
|
|
1458
1458
|
const aslintRunner = await fs.readFile(
|
|
1459
|
-
new URL('../procs/aslint.js', import.meta.url),
|
|
1459
|
+
new URL('../procs/aslint.js', import.meta.url),
|
|
1460
1460
|
'utf8'
|
|
1461
1461
|
);
|
|
1462
|
-
|
|
1462
|
+
|
|
1463
1463
|
// Challenge 2: Monorepo package resolution
|
|
1464
1464
|
const aslintBundle = await fs.readFile(
|
|
1465
1465
|
new URL('../node_modules/aslint-testaro/aslint.bundle.js', import.meta.url),
|
|
1466
1466
|
'utf8'
|
|
1467
1467
|
);
|
|
1468
|
-
|
|
1468
|
+
|
|
1469
1469
|
// Challenge 3: Complex script injection with typing
|
|
1470
1470
|
await page.evaluate(
|
|
1471
1471
|
(args: ScriptInjectionArgs) => {
|
|
@@ -1473,18 +1473,18 @@ export class ASLintTool implements TestingTool {
|
|
|
1473
1473
|
},
|
|
1474
1474
|
{ scriptNonce: options.scriptNonce, aslintBundle, aslintRunner }
|
|
1475
1475
|
);
|
|
1476
|
-
|
|
1476
|
+
|
|
1477
1477
|
// Challenge 4: Async waiting with timeout
|
|
1478
1478
|
const reportLoc = page.locator('#aslintResult');
|
|
1479
|
-
await reportLoc.waitFor({
|
|
1480
|
-
state: 'attached',
|
|
1481
|
-
timeout: 1000 * options.timeLimit
|
|
1479
|
+
await reportLoc.waitFor({
|
|
1480
|
+
state: 'attached',
|
|
1481
|
+
timeout: 1000 * options.timeLimit
|
|
1482
1482
|
});
|
|
1483
|
-
|
|
1483
|
+
|
|
1484
1484
|
// Challenge 5: Complex result parsing
|
|
1485
1485
|
const actReport = await reportLoc.textContent();
|
|
1486
1486
|
const result = JSON.parse(actReport);
|
|
1487
|
-
|
|
1487
|
+
|
|
1488
1488
|
return this.standardizeResults(result);
|
|
1489
1489
|
}
|
|
1490
1490
|
}
|
|
@@ -1599,7 +1599,7 @@ export class AxeTool implements TestingTool {
|
|
|
1599
1599
|
async run(page: Page, options: AxeToolOptions): Promise<AxeToolResult> {
|
|
1600
1600
|
// Tool-specific implementation
|
|
1601
1601
|
}
|
|
1602
|
-
|
|
1602
|
+
|
|
1603
1603
|
async validate(page: Page, options: ValidationOptions): Promise<ValidationResult> {
|
|
1604
1604
|
// Tool-specific validation
|
|
1605
1605
|
}
|
|
@@ -1613,32 +1613,32 @@ export class AxeTool implements TestingTool {
|
|
|
1613
1613
|
// packages/testaro/src/orchestrator.ts
|
|
1614
1614
|
export class TestaroOrchestrator {
|
|
1615
1615
|
private tools: Map<string, TestingTool> = new Map();
|
|
1616
|
-
|
|
1616
|
+
|
|
1617
1617
|
async registerTool(name: string, tool: TestingTool): Promise<void> {
|
|
1618
1618
|
this.tools.set(name, tool);
|
|
1619
1619
|
}
|
|
1620
|
-
|
|
1620
|
+
|
|
1621
1621
|
async runTools(
|
|
1622
|
-
page: Page,
|
|
1622
|
+
page: Page,
|
|
1623
1623
|
toolConfigs: ToolConfig[]
|
|
1624
1624
|
): Promise<ToolResult[]> {
|
|
1625
1625
|
// Parallel execution of tools
|
|
1626
1626
|
const results = await Promise.all(
|
|
1627
1627
|
toolConfigs.map(config => this.runTool(page, config))
|
|
1628
1628
|
);
|
|
1629
|
-
|
|
1629
|
+
|
|
1630
1630
|
return results;
|
|
1631
1631
|
}
|
|
1632
|
-
|
|
1632
|
+
|
|
1633
1633
|
private async runTool(
|
|
1634
|
-
page: Page,
|
|
1634
|
+
page: Page,
|
|
1635
1635
|
config: ToolConfig
|
|
1636
1636
|
): Promise<ToolResult> {
|
|
1637
1637
|
const tool = this.tools.get(config.name);
|
|
1638
1638
|
if (!tool) {
|
|
1639
1639
|
throw new Error(`Tool ${config.name} not found`);
|
|
1640
1640
|
}
|
|
1641
|
-
|
|
1641
|
+
|
|
1642
1642
|
return await tool.run(page, config.options);
|
|
1643
1643
|
}
|
|
1644
1644
|
}
|
|
@@ -1651,30 +1651,30 @@ export class TestaroOrchestrator {
|
|
|
1651
1651
|
// apps/tool-server/src/server.ts
|
|
1652
1652
|
export class ToolServer {
|
|
1653
1653
|
private tools: Map<string, TestingTool> = new Map();
|
|
1654
|
-
|
|
1654
|
+
|
|
1655
1655
|
async start(port: number): Promise<void> {
|
|
1656
1656
|
// Register available tools
|
|
1657
1657
|
await this.registerTools();
|
|
1658
|
-
|
|
1658
|
+
|
|
1659
1659
|
// Start HTTP server
|
|
1660
1660
|
const server = express();
|
|
1661
1661
|
server.post('/run/:tool', this.handleToolRequest.bind(this));
|
|
1662
1662
|
server.listen(port);
|
|
1663
1663
|
}
|
|
1664
|
-
|
|
1664
|
+
|
|
1665
1665
|
private async handleToolRequest(
|
|
1666
|
-
req: Request,
|
|
1666
|
+
req: Request,
|
|
1667
1667
|
res: Response
|
|
1668
1668
|
): Promise<void> {
|
|
1669
1669
|
const { tool } = req.params;
|
|
1670
1670
|
const { pageData, options } = req.body;
|
|
1671
|
-
|
|
1671
|
+
|
|
1672
1672
|
const toolInstance = this.tools.get(tool);
|
|
1673
1673
|
if (!toolInstance) {
|
|
1674
1674
|
res.status(404).json({ error: 'Tool not found' });
|
|
1675
1675
|
return;
|
|
1676
1676
|
}
|
|
1677
|
-
|
|
1677
|
+
|
|
1678
1678
|
// Run tool on provided page data
|
|
1679
1679
|
const result = await toolInstance.run(pageData, options);
|
|
1680
1680
|
res.json(result);
|
|
@@ -1687,27 +1687,27 @@ export class ToolServer {
|
|
|
1687
1687
|
// packages/testaro/src/distributed-executor.ts
|
|
1688
1688
|
export class DistributedExecutor {
|
|
1689
1689
|
private toolServers: Map<string, string> = new Map();
|
|
1690
|
-
|
|
1690
|
+
|
|
1691
1691
|
async runTools(
|
|
1692
|
-
page: Page,
|
|
1692
|
+
page: Page,
|
|
1693
1693
|
toolConfigs: ToolConfig[]
|
|
1694
1694
|
): Promise<ToolResult[]> {
|
|
1695
1695
|
// Distribute tools across servers
|
|
1696
1696
|
const serverAssignments = this.assignToolsToServers(toolConfigs);
|
|
1697
|
-
|
|
1697
|
+
|
|
1698
1698
|
// Execute tools in parallel
|
|
1699
1699
|
const results = await Promise.all(
|
|
1700
|
-
serverAssignments.map(assignment =>
|
|
1700
|
+
serverAssignments.map(assignment =>
|
|
1701
1701
|
this.executeOnServer(assignment.server, assignment.tools, page)
|
|
1702
1702
|
)
|
|
1703
1703
|
);
|
|
1704
|
-
|
|
1704
|
+
|
|
1705
1705
|
return results.flat();
|
|
1706
1706
|
}
|
|
1707
|
-
|
|
1707
|
+
|
|
1708
1708
|
private async executeOnServer(
|
|
1709
|
-
server: string,
|
|
1710
|
-
tools: ToolConfig[],
|
|
1709
|
+
server: string,
|
|
1710
|
+
tools: ToolConfig[],
|
|
1711
1711
|
page: Page
|
|
1712
1712
|
): Promise<ToolResult[]> {
|
|
1713
1713
|
// Send page data and tool configs to server
|
|
@@ -1715,7 +1715,7 @@ export class DistributedExecutor {
|
|
|
1715
1715
|
method: 'POST',
|
|
1716
1716
|
body: JSON.stringify({ tools, pageData: await page.content() })
|
|
1717
1717
|
});
|
|
1718
|
-
|
|
1718
|
+
|
|
1719
1719
|
return await response.json();
|
|
1720
1720
|
}
|
|
1721
1721
|
}
|
|
@@ -1730,7 +1730,7 @@ export class CustomerARulesTool implements TestingTool {
|
|
|
1730
1730
|
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
1731
1731
|
// Customer-specific rule implementations
|
|
1732
1732
|
const violations = await this.checkCustomRules(page, options.rules);
|
|
1733
|
-
|
|
1733
|
+
|
|
1734
1734
|
return {
|
|
1735
1735
|
violations,
|
|
1736
1736
|
passes: [],
|
|
@@ -1738,19 +1738,19 @@ export class CustomerARulesTool implements TestingTool {
|
|
|
1738
1738
|
inapplicable: []
|
|
1739
1739
|
};
|
|
1740
1740
|
}
|
|
1741
|
-
|
|
1741
|
+
|
|
1742
1742
|
private async checkCustomRules(
|
|
1743
|
-
page: Page,
|
|
1743
|
+
page: Page,
|
|
1744
1744
|
rules: string[]
|
|
1745
1745
|
): Promise<Violation[]> {
|
|
1746
1746
|
// Implement customer-specific business rules
|
|
1747
1747
|
const results: Violation[] = [];
|
|
1748
|
-
|
|
1748
|
+
|
|
1749
1749
|
for (const rule of rules) {
|
|
1750
1750
|
const violations = await this.checkRule(page, rule);
|
|
1751
1751
|
results.push(...violations);
|
|
1752
1752
|
}
|
|
1753
|
-
|
|
1753
|
+
|
|
1754
1754
|
return results;
|
|
1755
1755
|
}
|
|
1756
1756
|
}
|
|
@@ -1882,7 +1882,7 @@ export class AxeTool implements TestingTool {
|
|
|
1882
1882
|
async run(page: Page, options: AxeToolOptions): Promise<AxeToolResult> {
|
|
1883
1883
|
// Tool-specific implementation
|
|
1884
1884
|
}
|
|
1885
|
-
|
|
1885
|
+
|
|
1886
1886
|
async validate(page: Page, options: ValidationOptions): Promise<ValidationResult> {
|
|
1887
1887
|
// Tool-specific validation
|
|
1888
1888
|
}
|
|
@@ -1893,32 +1893,32 @@ export class AxeTool implements TestingTool {
|
|
|
1893
1893
|
// packages/testaro/src/orchestrator.ts
|
|
1894
1894
|
export class TestaroOrchestrator {
|
|
1895
1895
|
private tools: Map<string, TestingTool> = new Map();
|
|
1896
|
-
|
|
1896
|
+
|
|
1897
1897
|
async registerTool(name: string, tool: TestingTool): Promise<void> {
|
|
1898
1898
|
this.tools.set(name, tool);
|
|
1899
1899
|
}
|
|
1900
|
-
|
|
1900
|
+
|
|
1901
1901
|
async runTools(
|
|
1902
|
-
page: Page,
|
|
1902
|
+
page: Page,
|
|
1903
1903
|
toolConfigs: ToolConfig[]
|
|
1904
1904
|
): Promise<ToolResult[]> {
|
|
1905
1905
|
// Parallel execution of tools
|
|
1906
1906
|
const results = await Promise.all(
|
|
1907
1907
|
toolConfigs.map(config => this.runTool(page, config))
|
|
1908
1908
|
);
|
|
1909
|
-
|
|
1909
|
+
|
|
1910
1910
|
return results;
|
|
1911
1911
|
}
|
|
1912
|
-
|
|
1912
|
+
|
|
1913
1913
|
private async runTool(
|
|
1914
|
-
page: Page,
|
|
1914
|
+
page: Page,
|
|
1915
1915
|
config: ToolConfig
|
|
1916
1916
|
): Promise<ToolResult> {
|
|
1917
1917
|
const tool = this.tools.get(config.name);
|
|
1918
1918
|
if (!tool) {
|
|
1919
1919
|
throw new Error(`Tool ${config.name} not found`);
|
|
1920
1920
|
}
|
|
1921
|
-
|
|
1921
|
+
|
|
1922
1922
|
return await tool.run(page, config.options);
|
|
1923
1923
|
}
|
|
1924
1924
|
}
|
|
@@ -1928,30 +1928,30 @@ export class TestaroOrchestrator {
|
|
|
1928
1928
|
// apps/tool-server/src/server.ts
|
|
1929
1929
|
export class ToolServer {
|
|
1930
1930
|
private tools: Map<string, TestingTool> = new Map();
|
|
1931
|
-
|
|
1931
|
+
|
|
1932
1932
|
async start(port: number): Promise<void> {
|
|
1933
1933
|
// Register available tools
|
|
1934
1934
|
await this.registerTools();
|
|
1935
|
-
|
|
1935
|
+
|
|
1936
1936
|
// Start HTTP server
|
|
1937
1937
|
const server = express();
|
|
1938
1938
|
server.post('/run/:tool', this.handleToolRequest.bind(this));
|
|
1939
1939
|
server.listen(port);
|
|
1940
1940
|
}
|
|
1941
|
-
|
|
1941
|
+
|
|
1942
1942
|
private async handleToolRequest(
|
|
1943
|
-
req: Request,
|
|
1943
|
+
req: Request,
|
|
1944
1944
|
res: Response
|
|
1945
1945
|
): Promise<void> {
|
|
1946
1946
|
const { tool } = req.params;
|
|
1947
1947
|
const { pageData, options } = req.body;
|
|
1948
|
-
|
|
1948
|
+
|
|
1949
1949
|
const toolInstance = this.tools.get(tool);
|
|
1950
1950
|
if (!toolInstance) {
|
|
1951
1951
|
res.status(404).json({ error: 'Tool not found' });
|
|
1952
1952
|
return;
|
|
1953
1953
|
}
|
|
1954
|
-
|
|
1954
|
+
|
|
1955
1955
|
// Run tool on provided page data
|
|
1956
1956
|
const result = await toolInstance.run(pageData, options);
|
|
1957
1957
|
res.json(result);
|
|
@@ -1963,27 +1963,27 @@ export class ToolServer {
|
|
|
1963
1963
|
// packages/testaro/src/distributed-executor.ts
|
|
1964
1964
|
export class DistributedExecutor {
|
|
1965
1965
|
private toolServers: Map<string, string> = new Map();
|
|
1966
|
-
|
|
1966
|
+
|
|
1967
1967
|
async runTools(
|
|
1968
|
-
page: Page,
|
|
1968
|
+
page: Page,
|
|
1969
1969
|
toolConfigs: ToolConfig[]
|
|
1970
1970
|
): Promise<ToolResult[]> {
|
|
1971
1971
|
// Distribute tools across servers
|
|
1972
1972
|
const serverAssignments = this.assignToolsToServers(toolConfigs);
|
|
1973
|
-
|
|
1973
|
+
|
|
1974
1974
|
// Execute tools in parallel
|
|
1975
1975
|
const results = await Promise.all(
|
|
1976
|
-
serverAssignments.map(assignment =>
|
|
1976
|
+
serverAssignments.map(assignment =>
|
|
1977
1977
|
this.executeOnServer(assignment.server, assignment.tools, page)
|
|
1978
1978
|
)
|
|
1979
1979
|
);
|
|
1980
|
-
|
|
1980
|
+
|
|
1981
1981
|
return results.flat();
|
|
1982
1982
|
}
|
|
1983
|
-
|
|
1983
|
+
|
|
1984
1984
|
private async executeOnServer(
|
|
1985
|
-
server: string,
|
|
1986
|
-
tools: ToolConfig[],
|
|
1985
|
+
server: string,
|
|
1986
|
+
tools: ToolConfig[],
|
|
1987
1987
|
page: Page
|
|
1988
1988
|
): Promise<ToolResult[]> {
|
|
1989
1989
|
// Send page data and tool configs to server
|
|
@@ -1991,7 +1991,7 @@ export class DistributedExecutor {
|
|
|
1991
1991
|
method: 'POST',
|
|
1992
1992
|
body: JSON.stringify({ tools, pageData: await page.content() })
|
|
1993
1993
|
});
|
|
1994
|
-
|
|
1994
|
+
|
|
1995
1995
|
return await response.json();
|
|
1996
1996
|
}
|
|
1997
1997
|
}
|
|
@@ -2003,7 +2003,7 @@ export class CustomerARulesTool implements TestingTool {
|
|
|
2003
2003
|
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
2004
2004
|
// Customer-specific rule implementations
|
|
2005
2005
|
const violations = await this.checkCustomRules(page, options.rules);
|
|
2006
|
-
|
|
2006
|
+
|
|
2007
2007
|
return {
|
|
2008
2008
|
violations,
|
|
2009
2009
|
passes: [],
|
|
@@ -2011,19 +2011,19 @@ export class CustomerARulesTool implements TestingTool {
|
|
|
2011
2011
|
inapplicable: []
|
|
2012
2012
|
};
|
|
2013
2013
|
}
|
|
2014
|
-
|
|
2014
|
+
|
|
2015
2015
|
private async checkCustomRules(
|
|
2016
|
-
page: Page,
|
|
2016
|
+
page: Page,
|
|
2017
2017
|
rules: string[]
|
|
2018
2018
|
): Promise<Violation[]> {
|
|
2019
2019
|
// Implement customer-specific business rules
|
|
2020
2020
|
const results: Violation[] = [];
|
|
2021
|
-
|
|
2021
|
+
|
|
2022
2022
|
for (const rule of rules) {
|
|
2023
2023
|
const violations = await this.checkRule(page, rule);
|
|
2024
2024
|
results.push(...violations);
|
|
2025
2025
|
}
|
|
2026
|
-
|
|
2026
|
+
|
|
2027
2027
|
return results;
|
|
2028
2028
|
}
|
|
2029
2029
|
}
|
|
@@ -2431,6 +2431,7 @@ describe('Database queries', () => {
|
|
|
2431
2431
|
|
|
2432
2432
|
/*
|
|
2433
2433
|
© 2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
2434
|
+
© 2025 Jonathan Robert Pool. All rights reserved.
|
|
2434
2435
|
|
|
2435
2436
|
MIT License
|
|
2436
2437
|
|
package/VALIDATION_README.md
CHANGED
package/actSpecs.js
CHANGED
package/netWatch.js
CHANGED
package/package.json
CHANGED
package/procs/doTestAct.js
CHANGED
package/procs/isInlineLink.js
CHANGED
package/procs/target.js
CHANGED
package/pw-aslint-claude.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2025 Jonathan Robert Pool. All rights reserved.
|
|
3
|
+
Licensed under the MIT License. See LICENSE file for details.
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
// aslint.config.js
|
|
2
7
|
const { defineConfig } = require('aslint');
|
|
3
8
|
|
|
@@ -29,16 +34,16 @@ test.describe('Accessibility Tests', () => {
|
|
|
29
34
|
|
|
30
35
|
// Get the page content
|
|
31
36
|
const content = await page.content();
|
|
32
|
-
|
|
37
|
+
|
|
33
38
|
// Run ASLint
|
|
34
39
|
const results = await linter.lint(content);
|
|
35
|
-
|
|
40
|
+
|
|
36
41
|
// Assert no accessibility violations
|
|
37
42
|
expect(results.violations).toHaveLength(0);
|
|
38
|
-
|
|
43
|
+
|
|
39
44
|
// Optional: Log detailed results
|
|
40
45
|
if (results.violations.length > 0) {
|
|
41
|
-
console.log('Accessibility violations found:',
|
|
46
|
+
console.log('Accessibility violations found:',
|
|
42
47
|
results.violations.map(v => ({
|
|
43
48
|
rule: v.rule,
|
|
44
49
|
message: v.message,
|
|
@@ -51,16 +56,16 @@ test.describe('Accessibility Tests', () => {
|
|
|
51
56
|
// Test specific components
|
|
52
57
|
test('check specific component accessibility', async ({ page }) => {
|
|
53
58
|
await page.goto('https://your-website.com/component');
|
|
54
|
-
|
|
59
|
+
|
|
55
60
|
// Wait for specific component to be visible
|
|
56
61
|
await page.waitForSelector('.your-component');
|
|
57
|
-
|
|
62
|
+
|
|
58
63
|
// Get component HTML
|
|
59
64
|
const componentHTML = await page.$eval(
|
|
60
65
|
'.your-component',
|
|
61
66
|
el => el.outerHTML
|
|
62
67
|
);
|
|
63
|
-
|
|
68
|
+
|
|
64
69
|
const results = await linter.lint(componentHTML);
|
|
65
70
|
expect(results.violations).toHaveLength(0);
|
|
66
71
|
});
|
package/run.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
© 2021–2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025 Jonathan Robert Pool. All rights reserved.
|
|
3
4
|
|
|
4
5
|
MIT License
|
|
5
6
|
|
|
@@ -677,7 +678,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
677
678
|
// Save the report.
|
|
678
679
|
let reportJSON = JSON.stringify(report);
|
|
679
680
|
await fs.writeFile(reportPath, reportJSON);
|
|
680
|
-
// Create a process
|
|
681
|
+
// Create a process to perform the act and add the result to the saved report.
|
|
681
682
|
const actResult = await new Promise(resolve => {
|
|
682
683
|
let closed = false;
|
|
683
684
|
const child = fork(
|
package/scripts/dumpAlts.js
CHANGED
package/testaro/adbID.js
CHANGED
package/testaro/altScheme.js
CHANGED
package/testaro/captionLoc.js
CHANGED
package/testaro/datalistRef.js
CHANGED
package/testaro/focVis.js
CHANGED
package/testaro/hovInd.js
CHANGED
package/testaro/imageLink.js
CHANGED
package/testaro/legendLoc.js
CHANGED
package/testaro/linkAmb.js
CHANGED
package/testaro/optRoleSel.js
CHANGED
package/testaro/phOnly.js
CHANGED
package/testaro/role.js
CHANGED
package/testaro/secHeading.js
CHANGED
package/testaro/targetSmall.js
CHANGED
package/testaro/targetTiny.js
CHANGED
package/testaro/textSem.js
CHANGED
package/tests/aslint.js
CHANGED
package/tests/axe.js
CHANGED
package/tests/ed11y.js
CHANGED
package/tests/ibm.js
CHANGED
package/tests/testaro.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
© 2023–2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025 Jonathan Robert Pool. All rights reserved.
|
|
3
4
|
|
|
4
5
|
MIT License
|
|
5
6
|
|
|
@@ -33,8 +34,6 @@
|
|
|
33
34
|
const {init, report} = require('../procs/testaro');
|
|
34
35
|
// Module to handle files.
|
|
35
36
|
const fs = require('fs/promises');
|
|
36
|
-
// Module to send a notice to an observer.
|
|
37
|
-
const {tellServer} = require('../procs/tellServer');
|
|
38
37
|
|
|
39
38
|
// ######## CONSTANTS
|
|
40
39
|
|
|
@@ -197,20 +196,11 @@ exports.reporter = async (page, report, actIndex) => {
|
|
|
197
196
|
// Add them to the argument array.
|
|
198
197
|
ruleArgs.push(... args[rule]);
|
|
199
198
|
}
|
|
200
|
-
// If granular reporting is specified:
|
|
201
|
-
const what = evalRules[rule] || etcRules[rule];
|
|
202
|
-
if (report.observe) {
|
|
203
|
-
// Report the rule to the server.
|
|
204
|
-
tellServer(
|
|
205
|
-
options.report,
|
|
206
|
-
`act=test&which=testaro&rule=${rule}&ruleWhat=${what}`,
|
|
207
|
-
`>>>>>> ${rule} (${what})`
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
199
|
// Test the page.
|
|
211
200
|
if (! result[rule]) {
|
|
212
201
|
result[rule] = {};
|
|
213
202
|
}
|
|
203
|
+
const what = evalRules[rule] || etcRules[rule];
|
|
214
204
|
result[rule].what = what;
|
|
215
205
|
const startTime = Date.now();
|
|
216
206
|
try {
|
package/tests/wax.js
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2022–2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025 Jonathan Robert Pool. All rights reserved.
|
|
4
|
+
|
|
5
|
+
MIT License
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
|
24
|
+
*/
|
|
25
|
+
|
|
1
26
|
# exJobs
|
|
2
27
|
|
|
3
28
|
Directory into which executor `dirWatch` archives jobs.
|