2323using System ;
2424using System . Collections . Concurrent ;
2525using System . Collections . Generic ;
26+ using System . Linq ;
2627using System . Threading . Tasks ;
2728using PuppeteerSharp . Bidi . Core ;
29+ using PuppeteerSharp . Helpers ;
2830
2931namespace PuppeteerSharp . Bidi ;
3032
@@ -102,40 +104,55 @@ public override async Task<IResponse> GoToAsync(string url, NavigationOptions op
102104 }
103105
104106 /// <inheritdoc />
105- public override Task < IResponse > WaitForNavigationAsync ( NavigationOptions options = null )
107+ public override async Task < IResponse > WaitForNavigationAsync ( NavigationOptions options = null )
106108 {
107- // TODO: This logic is missing tons of things.
108- var navigationTcs = new TaskCompletionSource < IResponse > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
109+ var timeout = options ? . Timeout ?? TimeoutSettings . NavigationTimeout ;
109110
110- // TODO: Async void is not safe. Refactor code.
111- BrowsingContext . Navigation += ( sender , args ) =>
111+ async Task < Navigation > WaitForEventNavigationAsync ( )
112112 {
113- args . Navigation . RequestCreated += async ( o , eventArgs ) =>
113+ // TODO: This logic is missing tons of things.
114+ var navigationTcs = new TaskCompletionSource < Navigation > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
115+
116+ // TODO: Async void is not safe. Refactor code.
117+ BrowsingContext . Navigation += ( sender , args ) => navigationTcs . TrySetResult ( args . Navigation ) ;
118+
119+ await navigationTcs . Task . ConfigureAwait ( false ) ;
120+
121+ var waitForLoadTask = WaitForLoadAsync ( options ) ;
122+
123+ // TODO: Add frame detached event.
124+ // TODO: Add fragment, failed and aborted events.
125+ await Task . WhenAny ( waitForLoadTask ) . WithTimeout ( timeout ) . ConfigureAwait ( false ) ;
126+
127+ return navigationTcs . Task . Result ;
128+ }
129+
130+ var waitForEventNavigationTask = WaitForEventNavigationAsync ( ) ;
131+ var waitForNetworkIdleTask = WaitForNetworkIdleAsync ( options ) ;
132+
133+ var waitForResponse = new Func < Task < IResponse > > ( async ( ) =>
134+ {
135+ await Task . WhenAll ( waitForEventNavigationTask , waitForNetworkIdleTask ) . ConfigureAwait ( false ) ;
136+ var navigation = waitForEventNavigationTask . Result ;
137+ var request = navigation . Request ;
138+
139+ if ( navigation . Request == null )
114140 {
115- try
116- {
117- var httpRequest = await BidiHttpRequest . Requests . GetItemAsync ( args . Navigation . Request )
118- . ConfigureAwait ( false ) ;
119-
120- if ( httpRequest . Response != null )
121- {
122- navigationTcs . TrySetResult ( httpRequest . Response ) ;
123- return ;
124- }
125-
126- args . Navigation . Request . Success += ( o , eventArgs ) =>
127- {
128- navigationTcs . TrySetResult ( httpRequest . Response ) ;
129- } ;
130- }
131- catch ( Exception ex )
132- {
133- navigationTcs . TrySetException ( ex ) ;
134- }
135- } ;
136- } ;
141+ return null ;
142+ }
143+
144+ var lastRequest = request . LastRedirect ?? request ;
145+ BidiHttpRequest . Requests . TryGetValue ( lastRequest , out var httpRequest ) ;
137146
138- return navigationTcs . Task ;
147+ return httpRequest . Response ;
148+ } ) ;
149+
150+ var waitForResponseTask = waitForResponse ( ) ;
151+
152+ // TODO: Listen to frame detached event.
153+ await Task . WhenAny ( waitForResponseTask ) . WithTimeout ( timeout ) . ConfigureAwait ( false ) ;
154+
155+ return waitForResponseTask . Result ;
139156 }
140157
141158 internal static BidiFrame From ( BidiPage parentPage , BidiFrame parentFrame , BrowsingContext browsingContext )
@@ -155,6 +172,37 @@ private PuppeteerException RewriteNavigationError(Exception ex, string url, int
155172 : new PuppeteerException ( "Navigation failed: " + ex . Message , ex ) ;
156173 }
157174
175+ private Task WaitForLoadAsync ( NavigationOptions options )
176+ {
177+ var waitUntil = options ? . WaitUntil ?? new [ ] { WaitUntilNavigation . Load } ;
178+ var timeout = options ? . Timeout ?? TimeoutSettings . NavigationTimeout ;
179+
180+ List < Task > tasks = new ( ) ;
181+
182+ if ( waitUntil . Contains ( WaitUntilNavigation . Load ) )
183+ {
184+ var loadTcs = new TaskCompletionSource < bool > ( ) ;
185+ BrowsingContext . Load += ( sender , args ) => loadTcs . TrySetResult ( true ) ;
186+ tasks . Add ( loadTcs . Task ) ;
187+ }
188+
189+ if ( waitUntil . Contains ( WaitUntilNavigation . DOMContentLoaded ) )
190+ {
191+ var domContentLoadedTcs = new TaskCompletionSource < bool > ( ) ;
192+ BrowsingContext . DomContentLoaded += ( sender , args ) => domContentLoadedTcs . TrySetResult ( true ) ;
193+ tasks . Add ( domContentLoadedTcs . Task ) ;
194+ }
195+
196+ // TODO: Check frame detached event.
197+ return Task . WhenAll ( tasks ) . WithTimeout ( timeout ) ;
198+ }
199+
200+ private Task WaitForNetworkIdleAsync ( NavigationOptions options )
201+ {
202+ // TODO: Complete this method.
203+ return Task . CompletedTask ;
204+ }
205+
158206 private async Task NavigateAsync ( string url )
159207 {
160208 // Some implementations currently only report errors when the
0 commit comments