|
6 | 6 | using System.Threading; |
7 | 7 | using System.Threading.Tasks; |
8 | 8 | using PuppeteerSharp; |
| 9 | +using NetInteractor.Config; |
9 | 10 |
|
10 | 11 | namespace NetInteractor.WebAccessors |
11 | 12 | { |
@@ -77,27 +78,61 @@ private async Task<IBrowser> GetBrowserAsync() |
77 | 78 | return _browser; |
78 | 79 | } |
79 | 80 |
|
80 | | - public async Task<ResponseInfo> GetAsync(string url) |
| 81 | + public async Task<ResponseInfo> GetAsync(string url, InteractActionConfig config = null) |
81 | 82 | { |
82 | 83 | var browser = await GetBrowserAsync(); |
83 | 84 | var page = await browser.NewPageAsync(); |
84 | 85 |
|
85 | 86 | try |
86 | 87 | { |
| 88 | + // Navigate to the URL and wait for network to be idle |
| 89 | + // This will handle the initial page load and any immediate redirects |
87 | 90 | var response = await page.GoToAsync(url, new NavigationOptions |
88 | 91 | { |
89 | 92 | WaitUntil = new[] { WaitUntilNavigation.Networkidle0 } |
90 | 93 | }); |
91 | 94 |
|
| 95 | + // Check if load delay is configured in options |
| 96 | + var loadDelayStr = config?.Options?.FirstOrDefault(attr => attr.Name == "loadDelay")?.Value; |
| 97 | + if (!string.IsNullOrEmpty(loadDelayStr) && int.TryParse(loadDelayStr, out var loadDelay)) |
| 98 | + { |
| 99 | + // After the page loads, check if JavaScript might trigger a delayed redirect |
| 100 | + // This handles cases like: setTimeout(() => window.location.href = '/other', 500) |
| 101 | + // We race between a delay and a navigation wait |
| 102 | + var delayTask = Task.Delay(loadDelay); |
| 103 | + var navigationTask = page.WaitForNavigationAsync(new NavigationOptions |
| 104 | + { |
| 105 | + WaitUntil = new[] { WaitUntilNavigation.Networkidle0 } |
| 106 | + }); |
| 107 | + |
| 108 | + var completedTask = await Task.WhenAny(delayTask, navigationTask); |
| 109 | + |
| 110 | + if (completedTask == navigationTask) |
| 111 | + { |
| 112 | + // Navigation occurred - await it to get the response and handle any exceptions |
| 113 | + try |
| 114 | + { |
| 115 | + response = await navigationTask; |
| 116 | + } |
| 117 | + catch (PuppeteerException) |
| 118 | + { |
| 119 | + // Navigation failed or was cancelled - use original response |
| 120 | + } |
| 121 | + } |
| 122 | + // else: delay completed first, meaning no navigation occurred within timeout - use original response |
| 123 | + // Note: The navigationTask will be cancelled when the page closes in the finally block |
| 124 | + } |
| 125 | + |
92 | 126 | return await GetResultFromResponse(page, response); |
93 | 127 | } |
94 | 128 | finally |
95 | 129 | { |
| 130 | + // Close the page. Any pending navigation will be cancelled. |
96 | 131 | await page.CloseAsync(); |
97 | 132 | } |
98 | 133 | } |
99 | 134 |
|
100 | | - public async Task<ResponseInfo> PostAsync(string url, NameValueCollection formValues) |
| 135 | + public async Task<ResponseInfo> PostAsync(string url, NameValueCollection formValues, InteractActionConfig config = null) |
101 | 136 | { |
102 | 137 | var browser = await GetBrowserAsync(); |
103 | 138 | var page = await browser.NewPageAsync(); |
|
0 commit comments