retestkit 1.4.1 → 1.5.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/README.md +59 -40
- package/dist/config.js +8 -8
- package/dist/config.js.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +21 -21
- package/dist/prompts/index.js.map +1 -1
- package/dist/prompts/templates/mcp/retest-crawl.md +7 -0
- package/{src/prompts/templates/mcp/webtest-discover-flows.md → dist/prompts/templates/mcp/retest-discover-flows.md} +1 -1
- package/{src/prompts/templates/mcp/webtest-discover.md → dist/prompts/templates/mcp/retest-discover.md} +2 -2
- package/dist/prompts/templates/mcp/retest-full-workflow.md +12 -0
- package/{src/prompts/templates/mcp/webtest-generate-tests.md → dist/prompts/templates/mcp/retest-generate-tests.md} +1 -1
- package/{src/prompts/templates/mcp/webtest-run-test.md → dist/prompts/templates/mcp/retest-run-test.md} +1 -1
- package/{src/prompts/templates/mcp/webtest-start.md → dist/prompts/templates/mcp/retest-start.md} +1 -1
- package/{src → dist}/prompts/templates/sampling/system-prefix.md +1 -1
- package/dist/resources/index.js +7 -7
- package/dist/resources/index.js.map +1 -1
- package/dist/schemas/config.js +2 -2
- package/dist/schemas/config.js.map +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/index.js.map +1 -1
- package/dist/server.js +3 -3
- package/dist/server.js.map +1 -1
- package/dist/test-utils/mock-context.js +22 -22
- package/dist/test-utils/mock-context.js.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +5 -5
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/retest/crawl.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/crawl.js +7 -7
- package/dist/tools/retest/crawl.js.map +1 -0
- package/dist/tools/retest/discover-features.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/discover-features.js +6 -6
- package/dist/tools/retest/discover-features.js.map +1 -0
- package/dist/tools/retest/discover-flows.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/discover-flows.js +6 -6
- package/dist/tools/retest/discover-flows.js.map +1 -0
- package/dist/tools/retest/generate-tests.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/generate-tests.js +5 -5
- package/dist/tools/retest/generate-tests.js.map +1 -0
- package/dist/tools/retest/index.d.ts.map +1 -0
- package/dist/tools/retest/index.js.map +1 -0
- package/dist/tools/retest/run-test-case.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/run-test-case.js +3 -3
- package/dist/tools/retest/run-test-case.js.map +1 -0
- package/dist/tools/retest/schemas.d.ts.map +1 -0
- package/dist/tools/retest/schemas.js.map +1 -0
- package/dist/tools/retest/start-analysis.d.ts.map +1 -0
- package/dist/tools/{webtest → retest}/start-analysis.js +5 -5
- package/dist/tools/retest/start-analysis.js.map +1 -0
- package/dist/workspace/index.js +8 -8
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/types.d.ts +2 -2
- package/dist/workspace/types.d.ts.map +1 -1
- package/package.json +6 -2
- package/.claude/commands/openspec/apply.md +0 -23
- package/.claude/commands/openspec/archive.md +0 -27
- package/.claude/commands/openspec/proposal.md +0 -28
- package/.gemini/commands/openspec/apply.toml +0 -21
- package/.gemini/commands/openspec/archive.toml +0 -25
- package/.gemini/commands/openspec/proposal.toml +0 -26
- package/.github/prompts/openspec-apply.prompt.md +0 -22
- package/.github/prompts/openspec-archive.prompt.md +0 -26
- package/.github/prompts/openspec-proposal.prompt.md +0 -27
- package/.github/workflows/release.yml +0 -33
- package/.kilocode/workflows/openspec-apply.md +0 -17
- package/.kilocode/workflows/openspec-archive.md +0 -21
- package/.kilocode/workflows/openspec-proposal.md +0 -22
- package/.mcp.json +0 -23
- package/.opencode/command/openspec-apply.md +0 -25
- package/.opencode/command/openspec-archive.md +0 -28
- package/.opencode/command/openspec-proposal.md +0 -30
- package/.roo/commands/openspec-apply.md +0 -20
- package/.roo/commands/openspec-archive.md +0 -24
- package/.roo/commands/openspec-proposal.md +0 -25
- package/.vscode/mcp.json +0 -23
- package/AGENTS.md +0 -18
- package/CLAUDE.md +0 -18
- package/dist/tools/webtest/crawl.d.ts.map +0 -1
- package/dist/tools/webtest/crawl.js.map +0 -1
- package/dist/tools/webtest/discover-features.d.ts.map +0 -1
- package/dist/tools/webtest/discover-features.js.map +0 -1
- package/dist/tools/webtest/discover-flows.d.ts.map +0 -1
- package/dist/tools/webtest/discover-flows.js.map +0 -1
- package/dist/tools/webtest/generate-tests.d.ts.map +0 -1
- package/dist/tools/webtest/generate-tests.js.map +0 -1
- package/dist/tools/webtest/index.d.ts.map +0 -1
- package/dist/tools/webtest/index.js.map +0 -1
- package/dist/tools/webtest/run-test-case.d.ts.map +0 -1
- package/dist/tools/webtest/run-test-case.js.map +0 -1
- package/dist/tools/webtest/schemas.d.ts.map +0 -1
- package/dist/tools/webtest/schemas.js.map +0 -1
- package/dist/tools/webtest/start-analysis.d.ts.map +0 -1
- package/dist/tools/webtest/start-analysis.js.map +0 -1
- package/openspec/AGENTS.md +0 -456
- package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/proposal.md +0 -33
- package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/specs/webtest-resources/spec.md +0 -27
- package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/specs/webtest-tools/spec.md +0 -304
- package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/tasks.md +0 -43
- package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/design.md +0 -209
- package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/proposal.md +0 -41
- package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/specs/mcp-server-core/spec.md +0 -183
- package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/tasks.md +0 -112
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/design.md +0 -333
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/proposal.md +0 -66
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/mcp-server-core/spec.md +0 -129
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-lifecycle/spec.md +0 -138
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-logging/spec.md +0 -211
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-prompts/spec.md +0 -157
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-resources/spec.md +0 -213
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-sampling/spec.md +0 -257
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-tools/spec.md +0 -501
- package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/tasks.md +0 -264
- package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/proposal.md +0 -24
- package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/specs/webtest-tools/spec.md +0 -80
- package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/tasks.md +0 -8
- package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/design.md +0 -90
- package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/proposal.md +0 -28
- package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/specs/webtest-sampling/spec.md +0 -90
- package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/tasks.md +0 -33
- package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/design.md +0 -558
- package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/proposal.md +0 -119
- package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/specs/webtest-resources/spec.md +0 -109
- package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/specs/webtest-tools/spec.md +0 -121
- package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/tasks.md +0 -133
- package/openspec/changes/extract-prompts-to-markdown/design.md +0 -86
- package/openspec/changes/extract-prompts-to-markdown/proposal.md +0 -50
- package/openspec/changes/extract-prompts-to-markdown/specs/webtest-prompts/spec.md +0 -74
- package/openspec/changes/extract-prompts-to-markdown/tasks.md +0 -40
- package/openspec/changes/refactor-webtest-naming/design.md +0 -95
- package/openspec/changes/refactor-webtest-naming/proposal.md +0 -66
- package/openspec/changes/refactor-webtest-naming/specs/webtest-prompts/spec.md +0 -79
- package/openspec/changes/refactor-webtest-naming/specs/webtest-resources/spec.md +0 -80
- package/openspec/changes/refactor-webtest-naming/specs/webtest-sampling/spec.md +0 -122
- package/openspec/changes/refactor-webtest-naming/specs/webtest-tools/spec.md +0 -113
- package/openspec/changes/refactor-webtest-naming/tasks.md +0 -119
- package/openspec/changes/rename-package-to-retest/proposal.md +0 -52
- package/openspec/changes/rename-package-to-retest/specs/mcp-server-core/spec.md +0 -53
- package/openspec/changes/rename-package-to-retest/specs/retest-lifecycle/spec.md +0 -68
- package/openspec/changes/rename-package-to-retest/specs/retest-logging/spec.md +0 -35
- package/openspec/changes/rename-package-to-retest/specs/retest-prompts/spec.md +0 -159
- package/openspec/changes/rename-package-to-retest/specs/retest-resources/spec.md +0 -251
- package/openspec/changes/rename-package-to-retest/specs/retest-sampling/spec.md +0 -99
- package/openspec/changes/rename-package-to-retest/specs/retest-tools/spec.md +0 -295
- package/openspec/changes/rename-package-to-retest/tasks.md +0 -71
- package/openspec/project.md +0 -31
- package/openspec/specs/mcp-server-core/spec.md +0 -178
- package/openspec/specs/webtest-lifecycle/spec.md +0 -136
- package/openspec/specs/webtest-logging/spec.md +0 -209
- package/openspec/specs/webtest-prompts/spec.md +0 -155
- package/openspec/specs/webtest-resources/spec.md +0 -248
- package/openspec/specs/webtest-sampling/spec.md +0 -344
- package/openspec/specs/webtest-tools/spec.md +0 -282
- package/release.config.js +0 -9
- package/src/config.test.ts +0 -96
- package/src/config.ts +0 -32
- package/src/elicitation/index.test.ts +0 -399
- package/src/elicitation/index.ts +0 -171
- package/src/elicitation/types.ts +0 -68
- package/src/index.ts +0 -83
- package/src/lifecycle/index.test.ts +0 -260
- package/src/lifecycle/index.ts +0 -101
- package/src/logger.redaction.test.ts +0 -322
- package/src/logger.test.ts +0 -123
- package/src/logger.ts +0 -229
- package/src/playwright-client/index.ts +0 -392
- package/src/playwright-client/types.ts +0 -99
- package/src/progress/index.test.ts +0 -327
- package/src/progress/index.ts +0 -170
- package/src/progress/types.ts +0 -25
- package/src/prompts/index.test.ts +0 -451
- package/src/prompts/index.ts +0 -246
- package/src/prompts/loader.test.ts +0 -100
- package/src/prompts/loader.ts +0 -59
- package/src/prompts/templates/mcp/webtest-crawl.md +0 -7
- package/src/prompts/templates/mcp/webtest-full-workflow.md +0 -12
- package/src/resources/index.ts +0 -250
- package/src/resources/subscriptions.ts +0 -37
- package/src/sampling/index.test.ts +0 -414
- package/src/sampling/index.ts +0 -286
- package/src/sampling/prompts.ts +0 -194
- package/src/sampling/types.ts +0 -60
- package/src/schemas/config.ts +0 -39
- package/src/security/index.test.ts +0 -441
- package/src/security/index.ts +0 -361
- package/src/security/security-scenarios.test.ts +0 -468
- package/src/server.ts +0 -211
- package/src/test-utils/index.ts +0 -6
- package/src/test-utils/mock-context.ts +0 -426
- package/src/test-utils/mock-playwright-client.ts +0 -422
- package/src/tools/index.ts +0 -11
- package/src/tools/webtest/crawl.test.ts +0 -834
- package/src/tools/webtest/crawl.ts +0 -901
- package/src/tools/webtest/discover-features.ts +0 -412
- package/src/tools/webtest/discover-flows.ts +0 -408
- package/src/tools/webtest/generate-tests.test.ts +0 -532
- package/src/tools/webtest/generate-tests.ts +0 -425
- package/src/tools/webtest/index.ts +0 -7
- package/src/tools/webtest/integration.test.ts +0 -536
- package/src/tools/webtest/run-test-case.test.ts +0 -659
- package/src/tools/webtest/run-test-case.ts +0 -508
- package/src/tools/webtest/schemas.ts +0 -201
- package/src/tools/webtest/start-analysis.test.ts +0 -151
- package/src/tools/webtest/start-analysis.ts +0 -158
- package/src/transports/http.ts +0 -19
- package/src/transports/index.ts +0 -30
- package/src/transports/stdio.ts +0 -7
- package/src/types/capabilities.test.ts +0 -193
- package/src/types/capabilities.ts +0 -50
- package/src/types/context.ts +0 -21
- package/src/types/tool.ts +0 -11
- package/src/workspace/index.ts +0 -945
- package/src/workspace/markdown.ts +0 -272
- package/src/workspace/types.ts +0 -186
- package/tests/integration/server.test.ts +0 -89
- package/tests/integration/tools.test.ts +0 -99
- package/tsconfig.json +0 -20
- package/vitest.config.ts +0 -9
- package/vitest.integration.config.ts +0 -10
- /package/{src → dist}/prompts/templates/sampling/crawl-action.md +0 -0
- /package/{src → dist}/prompts/templates/sampling/feature-discovery.md +0 -0
- /package/{src → dist}/prompts/templates/sampling/flow-discovery.md +0 -0
- /package/{src → dist}/prompts/templates/sampling/page-content-wrapper.md +0 -0
- /package/{src → dist}/prompts/templates/sampling/test-evaluation.md +0 -0
- /package/{src → dist}/prompts/templates/sampling/test-generation.md +0 -0
- /package/dist/tools/{webtest → retest}/crawl.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/discover-features.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/discover-flows.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/generate-tests.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/index.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/index.js +0 -0
- /package/dist/tools/{webtest → retest}/run-test-case.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/schemas.d.ts +0 -0
- /package/dist/tools/{webtest → retest}/schemas.js +0 -0
- /package/dist/tools/{webtest → retest}/start-analysis.d.ts +0 -0
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { writeFileSync, mkdirSync, rmSync } from "node:fs";
|
|
3
|
-
import { resolve, dirname } from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { loadTemplate, interpolate, renderTemplate, clearTemplateCache } from "./loader.js";
|
|
6
|
-
|
|
7
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
|
|
9
|
-
describe("Template Loader", () => {
|
|
10
|
-
describe("interpolate", () => {
|
|
11
|
-
it("replaces single variable", () => {
|
|
12
|
-
const result = interpolate("Hello ${name}!", { name: "World" });
|
|
13
|
-
expect(result).toBe("Hello World!");
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it("replaces multiple variables", () => {
|
|
17
|
-
const result = interpolate("${greeting} ${name}!", { greeting: "Hello", name: "World" });
|
|
18
|
-
expect(result).toBe("Hello World!");
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("replaces same variable multiple times", () => {
|
|
22
|
-
const result = interpolate("${x} + ${x} = ${y}", { x: "1", y: "2" });
|
|
23
|
-
expect(result).toBe("1 + 1 = 2");
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("keeps unmatched placeholders unchanged", () => {
|
|
27
|
-
const result = interpolate("Hello ${name}! Your id is ${id}.", { name: "World" });
|
|
28
|
-
expect(result).toBe("Hello World! Your id is ${id}.");
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("handles empty vars object", () => {
|
|
32
|
-
const result = interpolate("Hello ${name}!", {});
|
|
33
|
-
expect(result).toBe("Hello ${name}!");
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("converts numbers to strings", () => {
|
|
37
|
-
const result = interpolate("Count: ${count}", { count: 42 });
|
|
38
|
-
expect(result).toBe("Count: 42");
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("converts booleans to strings", () => {
|
|
42
|
-
const result = interpolate("Active: ${active}", { active: true });
|
|
43
|
-
expect(result).toBe("Active: true");
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it("handles undefined values by keeping placeholder", () => {
|
|
47
|
-
const result = interpolate("Value: ${val}", { val: undefined });
|
|
48
|
-
expect(result).toBe("Value: ${val}");
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("preserves text without placeholders", () => {
|
|
52
|
-
const result = interpolate("No variables here", { name: "ignored" });
|
|
53
|
-
expect(result).toBe("No variables here");
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("handles multiline templates", () => {
|
|
57
|
-
const template = `Line 1: \${a}
|
|
58
|
-
Line 2: \${b}
|
|
59
|
-
Line 3: \${c}`;
|
|
60
|
-
const result = interpolate(template, { a: "A", b: "B", c: "C" });
|
|
61
|
-
expect(result).toBe("Line 1: A\nLine 2: B\nLine 3: C");
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
describe("loadTemplate", () => {
|
|
66
|
-
beforeEach(() => {
|
|
67
|
-
clearTemplateCache();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it("loads existing template file", () => {
|
|
71
|
-
// This test depends on actual template files existing
|
|
72
|
-
// Will be validated after templates are created
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it("throws error for non-existent template", () => {
|
|
76
|
-
expect(() => loadTemplate("sampling", "non-existent-template")).toThrow();
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it("caches loaded templates", () => {
|
|
80
|
-
// Cache behavior is internal, but we can verify it doesn't throw on repeated calls
|
|
81
|
-
// Will be validated after templates are created
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe("renderTemplate", () => {
|
|
86
|
-
beforeEach(() => {
|
|
87
|
-
clearTemplateCache();
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("loads and interpolates template in one call", () => {
|
|
91
|
-
// Will be validated after templates are created
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
describe("clearTemplateCache", () => {
|
|
96
|
-
it("clears the cache without error", () => {
|
|
97
|
-
expect(() => clearTemplateCache()).not.toThrow();
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
});
|
package/src/prompts/loader.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { resolve, dirname } from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
|
|
5
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
|
|
7
|
-
const templateCache = new Map<string, string>();
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Load a template file from the templates directory.
|
|
11
|
-
* Templates are cached after first load.
|
|
12
|
-
*/
|
|
13
|
-
export function loadTemplate(category: "sampling" | "mcp", name: string): string {
|
|
14
|
-
const cacheKey = `${category}/${name}`;
|
|
15
|
-
|
|
16
|
-
if (templateCache.has(cacheKey)) {
|
|
17
|
-
return templateCache.get(cacheKey)!;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const templatePath = resolve(__dirname, "templates", category, `${name}.md`);
|
|
21
|
-
const content = readFileSync(templatePath, "utf-8");
|
|
22
|
-
templateCache.set(cacheKey, content);
|
|
23
|
-
|
|
24
|
-
return content;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Interpolate variables in a template string.
|
|
29
|
-
* Replaces ${varName} patterns with values from the vars object.
|
|
30
|
-
* Unmatched placeholders are left unchanged.
|
|
31
|
-
*/
|
|
32
|
-
export function interpolate(template: string, vars: Record<string, string | number | boolean | undefined>): string {
|
|
33
|
-
return template.replace(/\$\{(\w+)\}/g, (match, varName) => {
|
|
34
|
-
const value = vars[varName];
|
|
35
|
-
if (value === undefined) {
|
|
36
|
-
return match; // Keep placeholder if var not provided
|
|
37
|
-
}
|
|
38
|
-
return String(value);
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Load a template and interpolate variables in one step.
|
|
44
|
-
*/
|
|
45
|
-
export function renderTemplate(
|
|
46
|
-
category: "sampling" | "mcp",
|
|
47
|
-
name: string,
|
|
48
|
-
vars: Record<string, string | number | boolean | undefined> = {}
|
|
49
|
-
): string {
|
|
50
|
-
const template = loadTemplate(category, name);
|
|
51
|
-
return interpolate(template, vars);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Clear the template cache (useful for testing).
|
|
56
|
-
*/
|
|
57
|
-
export function clearTemplateCache(): void {
|
|
58
|
-
templateCache.clear();
|
|
59
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
Please crawl the web application with these parameters:
|
|
2
|
-
|
|
3
|
-
Analysis ID: ${analysisId}
|
|
4
|
-
Goal: ${goal}
|
|
5
|
-
Strategy: ${strategy}
|
|
6
|
-
|
|
7
|
-
Use webtest_crawl_app to explore the application. Report progress and let me know if you encounter any obstacles (cookie banners, modals, authentication).
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
Please run a complete web testing workflow for: ${url}
|
|
2
|
-
Focus: ${focus}
|
|
3
|
-
|
|
4
|
-
Execute these steps in order:
|
|
5
|
-
1. webtest_init - Initialize the workspace
|
|
6
|
-
2. webtest_crawl_app - Explore the application with a goal related to "${focus}"
|
|
7
|
-
3. webtest_discover_features - Identify application features
|
|
8
|
-
4. webtest_discover_flows - Discover flows for each feature
|
|
9
|
-
5. webtest_generate_tests - Create test cases
|
|
10
|
-
6. webtest_run_test - Run at least one critical test
|
|
11
|
-
|
|
12
|
-
Report progress at each step and summarize the overall testing results at the end.
|
package/src/resources/index.ts
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { join, extname } from "node:path";
|
|
3
|
-
import type { Logger } from "../logger.js";
|
|
4
|
-
import type { Config } from "../schemas/config.js";
|
|
5
|
-
import type { ClientCapabilities } from "../types/capabilities.js";
|
|
6
|
-
import type { WorkspaceManager } from "../workspace/index.js";
|
|
7
|
-
import { createResourceSubscriptions, type ResourceSubscriptions } from "./subscriptions.js";
|
|
8
|
-
|
|
9
|
-
export { createResourceSubscriptions, type ResourceSubscriptions };
|
|
10
|
-
|
|
11
|
-
export interface Resource {
|
|
12
|
-
uri: string;
|
|
13
|
-
name: string;
|
|
14
|
-
description?: string;
|
|
15
|
-
mimeType?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface ResourceContent {
|
|
19
|
-
uri: string;
|
|
20
|
-
mimeType: string;
|
|
21
|
-
text?: string;
|
|
22
|
-
blob?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface ResourceManager {
|
|
26
|
-
listResources(analysisId?: string): Promise<Resource[]>;
|
|
27
|
-
readResource(uri: string): Promise<ResourceContent>;
|
|
28
|
-
notifyListChanged(): Promise<void>;
|
|
29
|
-
notifyResourceUpdated(uri: string): Promise<void>;
|
|
30
|
-
subscriptions: ResourceSubscriptions;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const MIME_TYPES: Record<string, string> = {
|
|
34
|
-
".json": "application/json",
|
|
35
|
-
".md": "text/markdown",
|
|
36
|
-
".html": "text/html",
|
|
37
|
-
".png": "image/png",
|
|
38
|
-
".jpg": "image/jpeg",
|
|
39
|
-
".jpeg": "image/jpeg",
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export function createResourceManager(
|
|
43
|
-
config: Config,
|
|
44
|
-
workspaceManager: WorkspaceManager,
|
|
45
|
-
sendNotification: (method: string, params: unknown) => Promise<void>,
|
|
46
|
-
capabilities: ClientCapabilities,
|
|
47
|
-
logger: Logger
|
|
48
|
-
): ResourceManager {
|
|
49
|
-
const subscriptions = createResourceSubscriptions(logger);
|
|
50
|
-
const hasListChanged = capabilities.resourcesListChanged;
|
|
51
|
-
const hasSubscribe = capabilities.resourcesSubscribe;
|
|
52
|
-
|
|
53
|
-
function parseWebtestUri(uri: string): { analysisId: string; path: string } | null {
|
|
54
|
-
if (!uri.startsWith("webtest://")) {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const withoutScheme = uri.slice("webtest://".length);
|
|
59
|
-
const slashIndex = withoutScheme.indexOf("/");
|
|
60
|
-
|
|
61
|
-
if (slashIndex === -1) {
|
|
62
|
-
return { analysisId: withoutScheme, path: "" };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
analysisId: withoutScheme.slice(0, slashIndex),
|
|
67
|
-
path: withoutScheme.slice(slashIndex + 1),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function getMimeType(path: string): string {
|
|
72
|
-
const ext = extname(path).toLowerCase();
|
|
73
|
-
return MIME_TYPES[ext] || "application/octet-stream";
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
subscriptions,
|
|
78
|
-
|
|
79
|
-
async listResources(analysisId?: string): Promise<Resource[]> {
|
|
80
|
-
const resources: Resource[] = [];
|
|
81
|
-
|
|
82
|
-
const workspaces = analysisId
|
|
83
|
-
? [analysisId]
|
|
84
|
-
: await workspaceManager.listWorkspaces();
|
|
85
|
-
|
|
86
|
-
for (const wsId of workspaces) {
|
|
87
|
-
if (!(await workspaceManager.workspaceExists(wsId))) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const index = await workspaceManager.readWorkspaceIndex(wsId);
|
|
92
|
-
|
|
93
|
-
// Add workspace index (now markdown)
|
|
94
|
-
resources.push({
|
|
95
|
-
uri: `webtest://${wsId}/index.md`,
|
|
96
|
-
name: `Analysis: ${index.url}`,
|
|
97
|
-
description: `Analysis workspace for ${index.domain}`,
|
|
98
|
-
mimeType: "text/markdown",
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// Add crawl resources
|
|
102
|
-
for (const crawl of index.crawls) {
|
|
103
|
-
resources.push({
|
|
104
|
-
uri: `webtest://${wsId}/crawls/${crawl.crawlId}/index.md`,
|
|
105
|
-
name: `Crawl: ${crawl.goal.slice(0, 50)}`,
|
|
106
|
-
description: `Crawl ${crawl.status} - ${crawl.pagesVisited} pages`,
|
|
107
|
-
mimeType: "text/markdown",
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// Read crawl index to get page resources
|
|
111
|
-
try {
|
|
112
|
-
const crawlIndex = await workspaceManager.readCrawlIndex(
|
|
113
|
-
wsId,
|
|
114
|
-
crawl.crawlId
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
for (const page of crawlIndex.pages) {
|
|
118
|
-
resources.push({
|
|
119
|
-
uri: page.screenshotUri,
|
|
120
|
-
name: `Screenshot: ${page.title || page.url}`,
|
|
121
|
-
mimeType: "image/png",
|
|
122
|
-
});
|
|
123
|
-
resources.push({
|
|
124
|
-
uri: page.snapshotUri,
|
|
125
|
-
name: `Snapshot: ${page.title || page.url}`,
|
|
126
|
-
mimeType: "text/markdown",
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
} catch {
|
|
130
|
-
// Crawl index might not exist yet
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Add features resources (new structure)
|
|
135
|
-
if (index.features) {
|
|
136
|
-
resources.push({
|
|
137
|
-
uri: index.features.featuresUri,
|
|
138
|
-
name: `Features (${index.features.featureCount})`,
|
|
139
|
-
description: "Discovered application features",
|
|
140
|
-
mimeType: "text/markdown",
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Add feature flows resources
|
|
145
|
-
if (index.featureFlows) {
|
|
146
|
-
for (const flow of index.featureFlows) {
|
|
147
|
-
resources.push({
|
|
148
|
-
uri: flow.flowsUri,
|
|
149
|
-
name: `Flows: ${flow.featureSlug}`,
|
|
150
|
-
description: `${flow.flowCount} flows for ${flow.featureSlug} feature`,
|
|
151
|
-
mimeType: "text/markdown",
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
// Add test resources
|
|
158
|
-
if (index.tests) {
|
|
159
|
-
resources.push({
|
|
160
|
-
uri: index.tests.testsUri,
|
|
161
|
-
name: `Tests (${index.tests.testCount} cases)`,
|
|
162
|
-
description: "Generated test cases",
|
|
163
|
-
mimeType: "text/markdown",
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Add test run resources
|
|
168
|
-
for (const run of index.runs) {
|
|
169
|
-
resources.push({
|
|
170
|
-
uri: `webtest://${wsId}/runs/${run.runId}/report.md`,
|
|
171
|
-
name: `Test Run: ${run.testCaseId}`,
|
|
172
|
-
description: `Test run ${run.status}`,
|
|
173
|
-
mimeType: "text/markdown",
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return resources;
|
|
179
|
-
},
|
|
180
|
-
|
|
181
|
-
async readResource(uri: string): Promise<ResourceContent> {
|
|
182
|
-
const parsed = parseWebtestUri(uri);
|
|
183
|
-
|
|
184
|
-
if (!parsed) {
|
|
185
|
-
throw new Error(`Invalid resource URI: ${uri}`);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const { analysisId, path } = parsed;
|
|
189
|
-
const workspacePath = workspaceManager.getWorkspacePath(analysisId);
|
|
190
|
-
const filePath = join(workspacePath, path);
|
|
191
|
-
const mimeType = getMimeType(path);
|
|
192
|
-
|
|
193
|
-
try {
|
|
194
|
-
if (mimeType.startsWith("image/")) {
|
|
195
|
-
const data = await readFile(filePath);
|
|
196
|
-
return {
|
|
197
|
-
uri,
|
|
198
|
-
mimeType,
|
|
199
|
-
blob: data.toString("base64"),
|
|
200
|
-
};
|
|
201
|
-
} else {
|
|
202
|
-
const text = await readFile(filePath, "utf-8");
|
|
203
|
-
return {
|
|
204
|
-
uri,
|
|
205
|
-
mimeType,
|
|
206
|
-
text,
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
} catch (error) {
|
|
210
|
-
throw new Error(
|
|
211
|
-
`Resource not found: ${uri} (${error instanceof Error ? error.message : "Unknown error"})`
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
|
|
216
|
-
async notifyListChanged(): Promise<void> {
|
|
217
|
-
if (!hasListChanged) {
|
|
218
|
-
logger.debug("listChanged notification skipped (not supported)");
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
logger.debug("Emitting resources/list_changed notification");
|
|
223
|
-
|
|
224
|
-
try {
|
|
225
|
-
await sendNotification("notifications/resources/list_changed", {});
|
|
226
|
-
} catch (error) {
|
|
227
|
-
logger.warn("Failed to emit list_changed notification", {
|
|
228
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
async notifyResourceUpdated(uri: string): Promise<void> {
|
|
234
|
-
if (!hasSubscribe || !subscriptions.isSubscribed(uri)) {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
logger.debug("Emitting resources/updated notification", { uri });
|
|
239
|
-
|
|
240
|
-
try {
|
|
241
|
-
await sendNotification("notifications/resources/updated", { uri });
|
|
242
|
-
} catch (error) {
|
|
243
|
-
logger.warn("Failed to emit resource updated notification", {
|
|
244
|
-
uri,
|
|
245
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
},
|
|
249
|
-
};
|
|
250
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { Logger } from "../logger.js";
|
|
2
|
-
|
|
3
|
-
export interface ResourceSubscriptions {
|
|
4
|
-
subscribe(uri: string): void;
|
|
5
|
-
unsubscribe(uri: string): void;
|
|
6
|
-
isSubscribed(uri: string): boolean;
|
|
7
|
-
getSubscribers(): string[];
|
|
8
|
-
clear(): void;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function createResourceSubscriptions(logger: Logger): ResourceSubscriptions {
|
|
12
|
-
const subscriptions = new Set<string>();
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
subscribe(uri: string): void {
|
|
16
|
-
subscriptions.add(uri);
|
|
17
|
-
logger.debug("Resource subscribed", { uri });
|
|
18
|
-
},
|
|
19
|
-
|
|
20
|
-
unsubscribe(uri: string): void {
|
|
21
|
-
subscriptions.delete(uri);
|
|
22
|
-
logger.debug("Resource unsubscribed", { uri });
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
isSubscribed(uri: string): boolean {
|
|
26
|
-
return subscriptions.has(uri);
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
getSubscribers(): string[] {
|
|
30
|
-
return Array.from(subscriptions);
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
clear(): void {
|
|
34
|
-
subscriptions.clear();
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
}
|