@route-intelligence/playwright 2.1.0
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/dist/index.d.ts +11 -0
- package/dist/index.js +89 -0
- package/package.json +34 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SerializedGraph } from '@route-intelligence/shared';
|
|
2
|
+
|
|
3
|
+
interface TestGeneratorOptions {
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
includeDeadRoutes?: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare function generateNavigationTests(graph: SerializedGraph, options?: TestGeneratorOptions): string;
|
|
8
|
+
declare function generateBrokenLinkTests(graph: SerializedGraph): string;
|
|
9
|
+
declare function generateMissingRouteTests(graph: SerializedGraph): string;
|
|
10
|
+
|
|
11
|
+
export { type TestGeneratorOptions, generateBrokenLinkTests, generateMissingRouteTests, generateNavigationTests };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
function generateNavigationTests(graph, options = {}) {
|
|
3
|
+
const baseUrl = options.baseUrl ?? "http://localhost:3000";
|
|
4
|
+
const routes = graph.nodes.filter(
|
|
5
|
+
(n) => n.attributes.type === "route" && !n.attributes.path.includes("[") && (options.includeDeadRoutes || !n.attributes.isDead)
|
|
6
|
+
);
|
|
7
|
+
const navEdges = graph.edges.filter(
|
|
8
|
+
(e) => e.attributes.type === "navigation" || e.attributes.type === "prefetch"
|
|
9
|
+
);
|
|
10
|
+
const lines = [
|
|
11
|
+
"import { test, expect } from '@playwright/test';",
|
|
12
|
+
"",
|
|
13
|
+
`const BASE_URL = '${baseUrl}';`,
|
|
14
|
+
""
|
|
15
|
+
];
|
|
16
|
+
for (const route of routes) {
|
|
17
|
+
const safeName = route.attributes.path.replace(/[^a-zA-Z0-9]/g, "_") || "root";
|
|
18
|
+
lines.push(
|
|
19
|
+
`test('route ${route.attributes.path} is accessible', async ({ page }) => {`,
|
|
20
|
+
` const response = await page.goto(BASE_URL + '${route.attributes.path === "/" ? "" : route.attributes.path}');`,
|
|
21
|
+
" expect(response?.status()).toBeLessThan(400);",
|
|
22
|
+
"});",
|
|
23
|
+
""
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
for (const edge of navEdges) {
|
|
27
|
+
const source = graph.nodes.find((n) => n.id === edge.source);
|
|
28
|
+
const target = graph.nodes.find((n) => n.id === edge.target);
|
|
29
|
+
if (!source || !target) continue;
|
|
30
|
+
if (source.attributes.path.includes("[") || target.attributes.path.includes("[")) continue;
|
|
31
|
+
lines.push(
|
|
32
|
+
`test('navigation ${source.attributes.path} -> ${target.attributes.path}', async ({ page }) => {`,
|
|
33
|
+
` await page.goto(BASE_URL + '${source.attributes.path === "/" ? "" : source.attributes.path}');`,
|
|
34
|
+
` // Navigation via ${edge.attributes.source}`,
|
|
35
|
+
"});",
|
|
36
|
+
""
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
lines.push(
|
|
40
|
+
'test.describe("Navigation Coverage", () => {',
|
|
41
|
+
` test('covers ${routes.length} routes', async () => {`,
|
|
42
|
+
` expect(${routes.length}).toBeGreaterThan(0);`,
|
|
43
|
+
" });",
|
|
44
|
+
"});"
|
|
45
|
+
);
|
|
46
|
+
return lines.join("\n");
|
|
47
|
+
}
|
|
48
|
+
function generateBrokenLinkTests(graph) {
|
|
49
|
+
const brokenEdges = graph.edges.filter(
|
|
50
|
+
(e) => e.attributes.diagnostics?.some((d) => d.ruleId === "broken-link")
|
|
51
|
+
);
|
|
52
|
+
const lines = [
|
|
53
|
+
"import { test, expect } from '@playwright/test';",
|
|
54
|
+
"",
|
|
55
|
+
'test.describe("Broken Navigation Detection", () => {'
|
|
56
|
+
];
|
|
57
|
+
for (const edge of brokenEdges) {
|
|
58
|
+
lines.push(
|
|
59
|
+
` test('broken link from ${edge.source} to ${edge.target}', async () => {`,
|
|
60
|
+
" expect(true).toBe(false); // Broken link detected",
|
|
61
|
+
" });"
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
if (brokenEdges.length === 0) {
|
|
65
|
+
lines.push(" test('no broken links detected', async () => { expect(true).toBe(true); });");
|
|
66
|
+
}
|
|
67
|
+
lines.push("});");
|
|
68
|
+
return lines.join("\n");
|
|
69
|
+
}
|
|
70
|
+
function generateMissingRouteTests(graph) {
|
|
71
|
+
const deadRoutes = graph.nodes.filter(
|
|
72
|
+
(n) => n.attributes.isDead && n.attributes.type === "route"
|
|
73
|
+
);
|
|
74
|
+
const lines = [
|
|
75
|
+
"import { test, expect } from '@playwright/test';",
|
|
76
|
+
"",
|
|
77
|
+
'test.describe("Missing Route Coverage", () => {'
|
|
78
|
+
];
|
|
79
|
+
for (const route of deadRoutes) {
|
|
80
|
+
lines.push(` test.todo('add coverage for dead route ${route.attributes.path}');`);
|
|
81
|
+
}
|
|
82
|
+
lines.push("});");
|
|
83
|
+
return lines.join("\n");
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
generateBrokenLinkTests,
|
|
87
|
+
generateMissingRouteTests,
|
|
88
|
+
generateNavigationTests
|
|
89
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@route-intelligence/playwright",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Playwright test generation from route graphs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"development": "./src/index.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
19
|
+
"typecheck": "tsc --noEmit"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@route-intelligence/shared": "*"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@route-intelligence/tsconfig": "*",
|
|
26
|
+
"@types/node": "^22.15.32",
|
|
27
|
+
"tsup": "^8.4.0",
|
|
28
|
+
"typescript": "^5.8.3"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
}
|
|
34
|
+
}
|