Skip to content

Commit 51bbc31

Browse files
authored
test: update fetchMock routing (#31)
1 parent 55e3360 commit 51bbc31

File tree

4 files changed

+298
-128
lines changed

4 files changed

+298
-128
lines changed

tests/__snapshots__/stdioTransport.test.ts.snap

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
22

3-
exports[`External URLs should fetch a document 1`] = `
4-
[
5-
"# Example Fixture",
6-
"This is a local offline fixture used by the MCP external URLs test.",
7-
"It includes the token PatternFly to satisfy test assertions.",
8-
]
9-
`;
10-
113
exports[`Hosted mode, --docs-host should read llms-files and includes expected tokens 1`] = `
124
[
135
"# @patternfly/react-core 6.0.0",
@@ -289,19 +281,6 @@ exports[`Logging should allow setting logging options, stderr 1`] = `
289281
]
290282
`;
291283

292-
exports[`Logging should allow setting logging options, verbose 1`] = `
293-
[
294-
"[INFO]: Registered tool: usePatternFlyDocs
295-
",
296-
"[INFO]: Registered tool: fetchDocs
297-
",
298-
"[INFO]: Registered tool: componentSchemas
299-
",
300-
"[INFO]: PatternFly MCP server running on stdio
301-
",
302-
]
303-
`;
304-
305284
exports[`Logging should allow setting logging options, with log level filtering 1`] = `[]`;
306285

307286
exports[`Logging should allow setting logging options, with mcp protocol 1`] = `
@@ -425,6 +404,30 @@ You can find documentation on PatternFly's components at [PatternFly All compone
425404
"
426405
`;
427406

407+
exports[`PatternFly MCP, STDIO should concatenate headers and separator with two remote files 1`] = `
408+
"# Documentation from http://127.0.0.1:5010/notARealPath/README.md
409+
410+
# PatternFly Development Rules
411+
This is a generated offline fixture used by the MCP external URLs test.
412+
413+
Essential rules and guidelines working with PatternFly applications.
414+
415+
## Quick Navigation
416+
417+
### 🚀 Setup & Environment
418+
- **Setup Rules** - Project initialization requirements
419+
- **Quick Start** - Essential setup steps
420+
- **Environment Rules** - Development configuration
421+
422+
---
423+
424+
# Documentation from http://127.0.0.1:5010/notARealPath/AboutModal.md
425+
426+
# Test Document
427+
428+
This is a test document for mocking remote HTTP requests."
429+
`;
430+
428431
exports[`PatternFly MCP, STDIO should expose expected tools and stable shape 1`] = `
429432
{
430433
"toolNames": [

tests/stdioTransport.test.ts

Lines changed: 96 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,80 @@
11
/**
22
* Requires: npm run build prior to running Jest.
33
*/
4-
import { startServer, type StdioTransportClient } from './utils/stdioTransportClient';
5-
import { loadFixture } from './utils/fixtures';
4+
import {
5+
startServer,
6+
type StdioTransportClient,
7+
type RpcRequest
8+
} from './utils/stdioTransportClient';
69
import { setupFetchMock } from './utils/fetchMock';
710

811
describe('PatternFly MCP, STDIO', () => {
9-
let client: StdioTransportClient;
12+
let FETCH_MOCK: Awaited<ReturnType<typeof setupFetchMock>> | undefined;
13+
let CLIENT: StdioTransportClient;
14+
// We're unable to mock fetch for stdio since it runs in a separate process, so we run a server and use that path for mocking external URLs.
15+
let URL_MOCK: string;
1016

11-
beforeEach(async () => {
12-
client = await startServer();
17+
beforeAll(async () => {
18+
FETCH_MOCK = await setupFetchMock({
19+
port: 5010,
20+
routes: [
21+
{
22+
url: /\/README\.md$/,
23+
// url: '/notARealPath/README.md',
24+
status: 200,
25+
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
26+
body: `# PatternFly Development Rules
27+
This is a generated offline fixture used by the MCP external URLs test.
28+
29+
Essential rules and guidelines working with PatternFly applications.
30+
31+
## Quick Navigation
32+
33+
### 🚀 Setup & Environment
34+
- **Setup Rules** - Project initialization requirements
35+
- **Quick Start** - Essential setup steps
36+
- **Environment Rules** - Development configuration`
37+
},
38+
{
39+
url: /.*\.md$/,
40+
// url: '/notARealPath/AboutModal.md',
41+
status: 200,
42+
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
43+
body: '# Test Document\n\nThis is a test document for mocking remote HTTP requests.'
44+
}
45+
]
46+
});
47+
48+
URL_MOCK = `${FETCH_MOCK?.fixture?.baseUrl}/`;
49+
CLIENT = await startServer();
50+
});
51+
52+
afterAll(async () => {
53+
if (CLIENT) {
54+
// You may still receive jest warnings about a running process, but clean up case we forget at the test level.
55+
await CLIENT.close();
56+
}
57+
58+
if (FETCH_MOCK) {
59+
await FETCH_MOCK.cleanup();
60+
}
1361
});
1462

15-
afterEach(async () => client.stop());
63+
it('should expose expected tools and stable shape', async () => {
64+
const response = await CLIENT.send({
65+
method: 'tools/list',
66+
params: {}
67+
});
68+
const tools = response?.result?.tools || [];
69+
const toolNames = tools.map((tool: any) => tool.name).sort();
70+
71+
expect({ toolNames }).toMatchSnapshot();
72+
});
1673

1774
it('should concatenate headers and separator with two local files', async () => {
1875
const req = {
76+
jsonrpc: '2.0',
77+
id: 1,
1978
method: 'tools/call',
2079
params: {
2180
name: 'usePatternFlyDocs',
@@ -26,33 +85,48 @@ describe('PatternFly MCP, STDIO', () => {
2685
]
2786
}
2887
}
29-
};
88+
} as RpcRequest;
3089

31-
const response = await client.send(req);
90+
const response = await CLIENT?.send(req);
3291
const text = response?.result?.content?.[0]?.text || '';
3392

3493
expect(text.startsWith('# Documentation from')).toBe(true);
3594
expect(text).toMatchSnapshot();
3695
});
3796

38-
it('should expose expected tools and stable shape', async () => {
39-
const response = await client.send({ method: 'tools/list' });
40-
const tools = response?.result?.tools || [];
41-
const toolNames = tools.map((tool: any) => tool.name).sort();
97+
it('should concatenate headers and separator with two remote files', async () => {
98+
const req = {
99+
jsonrpc: '2.0',
100+
id: 1,
101+
method: 'tools/call',
102+
params: {
103+
name: 'fetchDocs',
104+
arguments: {
105+
urlList: [
106+
// URL_MOCK
107+
`${URL_MOCK}notARealPath/README.md`,
108+
`${URL_MOCK}notARealPath/AboutModal.md`
109+
]
110+
}
111+
}
112+
} as RpcRequest;
42113

43-
expect(toolNames).toEqual(expect.arrayContaining(['usePatternFlyDocs', 'fetchDocs']));
44-
expect({ toolNames }).toMatchSnapshot();
114+
const response = await CLIENT.send(req, { timeoutMs: 10000 });
115+
const text = response?.result?.content?.[0]?.text || '';
116+
117+
// expect(text.startsWith('# Documentation from')).toBe(true);
118+
expect(text).toMatchSnapshot();
45119
});
46120
});
47121

48122
describe('Hosted mode, --docs-host', () => {
49-
let client: StdioTransportClient;
123+
let CLIENT: StdioTransportClient;
50124

51125
beforeEach(async () => {
52-
client = await startServer({ args: ['--docs-host'] });
126+
CLIENT = await startServer({ args: ['--docs-host'] });
53127
});
54128

55-
afterEach(async () => client.stop());
129+
afterEach(async () => CLIENT.stop());
56130

57131
it('should read llms-files and includes expected tokens', async () => {
58132
const req = {
@@ -62,7 +136,7 @@ describe('Hosted mode, --docs-host', () => {
62136
arguments: { urlList: ['react-core/6.0.0/llms.txt'] }
63137
}
64138
};
65-
const resp = await client.send(req);
139+
const resp = await CLIENT.send(req);
66140
const text = resp?.result?.content?.[0]?.text || '';
67141

68142
expect(text.startsWith('# Documentation from')).toBe(true);
@@ -81,66 +155,20 @@ describe('Logging', () => {
81155
description: 'stderr',
82156
args: ['--log-stderr']
83157
},
84-
{
85-
description: 'verbose',
86-
args: ['--log-stderr', '--verbose']
87-
},
88158
{
89159
description: 'with log level filtering',
90160
args: ['--log-level', 'warn']
91161
},
92162
{
93163
description: 'with mcp protocol',
94-
args: ['--verbose', '--log-protocol']
164+
args: ['--log-protocol']
95165
}
96166
])('should allow setting logging options, $description', async ({ args }) => {
97167
const serverArgs = [...args];
98-
const client = await startServer({ args: serverArgs });
99-
100-
expect(client.logs()).toMatchSnapshot();
101-
102-
await client.stop();
103-
});
104-
});
105-
106-
describe('External URLs', () => {
107-
let fetchMock: Awaited<ReturnType<typeof setupFetchMock>> | undefined;
108-
let url: string;
109-
let client: StdioTransportClient;
110-
111-
beforeEach(async () => {
112-
client = await startServer();
113-
});
168+
const CLIENT = await startServer({ args: serverArgs });
114169

115-
afterEach(async () => client.stop());
170+
expect(CLIENT.logs()).toMatchSnapshot();
116171

117-
beforeAll(async () => {
118-
// Note: The helper creates index-based paths based on routing (/0, /1, etc.), so we use /0 for the first route
119-
fetchMock = await setupFetchMock({
120-
routes: [
121-
{
122-
url: /\/readme$/,
123-
status: 200,
124-
headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
125-
body: loadFixture('README.md')
126-
}
127-
]
128-
});
129-
url = `${fetchMock.fixture.baseUrl}/0`;
130-
});
131-
132-
afterAll(async () => fetchMock?.cleanup());
133-
134-
it('should fetch a document', async () => {
135-
const req = {
136-
method: 'tools/call',
137-
params: { name: 'fetchDocs', arguments: { urlList: [url] } }
138-
};
139-
const resp = await client.send(req, { timeoutMs: 10000 });
140-
const text = resp?.result?.content?.[0]?.text || '';
141-
142-
expect(text.startsWith('# Documentation from')).toBe(true);
143-
expect(/patternfly/i.test(text)).toBe(true);
144-
expect(text.split(/\n/g).filter(Boolean).splice(1)).toMatchSnapshot();
172+
await CLIENT.stop();
145173
});
146174
});

0 commit comments

Comments
 (0)