@frontmcp/testing 0.5.0 → 0.6.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/package.json +4 -4
- package/src/auth/mock-api-server.d.ts +99 -0
- package/src/auth/mock-api-server.js +200 -0
- package/src/auth/mock-api-server.js.map +1 -0
- package/src/auth/mock-oauth-server.d.ts +85 -0
- package/src/auth/mock-oauth-server.js +253 -0
- package/src/auth/mock-oauth-server.js.map +1 -0
- package/src/client/mcp-test-client.builder.d.ts +43 -1
- package/src/client/mcp-test-client.builder.js +52 -0
- package/src/client/mcp-test-client.builder.js.map +1 -1
- package/src/client/mcp-test-client.js +22 -14
- package/src/client/mcp-test-client.js.map +1 -1
- package/src/client/mcp-test-client.types.d.ts +67 -6
- package/src/client/mcp-test-client.types.js +9 -0
- package/src/client/mcp-test-client.types.js.map +1 -1
- package/src/example-tools/index.d.ts +19 -0
- package/src/example-tools/index.js +40 -0
- package/src/example-tools/index.js.map +1 -0
- package/src/example-tools/tool-configs.d.ts +170 -0
- package/src/example-tools/tool-configs.js +222 -0
- package/src/example-tools/tool-configs.js.map +1 -0
- package/src/expect.d.ts +6 -5
- package/src/expect.js.map +1 -1
- package/src/fixtures/fixture-types.d.ts +19 -0
- package/src/fixtures/fixture-types.js.map +1 -1
- package/src/fixtures/test-fixture.d.ts +3 -1
- package/src/fixtures/test-fixture.js +35 -4
- package/src/fixtures/test-fixture.js.map +1 -1
- package/src/index.d.ts +7 -0
- package/src/index.js +40 -1
- package/src/index.js.map +1 -1
- package/src/matchers/matcher-types.js.map +1 -1
- package/src/matchers/mcp-matchers.d.ts +7 -0
- package/src/matchers/mcp-matchers.js +8 -4
- package/src/matchers/mcp-matchers.js.map +1 -1
- package/src/platform/index.d.ts +28 -0
- package/src/platform/index.js +47 -0
- package/src/platform/index.js.map +1 -0
- package/src/platform/platform-client-info.d.ts +97 -0
- package/src/platform/platform-client-info.js +155 -0
- package/src/platform/platform-client-info.js.map +1 -0
- package/src/platform/platform-types.d.ts +72 -0
- package/src/platform/platform-types.js +110 -0
- package/src/platform/platform-types.js.map +1 -0
- package/src/server/test-server.d.ts +4 -0
- package/src/server/test-server.js +58 -3
- package/src/server/test-server.js.map +1 -1
- package/src/transport/streamable-http.transport.js +6 -0
- package/src/transport/streamable-http.transport.js.map +1 -1
- package/src/transport/transport.interface.d.ts +3 -0
- package/src/transport/transport.interface.js.map +1 -1
- package/src/ui/ui-assertions.d.ts +59 -0
- package/src/ui/ui-assertions.js +152 -0
- package/src/ui/ui-assertions.js.map +1 -1
- package/src/ui/ui-matchers.d.ts +8 -0
- package/src/ui/ui-matchers.js +218 -0
- package/src/ui/ui-matchers.js.map +1 -1
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file tool-configs.ts
|
|
3
|
+
* @description Shared tool configurations for platform E2E testing.
|
|
4
|
+
*
|
|
5
|
+
* These configurations provide consistent test fixtures for validating
|
|
6
|
+
* platform-specific meta key behavior across E2E test projects.
|
|
7
|
+
*
|
|
8
|
+
* @example Usage in E2E tool implementation
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { Tool, ToolContext } from '@frontmcp/sdk';
|
|
11
|
+
* import { BASIC_UI_TOOL_CONFIG, FULL_UI_TOOL_CONFIG } from '@frontmcp/testing';
|
|
12
|
+
*
|
|
13
|
+
* @Tool({
|
|
14
|
+
* name: BASIC_UI_TOOL_CONFIG.name,
|
|
15
|
+
* description: BASIC_UI_TOOL_CONFIG.description,
|
|
16
|
+
* ui: BASIC_UI_TOOL_CONFIG.ui,
|
|
17
|
+
* })
|
|
18
|
+
* export class BasicUITool extends ToolContext<typeof inputSchema, typeof outputSchema> {
|
|
19
|
+
* async execute(input) {
|
|
20
|
+
* return { message: `Hello, ${input.name}!`, timestamp: Date.now() };
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
/**
|
|
27
|
+
* Input schema for the basic UI tool.
|
|
28
|
+
*/
|
|
29
|
+
export declare const basicUIToolInputSchema: z.ZodObject<{
|
|
30
|
+
name: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
/**
|
|
33
|
+
* Output schema for the basic UI tool.
|
|
34
|
+
*/
|
|
35
|
+
export declare const basicUIToolOutputSchema: z.ZodObject<{
|
|
36
|
+
message: z.ZodString;
|
|
37
|
+
timestamp: z.ZodNumber;
|
|
38
|
+
}, z.core.$strip>;
|
|
39
|
+
/**
|
|
40
|
+
* Basic UI tool configuration with minimal UI config.
|
|
41
|
+
* Use this for testing that platform-specific meta keys are correctly applied.
|
|
42
|
+
*/
|
|
43
|
+
export declare const BASIC_UI_TOOL_CONFIG: {
|
|
44
|
+
readonly name: "platform-test-basic";
|
|
45
|
+
readonly description: "Basic UI tool for platform testing";
|
|
46
|
+
readonly inputSchema: z.ZodObject<{
|
|
47
|
+
name: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
48
|
+
}, z.core.$strip>;
|
|
49
|
+
readonly outputSchema: z.ZodObject<{
|
|
50
|
+
message: z.ZodString;
|
|
51
|
+
timestamp: z.ZodNumber;
|
|
52
|
+
}, z.core.$strip>;
|
|
53
|
+
readonly ui: {
|
|
54
|
+
/**
|
|
55
|
+
* Simple template that displays the output.
|
|
56
|
+
* Works with all platforms.
|
|
57
|
+
*/
|
|
58
|
+
readonly template: string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Input schema for the full UI tool.
|
|
63
|
+
*/
|
|
64
|
+
export declare const fullUIToolInputSchema: z.ZodObject<{
|
|
65
|
+
name: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
66
|
+
count: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
67
|
+
}, z.core.$strip>;
|
|
68
|
+
/**
|
|
69
|
+
* Output schema for the full UI tool.
|
|
70
|
+
*/
|
|
71
|
+
export declare const fullUIToolOutputSchema: z.ZodObject<{
|
|
72
|
+
message: z.ZodString;
|
|
73
|
+
count: z.ZodNumber;
|
|
74
|
+
items: z.ZodArray<z.ZodString>;
|
|
75
|
+
timestamp: z.ZodNumber;
|
|
76
|
+
}, z.core.$strip>;
|
|
77
|
+
/**
|
|
78
|
+
* Full UI tool configuration with all UI options.
|
|
79
|
+
* Use this for testing comprehensive platform-specific meta key behavior.
|
|
80
|
+
*/
|
|
81
|
+
export declare const FULL_UI_TOOL_CONFIG: {
|
|
82
|
+
readonly name: "platform-test-full";
|
|
83
|
+
readonly description: "Full UI tool with all options for comprehensive platform testing";
|
|
84
|
+
readonly inputSchema: z.ZodObject<{
|
|
85
|
+
name: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
86
|
+
count: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
87
|
+
}, z.core.$strip>;
|
|
88
|
+
readonly outputSchema: z.ZodObject<{
|
|
89
|
+
message: z.ZodString;
|
|
90
|
+
count: z.ZodNumber;
|
|
91
|
+
items: z.ZodArray<z.ZodString>;
|
|
92
|
+
timestamp: z.ZodNumber;
|
|
93
|
+
}, z.core.$strip>;
|
|
94
|
+
readonly ui: {
|
|
95
|
+
/**
|
|
96
|
+
* Template with more complex UI elements.
|
|
97
|
+
*/
|
|
98
|
+
readonly template: string;
|
|
99
|
+
/**
|
|
100
|
+
* Widget is accessible for callback invocations.
|
|
101
|
+
*/
|
|
102
|
+
readonly widgetAccessible: true;
|
|
103
|
+
/**
|
|
104
|
+
* Invocation status messages for OpenAI.
|
|
105
|
+
*/
|
|
106
|
+
readonly invocationStatus: {
|
|
107
|
+
readonly invoking: "Processing request...";
|
|
108
|
+
readonly invoked: "Request completed";
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Content Security Policy configuration.
|
|
112
|
+
*/
|
|
113
|
+
readonly csp: {
|
|
114
|
+
readonly connectDomains: readonly ["https://api.example.com"];
|
|
115
|
+
readonly resourceDomains: readonly ["https://cdn.example.com"];
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Display mode for the widget.
|
|
119
|
+
*/
|
|
120
|
+
readonly displayMode: "inline";
|
|
121
|
+
/**
|
|
122
|
+
* Prefers border around the widget.
|
|
123
|
+
*/
|
|
124
|
+
readonly prefersBorder: true;
|
|
125
|
+
/**
|
|
126
|
+
* Custom sandbox domain.
|
|
127
|
+
*/
|
|
128
|
+
readonly sandboxDomain: "sandbox.example.com";
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Generate output for the basic UI tool.
|
|
133
|
+
*/
|
|
134
|
+
export declare function generateBasicUIToolOutput(input: z.infer<typeof basicUIToolInputSchema>): {
|
|
135
|
+
message: string;
|
|
136
|
+
timestamp: number;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Generate output for the full UI tool.
|
|
140
|
+
*/
|
|
141
|
+
export declare function generateFullUIToolOutput(input: z.infer<typeof fullUIToolInputSchema>): {
|
|
142
|
+
message: string;
|
|
143
|
+
count: number;
|
|
144
|
+
items: string[];
|
|
145
|
+
timestamp: number;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Expected meta keys for OpenAI platform in tools/list response.
|
|
149
|
+
*/
|
|
150
|
+
export declare const EXPECTED_OPENAI_TOOLS_LIST_META_KEYS: readonly ["openai/outputTemplate", "openai/resultCanProduceWidget", "openai/widgetAccessible"];
|
|
151
|
+
/**
|
|
152
|
+
* Expected meta keys for OpenAI platform in tools/call response.
|
|
153
|
+
*/
|
|
154
|
+
export declare const EXPECTED_OPENAI_TOOL_CALL_META_KEYS: readonly ["openai/html", "openai/mimeType", "openai/type"];
|
|
155
|
+
/**
|
|
156
|
+
* Expected meta keys for ext-apps platform in tools/list response (SEP-1865).
|
|
157
|
+
*/
|
|
158
|
+
export declare const EXPECTED_EXTAPPS_TOOLS_LIST_META_KEYS: readonly ["ui/resourceUri", "ui/mimeType", "ui/cdn", "ui/type"];
|
|
159
|
+
/**
|
|
160
|
+
* Expected meta keys for ext-apps platform in tools/call response (SEP-1865).
|
|
161
|
+
*/
|
|
162
|
+
export declare const EXPECTED_EXTAPPS_TOOL_CALL_META_KEYS: readonly ["ui/html", "ui/mimeType", "ui/type"];
|
|
163
|
+
/**
|
|
164
|
+
* Expected meta keys for FrontMCP platforms in tools/list response (Claude, Cursor, etc.).
|
|
165
|
+
*/
|
|
166
|
+
export declare const EXPECTED_FRONTMCP_TOOLS_LIST_META_KEYS: readonly ["frontmcp/outputTemplate", "frontmcp/resultCanProduceWidget", "ui/cdn", "ui/type"];
|
|
167
|
+
/**
|
|
168
|
+
* Expected meta keys for FrontMCP platforms in tools/call response (Claude, Cursor, etc.).
|
|
169
|
+
*/
|
|
170
|
+
export declare const EXPECTED_FRONTMCP_TOOL_CALL_META_KEYS: readonly ["frontmcp/html", "frontmcp/mimeType", "ui/html", "ui/mimeType"];
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file tool-configs.ts
|
|
4
|
+
* @description Shared tool configurations for platform E2E testing.
|
|
5
|
+
*
|
|
6
|
+
* These configurations provide consistent test fixtures for validating
|
|
7
|
+
* platform-specific meta key behavior across E2E test projects.
|
|
8
|
+
*
|
|
9
|
+
* @example Usage in E2E tool implementation
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { Tool, ToolContext } from '@frontmcp/sdk';
|
|
12
|
+
* import { BASIC_UI_TOOL_CONFIG, FULL_UI_TOOL_CONFIG } from '@frontmcp/testing';
|
|
13
|
+
*
|
|
14
|
+
* @Tool({
|
|
15
|
+
* name: BASIC_UI_TOOL_CONFIG.name,
|
|
16
|
+
* description: BASIC_UI_TOOL_CONFIG.description,
|
|
17
|
+
* ui: BASIC_UI_TOOL_CONFIG.ui,
|
|
18
|
+
* })
|
|
19
|
+
* export class BasicUITool extends ToolContext<typeof inputSchema, typeof outputSchema> {
|
|
20
|
+
* async execute(input) {
|
|
21
|
+
* return { message: `Hello, ${input.name}!`, timestamp: Date.now() };
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.EXPECTED_FRONTMCP_TOOL_CALL_META_KEYS = exports.EXPECTED_FRONTMCP_TOOLS_LIST_META_KEYS = exports.EXPECTED_EXTAPPS_TOOL_CALL_META_KEYS = exports.EXPECTED_EXTAPPS_TOOLS_LIST_META_KEYS = exports.EXPECTED_OPENAI_TOOL_CALL_META_KEYS = exports.EXPECTED_OPENAI_TOOLS_LIST_META_KEYS = exports.FULL_UI_TOOL_CONFIG = exports.fullUIToolOutputSchema = exports.fullUIToolInputSchema = exports.BASIC_UI_TOOL_CONFIG = exports.basicUIToolOutputSchema = exports.basicUIToolInputSchema = void 0;
|
|
28
|
+
exports.generateBasicUIToolOutput = generateBasicUIToolOutput;
|
|
29
|
+
exports.generateFullUIToolOutput = generateFullUIToolOutput;
|
|
30
|
+
const zod_1 = require("zod");
|
|
31
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
32
|
+
// BASIC UI TOOL CONFIG
|
|
33
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
34
|
+
/**
|
|
35
|
+
* Input schema for the basic UI tool.
|
|
36
|
+
*/
|
|
37
|
+
exports.basicUIToolInputSchema = zod_1.z.object({
|
|
38
|
+
name: zod_1.z.string().optional().default('World'),
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Output schema for the basic UI tool.
|
|
42
|
+
*/
|
|
43
|
+
exports.basicUIToolOutputSchema = zod_1.z.object({
|
|
44
|
+
message: zod_1.z.string(),
|
|
45
|
+
timestamp: zod_1.z.number(),
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* Basic UI tool configuration with minimal UI config.
|
|
49
|
+
* Use this for testing that platform-specific meta keys are correctly applied.
|
|
50
|
+
*/
|
|
51
|
+
exports.BASIC_UI_TOOL_CONFIG = {
|
|
52
|
+
name: 'platform-test-basic',
|
|
53
|
+
description: 'Basic UI tool for platform testing',
|
|
54
|
+
inputSchema: exports.basicUIToolInputSchema,
|
|
55
|
+
outputSchema: exports.basicUIToolOutputSchema,
|
|
56
|
+
ui: {
|
|
57
|
+
/**
|
|
58
|
+
* Simple template that displays the output.
|
|
59
|
+
* Works with all platforms.
|
|
60
|
+
*/
|
|
61
|
+
template: `
|
|
62
|
+
<div class="platform-test-basic">
|
|
63
|
+
<h1>Platform Test - Basic</h1>
|
|
64
|
+
<p>Message: {output.message}</p>
|
|
65
|
+
<p>Timestamp: {output.timestamp}</p>
|
|
66
|
+
</div>
|
|
67
|
+
`.trim(),
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
71
|
+
// FULL UI TOOL CONFIG
|
|
72
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
73
|
+
/**
|
|
74
|
+
* Input schema for the full UI tool.
|
|
75
|
+
*/
|
|
76
|
+
exports.fullUIToolInputSchema = zod_1.z.object({
|
|
77
|
+
name: zod_1.z.string().optional().default('World'),
|
|
78
|
+
count: zod_1.z.number().optional().default(1),
|
|
79
|
+
});
|
|
80
|
+
/**
|
|
81
|
+
* Output schema for the full UI tool.
|
|
82
|
+
*/
|
|
83
|
+
exports.fullUIToolOutputSchema = zod_1.z.object({
|
|
84
|
+
message: zod_1.z.string(),
|
|
85
|
+
count: zod_1.z.number(),
|
|
86
|
+
items: zod_1.z.array(zod_1.z.string()),
|
|
87
|
+
timestamp: zod_1.z.number(),
|
|
88
|
+
});
|
|
89
|
+
/**
|
|
90
|
+
* Full UI tool configuration with all UI options.
|
|
91
|
+
* Use this for testing comprehensive platform-specific meta key behavior.
|
|
92
|
+
*/
|
|
93
|
+
exports.FULL_UI_TOOL_CONFIG = {
|
|
94
|
+
name: 'platform-test-full',
|
|
95
|
+
description: 'Full UI tool with all options for comprehensive platform testing',
|
|
96
|
+
inputSchema: exports.fullUIToolInputSchema,
|
|
97
|
+
outputSchema: exports.fullUIToolOutputSchema,
|
|
98
|
+
ui: {
|
|
99
|
+
/**
|
|
100
|
+
* Template with more complex UI elements.
|
|
101
|
+
*/
|
|
102
|
+
template: `
|
|
103
|
+
<div class="platform-test-full">
|
|
104
|
+
<h1>Platform Test - Full</h1>
|
|
105
|
+
<div class="message-box">
|
|
106
|
+
<strong>Message:</strong> {output.message}
|
|
107
|
+
</div>
|
|
108
|
+
<div class="count-box">
|
|
109
|
+
<strong>Count:</strong> {output.count}
|
|
110
|
+
</div>
|
|
111
|
+
<div class="items-list">
|
|
112
|
+
<strong>Items:</strong>
|
|
113
|
+
<ul>
|
|
114
|
+
{output.items.map(item => <li key={item}>{item}</li>)}
|
|
115
|
+
</ul>
|
|
116
|
+
</div>
|
|
117
|
+
<footer>
|
|
118
|
+
<small>Generated at: {new Date(output.timestamp).toISOString()}</small>
|
|
119
|
+
</footer>
|
|
120
|
+
</div>
|
|
121
|
+
`.trim(),
|
|
122
|
+
/**
|
|
123
|
+
* Widget is accessible for callback invocations.
|
|
124
|
+
*/
|
|
125
|
+
widgetAccessible: true,
|
|
126
|
+
/**
|
|
127
|
+
* Invocation status messages for OpenAI.
|
|
128
|
+
*/
|
|
129
|
+
invocationStatus: {
|
|
130
|
+
invoking: 'Processing request...',
|
|
131
|
+
invoked: 'Request completed',
|
|
132
|
+
},
|
|
133
|
+
/**
|
|
134
|
+
* Content Security Policy configuration.
|
|
135
|
+
*/
|
|
136
|
+
csp: {
|
|
137
|
+
connectDomains: ['https://api.example.com'],
|
|
138
|
+
resourceDomains: ['https://cdn.example.com'],
|
|
139
|
+
},
|
|
140
|
+
/**
|
|
141
|
+
* Display mode for the widget.
|
|
142
|
+
*/
|
|
143
|
+
displayMode: 'inline',
|
|
144
|
+
/**
|
|
145
|
+
* Prefers border around the widget.
|
|
146
|
+
*/
|
|
147
|
+
prefersBorder: true,
|
|
148
|
+
/**
|
|
149
|
+
* Custom sandbox domain.
|
|
150
|
+
*/
|
|
151
|
+
sandboxDomain: 'sandbox.example.com',
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
155
|
+
// TOOL EXECUTION HELPERS
|
|
156
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
157
|
+
/**
|
|
158
|
+
* Generate output for the basic UI tool.
|
|
159
|
+
*/
|
|
160
|
+
function generateBasicUIToolOutput(input) {
|
|
161
|
+
return {
|
|
162
|
+
message: `Hello, ${input.name}!`,
|
|
163
|
+
timestamp: Date.now(),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Generate output for the full UI tool.
|
|
168
|
+
*/
|
|
169
|
+
function generateFullUIToolOutput(input) {
|
|
170
|
+
const items = [];
|
|
171
|
+
for (let i = 1; i <= input.count; i++) {
|
|
172
|
+
items.push(`Item ${i}`);
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
message: `Hello, ${input.name}! You requested ${input.count} item(s).`,
|
|
176
|
+
count: input.count,
|
|
177
|
+
items,
|
|
178
|
+
timestamp: Date.now(),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
182
|
+
// EXPECTED META KEYS
|
|
183
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
184
|
+
/**
|
|
185
|
+
* Expected meta keys for OpenAI platform in tools/list response.
|
|
186
|
+
*/
|
|
187
|
+
exports.EXPECTED_OPENAI_TOOLS_LIST_META_KEYS = [
|
|
188
|
+
'openai/outputTemplate',
|
|
189
|
+
'openai/resultCanProduceWidget',
|
|
190
|
+
'openai/widgetAccessible',
|
|
191
|
+
];
|
|
192
|
+
/**
|
|
193
|
+
* Expected meta keys for OpenAI platform in tools/call response.
|
|
194
|
+
*/
|
|
195
|
+
exports.EXPECTED_OPENAI_TOOL_CALL_META_KEYS = ['openai/html', 'openai/mimeType', 'openai/type'];
|
|
196
|
+
/**
|
|
197
|
+
* Expected meta keys for ext-apps platform in tools/list response (SEP-1865).
|
|
198
|
+
*/
|
|
199
|
+
exports.EXPECTED_EXTAPPS_TOOLS_LIST_META_KEYS = ['ui/resourceUri', 'ui/mimeType', 'ui/cdn', 'ui/type'];
|
|
200
|
+
/**
|
|
201
|
+
* Expected meta keys for ext-apps platform in tools/call response (SEP-1865).
|
|
202
|
+
*/
|
|
203
|
+
exports.EXPECTED_EXTAPPS_TOOL_CALL_META_KEYS = ['ui/html', 'ui/mimeType', 'ui/type'];
|
|
204
|
+
/**
|
|
205
|
+
* Expected meta keys for FrontMCP platforms in tools/list response (Claude, Cursor, etc.).
|
|
206
|
+
*/
|
|
207
|
+
exports.EXPECTED_FRONTMCP_TOOLS_LIST_META_KEYS = [
|
|
208
|
+
'frontmcp/outputTemplate',
|
|
209
|
+
'frontmcp/resultCanProduceWidget',
|
|
210
|
+
'ui/cdn',
|
|
211
|
+
'ui/type',
|
|
212
|
+
];
|
|
213
|
+
/**
|
|
214
|
+
* Expected meta keys for FrontMCP platforms in tools/call response (Claude, Cursor, etc.).
|
|
215
|
+
*/
|
|
216
|
+
exports.EXPECTED_FRONTMCP_TOOL_CALL_META_KEYS = [
|
|
217
|
+
'frontmcp/html',
|
|
218
|
+
'frontmcp/mimeType',
|
|
219
|
+
'ui/html',
|
|
220
|
+
'ui/mimeType',
|
|
221
|
+
];
|
|
222
|
+
//# sourceMappingURL=tool-configs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-configs.js","sourceRoot":"","sources":["../../../src/example-tools/tool-configs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @file tool-configs.ts\n * @description Shared tool configurations for platform E2E testing.\n *\n * These configurations provide consistent test fixtures for validating\n * platform-specific meta key behavior across E2E test projects.\n *\n * @example Usage in E2E tool implementation\n * ```typescript\n * import { Tool, ToolContext } from '@frontmcp/sdk';\n * import { BASIC_UI_TOOL_CONFIG, FULL_UI_TOOL_CONFIG } from '@frontmcp/testing';\n *\n * @Tool({\n * name: BASIC_UI_TOOL_CONFIG.name,\n * description: BASIC_UI_TOOL_CONFIG.description,\n * ui: BASIC_UI_TOOL_CONFIG.ui,\n * })\n * export class BasicUITool extends ToolContext<typeof inputSchema, typeof outputSchema> {\n * async execute(input) {\n * return { message: `Hello, ${input.name}!`, timestamp: Date.now() };\n * }\n * }\n * ```\n */\n\nimport { z } from 'zod';\n\n// ═══════════════════════════════════════════════════════════════════\n// BASIC UI TOOL CONFIG\n// ═══════════════════════════════════════════════════════════════════\n\n/**\n * Input schema for the basic UI tool.\n */\nexport const basicUIToolInputSchema = z.object({\n name: z.string().optional().default('World'),\n});\n\n/**\n * Output schema for the basic UI tool.\n */\nexport const basicUIToolOutputSchema = z.object({\n message: z.string(),\n timestamp: z.number(),\n});\n\n/**\n * Basic UI tool configuration with minimal UI config.\n * Use this for testing that platform-specific meta keys are correctly applied.\n */\nexport const BASIC_UI_TOOL_CONFIG = {\n name: 'platform-test-basic',\n description: 'Basic UI tool for platform testing',\n inputSchema: basicUIToolInputSchema,\n outputSchema: basicUIToolOutputSchema,\n ui: {\n /**\n * Simple template that displays the output.\n * Works with all platforms.\n */\n template: `\n<div class=\"platform-test-basic\">\n <h1>Platform Test - Basic</h1>\n <p>Message: {output.message}</p>\n <p>Timestamp: {output.timestamp}</p>\n</div>\n `.trim(),\n },\n} as const;\n\n// ═══════════════════════════════════════════════════════════════════\n// FULL UI TOOL CONFIG\n// ═══════════════════════════════════════════════════════════════════\n\n/**\n * Input schema for the full UI tool.\n */\nexport const fullUIToolInputSchema = z.object({\n name: z.string().optional().default('World'),\n count: z.number().optional().default(1),\n});\n\n/**\n * Output schema for the full UI tool.\n */\nexport const fullUIToolOutputSchema = z.object({\n message: z.string(),\n count: z.number(),\n items: z.array(z.string()),\n timestamp: z.number(),\n});\n\n/**\n * Full UI tool configuration with all UI options.\n * Use this for testing comprehensive platform-specific meta key behavior.\n */\nexport const FULL_UI_TOOL_CONFIG = {\n name: 'platform-test-full',\n description: 'Full UI tool with all options for comprehensive platform testing',\n inputSchema: fullUIToolInputSchema,\n outputSchema: fullUIToolOutputSchema,\n ui: {\n /**\n * Template with more complex UI elements.\n */\n template: `\n<div class=\"platform-test-full\">\n <h1>Platform Test - Full</h1>\n <div class=\"message-box\">\n <strong>Message:</strong> {output.message}\n </div>\n <div class=\"count-box\">\n <strong>Count:</strong> {output.count}\n </div>\n <div class=\"items-list\">\n <strong>Items:</strong>\n <ul>\n {output.items.map(item => <li key={item}>{item}</li>)}\n </ul>\n </div>\n <footer>\n <small>Generated at: {new Date(output.timestamp).toISOString()}</small>\n </footer>\n</div>\n `.trim(),\n /**\n * Widget is accessible for callback invocations.\n */\n widgetAccessible: true,\n /**\n * Invocation status messages for OpenAI.\n */\n invocationStatus: {\n invoking: 'Processing request...',\n invoked: 'Request completed',\n },\n /**\n * Content Security Policy configuration.\n */\n csp: {\n connectDomains: ['https://api.example.com'],\n resourceDomains: ['https://cdn.example.com'],\n },\n /**\n * Display mode for the widget.\n */\n displayMode: 'inline' as const,\n /**\n * Prefers border around the widget.\n */\n prefersBorder: true,\n /**\n * Custom sandbox domain.\n */\n sandboxDomain: 'sandbox.example.com',\n },\n} as const;\n\n// ═══════════════════════════════════════════════════════════════════\n// TOOL EXECUTION HELPERS\n// ═══════════════════════════════════════════════════════════════════\n\n/**\n * Generate output for the basic UI tool.\n */\nexport function generateBasicUIToolOutput(input: z.infer<typeof basicUIToolInputSchema>) {\n return {\n message: `Hello, ${input.name}!`,\n timestamp: Date.now(),\n };\n}\n\n/**\n * Generate output for the full UI tool.\n */\nexport function generateFullUIToolOutput(input: z.infer<typeof fullUIToolInputSchema>) {\n const items: string[] = [];\n for (let i = 1; i <= input.count; i++) {\n items.push(`Item ${i}`);\n }\n return {\n message: `Hello, ${input.name}! You requested ${input.count} item(s).`,\n count: input.count,\n items,\n timestamp: Date.now(),\n };\n}\n\n// ═══════════════════════════════════════════════════════════════════\n// EXPECTED META KEYS\n// ═══════════════════════════════════════════════════════════════════\n\n/**\n * Expected meta keys for OpenAI platform in tools/list response.\n */\nexport const EXPECTED_OPENAI_TOOLS_LIST_META_KEYS = [\n 'openai/outputTemplate',\n 'openai/resultCanProduceWidget',\n 'openai/widgetAccessible',\n] as const;\n\n/**\n * Expected meta keys for OpenAI platform in tools/call response.\n */\nexport const EXPECTED_OPENAI_TOOL_CALL_META_KEYS = ['openai/html', 'openai/mimeType', 'openai/type'] as const;\n\n/**\n * Expected meta keys for ext-apps platform in tools/list response (SEP-1865).\n */\nexport const EXPECTED_EXTAPPS_TOOLS_LIST_META_KEYS = ['ui/resourceUri', 'ui/mimeType', 'ui/cdn', 'ui/type'] as const;\n\n/**\n * Expected meta keys for ext-apps platform in tools/call response (SEP-1865).\n */\nexport const EXPECTED_EXTAPPS_TOOL_CALL_META_KEYS = ['ui/html', 'ui/mimeType', 'ui/type'] as const;\n\n/**\n * Expected meta keys for FrontMCP platforms in tools/list response (Claude, Cursor, etc.).\n */\nexport const EXPECTED_FRONTMCP_TOOLS_LIST_META_KEYS = [\n 'frontmcp/outputTemplate',\n 'frontmcp/resultCanProduceWidget',\n 'ui/cdn',\n 'ui/type',\n] as const;\n\n/**\n * Expected meta keys for FrontMCP platforms in tools/call response (Claude, Cursor, etc.).\n */\nexport const EXPECTED_FRONTMCP_TOOL_CALL_META_KEYS = [\n 'frontmcp/html',\n 'frontmcp/mimeType',\n 'ui/html',\n 'ui/mimeType',\n] as const;\n"]}
|
package/src/expect.d.ts
CHANGED
|
@@ -17,29 +17,30 @@
|
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
19
|
import { expect as jestExpect } from '@jest/globals';
|
|
20
|
+
import type { Matchers } from 'expect';
|
|
20
21
|
import type { McpMatchers } from './matchers/matcher-types';
|
|
21
22
|
/**
|
|
22
23
|
* Extended Jest matchers interface that includes MCP matchers
|
|
23
24
|
*/
|
|
24
|
-
type McpExpectMatchers<R =
|
|
25
|
+
type McpExpectMatchers<R extends void | Promise<void>, T = unknown> = Matchers<R, T> & McpMatchers<R> & {
|
|
25
26
|
/**
|
|
26
27
|
* Inverts the matchers that follow
|
|
27
28
|
*/
|
|
28
|
-
not:
|
|
29
|
+
not: Matchers<R, T> & McpMatchers<R>;
|
|
29
30
|
/**
|
|
30
31
|
* Used to access matchers that are resolved asynchronously
|
|
31
32
|
*/
|
|
32
|
-
resolves:
|
|
33
|
+
resolves: Matchers<Promise<void>, T> & McpMatchers<Promise<void>>;
|
|
33
34
|
/**
|
|
34
35
|
* Used to access matchers that are rejected asynchronously
|
|
35
36
|
*/
|
|
36
|
-
rejects:
|
|
37
|
+
rejects: Matchers<Promise<void>, T> & McpMatchers<Promise<void>>;
|
|
37
38
|
};
|
|
38
39
|
/**
|
|
39
40
|
* Extended expect interface with MCP matchers
|
|
40
41
|
*/
|
|
41
42
|
interface McpExpect {
|
|
42
|
-
<T = unknown>(actual: T): McpExpectMatchers<T>;
|
|
43
|
+
<T = unknown>(actual: T): McpExpectMatchers<void, T>;
|
|
43
44
|
anything(): ReturnType<typeof jestExpect.anything>;
|
|
44
45
|
any(classType: unknown): ReturnType<typeof jestExpect.any>;
|
|
45
46
|
arrayContaining<E = unknown>(arr: readonly E[]): ReturnType<typeof jestExpect.arrayContaining>;
|
package/src/expect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expect.js","sourceRoot":"","sources":["../../src/expect.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;AAEH,2CAAqD;
|
|
1
|
+
{"version":3,"file":"expect.js","sourceRoot":"","sources":["../../src/expect.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;AAEH,2CAAqD;AAqDrD;;;;;;GAMG;AACU,QAAA,MAAM,GAAG,gBAAkC,CAAC","sourcesContent":["/**\n * @file expect.ts\n * @description Pre-typed expect export with MCP custom matchers\n *\n * This is the Playwright-style approach - instead of relying on global type\n * augmentation (which can be fragile across monorepos and path mappings),\n * we export a properly typed expect function that includes all MCP matchers.\n *\n * @example\n * ```typescript\n * import { test, expect } from '@frontmcp/testing';\n *\n * test('tools are available', async ({ mcp }) => {\n * const tools = await mcp.tools.list();\n * expect(tools).toContainTool('my-tool'); // Properly typed!\n * });\n * ```\n */\n\nimport { expect as jestExpect } from '@jest/globals';\nimport type { Matchers } from 'expect';\nimport type { McpMatchers } from './matchers/matcher-types';\n\n/**\n * Extended Jest matchers interface that includes MCP matchers\n */\ntype McpExpectMatchers<R extends void | Promise<void>, T = unknown> = Matchers<R, T> &\n McpMatchers<R> & {\n /**\n * Inverts the matchers that follow\n */\n not: Matchers<R, T> & McpMatchers<R>;\n\n /**\n * Used to access matchers that are resolved asynchronously\n */\n resolves: Matchers<Promise<void>, T> & McpMatchers<Promise<void>>;\n\n /**\n * Used to access matchers that are rejected asynchronously\n */\n rejects: Matchers<Promise<void>, T> & McpMatchers<Promise<void>>;\n };\n\n/**\n * Extended expect interface with MCP matchers\n */\ninterface McpExpect {\n <T = unknown>(actual: T): McpExpectMatchers<void, T>;\n\n // Asymmetric matchers\n anything(): ReturnType<typeof jestExpect.anything>;\n any(classType: unknown): ReturnType<typeof jestExpect.any>;\n arrayContaining<E = unknown>(arr: readonly E[]): ReturnType<typeof jestExpect.arrayContaining>;\n objectContaining<E = Record<string, unknown>>(obj: E): ReturnType<typeof jestExpect.objectContaining>;\n stringContaining(str: string): ReturnType<typeof jestExpect.stringContaining>;\n stringMatching(str: string | RegExp): ReturnType<typeof jestExpect.stringMatching>;\n\n // expect.not\n not: {\n arrayContaining<E = unknown>(arr: readonly E[]): ReturnType<typeof jestExpect.not.arrayContaining>;\n objectContaining<E = Record<string, unknown>>(obj: E): ReturnType<typeof jestExpect.not.objectContaining>;\n stringContaining(str: string): ReturnType<typeof jestExpect.not.stringContaining>;\n stringMatching(str: string | RegExp): ReturnType<typeof jestExpect.not.stringMatching>;\n };\n\n // Utilities\n extend(matchers: Record<string, unknown>): void;\n assertions(num: number): void;\n hasAssertions(): void;\n}\n\n/**\n * Pre-typed expect with MCP custom matchers included\n *\n * This approach (similar to Playwright's) provides type safety without\n * relying on global TypeScript namespace augmentation, which can be\n * problematic in monorepo setups with path mappings.\n */\nexport const expect = jestExpect as unknown as McpExpect;\n"]}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @description Type definitions for test fixtures
|
|
4
4
|
*/
|
|
5
5
|
import type { McpTestClient } from '../client/mcp-test-client';
|
|
6
|
+
import type { McpTestClientBuilder } from '../client/mcp-test-client.builder';
|
|
6
7
|
import type { JWK } from 'jose';
|
|
7
8
|
/**
|
|
8
9
|
* Configuration passed to test.use()
|
|
@@ -122,7 +123,25 @@ export interface ServerFixture {
|
|
|
122
123
|
createClient(options?: {
|
|
123
124
|
transport?: 'sse' | 'streamable-http';
|
|
124
125
|
token?: string;
|
|
126
|
+
clientInfo?: {
|
|
127
|
+
name: string;
|
|
128
|
+
version: string;
|
|
129
|
+
};
|
|
125
130
|
}): Promise<McpTestClient>;
|
|
131
|
+
/**
|
|
132
|
+
* Create a client builder for full customization.
|
|
133
|
+
* Use this when you need to set platform-specific capabilities.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const client = await server
|
|
138
|
+
* .createClientBuilder()
|
|
139
|
+
* .withTransport('streamable-http')
|
|
140
|
+
* .withPlatform('ext-apps') // Auto-sets clientInfo AND capabilities
|
|
141
|
+
* .buildAndConnect();
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
createClientBuilder(): McpTestClientBuilder;
|
|
126
145
|
/**
|
|
127
146
|
* Restart the server
|
|
128
147
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixture-types.js","sourceRoot":"","sources":["../../../src/fixtures/fixture-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * @file fixture-types.ts\n * @description Type definitions for test fixtures\n */\n\nimport type { McpTestClient } from '../client/mcp-test-client';\nimport type { JWK } from 'jose';\n\n// ═══════════════════════════════════════════════════════════════════\n// TEST CONFIGURATION\n// ═══════════════════════════════════════════════════════════════════\n\n/**\n * Configuration passed to test.use()\n */\nexport interface TestConfig {\n /** Server entry file path (e.g., './src/main.ts') */\n server?: string;\n /** Port to run server on (default: auto-select available port) */\n port?: number;\n /** Transport type (default: 'streamable-http') */\n transport?: 'sse' | 'streamable-http';\n /** Auth configuration for the server */\n auth?: {\n mode?: 'public' | 'orchestrated';\n type?: 'local' | 'remote';\n };\n /**\n * Enable public mode for the test client.\n * When true, no Authorization header is sent and anonymous token is not requested.\n * Use this for testing servers configured with `auth: { mode: 'public' }`.\n */\n publicMode?: boolean;\n /** Server log level */\n logLevel?: 'debug' | 'info' | 'warn' | 'error';\n /** Environment variables to pass to the server */\n env?: Record<string, string>;\n /** Startup timeout in ms (default: 30000) */\n startupTimeout?: number;\n /** Base URL for connecting to an external/already running server */\n baseUrl?: string;\n}\n\n// ═══════════════════════════════════════════════════════════════════\n// FIXTURE TYPES\n// ═══════════════════════════════════════════════════════════════════\n\n/**\n * Fixtures available in test functions\n */\nexport interface TestFixtures {\n /** Auto-connected MCP client */\n mcp: McpTestClient;\n /** Token factory for auth testing */\n auth: AuthFixture;\n /** Server control */\n server: ServerFixture;\n}\n\n/**\n * Auth fixture for creating and managing test tokens\n */\nexport interface AuthFixture {\n /**\n * Create a JWT token with the specified claims\n */\n createToken(options: {\n sub: string;\n scopes?: string[];\n email?: string;\n name?: string;\n claims?: Record<string, unknown>;\n expiresIn?: number;\n }): Promise<string>;\n\n /**\n * Create an expired token (for testing token expiration)\n */\n createExpiredToken(options: { sub: string }): Promise<string>;\n\n /**\n * Create a token with an invalid signature (for testing signature validation)\n */\n createInvalidToken(options: { sub: string }): string;\n\n /**\n * Pre-built test users with common permission sets\n */\n users: {\n admin: TestUser;\n user: TestUser;\n readOnly: TestUser;\n };\n\n /**\n * Get the public JWKS for verifying tokens\n */\n getJwks(): Promise<{ keys: JWK[] }>;\n\n /**\n * Get the issuer URL\n */\n getIssuer(): string;\n\n /**\n * Get the audience\n */\n getAudience(): string;\n}\n\n/**\n * Pre-defined test user\n */\nexport interface TestUser {\n sub: string;\n scopes: string[];\n email?: string;\n name?: string;\n}\n\n/**\n * Server fixture for controlling the test server\n */\nexport interface ServerFixture {\n /**\n * Server information\n */\n info: {\n baseUrl: string;\n port: number;\n pid?: number;\n };\n\n /**\n * Create an additional MCP client connected to this server\n */\n createClient(options?: {
|
|
1
|
+
{"version":3,"file":"fixture-types.js","sourceRoot":"","sources":["../../../src/fixtures/fixture-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * @file fixture-types.ts\n * @description Type definitions for test fixtures\n */\n\nimport type { McpTestClient } from '../client/mcp-test-client';\nimport type { McpTestClientBuilder } from '../client/mcp-test-client.builder';\nimport type { JWK } from 'jose';\n\n// ═══════════════════════════════════════════════════════════════════\n// TEST CONFIGURATION\n// ═══════════════════════════════════════════════════════════════════\n\n/**\n * Configuration passed to test.use()\n */\nexport interface TestConfig {\n /** Server entry file path (e.g., './src/main.ts') */\n server?: string;\n /** Port to run server on (default: auto-select available port) */\n port?: number;\n /** Transport type (default: 'streamable-http') */\n transport?: 'sse' | 'streamable-http';\n /** Auth configuration for the server */\n auth?: {\n mode?: 'public' | 'orchestrated';\n type?: 'local' | 'remote';\n };\n /**\n * Enable public mode for the test client.\n * When true, no Authorization header is sent and anonymous token is not requested.\n * Use this for testing servers configured with `auth: { mode: 'public' }`.\n */\n publicMode?: boolean;\n /** Server log level */\n logLevel?: 'debug' | 'info' | 'warn' | 'error';\n /** Environment variables to pass to the server */\n env?: Record<string, string>;\n /** Startup timeout in ms (default: 30000) */\n startupTimeout?: number;\n /** Base URL for connecting to an external/already running server */\n baseUrl?: string;\n}\n\n// ═══════════════════════════════════════════════════════════════════\n// FIXTURE TYPES\n// ═══════════════════════════════════════════════════════════════════\n\n/**\n * Fixtures available in test functions\n */\nexport interface TestFixtures {\n /** Auto-connected MCP client */\n mcp: McpTestClient;\n /** Token factory for auth testing */\n auth: AuthFixture;\n /** Server control */\n server: ServerFixture;\n}\n\n/**\n * Auth fixture for creating and managing test tokens\n */\nexport interface AuthFixture {\n /**\n * Create a JWT token with the specified claims\n */\n createToken(options: {\n sub: string;\n scopes?: string[];\n email?: string;\n name?: string;\n claims?: Record<string, unknown>;\n expiresIn?: number;\n }): Promise<string>;\n\n /**\n * Create an expired token (for testing token expiration)\n */\n createExpiredToken(options: { sub: string }): Promise<string>;\n\n /**\n * Create a token with an invalid signature (for testing signature validation)\n */\n createInvalidToken(options: { sub: string }): string;\n\n /**\n * Pre-built test users with common permission sets\n */\n users: {\n admin: TestUser;\n user: TestUser;\n readOnly: TestUser;\n };\n\n /**\n * Get the public JWKS for verifying tokens\n */\n getJwks(): Promise<{ keys: JWK[] }>;\n\n /**\n * Get the issuer URL\n */\n getIssuer(): string;\n\n /**\n * Get the audience\n */\n getAudience(): string;\n}\n\n/**\n * Pre-defined test user\n */\nexport interface TestUser {\n sub: string;\n scopes: string[];\n email?: string;\n name?: string;\n}\n\n/**\n * Server fixture for controlling the test server\n */\nexport interface ServerFixture {\n /**\n * Server information\n */\n info: {\n baseUrl: string;\n port: number;\n pid?: number;\n };\n\n /**\n * Create an additional MCP client connected to this server\n */\n createClient(options?: {\n transport?: 'sse' | 'streamable-http';\n token?: string;\n clientInfo?: { name: string; version: string };\n }): Promise<McpTestClient>;\n\n /**\n * Create a client builder for full customization.\n * Use this when you need to set platform-specific capabilities.\n *\n * @example\n * ```typescript\n * const client = await server\n * .createClientBuilder()\n * .withTransport('streamable-http')\n * .withPlatform('ext-apps') // Auto-sets clientInfo AND capabilities\n * .buildAndConnect();\n * ```\n */\n createClientBuilder(): McpTestClientBuilder;\n\n /**\n * Restart the server\n */\n restart(): Promise<void>;\n\n /**\n * Get captured server logs\n */\n getLogs(): string[];\n\n /**\n * Clear captured server logs\n */\n clearLogs(): void;\n}\n\n// ═══════════════════════════════════════════════════════════════════\n// TEST FUNCTION TYPE\n// ═══════════════════════════════════════════════════════════════════\n\n/**\n * Test function that receives fixtures\n */\nexport type TestFn = (fixtures: TestFixtures) => Promise<void> | void;\n\n/**\n * Enhanced test function with fixture support\n */\nexport interface TestWithFixtures {\n (name: string, fn: TestFn): void;\n\n /** Configure fixtures for this test file/suite */\n use(config: TestConfig): void;\n\n /** Create a describe block */\n describe: typeof describe;\n\n /** Run before all tests in the file */\n beforeAll: typeof beforeAll;\n\n /** Run before each test */\n beforeEach: typeof beforeEach;\n\n /** Run after each test */\n afterEach: typeof afterEach;\n\n /** Run after all tests in the file */\n afterAll: typeof afterAll;\n\n /** Skip a test */\n skip(name: string, fn: TestFn): void;\n\n /** Run only this test */\n only(name: string, fn: TestFn): void;\n\n /** Mark test as todo (not implemented) */\n todo(name: string): void;\n}\n"]}
|
|
@@ -30,8 +30,10 @@ declare function initializeSharedResources(): Promise<void>;
|
|
|
30
30
|
declare function createTestFixtures(): Promise<TestFixtures>;
|
|
31
31
|
/**
|
|
32
32
|
* Clean up fixtures after a single test
|
|
33
|
+
* @param fixtures - The test fixtures to clean up
|
|
34
|
+
* @param testFailed - Whether the test failed (to output server logs)
|
|
33
35
|
*/
|
|
34
|
-
declare function cleanupTestFixtures(fixtures: TestFixtures): Promise<void>;
|
|
36
|
+
declare function cleanupTestFixtures(fixtures: TestFixtures, _testFailed?: boolean): Promise<void>;
|
|
35
37
|
/**
|
|
36
38
|
* Clean up shared resources after all tests in a file
|
|
37
39
|
*/
|
|
@@ -27,6 +27,7 @@ exports.cleanupTestFixtures = cleanupTestFixtures;
|
|
|
27
27
|
exports.initializeSharedResources = initializeSharedResources;
|
|
28
28
|
exports.cleanupSharedResources = cleanupSharedResources;
|
|
29
29
|
const mcp_test_client_1 = require("../client/mcp-test-client");
|
|
30
|
+
const mcp_test_client_builder_1 = require("../client/mcp-test-client.builder");
|
|
30
31
|
const token_factory_1 = require("../auth/token-factory");
|
|
31
32
|
const test_server_1 = require("../server/test-server");
|
|
32
33
|
// ═══════════════════════════════════════════════════════════════════
|
|
@@ -98,8 +99,10 @@ async function createTestFixtures() {
|
|
|
98
99
|
}
|
|
99
100
|
/**
|
|
100
101
|
* Clean up fixtures after a single test
|
|
102
|
+
* @param fixtures - The test fixtures to clean up
|
|
103
|
+
* @param testFailed - Whether the test failed (to output server logs)
|
|
101
104
|
*/
|
|
102
|
-
async function cleanupTestFixtures(fixtures) {
|
|
105
|
+
async function cleanupTestFixtures(fixtures, _testFailed = false) {
|
|
103
106
|
// Disconnect client
|
|
104
107
|
if (fixtures.mcp.isConnected()) {
|
|
105
108
|
await fixtures.mcp.disconnect();
|
|
@@ -174,12 +177,25 @@ function createServerFixture(server) {
|
|
|
174
177
|
return {
|
|
175
178
|
info: server.info,
|
|
176
179
|
createClient: async (opts) => {
|
|
180
|
+
// Inherit publicMode from current config when creating additional clients
|
|
181
|
+
// This ensures all clients connect to a public server correctly
|
|
177
182
|
return mcp_test_client_1.McpTestClient.create({
|
|
178
183
|
baseUrl: server.info.baseUrl,
|
|
179
184
|
transport: opts?.transport ?? 'streamable-http',
|
|
180
185
|
auth: opts?.token ? { token: opts.token } : undefined,
|
|
186
|
+
clientInfo: opts?.clientInfo,
|
|
187
|
+
publicMode: currentConfig.publicMode,
|
|
181
188
|
}).buildAndConnect();
|
|
182
189
|
},
|
|
190
|
+
createClientBuilder: () => {
|
|
191
|
+
// Return a pre-configured builder with the server's base URL and publicMode
|
|
192
|
+
// This allows full customization including platform-specific capabilities
|
|
193
|
+
const builder = new mcp_test_client_builder_1.McpTestClientBuilder({
|
|
194
|
+
baseUrl: server.info.baseUrl,
|
|
195
|
+
publicMode: currentConfig.publicMode,
|
|
196
|
+
});
|
|
197
|
+
return builder;
|
|
198
|
+
},
|
|
183
199
|
restart: () => server.restart(),
|
|
184
200
|
getLogs: () => server.getLogs(),
|
|
185
201
|
clearLogs: () => server.clearLogs(),
|
|
@@ -205,11 +221,16 @@ function resolveServerCommand(server) {
|
|
|
205
221
|
function testWithFixtures(name, fn) {
|
|
206
222
|
it(name, async () => {
|
|
207
223
|
const fixtures = await createTestFixtures();
|
|
224
|
+
let testFailed = false;
|
|
208
225
|
try {
|
|
209
226
|
await fn(fixtures);
|
|
210
227
|
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
testFailed = true;
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
211
232
|
finally {
|
|
212
|
-
await cleanupTestFixtures(fixtures);
|
|
233
|
+
await cleanupTestFixtures(fixtures, testFailed);
|
|
213
234
|
}
|
|
214
235
|
});
|
|
215
236
|
}
|
|
@@ -231,11 +252,16 @@ function use(config) {
|
|
|
231
252
|
function skip(name, fn) {
|
|
232
253
|
it.skip(name, async () => {
|
|
233
254
|
const fixtures = await createTestFixtures();
|
|
255
|
+
let testFailed = false;
|
|
234
256
|
try {
|
|
235
257
|
await fn(fixtures);
|
|
236
258
|
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
testFailed = true;
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
237
263
|
finally {
|
|
238
|
-
await cleanupTestFixtures(fixtures);
|
|
264
|
+
await cleanupTestFixtures(fixtures, testFailed);
|
|
239
265
|
}
|
|
240
266
|
});
|
|
241
267
|
}
|
|
@@ -245,11 +271,16 @@ function skip(name, fn) {
|
|
|
245
271
|
function only(name, fn) {
|
|
246
272
|
it.only(name, async () => {
|
|
247
273
|
const fixtures = await createTestFixtures();
|
|
274
|
+
let testFailed = false;
|
|
248
275
|
try {
|
|
249
276
|
await fn(fixtures);
|
|
250
277
|
}
|
|
278
|
+
catch (error) {
|
|
279
|
+
testFailed = true;
|
|
280
|
+
throw error;
|
|
281
|
+
}
|
|
251
282
|
finally {
|
|
252
|
-
await cleanupTestFixtures(fixtures);
|
|
283
|
+
await cleanupTestFixtures(fixtures, testFailed);
|
|
253
284
|
}
|
|
254
285
|
});
|
|
255
286
|
}
|