mirror of
https://github.com/microsoft/playwright-mcp.git
synced 2025-07-27 00:52:27 +08:00
feat(wait): allow waiting for given text (#390)
Fixes https://github.com/microsoft/playwright-mcp/issues/389
This commit is contained in:
parent
65716b60dd
commit
c28b480b51
10
README.md
10
README.md
@ -518,11 +518,13 @@ X Y coordinate space, based on the provided screenshot.
|
|||||||
|
|
||||||
<!-- NOTE: This has been generated via update-readme.js -->
|
<!-- NOTE: This has been generated via update-readme.js -->
|
||||||
|
|
||||||
- **browser_wait**
|
- **browser_wait_for**
|
||||||
- Title: Wait
|
- Title: Wait for
|
||||||
- Description: Wait for a specified time in seconds
|
- Description: Wait for text to appear or disappear or a specified time to pass
|
||||||
- Parameters:
|
- Parameters:
|
||||||
- `time` (number): The time to wait in seconds
|
- `time` (number, optional): The time to wait in seconds
|
||||||
|
- `text` (string, optional): The text to wait for
|
||||||
|
- `textGone` (string, optional): The text to wait for to disappear
|
||||||
- Read-only: **true**
|
- Read-only: **true**
|
||||||
|
|
||||||
<!-- NOTE: This has been generated via update-readme.js -->
|
<!-- NOTE: This has been generated via update-readme.js -->
|
||||||
|
@ -21,19 +21,44 @@ const wait: ToolFactory = captureSnapshot => defineTool({
|
|||||||
capability: 'wait',
|
capability: 'wait',
|
||||||
|
|
||||||
schema: {
|
schema: {
|
||||||
name: 'browser_wait',
|
name: 'browser_wait_for',
|
||||||
title: 'Wait',
|
title: 'Wait for',
|
||||||
description: 'Wait for a specified time in seconds',
|
description: 'Wait for text to appear or disappear or a specified time to pass',
|
||||||
inputSchema: z.object({
|
inputSchema: z.object({
|
||||||
time: z.number().describe('The time to wait in seconds'),
|
time: z.number().optional().describe('The time to wait in seconds'),
|
||||||
|
text: z.string().optional().describe('The text to wait for'),
|
||||||
|
textGone: z.string().optional().describe('The text to wait for to disappear'),
|
||||||
}),
|
}),
|
||||||
type: 'readOnly',
|
type: 'readOnly',
|
||||||
},
|
},
|
||||||
|
|
||||||
handle: async (context, params) => {
|
handle: async (context, params) => {
|
||||||
await new Promise(f => setTimeout(f, Math.min(10000, params.time * 1000)));
|
if (!params.text && !params.textGone && !params.time)
|
||||||
|
throw new Error('Either time, text or textGone must be provided');
|
||||||
|
|
||||||
|
const code: string[] = [];
|
||||||
|
|
||||||
|
if (params.time) {
|
||||||
|
code.push(`await new Promise(f => setTimeout(f, ${params.time!} * 1000));`);
|
||||||
|
await new Promise(f => setTimeout(f, Math.min(10000, params.time! * 1000)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const tab = context.currentTabOrDie();
|
||||||
|
const locator = params.text ? tab.page.getByText(params.text).first() : undefined;
|
||||||
|
const goneLocator = params.textGone ? tab.page.getByText(params.textGone).first() : undefined;
|
||||||
|
|
||||||
|
if (goneLocator) {
|
||||||
|
code.push(`await page.getByText(${JSON.stringify(params.textGone)}).first().waitFor({ state: 'hidden' });`);
|
||||||
|
await goneLocator.waitFor({ state: 'hidden' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locator) {
|
||||||
|
code.push(`await page.getByText(${JSON.stringify(params.text)}).first().waitFor({ state: 'visible' });`);
|
||||||
|
await locator.waitFor({ state: 'visible' });
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: [`// Waited for ${params.time} seconds`],
|
code,
|
||||||
captureSnapshot,
|
captureSnapshot,
|
||||||
waitForNetwork: false,
|
waitForNetwork: false,
|
||||||
};
|
};
|
||||||
|
@ -43,7 +43,7 @@ test('test snapshot tool list', async ({ client }) => {
|
|||||||
'browser_tab_new',
|
'browser_tab_new',
|
||||||
'browser_tab_select',
|
'browser_tab_select',
|
||||||
'browser_take_screenshot',
|
'browser_take_screenshot',
|
||||||
'browser_wait',
|
'browser_wait_for',
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ test('test vision tool list', async ({ visionClient }) => {
|
|||||||
'browser_tab_list',
|
'browser_tab_list',
|
||||||
'browser_tab_new',
|
'browser_tab_new',
|
||||||
'browser_tab_select',
|
'browser_tab_select',
|
||||||
'browser_wait',
|
'browser_wait_for',
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
85
tests/wait.spec.ts
Normal file
85
tests/wait.spec.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { test, expect } from './fixtures.js';
|
||||||
|
|
||||||
|
test('browser_wait_for(text)', async ({ client, server }) => {
|
||||||
|
server.setContent('/', `
|
||||||
|
<script>
|
||||||
|
function update() {
|
||||||
|
setTimeout(() => {
|
||||||
|
document.querySelector('div').textContent = 'Text to appear';
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<body>
|
||||||
|
<button onclick="update()">Click me</button>
|
||||||
|
<div>Text to disappear</div>
|
||||||
|
</body>
|
||||||
|
`, 'text/html');
|
||||||
|
|
||||||
|
await client.callTool({
|
||||||
|
name: 'browser_navigate',
|
||||||
|
arguments: { url: server.PREFIX },
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.callTool({
|
||||||
|
name: 'browser_click',
|
||||||
|
arguments: {
|
||||||
|
element: 'Click me',
|
||||||
|
ref: 's1e3',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await client.callTool({
|
||||||
|
name: 'browser_wait_for',
|
||||||
|
arguments: { text: 'Text to appear' },
|
||||||
|
})).toContainTextContent(`- generic [ref=s3e4]: Text to appear`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('browser_wait_for(textGone)', async ({ client, server }) => {
|
||||||
|
server.setContent('/', `
|
||||||
|
<script>
|
||||||
|
function update() {
|
||||||
|
setTimeout(() => {
|
||||||
|
document.querySelector('div').textContent = 'Text to appear';
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<body>
|
||||||
|
<button onclick="update()">Click me</button>
|
||||||
|
<div>Text to disappear</div>
|
||||||
|
</body>
|
||||||
|
`, 'text/html');
|
||||||
|
|
||||||
|
await client.callTool({
|
||||||
|
name: 'browser_navigate',
|
||||||
|
arguments: { url: server.PREFIX },
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.callTool({
|
||||||
|
name: 'browser_click',
|
||||||
|
arguments: {
|
||||||
|
element: 'Click me',
|
||||||
|
ref: 's1e3',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await client.callTool({
|
||||||
|
name: 'browser_wait_for',
|
||||||
|
arguments: { textGone: 'Text to disappear' },
|
||||||
|
})).toContainTextContent(`- generic [ref=s3e4]: Text to appear`);
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user