chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,905 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import assert from 'node:assert';
|
||||
import {describe, it} from 'node:test';
|
||||
|
||||
import sinon from 'sinon';
|
||||
|
||||
import type {McpContext} from '../../src/McpContext.js';
|
||||
import type {McpResponse} from '../../src/McpResponse.js';
|
||||
import {TextSnapshot} from '../../src/TextSnapshot.js';
|
||||
import {
|
||||
executeThirdPartyDeveloperTool,
|
||||
listThirdPartyDeveloperTools,
|
||||
} from '../../src/tools/thirdPartyDeveloper.js';
|
||||
import type {ToolGroups} from '../../src/tools/thirdPartyDeveloper.js';
|
||||
import {withMcpContext} from '../utils.js';
|
||||
|
||||
describe('thirdPartyDeveloperTools', () => {
|
||||
describe('list_3p_developer_tools', () => {
|
||||
it('lists tools', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
const page = await context.newPage();
|
||||
response.setPage(page);
|
||||
|
||||
await page.pptrPage.evaluate(() => {
|
||||
const mockToolGroup = {
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'test tool description',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
arg: {type: 'string'},
|
||||
},
|
||||
},
|
||||
execute: () => 'result',
|
||||
},
|
||||
],
|
||||
};
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith(mockToolGroup);
|
||||
});
|
||||
});
|
||||
|
||||
await listThirdPartyDeveloperTools.handler(
|
||||
{params: {}, page},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
const result = await response.handle(
|
||||
'list_3p_developer_tools',
|
||||
context,
|
||||
);
|
||||
// @ts-expect-error `structuredContent` has `thirdPartyDeveloperTools`
|
||||
const groups = result.structuredContent.thirdPartyDeveloperTools;
|
||||
assert.strictEqual(groups.length, 1);
|
||||
const actualGroup = groups[0];
|
||||
assert.strictEqual(actualGroup.name, 'test-group');
|
||||
assert.strictEqual(actualGroup.description, 'test description');
|
||||
assert.strictEqual(actualGroup.tools.length, 1);
|
||||
assert.strictEqual(actualGroup.tools[0].name, 'test-tool');
|
||||
assert.strictEqual(
|
||||
actualGroup.tools[0].description,
|
||||
'test tool description',
|
||||
);
|
||||
assert.deepEqual(actualGroup.tools[0].inputSchema, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
arg: {type: 'string'},
|
||||
},
|
||||
});
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('handles empty response', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
const page = await context.newPage();
|
||||
response.setPage(page);
|
||||
await page.pptrPage.evaluate(() => {
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith({});
|
||||
});
|
||||
});
|
||||
|
||||
await listThirdPartyDeveloperTools.handler(
|
||||
{params: {}, page},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
const result = await response.handle(
|
||||
'list_3p_developer_tools',
|
||||
context,
|
||||
);
|
||||
assert.ok(result.structuredContent);
|
||||
assert.deepStrictEqual(
|
||||
(
|
||||
result.structuredContent as {
|
||||
thirdPartyDeveloperTools?: ToolGroups;
|
||||
}
|
||||
).thirdPartyDeveloperTools,
|
||||
undefined,
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('handles no response', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
const page = await context.newPage();
|
||||
response.setPage(page);
|
||||
await page.pptrPage.evaluate(() => {
|
||||
window.addEventListener('devtoolstooldiscovery', () => {
|
||||
// do nothing
|
||||
});
|
||||
});
|
||||
|
||||
await listThirdPartyDeveloperTools.handler(
|
||||
{params: {}, page},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
const result = await response.handle(
|
||||
'list_3p_developer_tools',
|
||||
context,
|
||||
);
|
||||
assert.ok(result.structuredContent);
|
||||
assert.deepStrictEqual(
|
||||
(
|
||||
result.structuredContent as {
|
||||
thirdPartyDeveloperTools?: ToolGroups;
|
||||
}
|
||||
).thirdPartyDeveloperTools,
|
||||
undefined,
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('handles no eventListener', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
const page = await context.newPage();
|
||||
response.setPage(page);
|
||||
await listThirdPartyDeveloperTools.handler(
|
||||
{params: {}, page},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
const result = await response.handle(
|
||||
'list_3p_developer_tools',
|
||||
context,
|
||||
);
|
||||
assert.ok(result.structuredContent);
|
||||
assert.deepStrictEqual(
|
||||
(
|
||||
result.structuredContent as {
|
||||
thirdPartyDeveloperTools?: ToolGroups;
|
||||
}
|
||||
).thirdPartyDeveloperTools,
|
||||
undefined,
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('lists multiple toolgroups', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
const page = await context.newPage();
|
||||
response.setPage(page);
|
||||
|
||||
await page.pptrPage.evaluate(() => {
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith?.({
|
||||
name: 'group-1',
|
||||
description: 'desc-1',
|
||||
tools: [
|
||||
{
|
||||
name: 'tool-1',
|
||||
description: 'tool-1-desc',
|
||||
inputSchema: {},
|
||||
execute: () => 'r1',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith?.({
|
||||
name: 'group-2',
|
||||
description: 'desc-2',
|
||||
tools: [
|
||||
{
|
||||
name: 'tool-2',
|
||||
description: 'tool-2-desc',
|
||||
inputSchema: {},
|
||||
execute: () => 'r2',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
await listThirdPartyDeveloperTools.handler(
|
||||
{params: {}, page},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
const result = await response.handle(
|
||||
'list_3p_developer_tools',
|
||||
context,
|
||||
);
|
||||
const actualGroups =
|
||||
// @ts-expect-error structuredContent has `thirdPartyDeveloperTools`
|
||||
result.structuredContent.thirdPartyDeveloperTools;
|
||||
assert.ok(actualGroups);
|
||||
assert.strictEqual(actualGroups.length, 2);
|
||||
assert.strictEqual(actualGroups[0].name, 'group-1');
|
||||
assert.strictEqual(actualGroups[1].name, 'group-2');
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('clears window.__dtmcp.toolGroups on subsequent getToolGroups calls', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
const page = await context.newPage();
|
||||
response.setPage(page);
|
||||
|
||||
await page.pptrPage.evaluate(() => {
|
||||
const mockToolGroup = {
|
||||
name: 'group-1',
|
||||
description: 'desc-1',
|
||||
tools: [
|
||||
{
|
||||
name: 'tool-1',
|
||||
description: 'tool-1-desc',
|
||||
inputSchema: {},
|
||||
execute: () => 'r1',
|
||||
},
|
||||
],
|
||||
};
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith(mockToolGroup);
|
||||
});
|
||||
});
|
||||
|
||||
await listThirdPartyDeveloperTools.handler(
|
||||
{params: {}, page},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
await response.handle('list_3p_developer_tools', context);
|
||||
|
||||
let groupsLength = await page.pptrPage.evaluate(
|
||||
() => window.__dtmcp?.toolGroups?.length,
|
||||
);
|
||||
assert.strictEqual(groupsLength, 1);
|
||||
|
||||
await listThirdPartyDeveloperTools.handler(
|
||||
{params: {}, page},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
await response.handle('list_3p_developer_tools', context);
|
||||
|
||||
groupsLength = await page.pptrPage.evaluate(
|
||||
() => window.__dtmcp?.toolGroups?.length,
|
||||
);
|
||||
assert.strictEqual(groupsLength, 1);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('execute_3p_developer_tool', () => {
|
||||
async function setupThirdPartyDeveloperTools(
|
||||
response: McpResponse,
|
||||
context: McpContext,
|
||||
evaluateFn: () => void,
|
||||
) {
|
||||
const page = await context.newPage();
|
||||
response.setPage(page);
|
||||
await page.pptrPage.evaluate(evaluateFn);
|
||||
await listThirdPartyDeveloperTools.handler(
|
||||
{params: {}, page},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
await response.handle('list_3p_developer_tools', context);
|
||||
}
|
||||
|
||||
it('executes a tool', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
await setupThirdPartyDeveloperTools(response, context, () => {
|
||||
const mockToolGroup = {
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'test tool description',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
arg: {type: 'string'},
|
||||
},
|
||||
required: ['arg'],
|
||||
},
|
||||
execute: () => 'result',
|
||||
},
|
||||
],
|
||||
};
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith(mockToolGroup);
|
||||
});
|
||||
});
|
||||
|
||||
await executeThirdPartyDeveloperTool.handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'test-tool',
|
||||
params: JSON.stringify({arg: 'value'}),
|
||||
},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
assert.strictEqual(
|
||||
response.responseLines[0],
|
||||
JSON.stringify('result', null, 2),
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if tool not found in list', async () => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
await setupThirdPartyDeveloperTools(response, context, () => {
|
||||
const mockToolGroup = {
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [],
|
||||
};
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith(mockToolGroup);
|
||||
});
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await executeThirdPartyDeveloperTool.handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'missing-tool',
|
||||
params: JSON.stringify({}),
|
||||
},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{message: /Tool missing-tool not found/},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('throws if parameters are invalid', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
await setupThirdPartyDeveloperTools(response, context, () => {
|
||||
const mockToolGroup = {
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'test tool description',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
arg: {type: 'string'},
|
||||
},
|
||||
required: ['arg'],
|
||||
},
|
||||
execute: () => 'result',
|
||||
},
|
||||
],
|
||||
};
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith(mockToolGroup);
|
||||
});
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await executeThirdPartyDeveloperTool.handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'test-tool',
|
||||
params: JSON.stringify({}), // Missing required 'arg'
|
||||
},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
},
|
||||
{message: /Invalid parameters for tool test-tool/},
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('handles JSON result', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
await setupThirdPartyDeveloperTools(response, context, () => {
|
||||
const mockToolGroup = {
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'test tool description',
|
||||
inputSchema: {},
|
||||
execute: () => ({foo: 'bar'}),
|
||||
},
|
||||
],
|
||||
};
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith(mockToolGroup);
|
||||
});
|
||||
});
|
||||
|
||||
await executeThirdPartyDeveloperTool.handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'test-tool',
|
||||
params: JSON.stringify({}),
|
||||
},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
assert.strictEqual(
|
||||
response.responseLines[0],
|
||||
JSON.stringify({foo: 'bar'}, null, 2),
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('replaces uid with element handle in params', async () => {
|
||||
await withMcpContext(async (response, context) => {
|
||||
const page = await context.newPage();
|
||||
response.setPage(page);
|
||||
|
||||
page.thirdPartyDeveloperTools = [
|
||||
{
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'test tool description',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
element: {type: 'object'},
|
||||
},
|
||||
required: ['element'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
await page.pptrPage.evaluate(() => {
|
||||
window.__dtmcp = {
|
||||
executeTool: async (
|
||||
_name: string,
|
||||
args: Record<string, unknown>,
|
||||
) => {
|
||||
const el = args.element;
|
||||
if (el instanceof HTMLElement) {
|
||||
return {
|
||||
isElement: true,
|
||||
tagName: el.tagName,
|
||||
id: el.id,
|
||||
};
|
||||
}
|
||||
return {
|
||||
isElement: false,
|
||||
tagName: '',
|
||||
id: '',
|
||||
};
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await page.pptrPage.evaluate(() => {
|
||||
const div = document.createElement('div');
|
||||
div.id = 'test-id';
|
||||
document.body.appendChild(div);
|
||||
});
|
||||
|
||||
const handle = await page.pptrPage.$('#test-id');
|
||||
if (!handle) {
|
||||
throw new Error('Handle not found');
|
||||
}
|
||||
|
||||
page.getElementByUid = async (uid: string) => {
|
||||
if (uid === 'some-uid') {
|
||||
return handle;
|
||||
}
|
||||
throw new Error('Not found');
|
||||
};
|
||||
|
||||
await executeThirdPartyDeveloperTool.handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'test-tool',
|
||||
params: JSON.stringify({element: {uid: 'some-uid'}}),
|
||||
},
|
||||
page: page,
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
response.responseLines[0],
|
||||
JSON.stringify(
|
||||
{
|
||||
isElement: true,
|
||||
tagName: 'DIV',
|
||||
id: 'test-id',
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('processToolResult replaces functions with "<Function object>"', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
await setupThirdPartyDeveloperTools(response, context, () => {
|
||||
const mockToolGroup = {
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'test tool description',
|
||||
inputSchema: {},
|
||||
execute: () => ({
|
||||
foo: 'bar',
|
||||
func: () => undefined,
|
||||
}),
|
||||
},
|
||||
],
|
||||
};
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith(mockToolGroup);
|
||||
});
|
||||
});
|
||||
|
||||
await executeThirdPartyDeveloperTool.handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'test-tool',
|
||||
params: JSON.stringify({}),
|
||||
},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
assert.strictEqual(
|
||||
response.responseLines[0],
|
||||
JSON.stringify({foo: 'bar', func: '<Function object>'}, null, 2),
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('processToolResult replaces circular references with "<Circular reference>"', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
await setupThirdPartyDeveloperTools(response, context, () => {
|
||||
const mockToolGroup = {
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'test tool description',
|
||||
inputSchema: {},
|
||||
execute: () => {
|
||||
const obj: Record<string, unknown> = {foo: 'bar'};
|
||||
obj.self = obj;
|
||||
return obj;
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith(mockToolGroup);
|
||||
});
|
||||
});
|
||||
|
||||
await executeThirdPartyDeveloperTool.handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'test-tool',
|
||||
params: JSON.stringify({}),
|
||||
},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
assert.strictEqual(
|
||||
response.responseLines[0],
|
||||
JSON.stringify({foo: 'bar', self: '<Circular reference>'}, null, 2),
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('processToolResult replaces non-plain objects with "<ConstructorName instance>"', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
await setupThirdPartyDeveloperTools(response, context, () => {
|
||||
class CustomClass {
|
||||
val = 'value';
|
||||
}
|
||||
const mockToolGroup = {
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'test tool description',
|
||||
inputSchema: {},
|
||||
execute: () => ({
|
||||
foo: 'bar',
|
||||
custom: new CustomClass(),
|
||||
}),
|
||||
},
|
||||
],
|
||||
};
|
||||
window.addEventListener('devtoolstooldiscovery', (e: Event) => {
|
||||
// @ts-expect-error Event has `respondWith`
|
||||
e.respondWith(mockToolGroup);
|
||||
});
|
||||
});
|
||||
|
||||
await executeThirdPartyDeveloperTool.handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'test-tool',
|
||||
params: JSON.stringify({}),
|
||||
},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
assert.strictEqual(
|
||||
response.responseLines[0],
|
||||
JSON.stringify(
|
||||
{foo: 'bar', custom: '<CustomClass instance>'},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('stashDOMElement stashes elements and returns UID', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
const page = await context.newPage();
|
||||
response.setPage(page);
|
||||
|
||||
page.thirdPartyDeveloperTools = [
|
||||
{
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'test tool description',
|
||||
inputSchema: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
await page.pptrPage.evaluate(() => {
|
||||
window.__dtmcp = {
|
||||
executeTool: async () => {
|
||||
const div = document.createElement('div');
|
||||
div.id = 'test-element';
|
||||
document.body.appendChild(div);
|
||||
return div;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await executeThirdPartyDeveloperTool.handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'test-tool',
|
||||
params: JSON.stringify({}),
|
||||
},
|
||||
page: page,
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
response.responseLines[0],
|
||||
JSON.stringify({uid: '1_1'}, null, 2),
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('creates a new snapshot if the third-party developer tool response contains a DOM element', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
const page = await context.newPage();
|
||||
response.setPage(page);
|
||||
|
||||
page.thirdPartyDeveloperTools = [
|
||||
{
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'test tool description',
|
||||
inputSchema: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
await page.pptrPage.evaluate(() => {
|
||||
window.__dtmcp = {
|
||||
executeTool: async () => {
|
||||
const div = document.createElement('div');
|
||||
div.id = 'test-element';
|
||||
document.body.appendChild(div);
|
||||
return div;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await executeThirdPartyDeveloperTool.handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'test-tool',
|
||||
params: JSON.stringify({}),
|
||||
},
|
||||
page: page,
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
response.responseLines[0],
|
||||
JSON.stringify({uid: '1_1'}, null, 2),
|
||||
);
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('does not create a new snapshot if the third-party developer tool response does not contain a DOM element', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context) => {
|
||||
const page = await context.newPage();
|
||||
response.setPage(page);
|
||||
|
||||
page.thirdPartyDeveloperTools = [
|
||||
{
|
||||
name: 'test-group',
|
||||
description: 'test description',
|
||||
tools: [
|
||||
{
|
||||
name: 'test-tool',
|
||||
description: 'test tool description',
|
||||
inputSchema: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
await page.pptrPage.evaluate(() => {
|
||||
window.__dtmcp = {
|
||||
executeTool: async () => {
|
||||
return 'simple-result';
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const stubSnapshot = sinon
|
||||
.stub(TextSnapshot, 'create')
|
||||
.resolves({} as TextSnapshot);
|
||||
|
||||
await executeThirdPartyDeveloperTool.handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'test-tool',
|
||||
params: JSON.stringify({}),
|
||||
},
|
||||
page: page,
|
||||
},
|
||||
response,
|
||||
context,
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
stubSnapshot.notCalled,
|
||||
'Expected TextSnapshot.create not to be called',
|
||||
);
|
||||
assert.strictEqual(
|
||||
response.responseLines[0],
|
||||
JSON.stringify('simple-result', null, 2),
|
||||
);
|
||||
|
||||
stubSnapshot.restore();
|
||||
},
|
||||
undefined,
|
||||
{categoryExperimentalThirdParty: true},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user