Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!DOCTYPE html>
<meta charset="utf-8">
<title>WebMCP: executeTool with Unregistered Declarative Tool</title>
<link rel="author" href="mailto:dom@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/helpers.js"></script>
<body>
<script>
promise_test(async t => {
const form = document.createElement('form');
form.setAttribute('toolname', 'endless_tool');
form.setAttribute('tooldescription', 'Endless declarative tool');
form.setAttribute('toolautosubmit', '');
document.body.appendChild(form);
t.add_cleanup(() => form.remove());
await waitForTool('endless_tool');
let resolveRespondWith;
const submitted_promise = new Promise((resolve) => {
form.addEventListener('submit', (e) => {
e.preventDefault();
// Respond with a Promise that resolves when resolveRespondWith is called.
e.respondWith(new Promise(res => {
resolveRespondWith = res;
}));
resolve();
});
});
const tools = await document.modelContext.getTools();
const tool = tools.find(t => t.name === 'endless_tool');
assert_true(!!tool, 'Tool should be registered');
const execute_promise = document.modelContext.executeTool(tool, '{}');
// Wait deterministically for the form to submit and call respondWith().
await submitted_promise;
const toolChangePromise = new Promise(resolve =>
document.modelContext.addEventListener('toolchange', resolve, { once: true }));
// Unregister the declarative tool by removing the form element while execution is pending.
form.remove();
await toolChangePromise;
const currentTools = await document.modelContext.getTools();
assert_array_equals(currentTools, [], 'Unregistered tool should no longer be returned by getTools()');
resolveRespondWith('form_dom_result');
const result = await execute_promise;
assert_equals(result, 'form_dom_result', 'Pending execution Promise should resolve to tool result even if form element was removed from DOM');
}, 'Pending executeTool() Promise resolves successfully when target declarative tool is unregistered via DOM removal');
promise_test(async t => {
const form = document.createElement('form');
form.setAttribute('toolname', 'endless_tool_attr');
form.setAttribute('tooldescription', 'Endless declarative tool attribute');
form.setAttribute('toolautosubmit', '');
document.body.appendChild(form);
t.add_cleanup(() => form.remove());
await waitForTool('endless_tool_attr');
let resolveRespondWith;
const submitted_promise = new Promise((resolve) => {
form.addEventListener('submit', (e) => {
e.preventDefault();
e.respondWith(new Promise(res => {
resolveRespondWith = res;
}));
resolve();
});
});
const tools = await document.modelContext.getTools();
const tool = tools.find(t => t.name === 'endless_tool_attr');
assert_true(!!tool, 'Tool should be registered');
const execute_promise = document.modelContext.executeTool(tool, '{}');
// Wait deterministically for the form to submit and call respondWith().
await submitted_promise;
const toolChangePromise = new Promise(resolve =>
document.modelContext.addEventListener('toolchange', resolve, { once: true }));
// Unregister by removing required tooldescription attribute while execution is pending.
form.removeAttribute('tooldescription');
await toolChangePromise;
const currentTools = await document.modelContext.getTools();
assert_array_equals(currentTools, [], 'Unregistered tool should no longer be returned by getTools()');
resolveRespondWith('form_attr_result');
const result = await execute_promise;
assert_equals(result, 'form_attr_result', 'Pending execution Promise should resolve to tool result even if form attribute was removed');
}, 'Pending executeTool() Promise resolves successfully when target declarative tool is unregistered via attribute removal');
</script>
</body>