Skip to content

Commit c765e0e

Browse files
Add handling
1 parent 5e13fb7 commit c765e0e

5 files changed

Lines changed: 66 additions & 7 deletions

File tree

src/McpPage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export class McpPage implements ContextPage {
117117

118118
waitForEventsAfterAction(
119119
action: () => Promise<unknown>,
120-
options?: {timeout?: number; handleDialog?: boolean},
120+
options?: {timeout?: number; handleDialog?: 'accept' | 'dismiss' | string},
121121
): Promise<void> {
122122
const helper = this.createWaitForHelper(
123123
this.cpuThrottlingRate,

src/WaitForHelper.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,17 @@ export class WaitForHelper {
126126

127127
async waitForEventsAfterAction(
128128
action: () => Promise<unknown>,
129-
options?: {timeout?: number; handleDialog?: boolean},
129+
options?: {timeout?: number; handleDialog?: 'accept' | 'dismiss' | string},
130130
): Promise<void> {
131131
if (options?.handleDialog) {
132-
const dialogHandler = (dialog: Pick<Dialog, 'accept'>) => {
133-
void dialog.accept();
132+
const dialogHandler = (dialog: Pick<Dialog, 'accept' | 'dismiss'>) => {
133+
if (options.handleDialog === 'dismiss') {
134+
void dialog.dismiss();
135+
} else if (options.handleDialog === 'accept') {
136+
void dialog.accept();
137+
} else {
138+
void dialog.accept(options.handleDialog);
139+
}
134140
};
135141
this.#page.on('dialog', dialogHandler);
136142
this.#abortController.signal.addEventListener('abort', () => {

src/tools/ToolDefinition.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ export type ContextPage = Readonly<{
224224
clearDialog(): void;
225225
waitForEventsAfterAction(
226226
action: () => Promise<unknown>,
227-
options?: {timeout?: number; handleDialog?: boolean},
227+
options?: {timeout?: number; handleDialog?: 'accept' | 'dismiss' | string},
228228
): Promise<void>;
229229
getInPageTools(): ToolGroup<InPageToolDefinition> | undefined;
230230
}>;

src/tools/script.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ Example with arguments: \`(el) => {
4646
)
4747
.optional()
4848
.describe(`An optional list of arguments to pass to the function.`),
49+
dialogAction: zod
50+
.string()
51+
.optional()
52+
.describe(
53+
'Handle dialogs while execution. "accept", "dismiss", or a string for window.prompt. Defaults to accept.',
54+
),
4955
...(cliArgs?.experimentalPageIdRouting ? pageIdSchema : {}),
5056
...(cliArgs?.categoryExtensions
5157
? {
@@ -64,6 +70,7 @@ Example with arguments: \`(el) => {
6470
args: uidArgs,
6571
function: fnString,
6672
pageId,
73+
dialogAction,
6774
} = request.params;
6875

6976
if (cliArgs?.categoryExtensions && serviceWorkerId) {
@@ -81,7 +88,7 @@ Example with arguments: \`(el) => {
8188
async () => {
8289
await performEvaluation(worker, fnString, [], response);
8390
},
84-
{handleDialog: true},
91+
{handleDialog: dialogAction ?? 'accept'},
8592
);
8693
return;
8794
}
@@ -106,7 +113,7 @@ Example with arguments: \`(el) => {
106113
async () => {
107114
await performEvaluation(evaluatable, fnString, args, response);
108115
},
109-
{handleDialog: true},
116+
{handleDialog: dialogAction ?? 'accept'},
110117
);
111118
} finally {
112119
void Promise.allSettled(args.map(arg => arg.dispose()));

tests/tools/script.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,52 @@ describe('script', () => {
121121
});
122122
});
123123

124+
it('work for scripts that trigger dialogs and dismiss them', async () => {
125+
await withMcpContext(async (response, context) => {
126+
const page = context.getSelectedPptrPage();
127+
128+
await page.setContent(html`<button id="test">test</button>`);
129+
130+
await evaluateScript().handler(
131+
{
132+
params: {
133+
function: String(() => {
134+
return confirm('hello');
135+
}),
136+
dialogAction: 'dismiss',
137+
},
138+
},
139+
response,
140+
context,
141+
);
142+
const lineEvaluation = response.responseLines.at(2)!;
143+
assert.strictEqual(JSON.parse(lineEvaluation), false);
144+
});
145+
});
146+
147+
it('work for scripts that trigger prompts and fill them', async () => {
148+
await withMcpContext(async (response, context) => {
149+
const page = context.getSelectedPptrPage();
150+
151+
await page.setContent(html`<button id="test">test</button>`);
152+
153+
await evaluateScript().handler(
154+
{
155+
params: {
156+
function: String(() => {
157+
return prompt('Enter your name:');
158+
}),
159+
dialogAction: 'John Doe',
160+
},
161+
},
162+
response,
163+
context,
164+
);
165+
const lineEvaluation = response.responseLines.at(2)!;
166+
assert.strictEqual(JSON.parse(lineEvaluation), 'John Doe');
167+
});
168+
});
169+
124170
it('work for async functions', async () => {
125171
await withMcpContext(async (response, context) => {
126172
const page = context.getSelectedPptrPage();

0 commit comments

Comments
 (0)