@frontmcp/testing 1.9.6 → 1.9.7

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 CHANGED
@@ -1,34 +1,34 @@
1
1
  # @frontmcp/testing
2
2
 
3
- E2E testing framework for FrontMCP servers.
3
+ End-to-end tests for FrontMCP servers. It starts your server, gives each test `mcp`, an MCP client connected to it, and adds matchers like `toBeSuccessful()` and `toContainTool()` to `expect`. Tests run under Jest, with `frontmcp test` or your own Jest configuration. It also has the pieces to build tests of your own: a JSON Web Token (JWT) factory, mock OAuth and API servers, HTTP mocking and request interceptors.
4
4
 
5
- [![NPM](https://img.shields.io/npm/v/@frontmcp/testing.svg)](https://www.npmjs.com/package/@frontmcp/testing)
5
+ [![npm](https://img.shields.io/npm/v/@frontmcp/testing.svg)](https://www.npmjs.com/package/@frontmcp/testing) [![License](https://img.shields.io/npm/l/@frontmcp/testing.svg)](https://github.com/agentfront/frontmcp/blob/main/LICENSE)
6
6
 
7
7
  ## Install
8
8
 
9
9
  ```bash
10
- npm install -D @frontmcp/testing
10
+ npm install -D @frontmcp/testing jest tsx
11
11
  ```
12
12
 
13
- Peer dependencies: `@frontmcp/sdk`, `jest`, `@jest/globals`. Optional: `@playwright/test` (for browser OAuth flow testing).
13
+ Requires Node.js 24 or later, and `@frontmcp/sdk` in the project (a peer dependency, as is `@frontmcp/lazy-zod`, which comes with the SDK). `jest` (29 or 30) runs the tests, and `@jest/globals`, which comes with it, provides `expect`; both are optional peers so that the token factory and mock servers work outside Jest. The library starts your server with `tsx`. `@swc/jest`, which compiles the tests, is installed with the package.
14
14
 
15
- ## Quick Start
15
+ ## Usage
16
16
 
17
17
  ```ts
18
+ // e2e/tickets.e2e.spec.ts
18
19
  import { expect, test } from '@frontmcp/testing';
19
20
 
20
- import MyServer from './src/main';
21
-
22
- test.use({ server: MyServer });
21
+ test.use({ server: './src/main.ts' });
23
22
 
24
23
  test('server exposes tools', async ({ mcp }) => {
25
24
  const tools = await mcp.tools.list();
26
- expect(tools).toContainTool('my-tool');
25
+ expect(tools).toContainTool('search_tickets');
27
26
  });
28
27
 
29
28
  test('tool execution works', async ({ mcp }) => {
30
- const result = await mcp.tools.call('my-tool', { input: 'test' });
29
+ const result = await mcp.tools.call('search_tickets', { query: 'log' });
31
30
  expect(result).toBeSuccessful();
31
+ expect(result.json()).toEqual({ tickets: [{ id: 'T-1', title: 'Cannot log in' }] });
32
32
  });
33
33
  ```
34
34
 
@@ -36,70 +36,80 @@ test('tool execution works', async ({ mcp }) => {
36
36
  npx frontmcp test
37
37
  ```
38
38
 
39
- The library handles server startup, MCP client connection, test execution, and cleanup.
39
+ `frontmcp test` (from the [`frontmcp`](https://www.npmjs.com/package/frontmcp) CLI) runs `src/**/*.spec.ts`, `__tests__/**/*.spec.ts` and `e2e/**/*.e2e.spec.ts` with a Jest configuration it generates. With a `jest.config.*` of your own, use `preset: '@frontmcp/testing'` for the same settings. The server starts when the first test that needs it runs, and tests with the same `test.use()` options share it.
40
40
 
41
41
  ## Fixtures
42
42
 
43
- | Fixture | Description |
44
- | -------- | ----------------------------------------------------------------------------------------------------- |
45
- | `mcp` | Auto-connected MCP client — tools, resources, prompts, raw protocol, notifications, logs |
46
- | `server` | Server control — `createClient()`, `restart()`, `onHook()`, `getLogs()` |
47
- | `auth` | Token factory — `createToken()`, `createExpiredToken()`, `createInvalidToken()`, pre-built test users |
43
+ | Fixture | Description |
44
+ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
+ | `mcp` | A client connected to the server, new for each test: `tools`, `resources`, `prompts`, raw requests, notifications and logs |
46
+ | `server` | The running server: `info` (`baseUrl`, `port`, `pid`), `createClient()`, `createClientBuilder()`, `restart()`, `getLogs()`, `clearLogs()` |
47
+ | `auth` | Makes JWTs: `createToken()`, `createExpiredToken()`, `createInvalidToken()`, `users` (`admin`, `user`, `readOnly`), `getJwks()`, `getIssuer()`, `getAudience()` |
48
+
49
+ `test.beforeEach()` and `test.afterEach()` receive the same fixtures when their callback takes a parameter.
50
+
51
+ ## Matchers
48
52
 
49
- ## Custom Matchers
53
+ **Tools**: `toContainTool`, `toBeSuccessful`, `toBeError`, `toHaveTextContent`, `toHaveImageContent`, `toHaveResourceContent`
50
54
 
51
- **Tools** — `toContainTool`, `toBeSuccessful`, `toBeError`, `toHaveTextContent`, `toHaveImageContent`, `toHaveResourceContent`
55
+ **Resources**: `toContainResource`, `toContainResourceTemplate`, `toHaveMimeType`
52
56
 
53
- **Resources** — `toContainResource`, `toContainResourceTemplate`, `toHaveMimeType`
57
+ **Prompts**: `toContainPrompt`, `toHaveMessages`
54
58
 
55
- **Prompts** — `toContainPrompt`, `toHaveMessages`, `toHaveRole`, `toContainText`
59
+ **Protocol**: `toBeValidJsonRpc`, `toHaveResult`, `toHaveError`, `toHaveErrorCode`
56
60
 
57
- **Protocol** — `toBeValidJsonRpc`, `toHaveResult`, `toHaveError`, `toHaveErrorCode`
61
+ **Tool UI**: `toHaveRenderedHtml`, `toContainHtmlElement`, `toContainBoundValue`, `toBeXssSafe`, `toHaveWidgetMetadata`, `toHaveCssClass`, `toNotContainRawContent`, `toHaveProperHtmlStructure`
58
62
 
59
- **Tool UI** — `toHaveRenderedHtml`, `toContainHtmlElement`, `toContainBoundValue`, `toBeXssSafe`, `toHaveWidgetMetadata`, `toHaveCssClass`, `toNotContainRawContent`, `toHaveProperHtmlStructure`
63
+ Use them through the `expect` this package exports, which is Jest's `expect` with these matchers typed. `frontmcp test` and the preset also register them on Jest's global `expect`, through `@frontmcp/testing/setup`, which you can add to `setupFilesAfterEnv` yourself.
60
64
 
61
65
  ## Configuration
62
66
 
63
67
  ```ts
68
+ import { test } from '@frontmcp/testing';
69
+
64
70
  test.use({
65
- server: MyServer,
66
- port: 3003, // default: auto
71
+ server: './src/main.ts', // the entry file, run with tsx
72
+ port: 3003, // default: a free port
67
73
  transport: 'streamable-http', // or 'sse'
68
- auth: { mode: 'public' },
74
+ entryPath: '/mcp', // if the server sets http.entryPath
75
+ publicMode: true, // send no Authorization header, for auth: { mode: 'public' }
69
76
  logLevel: 'debug',
70
77
  env: { API_KEY: 'test' },
78
+ startupTimeout: 30_000,
71
79
  });
72
80
  ```
73
81
 
82
+ Call `test.use()` at the top of a file to configure every test in it, or inside `test.describe()` to configure that block, which then gets a server of its own. `baseUrl` tests a server that's already running instead of starting one.
83
+
84
+ ## Other exports
85
+
86
+ | Export | Use it to |
87
+ | ------------------------------------------------------- | ----------------------------------------------------------------------------------- |
88
+ | `McpTestClient`, `TestServer` | Start a server and connect a client yourself, without the fixtures |
89
+ | `TestTokenFactory`, `MockOAuthServer`, `MockCimdServer` | Sign tokens, stand in for an OAuth provider, and serve client ID metadata documents |
90
+ | `MockAPIServer`, `httpMock`, `httpResponse` | Answer the HTTP calls your tools make |
91
+ | `mockResponse`, `interceptors` | Mock or change MCP requests on the `mcp` client |
92
+ | `perfTest`, `LeakDetector`, `MetricsCollector` | Measure memory and time, and find leaks |
93
+
74
94
  ## Docs
75
95
 
76
- | Topic | Link |
77
- | ------------------ | --------------------------------- |
78
- | Getting started | [Testing Overview][docs-overview] |
79
- | Testing tools | [Tools][docs-tools] |
80
- | Testing Tool UI | [Tool UI][docs-tool-ui] |
81
- | Testing resources | [Resources][docs-resources] |
82
- | Testing prompts | [Prompts][docs-prompts] |
83
- | Testing auth | [Authentication][docs-auth] |
84
- | Testing transports | [Transports][docs-transports] |
85
- | HTTP mocking | [HTTP Mocking][docs-mocking] |
96
+ - [`@frontmcp/testing`](https://frontmcp.dev/reference/testing): `test`, the `mcp` client, result wrappers and running tests
97
+ - [Fixtures](https://frontmcp.dev/reference/testing/fixtures): every `test.use()` option, and the `mcp`, `server` and `auth` fixtures
98
+ - [Matchers](https://frontmcp.dev/reference/testing/matchers): what each matcher checks
99
+ - [Interceptors and HTTP mocking](https://frontmcp.dev/reference/testing/interceptors): `mcp.mock`, `mcp.intercept`, `MockAPIServer` and `httpMock`
100
+ - [Testing authentication](https://frontmcp.dev/reference/testing/auth): tokens, mock OAuth servers and signing in
101
+ - [Testing your server](https://frontmcp.dev/learn/testing-your-server): a guided introduction
86
102
 
87
- ## Related Packages
103
+ ## Related packages
88
104
 
89
- - [`@frontmcp/sdk`](../sdk) — core framework
90
- - [`@frontmcp/ui`](../ui) — UI components tested with `toHaveRenderedHtml` and friends
105
+ - [`@frontmcp/sdk`](https://www.npmjs.com/package/@frontmcp/sdk): the framework the servers under test are built with
106
+ - [`frontmcp`](https://www.npmjs.com/package/frontmcp): the CLI, whose `frontmcp test` runs your tests
107
+ - [`@frontmcp/observability`](https://www.npmjs.com/package/@frontmcp/observability): has `createTestTracer()` to check the spans a test records
91
108
 
92
- ## License
109
+ ## Contributing
93
110
 
94
- Apache-2.0 — see [LICENSE](../../LICENSE).
111
+ Source: [`libs/testing`](https://github.com/agentfront/frontmcp/tree/main/libs/testing). Issues and pull requests are welcome; see [CONTRIBUTING.md](https://github.com/agentfront/frontmcp/blob/main/CONTRIBUTING.md).
95
112
 
96
- <!-- links -->
113
+ ## License
97
114
 
98
- [docs-overview]: https://frontmcp.dev/reference/testing
99
- [docs-tools]: https://frontmcp.dev/reference/testing
100
- [docs-tool-ui]: https://frontmcp.dev/reference/testing
101
- [docs-resources]: https://frontmcp.dev/reference/testing
102
- [docs-prompts]: https://frontmcp.dev/reference/testing
103
- [docs-auth]: https://frontmcp.dev/reference/testing/auth
104
- [docs-transports]: https://frontmcp.dev/reference/testing
105
- [docs-mocking]: https://frontmcp.dev/reference/testing/interceptors#httpmock
115
+ Apache-2.0. See [LICENSE](https://github.com/agentfront/frontmcp/blob/main/LICENSE).
package/esm/package.json CHANGED
@@ -1,25 +1,25 @@
1
1
  {
2
2
  "name": "@frontmcp/testing",
3
- "version": "1.9.6",
4
- "description": "E2E testing framework for FrontMCP servers - MCP client, auth mocks, Playwright integration",
3
+ "version": "1.9.7",
4
+ "description": "End-to-end testing for FrontMCP servers: Jest fixtures with a connected MCP client, MCP matchers, JWT and OAuth mocks, and HTTP mocking",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "homepage": "https://frontmcp.dev/reference/testing",
7
7
  "license": "Apache-2.0",
8
8
  "keywords": [
9
+ "frontmcp",
9
10
  "mcp",
11
+ "model-context-protocol",
10
12
  "testing",
11
13
  "e2e",
12
14
  "integration-testing",
15
+ "jest",
13
16
  "mcp-client",
14
- "playwright",
15
- "agentfront",
16
- "frontmcp",
17
- "framework",
18
- "typescript"
17
+ "agentfront"
19
18
  ],
20
19
  "repository": {
21
20
  "type": "git",
22
- "url": "git+https://github.com/agentfront/frontmcp.git"
21
+ "url": "git+https://github.com/agentfront/frontmcp.git",
22
+ "directory": "libs/testing"
23
23
  },
24
24
  "bugs": {
25
25
  "url": "https://github.com/agentfront/frontmcp/issues"
@@ -87,9 +87,9 @@
87
87
  "./esm": null
88
88
  },
89
89
  "peerDependencies": {
90
- "@frontmcp/lazy-zod": "1.9.6",
91
- "@frontmcp/sdk": "1.9.6",
92
- "@frontmcp/ui": "1.9.6",
90
+ "@frontmcp/lazy-zod": "1.9.7",
91
+ "@frontmcp/sdk": "1.9.7",
92
+ "@frontmcp/ui": "1.9.7",
93
93
  "@jest/globals": "^29.0.0 || ^30.0.0",
94
94
  "@playwright/test": "^1.40.0",
95
95
  "jest": "^29.0.0 || ^30.0.0"
@@ -112,8 +112,8 @@
112
112
  "node": ">=24.0.0"
113
113
  },
114
114
  "dependencies": {
115
- "@frontmcp/protocol": "1.9.6",
116
- "@frontmcp/utils": "1.9.6",
115
+ "@frontmcp/protocol": "1.9.7",
116
+ "@frontmcp/utils": "1.9.7",
117
117
  "@swc/core": "~1.15.41",
118
118
  "@swc/jest": "~0.2.38",
119
119
  "jose": "^6.0.11",
@@ -2,19 +2,25 @@ var __frontmcpModule = typeof process !== "undefined" && typeof process.getBuilt
2
2
  const require = __frontmcpModule ? __frontmcpModule.createRequire(import.meta.url || 'file:///') : undefined;
3
3
  // __frontmcpCreateRequire
4
4
  // libs/testing/src/playwright/index.ts
5
+ var PLAYWRIGHT_NOT_IMPLEMENTED_MESSAGE = "@frontmcp/testing/playwright is not implemented. For browser tests, use `test` and `expect` from `@playwright/test` against a server started with `TestServer.start()` from `@frontmcp/testing`. For OAuth flows without a browser, use `MockOAuthServer` and `TestTokenFactory` from `@frontmcp/testing`.";
6
+ function notImplemented() {
7
+ throw new Error(PLAYWRIGHT_NOT_IMPLEMENTED_MESSAGE);
8
+ }
9
+ function notImplementedApi(target) {
10
+ return new Proxy(target, {
11
+ apply: notImplemented,
12
+ get: (api, property) => typeof property === "string" && !(property in api) ? notImplemented() : Reflect.get(api, property)
13
+ });
14
+ }
5
15
  var playwrightIntegration = {
6
16
  version: "0.4.0",
7
17
  status: "planned",
8
- description: "Playwright integration for OAuth flow testing - coming in a future release"
9
- };
10
- function test(_name, _fn) {
11
- throw new Error(
12
- "Playwright integration not yet implemented. Use @frontmcp/testing for non-browser tests, or wait for a future release that includes playwright support."
13
- );
14
- }
15
- var expect = {
16
- notImplemented: true
18
+ description: "Playwright integration for OAuth flow testing - not implemented"
17
19
  };
20
+ var test = notImplementedApi((_name, _fn) => notImplemented());
21
+ var expect = notImplementedApi(
22
+ Object.assign(() => notImplemented(), { notImplemented: true })
23
+ );
18
24
  export {
19
25
  expect,
20
26
  playwrightIntegration,
package/package.json CHANGED
@@ -1,25 +1,25 @@
1
1
  {
2
2
  "name": "@frontmcp/testing",
3
- "version": "1.9.6",
4
- "description": "E2E testing framework for FrontMCP servers - MCP client, auth mocks, Playwright integration",
3
+ "version": "1.9.7",
4
+ "description": "End-to-end testing for FrontMCP servers: Jest fixtures with a connected MCP client, MCP matchers, JWT and OAuth mocks, and HTTP mocking",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "homepage": "https://frontmcp.dev/reference/testing",
7
7
  "license": "Apache-2.0",
8
8
  "keywords": [
9
+ "frontmcp",
9
10
  "mcp",
11
+ "model-context-protocol",
10
12
  "testing",
11
13
  "e2e",
12
14
  "integration-testing",
15
+ "jest",
13
16
  "mcp-client",
14
- "playwright",
15
- "agentfront",
16
- "frontmcp",
17
- "framework",
18
- "typescript"
17
+ "agentfront"
19
18
  ],
20
19
  "repository": {
21
20
  "type": "git",
22
- "url": "git+https://github.com/agentfront/frontmcp.git"
21
+ "url": "git+https://github.com/agentfront/frontmcp.git",
22
+ "directory": "libs/testing"
23
23
  },
24
24
  "bugs": {
25
25
  "url": "https://github.com/agentfront/frontmcp/issues"
@@ -87,9 +87,9 @@
87
87
  "./esm": null
88
88
  },
89
89
  "peerDependencies": {
90
- "@frontmcp/lazy-zod": "1.9.6",
91
- "@frontmcp/sdk": "1.9.6",
92
- "@frontmcp/ui": "1.9.6",
90
+ "@frontmcp/lazy-zod": "1.9.7",
91
+ "@frontmcp/sdk": "1.9.7",
92
+ "@frontmcp/ui": "1.9.7",
93
93
  "@jest/globals": "^29.0.0 || ^30.0.0",
94
94
  "@playwright/test": "^1.40.0",
95
95
  "jest": "^29.0.0 || ^30.0.0"
@@ -112,8 +112,8 @@
112
112
  "node": ">=24.0.0"
113
113
  },
114
114
  "dependencies": {
115
- "@frontmcp/protocol": "1.9.6",
116
- "@frontmcp/utils": "1.9.6",
115
+ "@frontmcp/protocol": "1.9.7",
116
+ "@frontmcp/utils": "1.9.7",
117
117
  "@swc/core": "~1.15.41",
118
118
  "@swc/jest": "~0.2.38",
119
119
  "jose": "^6.0.11",
@@ -1,38 +1,20 @@
1
1
  /**
2
2
  * @file playwright/index.ts
3
- * @description Playwright integration for OAuth flow testing (Future Phase)
3
+ * @description Not implemented: a Playwright integration for OAuth flow testing is planned.
4
4
  *
5
- * This module will provide Playwright-based testing utilities for:
6
- * - OAuth consent flow testing
7
- * - Login page interactions
8
- * - Browser-based authentication flows
9
- *
10
- * @example
11
- * ```typescript
12
- * import { test, expect } from '@frontmcp/testing/playwright';
13
- * import MyServer from './src/main';
14
- *
15
- * test.describe('OAuth Flow', () => {
16
- * test.use({
17
- * server: MyServer,
18
- * auth: { mode: 'local' }
19
- * });
20
- *
21
- * test('completes OAuth flow', async ({ page, oauth }) => {
22
- * const { authorizeUrl } = await oauth.startFlow({ ... });
23
- * await page.goto(authorizeUrl);
24
- * // Test login and consent pages
25
- * });
26
- * });
27
- * ```
5
+ * `test` and `expect` from this entry point throw when called or used (`test.describe`, `test.use`,
6
+ * `expect(value)`), with a message naming what to use instead:
7
+ * - Browser tests: `test` and `expect` from `@playwright/test`, against a server started with
8
+ * `TestServer.start()` from `@frontmcp/testing`.
9
+ * - OAuth flows without a browser: `MockOAuthServer` and `TestTokenFactory` from `@frontmcp/testing`.
28
10
  */
29
11
  export declare const playwrightIntegration: {
30
12
  version: string;
31
13
  status: string;
32
14
  description: string;
33
15
  };
34
- export declare function test(_name: string, _fn: () => Promise<void>): void;
35
- export declare const expect: {
36
- notImplemented: boolean;
16
+ export declare const test: (_name: string, _fn: () => Promise<void>) => void;
17
+ export declare const expect: (() => never) & {
18
+ notImplemented: true;
37
19
  };
38
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/playwright/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,eAAO,MAAM,qBAAqB;;;;CAIjC,CAAC;AAGF,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAMlE;AAGD,eAAO,MAAM,MAAM;;CAElB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/playwright/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAoBH,eAAO,MAAM,qBAAqB;;;;CAIjC,CAAC;AAEF,eAAO,MAAM,IAAI,UAA6B,MAAM,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,KAAG,IAAyB,CAAC;AAE3G,eAAO,MAAM,MAAM,SACC,KAAK;;CACxB,CAAC"}
@@ -25,19 +25,25 @@ __export(playwright_exports, {
25
25
  test: () => test
26
26
  });
27
27
  module.exports = __toCommonJS(playwright_exports);
28
+ var PLAYWRIGHT_NOT_IMPLEMENTED_MESSAGE = "@frontmcp/testing/playwright is not implemented. For browser tests, use `test` and `expect` from `@playwright/test` against a server started with `TestServer.start()` from `@frontmcp/testing`. For OAuth flows without a browser, use `MockOAuthServer` and `TestTokenFactory` from `@frontmcp/testing`.";
29
+ function notImplemented() {
30
+ throw new Error(PLAYWRIGHT_NOT_IMPLEMENTED_MESSAGE);
31
+ }
32
+ function notImplementedApi(target) {
33
+ return new Proxy(target, {
34
+ apply: notImplemented,
35
+ get: (api, property) => typeof property === "string" && !(property in api) ? notImplemented() : Reflect.get(api, property)
36
+ });
37
+ }
28
38
  var playwrightIntegration = {
29
39
  version: "0.4.0",
30
40
  status: "planned",
31
- description: "Playwright integration for OAuth flow testing - coming in a future release"
32
- };
33
- function test(_name, _fn) {
34
- throw new Error(
35
- "Playwright integration not yet implemented. Use @frontmcp/testing for non-browser tests, or wait for a future release that includes playwright support."
36
- );
37
- }
38
- var expect = {
39
- notImplemented: true
41
+ description: "Playwright integration for OAuth flow testing - not implemented"
40
42
  };
43
+ var test = notImplementedApi((_name, _fn) => notImplemented());
44
+ var expect = notImplementedApi(
45
+ Object.assign(() => notImplemented(), { notImplemented: true })
46
+ );
41
47
  // Annotate the CommonJS export names for ESM import in node:
42
48
  0 && (module.exports = {
43
49
  expect,