diff --git a/tests/basic.spec.ts b/tests/basic.spec.ts index d945611..20a377b 100644 --- a/tests/basic.spec.ts +++ b/tests/basic.spec.ts @@ -20,196 +20,72 @@ import path from 'node:path'; import { test, expect } from './fixtures'; test('test tool list', async ({ server, visionServer }) => { - const list = await server.send({ - jsonrpc: '2.0', - id: 1, - method: 'tools/list', - }); + const tools = await server.listTools(); + expect(tools.map(t => t.name)).toEqual([ + 'browser_navigate', + 'browser_go_back', + 'browser_go_forward', + 'browser_choose_file', + 'browser_snapshot', + 'browser_click', + 'browser_hover', + 'browser_type', + 'browser_select_option', + 'browser_take_screenshot', + 'browser_press_key', + 'browser_wait', + 'browser_save_as_pdf', + 'browser_close', + ]); - expect(list).toEqual(expect.objectContaining({ - id: 1, - result: expect.objectContaining({ - tools: [ - expect.objectContaining({ - name: 'browser_navigate', - }), - expect.objectContaining({ - name: 'browser_go_back', - }), - expect.objectContaining({ - name: 'browser_go_forward', - }), - expect.objectContaining({ - name: 'browser_choose_file', - }), - expect.objectContaining({ - name: 'browser_snapshot', - }), - expect.objectContaining({ - name: 'browser_click', - }), - expect.objectContaining({ - name: 'browser_hover', - }), - expect.objectContaining({ - name: 'browser_type', - }), - expect.objectContaining({ - name: 'browser_select_option', - }), - expect.objectContaining({ - name: 'browser_take_screenshot', - }), - expect.objectContaining({ - name: 'browser_press_key', - }), - expect.objectContaining({ - name: 'browser_wait', - }), - expect.objectContaining({ - name: 'browser_save_as_pdf', - }), - expect.objectContaining({ - name: 'browser_close', - }), - ], - }), - })); - - const visionList = await visionServer.send({ - jsonrpc: '2.0', - id: 1, - method: 'tools/list', - }); - - expect(visionList).toEqual(expect.objectContaining({ - id: 1, - result: expect.objectContaining({ - tools: expect.arrayContaining([ - expect.objectContaining({ - name: 'browser_navigate', - }), - expect.objectContaining({ - name: 'browser_go_back', - }), - expect.objectContaining({ - name: 'browser_go_forward', - }), - expect.objectContaining({ - name: 'browser_screenshot', - }), - expect.objectContaining({ - name: 'browser_move_mouse', - }), - expect.objectContaining({ - name: 'browser_click', - }), - expect.objectContaining({ - name: 'browser_drag', - }), - expect.objectContaining({ - name: 'browser_type', - }), - expect.objectContaining({ - name: 'browser_press_key', - }), - expect.objectContaining({ - name: 'browser_wait', - }), - expect.objectContaining({ - name: 'browser_save_as_pdf', - }), - expect.objectContaining({ - name: 'browser_close', - }), - ]), - }), - })); + const visionTools = await visionServer.listTools(); + expect(visionTools.map(t => t.name)).toEqual([ + 'browser_navigate', + 'browser_go_back', + 'browser_go_forward', + 'browser_choose_file', + 'browser_screenshot', + 'browser_move_mouse', + 'browser_click', + 'browser_drag', + 'browser_type', + 'browser_press_key', + 'browser_wait', + 'browser_save_as_pdf', + 'browser_close', + ]); }); test('test resources list', async ({ server }) => { - const list = await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'resources/list', - }); - - expect(list).toEqual(expect.objectContaining({ - id: 2, - result: expect.objectContaining({ - resources: [ - expect.objectContaining({ - uri: 'browser://console', - mimeType: 'text/plain', - }), - ], + expect(await server.listResources()).toEqual([ + expect.objectContaining({ + uri: 'browser://console', + mimeType: 'text/plain', }), - })); + ]); }); test('test browser_navigate', async ({ server }) => { - const response = await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_navigate', - arguments: { - url: 'data:text/html,TitleHello, world!', - }, - }, - }); - - expect(response).toEqual(expect.objectContaining({ - id: 2, - result: { - content: [{ - type: 'text', - text: ` + expect(await server.callTool('browser_navigate', { url: 'data:text/html,TitleHello, world!' })).toEqual([ + ` - Page URL: data:text/html,TitleHello, world! - Page Title: Title - Page Snapshot \`\`\`yaml - document [ref=s1e2]: Hello, world! \`\`\` -`, - }], - }, - })); +` + ]); }); test('test browser_click', async ({ server }) => { - await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_navigate', - arguments: { - url: 'data:text/html,Title', - }, - }, - }); + await server.callTool( + 'browser_navigate', + { url: 'data:text/html,Title' } + ); - const response = await server.send({ - jsonrpc: '2.0', - id: 3, - method: 'tools/call', - params: { - name: 'browser_click', - arguments: { - element: 'Submit button', - ref: 's1e4', - }, - }, - }); - - expect(response).toEqual(expect.objectContaining({ - id: 3, - result: { - content: [{ - type: 'text', - text: `\"Submit button\" clicked + expect(await server.callTool('browser_click', { element: 'Submit button', ref: 's1e4' })).toEqual([ + `\"Submit button\" clicked - Page URL: data:text/html,Title - Page Title: Title @@ -218,112 +94,37 @@ test('test browser_click', async ({ server }) => { - document [ref=s2e2]: - button \"Submit\" [ref=s2e4] \`\`\` -`, - }], - }, - })); +`]); }); test('test reopen browser', async ({ server }) => { - const response2 = await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_navigate', - arguments: { - url: 'data:text/html,TitleHello, world!', - }, - }, - }); + await server.callTool( + 'browser_navigate', + { url: 'data:text/html,TitleHello, world!' } + ); - expect(response2).toEqual(expect.objectContaining({ - id: 2, - })); + expect(await server.callTool('browser_close')).toEqual(['Page closed']); - const response3 = await server.send({ - jsonrpc: '2.0', - id: 3, - method: 'tools/call', - params: { - name: 'browser_close', - }, - }); - - expect(response3).toEqual(expect.objectContaining({ - id: 3, - result: { - content: [{ - text: 'Page closed', - type: 'text', - }], - }, - })); - - const response4 = await server.send({ - jsonrpc: '2.0', - id: 4, - method: 'tools/call', - params: { - name: 'browser_navigate', - arguments: { - url: 'data:text/html,TitleHello, world!', - }, - }, - }); - - expect(response4).toEqual(expect.objectContaining({ - id: 4, - result: { - content: [{ - type: 'text', - text: ` + expect(await server.callTool('browser_navigate', { url: 'data:text/html,TitleHello, world!' })).toEqual([` - Page URL: data:text/html,TitleHello, world! - Page Title: Title - Page Snapshot \`\`\`yaml - document [ref=s1e2]: Hello, world! \`\`\` -`, - }], - }, - })); +`,]); }); test.describe('test browser_select_option', () => { test('single option', async ({ server }) => { - await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_navigate', - arguments: { - url: 'data:text/html,Title', - }, - }, + await server.callTool('browser_navigate', { + url: 'data:text/html,Title', }); - const response = await server.send({ - jsonrpc: '2.0', - id: 3, - method: 'tools/call', - params: { - name: 'browser_select_option', - arguments: { - element: 'Select', - ref: 's1e4', - values: ['bar'], - }, - }, - }); + const response = await server.callTool('browser_select_option', { element: 'Select', ref: 's1e4', values: ['bar'] }); - expect(response).toEqual(expect.objectContaining({ - id: 3, - result: { - content: [{ - type: 'text', - text: `Selected option in \"Select\" + expect(response).toEqual([ + `Selected option in \"Select\" - Page URL: data:text/html,Title - Page Title: Title @@ -334,45 +135,18 @@ test.describe('test browser_select_option', () => { - option \"Foo\" [ref=s2e5] - option \"Bar\" [selected] [ref=s2e6] \`\`\` -`, - }], - }, - })); +`]); }); test('multiple option', async ({ server }) => { - await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_navigate', - arguments: { - url: 'data:text/html,Title', - }, - }, + await server.callTool('browser_navigate', { + url: 'data:text/html,Title', }); - const response = await server.send({ - jsonrpc: '2.0', - id: 3, - method: 'tools/call', - params: { - name: 'browser_select_option', - arguments: { - element: 'Select', - ref: 's1e4', - values: ['bar', 'baz'], - }, - }, - }); + const response = await server.callTool('browser_select_option', { element: 'Select', ref: 's1e4', values: ['bar', 'baz'] }); - expect(response).toEqual(expect.objectContaining({ - id: 3, - result: { - content: [{ - type: 'text', - text: `Selected option in \"Select\" + expect(response).toEqual([ + `Selected option in \"Select\" - Page URL: data:text/html,Title - Page Title: Title @@ -384,64 +158,27 @@ test.describe('test browser_select_option', () => { - option \"Bar\" [selected] [ref=s2e6] - option \"Baz\" [selected] [ref=s2e7] \`\`\` -`, - }], - }, - })); +`]); }); }); test('browser://console', async ({ server }) => { - await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_navigate', - arguments: { - url: 'data:text/html,', - }, - }, + await server.callTool('browser_navigate', { + url: 'data:text/html,', }); - - const response = await server.send({ - jsonrpc: '2.0', - id: 3, - method: 'resources/read', - params: { - uri: 'browser://console', - }, - }); - expect(response).toEqual(expect.objectContaining({ - result: expect.objectContaining({ - contents: [{ - uri: 'browser://console', - mimeType: 'text/plain', - text: '[LOG] Hello, world!\n[ERROR] Error', - }], - }), - })); + expect(await server.readResource('browser://console')).toEqual([{ + uri: 'browser://console', + mimeType: 'text/plain', + text: '[LOG] Hello, world!\n[ERROR] Error', + }]); }); test('stitched aria frames', async ({ server }) => { - const response = await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_navigate', - arguments: { - url: 'data:text/html,

Hello

', - }, - }, + const response = await server.callTool('browser_navigate', { + url: 'data:text/html,

Hello

', }); - expect(response).toEqual(expect.objectContaining({ - id: 2, - result: { - content: [{ - type: 'text', - text: ` + expect(response).toEqual([` - Page URL: data:text/html,

Hello

- Page Title: - Page Snapshot @@ -453,87 +190,47 @@ test('stitched aria frames', async ({ server }) => { - document [ref=f0s1e2]: - heading \"World\" [level=1] [ref=f0s1e4] \`\`\` -`, - }], - }, - })); +` + ]); }); test('browser_choose_file', async ({ server }) => { - let response = await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_navigate', - arguments: { - url: 'data:text/html,Title', - }, - }, + let response = await server.callTool('browser_navigate', { + url: 'data:text/html,Title', }); - expect(response.result.content[0].text).toContain('- textbox [ref=s1e4]'); + expect(response[0]).toContain('- textbox [ref=s1e4]'); - response = await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_click', - arguments: { - element: 'Textbox', - ref: 's1e4', - }, - }, + response = await server.callTool('browser_click', { + element: 'Textbox', + ref: 's1e4', }); - expect(response.result.content[0].text).toContain('There is a file chooser visible that requires browser_choose_file to be called'); + expect(response[0]).toContain('There is a file chooser visible that requires browser_choose_file to be called'); const filePath = test.info().outputPath('test.txt'); await fs.writeFile(filePath, 'Hello, world!'); - response = await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_choose_file', - arguments: { - paths: [filePath], - }, - }, + response = await server.callTool('browser_choose_file', { + paths: [filePath], }); - expect(response.result.content[0].text).not.toContain('There is a file chooser visible that requires browser_choose_file to be called'); - expect(response.result.content[0].text).toContain('textbox [ref=s3e4]: C:\\fakepath\\test.txt'); + expect(response[0]).not.toContain('There is a file chooser visible that requires browser_choose_file to be called'); + expect(response[0]).toContain('textbox [ref=s3e4]: C:\\fakepath\\test.txt'); - response = await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_click', - arguments: { - element: 'Textbox', - ref: 's3e4', - }, - }, + response = await server.callTool('browser_click', { + element: 'Textbox', + ref: 's3e4', }); - expect(response.result.content[0].text).toContain('There is a file chooser visible that requires browser_choose_file to be called'); - expect(response.result.content[0].text).toContain('button "Button" [ref=s4e5]'); - response = await server.send({ - jsonrpc: '2.0', - id: 2, - method: 'tools/call', - params: { - name: 'browser_click', - arguments: { - element: 'Button', - ref: 's4e5', - }, - }, + expect(response[0]).toContain('There is a file chooser visible that requires browser_choose_file to be called'); + expect(response[0]).toContain('button "Button" [ref=s4e5]'); + + response = await server.callTool('browser_click', { + element: 'Button', + ref: 's4e5', }); - expect(response.result.content[0].text, 'not submitting browser_choose_file dismisses file chooser').not.toContain('There is a file chooser visible that requires browser_choose_file to be called'); + + expect(response[0], 'not submitting browser_choose_file dismisses file chooser').not.toContain('There is a file chooser visible that requires browser_choose_file to be called'); }); test('sse transport', async () => { diff --git a/tests/fixtures.ts b/tests/fixtures.ts index e9b2dfd..9b3eed0 100644 --- a/tests/fixtures.ts +++ b/tests/fixtures.ts @@ -108,6 +108,49 @@ class MCPServer extends EventEmitter { this._child.stdin?.end(); }); } + + async listTools() { + const list = await this.send({ + jsonrpc: '2.0', + id: 0, + method: 'tools/list', + }); + return list.result.tools; + } + + async listResources() { + const list = await this.send({ + jsonrpc: '2.0', + id: 0, + method: 'resources/list', + }); + return list.result.resources; + } + + async callTool(name: string, args?: any) { + const result = await this.send({ + jsonrpc: '2.0', + id: 0, + method: 'tools/call', + params: { + name, + arguments: args, + } + }); + return result.result.content.map(c => c.text); + } + + async readResource(uri: string) { + const result = await this.send({ + jsonrpc: '2.0', + id: 0, + method: 'resources/read', + params: { + uri, + }, + }); + return result.result.contents; + } } type Fixtures = {