@@ -53,6 +53,8 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
5353 PageImpl ownerPage ;
5454 private static final Map <EventType , String > eventSubscriptions () {
5555 Map <EventType , String > result = new HashMap <>();
56+ result .put (EventType .CONSOLE , "console" );
57+ result .put (EventType .DIALOG , "dialog" );
5658 result .put (EventType .REQUEST , "request" );
5759 result .put (EventType .RESPONSE , "response" );
5860 result .put (EventType .REQUESTFINISHED , "requestFinished" );
@@ -77,6 +79,8 @@ static class HarRecorder {
7779
7880 enum EventType {
7981 CLOSE ,
82+ CONSOLE ,
83+ DIALOG ,
8084 PAGE ,
8185 REQUEST ,
8286 REQUESTFAILED ,
@@ -120,6 +124,26 @@ public void offClose(Consumer<BrowserContext> handler) {
120124 listeners .remove (EventType .CLOSE , handler );
121125 }
122126
127+ @ Override
128+ public void onConsoleMessage (Consumer <ConsoleMessage > handler ) {
129+ listeners .add (EventType .CONSOLE , handler );
130+ }
131+
132+ @ Override
133+ public void offConsoleMessage (Consumer <ConsoleMessage > handler ) {
134+ listeners .remove (EventType .CONSOLE , handler );
135+ }
136+
137+ @ Override
138+ public void onDialog (Consumer <Dialog > handler ) {
139+ listeners .add (EventType .DIALOG , handler );
140+ }
141+
142+ @ Override
143+ public void offDialog (Consumer <Dialog > handler ) {
144+ listeners .remove (EventType .DIALOG , handler );
145+ }
146+
123147 @ Override
124148 public void onPage (Consumer <Page > handler ) {
125149 listeners .add (EventType .PAGE , handler );
@@ -516,6 +540,18 @@ public void waitForCondition(BooleanSupplier predicate, WaitForConditionOptions
516540 runUntil (() -> {}, new WaitableRace <>(waitables ));
517541 }
518542
543+ @ Override
544+ public ConsoleMessage waitForConsoleMessage (WaitForConsoleMessageOptions options , Runnable code ) {
545+ return withWaitLogging ("BrowserContext.waitForConsoleMessage" , logger -> waitForConsoleMessageImpl (options , code ));
546+ }
547+
548+ private ConsoleMessage waitForConsoleMessageImpl (WaitForConsoleMessageOptions options , Runnable code ) {
549+ if (options == null ) {
550+ options = new WaitForConsoleMessageOptions ();
551+ }
552+ return waitForEventWithTimeout (EventType .CONSOLE , code , options .predicate , options .timeout );
553+ }
554+
519555 private class WaitableContextClose <R > extends WaitableEvent <EventType , R > {
520556 WaitableContextClose () {
521557 super (BrowserContextImpl .this .listeners , EventType .CLOSE );
@@ -554,7 +590,36 @@ WaitableResult<JsonElement> pause() {
554590
555591 @ Override
556592 protected void handleEvent (String event , JsonObject params ) {
557- if ("route" .equals (event )) {
593+ if ("dialog" .equals (event )) {
594+ String guid = params .getAsJsonObject ("dialog" ).get ("guid" ).getAsString ();
595+ DialogImpl dialog = connection .getExistingObject (guid );
596+ boolean hasListeners = false ;
597+ if (listeners .hasListeners (EventType .DIALOG )) {
598+ hasListeners = true ;
599+ listeners .notify (EventType .DIALOG , dialog );
600+ }
601+ PageImpl page = dialog .page ();
602+ if (page != null ) {
603+ if (page .listeners .hasListeners (PageImpl .EventType .DIALOG )) {
604+ hasListeners = true ;
605+ page .listeners .notify (PageImpl .EventType .DIALOG , dialog );
606+ }
607+ }
608+ // Although we do similar handling on the server side, we still need this logic
609+ // on the client side due to a possible race condition between two async calls:
610+ // a) removing "dialog" listener subscription (client->server)
611+ // b) actual "dialog" event (server->client)
612+ if (!hasListeners ) {
613+ if ("beforeunload" .equals (dialog .type ())) {
614+ try {
615+ dialog .accept ();
616+ } catch (PlaywrightException e ) {
617+ }
618+ } else {
619+ dialog .dismiss ();
620+ }
621+ }
622+ } else if ("route" .equals (event )) {
558623 RouteImpl route = connection .getExistingObject (params .getAsJsonObject ("route" ).get ("guid" ).getAsString ());
559624 handleRoute (route );
560625 } else if ("page" .equals (event )) {
@@ -570,6 +635,14 @@ protected void handleEvent(String event, JsonObject params) {
570635 if (binding != null ) {
571636 bindingCall .call (binding );
572637 }
638+ } else if ("console" .equals (event )) {
639+ String guid = params .getAsJsonObject ("message" ).get ("guid" ).getAsString ();
640+ ConsoleMessageImpl message = connection .getExistingObject (guid );
641+ listeners .notify (BrowserContextImpl .EventType .CONSOLE , message );
642+ PageImpl page = message .page ();
643+ if (page != null ) {
644+ page .listeners .notify (PageImpl .EventType .CONSOLE , message );
645+ }
573646 } else if ("request" .equals (event )) {
574647 String guid = params .getAsJsonObject ("request" ).get ("guid" ).getAsString ();
575648 RequestImpl request = connection .getExistingObject (guid );
0 commit comments