55 */
66
77import { logger } from '../logger.js' ;
8+ import type { Dialog } from '../third_party/index.js' ;
89import { zod } from '../third_party/index.js' ;
910
1011import { ToolCategory } from './categories.js' ;
@@ -120,6 +121,12 @@ export const navigatePage = defineTool({
120121 . boolean ( )
121122 . optional ( )
122123 . describe ( 'Whether to ignore cache on reload.' ) ,
124+ handleBeforeUnload : zod
125+ . enum ( [ 'accept' , 'decline' ] )
126+ . optional ( )
127+ . describe (
128+ 'Whether to auto accept or beforeunload dialogs triggered by this navigation. Default is accept.' ,
129+ ) ,
123130 ...timeoutSchema ,
124131 } ,
125132 handler : async ( request , response , context ) => {
@@ -136,62 +143,82 @@ export const navigatePage = defineTool({
136143 request . params . type = 'url' ;
137144 }
138145
139- await context . waitForEventsAfterAction ( async ( ) => {
140- switch ( request . params . type ) {
141- case 'url' :
142- if ( ! request . params . url ) {
143- throw new Error ( 'A URL is required for navigation of type=url.' ) ;
144- }
145- try {
146- await page . goto ( request . params . url , options ) ;
147- response . appendResponseLine (
148- `Successfully navigated to ${ request . params . url } .` ,
149- ) ;
150- } catch ( error ) {
151- response . appendResponseLine (
152- `Unable to navigate in the selected page: ${ error . message } .` ,
153- ) ;
154- }
155- break ;
156- case 'back' :
157- try {
158- await page . goBack ( options ) ;
159- response . appendResponseLine (
160- `Successfully navigated back to ${ page . url ( ) } .` ,
161- ) ;
162- } catch ( error ) {
163- response . appendResponseLine (
164- `Unable to navigate back in the selected page: ${ error . message } .` ,
165- ) ;
166- }
167- break ;
168- case 'forward' :
169- try {
170- await page . goForward ( options ) ;
171- response . appendResponseLine (
172- `Successfully navigated forward to ${ page . url ( ) } .` ,
173- ) ;
174- } catch ( error ) {
175- response . appendResponseLine (
176- `Unable to navigate forward in the selected page: ${ error . message } .` ,
177- ) ;
178- }
179- break ;
180- case 'reload' :
181- try {
182- await page . reload ( {
183- ...options ,
184- ignoreCache : request . params . ignoreCache ,
185- } ) ;
186- response . appendResponseLine ( `Successfully reloaded the page.` ) ;
187- } catch ( error ) {
188- response . appendResponseLine (
189- `Unable to reload the selected page: ${ error . message } .` ,
190- ) ;
191- }
192- break ;
146+ const handleBeforeUnload = request . params . handleBeforeUnload ?? 'accept' ;
147+ const dialogHandler = ( dialog : Dialog ) => {
148+ if ( dialog . type ( ) === 'beforeunload' ) {
149+ if ( handleBeforeUnload === 'accept' ) {
150+ response . appendResponseLine ( `Accepted a beforeunload dialog.` ) ;
151+ void dialog . accept ( ) ;
152+ } else {
153+ response . appendResponseLine ( `Declined a beforeunload dialog.` ) ;
154+ void dialog . dismiss ( ) ;
155+ }
156+ // We are not going to report the dialog like regular dialogs.
157+ context . clearDialog ( ) ;
193158 }
194- } ) ;
159+ } ;
160+ page . on ( 'dialog' , dialogHandler ) ;
161+
162+ try {
163+ await context . waitForEventsAfterAction ( async ( ) => {
164+ switch ( request . params . type ) {
165+ case 'url' :
166+ if ( ! request . params . url ) {
167+ throw new Error ( 'A URL is required for navigation of type=url.' ) ;
168+ }
169+ try {
170+ await page . goto ( request . params . url , options ) ;
171+ response . appendResponseLine (
172+ `Successfully navigated to ${ request . params . url } .` ,
173+ ) ;
174+ } catch ( error ) {
175+ response . appendResponseLine (
176+ `Unable to navigate in the selected page: ${ error . message } .` ,
177+ ) ;
178+ }
179+ break ;
180+ case 'back' :
181+ try {
182+ await page . goBack ( options ) ;
183+ response . appendResponseLine (
184+ `Successfully navigated back to ${ page . url ( ) } .` ,
185+ ) ;
186+ } catch ( error ) {
187+ response . appendResponseLine (
188+ `Unable to navigate back in the selected page: ${ error . message } .` ,
189+ ) ;
190+ }
191+ break ;
192+ case 'forward' :
193+ try {
194+ await page . goForward ( options ) ;
195+ response . appendResponseLine (
196+ `Successfully navigated forward to ${ page . url ( ) } .` ,
197+ ) ;
198+ } catch ( error ) {
199+ response . appendResponseLine (
200+ `Unable to navigate forward in the selected page: ${ error . message } .` ,
201+ ) ;
202+ }
203+ break ;
204+ case 'reload' :
205+ try {
206+ await page . reload ( {
207+ ...options ,
208+ ignoreCache : request . params . ignoreCache ,
209+ } ) ;
210+ response . appendResponseLine ( `Successfully reloaded the page.` ) ;
211+ } catch ( error ) {
212+ response . appendResponseLine (
213+ `Unable to reload the selected page: ${ error . message } .` ,
214+ ) ;
215+ }
216+ break ;
217+ }
218+ } ) ;
219+ } finally {
220+ page . off ( 'dialog' , dialogHandler ) ;
221+ }
195222
196223 response . setIncludePages ( true ) ;
197224 } ,
0 commit comments