Best Puppeteer-sharp code snippet using PuppeteerSharp.States.ExitingState.ExitAsync
ChromiumProcess.cs
Source:ChromiumProcess.cs
...133 /// Kills the Chromium process if it has not exited within this period.134 /// </summary>135 /// <param name="timeout">The maximum waiting time for a graceful process exit.</param>136 /// <returns></returns>137 public Task EnsureExitAsync(TimeSpan? timeout) => timeout.HasValue138 ? _currentState.ExitAsync(this, timeout.Value)139 : _currentState.KillAsync(this);140 /// <summary>141 /// Asynchronously kills Chromium process.142 /// </summary>143 /// <returns></returns>144 public Task KillAsync() => _currentState.KillAsync(this);145 /// <summary>146 /// Waits for Chromium process exit within a given timeout.147 /// </summary>148 /// <param name="timeout">The maximum wait period.</param>149 /// <returns><c>true</c> if Chromium process has exited within the given <paramref name="timeout"/>,150 /// or <c>false</c> otherwise.</returns>151 public async Task<bool> WaitForExitAsync(TimeSpan? timeout)152 {153 if (timeout.HasValue)154 {155 var completedTask = await Task.WhenAny(_exitCompletionSource.Task, Task.Delay(timeout.Value)).ConfigureAwait(false);156 return completedTask == _exitCompletionSource.Task;157 }158 await _exitCompletionSource.Task.ConfigureAwait(false);159 return true;160 }161 /// <inheritdoc />162 public override string ToString() => $"Chromium process; EndPoint={EndPoint}; State={_currentState}";163 #endregion164 #region Private methods165 private static (List<string> chromiumArgs, TempDirectory tempUserDataDir) PrepareChromiumArgs(LaunchOptions options)166 {167 var chromiumArgs = new List<string>();168 if (!options.IgnoreDefaultArgs)169 {170 chromiumArgs.AddRange(GetDefaultArgs(options));171 }172 else if (options.IgnoredDefaultArgs?.Length > 0)173 {174 chromiumArgs.AddRange(GetDefaultArgs(options).Except(options.IgnoredDefaultArgs));175 }176 else177 {178 chromiumArgs.AddRange(options.Args);179 }180 TempDirectory tempUserDataDir = null;181 if (!chromiumArgs.Any(argument => argument.StartsWith("--remote-debugging-", StringComparison.Ordinal)))182 {183 chromiumArgs.Add("--remote-debugging-port=0");184 }185 var userDataDirOption = chromiumArgs.FirstOrDefault(i => i.StartsWith(UserDataDirArgument, StringComparison.Ordinal));186 if (string.IsNullOrEmpty(userDataDirOption))187 {188 tempUserDataDir = new TempDirectory();189 chromiumArgs.Add($"{UserDataDirArgument}={tempUserDataDir.Path.Quote()}");190 }191 return (chromiumArgs, tempUserDataDir);192 }193 internal static string[] GetDefaultArgs(LaunchOptions options)194 {195 var chromeArguments = new List<string>(DefaultArgs);196 if (!string.IsNullOrEmpty(options.UserDataDir))197 {198 chromeArguments.Add($"{UserDataDirArgument}={options.UserDataDir.Quote()}");199 }200 if (options.Devtools)201 {202 chromeArguments.Add("--auto-open-devtools-for-tabs");203 }204 if (options.Headless)205 {206 chromeArguments.AddRange(new[]{207 "--headless",208 "--hide-scrollbars",209 "--mute-audio"210 });211 if (BrowserFetcher.GetCurrentPlatform() == Platform.Win32)212 {213 chromeArguments.Add("--disable-gpu");214 }215 }216 if (options.Args.All(arg => arg.StartsWith("-", StringComparison.Ordinal)))217 {218 chromeArguments.Add("about:blank");219 }220 chromeArguments.AddRange(options.Args);221 return chromeArguments.ToArray();222 }223 private static void SetEnvVariables(IDictionary<string, string> environment, IDictionary<string, string> customEnv, IDictionary realEnv)224 {225 foreach (DictionaryEntry item in realEnv)226 {227 environment[item.Key.ToString()] = item.Value.ToString();228 }229 if (customEnv != null)230 {231 foreach (var item in customEnv)232 {233 environment[item.Key] = item.Value;234 }235 }236 }237 #endregion238 #region State machine239 /// <summary>240 /// Represents state machine for Chromium process instances. The happy path runs along the241 /// following state transitions: <see cref="Initial"/>242 /// -> <see cref="Starting"/>243 /// -> <see cref="Started"/>244 /// -> <see cref="Exiting"/>245 /// -> <see cref="Exited"/>.246 /// -> <see cref="Disposed"/>.247 /// </summary>248 /// <remarks>249 /// <para>250 /// This state machine implements the following state transitions:251 /// <code>252 /// State Event Target State Action253 /// ======== =================== ============ ==========================================================254 /// Initial --StartAsync------> Starting Start process and wait for endpoint255 /// Initial --ExitAsync-------> Exited Cleanup temp user data256 /// Initial --KillAsync-------> Exited Cleanup temp user data257 /// Initial --Dispose---------> Disposed Cleanup temp user data258 /// Starting --StartAsync------> Starting -259 /// Starting --ExitAsync-------> Exiting Wait for process exit260 /// Starting --KillAsync-------> Killing Kill process261 /// Starting --Dispose---------> Disposed Kill process; Cleanup temp user data; throw ObjectDisposedException on outstanding async operations;262 /// Starting --endpoint ready--> Started Complete StartAsync successfully; Log process start263 /// Starting --process exit----> Exited Complete StartAsync with exception; Cleanup temp user data264 /// Started --StartAsync------> Started -265 /// Started --EnsureExitAsync-> Exiting Start exit timer; Log process exit266 /// Started --KillAsync-------> Killing Kill process; Log process exit267 /// Started --Dispose---------> Disposed Kill process; Log process exit; Cleanup temp user data; throw ObjectDisposedException on outstanding async operations;268 /// Started --process exit----> Exited Log process exit; Cleanup temp user data269 /// Exiting --StartAsync------> Exiting - (StartAsync throws InvalidOperationException)270 /// Exiting --ExitAsync-------> Exiting -271 /// Exiting --KillAsync-------> Killing Kill process272 /// Exiting --Dispose---------> Disposed Kill process; Cleanup temp user data; throw ObjectDisposedException on outstanding async operations;273 /// Exiting --exit timeout----> Killing Kill process274 /// Exiting --process exit----> Exited Cleanup temp user data; complete outstanding async operations;275 /// Killing --StartAsync------> Killing - (StartAsync throws InvalidOperationException)276 /// Killing --KillAsync-------> Killing -277 /// Killing --Dispose---------> Disposed Cleanup temp user data; throw ObjectDisposedException on outstanding async operations;278 /// Killing --process exit----> Exited Cleanup temp user data; complete outstanding async operations;279 /// Exited --StartAsync------> Killing - (StartAsync throws InvalidOperationException)280 /// Exited --KillAsync-------> Exited -281 /// Exited --Dispose---------> Disposed -282 /// Disposed --StartAsync------> Disposed -283 /// Disposed --KillAsync-------> Disposed -284 /// Disposed --Dispose---------> Disposed -285 /// </code>286 /// </para>287 /// </remarks>288 private abstract class State289 {290 #region Predefined states291 public static readonly State Initial = new InitialState();292 private static readonly StartingState Starting = new StartingState();293 private static readonly StartedState Started = new StartedState();294 private static readonly ExitingState Exiting = new ExitingState();295 private static readonly KillingState Killing = new KillingState();296 private static readonly ExitedState Exited = new ExitedState();297 private static readonly DisposedState Disposed = new DisposedState();298 #endregion299 #region Properties300 public bool IsExiting => this == Killing || this == Exiting;301 public bool IsExited => this == Exited || this == Disposed;302 #endregion303 #region Methods304 /// <summary>305 /// Attempts thread-safe transitions from a given state to this state.306 /// </summary>307 /// <param name="p">The Chromium process</param>308 /// <param name="fromState">The state from which state transition takes place</param>309 /// <returns>Returns <c>true</c> if transition is successful, or <c>false</c> if transition310 /// cannot be made because current state does not equal <paramref name="fromState"/>.</returns>311 protected bool TryEnter(ChromiumProcess p, State fromState)312 {313 if (Interlocked.CompareExchange(ref p._currentState, this, fromState) == fromState)314 {315 fromState.Leave(p);316 return true;317 }318 return false;319 }320 /// <summary>321 /// Notifies that state machine is about to transition to another state.322 /// </summary>323 /// <param name="p">The Chromium process</param>324 protected virtual void Leave(ChromiumProcess p)325 { }326 /// <summary>327 /// Handles process start request.328 /// </summary>329 /// <param name="p">The Chromium process</param>330 /// <returns></returns>331 public virtual Task StartAsync(ChromiumProcess p) => Task.FromException(InvalidOperation("start"));332 /// <summary>333 /// Handles process exit request.334 /// </summary>335 /// <param name="p">The Chromium process</param>336 /// <param name="timeout">The maximum waiting time for a graceful process exit.</param>337 /// <returns></returns>338 public virtual Task ExitAsync(ChromiumProcess p, TimeSpan timeout) => Task.FromException(InvalidOperation("exit"));339 /// <summary>340 /// Handles process kill request.341 /// </summary>342 /// <param name="p">The Chromium process</param>343 /// <returns></returns>344 public virtual Task KillAsync(ChromiumProcess p) => Task.FromException(InvalidOperation("kill"));345 /// <summary>346 /// Handles wait for process exit request.347 /// </summary>348 /// <param name="p">The Chromium process</param>349 /// <returns></returns>350 public virtual Task WaitForExitAsync(ChromiumProcess p) => p._exitCompletionSource.Task;351 /// <summary>352 /// Handles disposal of process and temporary user directory353 /// </summary>354 /// <param name="p"></param>355 public virtual void Dispose(ChromiumProcess p) => Disposed.EnterFrom(p, this);356 public override string ToString()357 {358 var name = GetType().Name;359 return name.Substring(0, name.Length - "State".Length);360 }361 private Exception InvalidOperation(string operationName)362 => new InvalidOperationException($"Cannot {operationName} in state {this}");363 /// <summary>364 /// Kills process if it is still alive.365 /// </summary>366 /// <param name="p"></param>367 private static void Kill(ChromiumProcess p)368 {369 try370 {371 if (!p.Process.HasExited)372 {373 p.Process.Kill();374 }375 }376 catch (InvalidOperationException)377 {378 // Ignore379 }380 }381 #endregion382 #region Concrete state classes383 private class InitialState : State384 {385 public override Task StartAsync(ChromiumProcess p) => Starting.EnterFromAsync(p, this);386 public override Task ExitAsync(ChromiumProcess p, TimeSpan timeout)387 {388 Exited.EnterFrom(p, this);389 return Task.CompletedTask;390 }391 public override Task KillAsync(ChromiumProcess p)392 {393 Exited.EnterFrom(p, this);394 return Task.CompletedTask;395 }396 public override Task WaitForExitAsync(ChromiumProcess p) => Task.FromException(InvalidOperation("wait for exit"));397 }398 private class StartingState : State399 {400 public Task EnterFromAsync(ChromiumProcess p, State fromState)401 {402 if (!TryEnter(p, fromState))403 {404 // Delegate StartAsync to current state, because it has already changed since405 // transition to this state was initiated.406 return p._currentState.StartAsync(p);407 }408 return StartCoreAsync(p);409 }410 public override Task StartAsync(ChromiumProcess p) => p._startCompletionSource.Task;411 public override Task ExitAsync(ChromiumProcess p, TimeSpan timeout) => Exiting.EnterFromAsync(p, this, timeout);412 public override Task KillAsync(ChromiumProcess p) => Killing.EnterFromAsync(p, this);413 public override void Dispose(ChromiumProcess p)414 {415 p._startCompletionSource.TrySetException(new ObjectDisposedException(p.ToString()));416 base.Dispose(p);417 }418 private async Task StartCoreAsync(ChromiumProcess p)419 {420 var output = new StringBuilder();421 void OnProcessDataReceivedWhileStarting(object sender, DataReceivedEventArgs e)422 {423 if (e.Data != null)424 {425 output.AppendLine(e.Data);426 var match = Regex.Match(e.Data, "^DevTools listening on (ws:\\/\\/.*)");427 if (match.Success)428 {429 p._startCompletionSource.SetResult(match.Groups[1].Value);430 }431 }432 }433 void OnProcessExitedWhileStarting(object sender, EventArgs e)434 {435 p._startCompletionSource.SetException(new ChromiumProcessException($"Failed to launch Chromium! {output}"));436 }437 void OnProcessExited(object sender, EventArgs e)438 {439 Exited.EnterFrom(p, p._currentState);440 }441 p.Process.ErrorDataReceived += OnProcessDataReceivedWhileStarting;442 p.Process.Exited += OnProcessExitedWhileStarting;443 p.Process.Exited += OnProcessExited;444 CancellationTokenSource cts = null;445 try446 {447 p.Process.Start();448 await Started.EnterFromAsync(p, this).ConfigureAwait(false);449 p.Process.BeginErrorReadLine();450 var timeout = p._options.Timeout;451 if (timeout > 0)452 {453 cts = new CancellationTokenSource(timeout);454 cts.Token.Register(() => p._startCompletionSource.TrySetException(455 new ChromiumProcessException($"Timed out after {timeout} ms while trying to connect to Chromium!")));456 }457 try458 {459 await p._startCompletionSource.Task.ConfigureAwait(false);460 await Started.EnterFromAsync(p, this).ConfigureAwait(false);461 }462 catch463 {464 await Killing.EnterFromAsync(p, this).ConfigureAwait(false);465 throw;466 }467 }468 finally469 {470 cts?.Dispose();471 p.Process.Exited -= OnProcessExitedWhileStarting;472 p.Process.ErrorDataReceived -= OnProcessDataReceivedWhileStarting;473 }474 }475 }476 private class StartedState : State477 {478 public Task EnterFromAsync(ChromiumProcess p, State fromState)479 {480 if (TryEnter(p, fromState))481 {482 // Process has not exited or been killed since transition to this state was initiated483 LogProcessCount(p, Interlocked.Increment(ref _processCount));484 }485 return Task.CompletedTask;486 }487 protected override void Leave(ChromiumProcess p)488 => LogProcessCount(p, Interlocked.Decrement(ref _processCount));489 public override Task StartAsync(ChromiumProcess p) => Task.CompletedTask;490 public override Task ExitAsync(ChromiumProcess p, TimeSpan timeout) => Exiting.EnterFromAsync(p, this, timeout);491 public override Task KillAsync(ChromiumProcess p) => Killing.EnterFromAsync(p, this);492 private static void LogProcessCount(ChromiumProcess p, int processCount)493 {494 try495 {496 p._logger?.LogInformation("Process Count: {ProcessCount}", processCount);497 }498 catch499 {500 // Prevent logging exception from causing havoc501 }502 }503 }504 private class ExitingState : State505 {506 public Task EnterFromAsync(ChromiumProcess p, State fromState, TimeSpan timeout)507 {508 return !TryEnter(p, fromState) ? p._currentState.ExitAsync(p, timeout) : ExitAsync(p, timeout);509 }510 public override async Task ExitAsync(ChromiumProcess p, TimeSpan timeout)511 {512 var timeoutTask = Task.Delay(timeout);513 var waitForExitTask = WaitForExitAsync(p);514 var completedTask = await Task.WhenAny(waitForExitTask, timeoutTask).ConfigureAwait(false);515 if (completedTask == timeoutTask)516 {517 await Killing.EnterFromAsync(p, this).ConfigureAwait(false);518 await waitForExitTask.ConfigureAwait(false);519 }520 }521 public override Task KillAsync(ChromiumProcess p) => Killing.EnterFromAsync(p, this);522 }523 private class KillingState : State524 {525 public Task EnterFromAsync(ChromiumProcess p, State fromState)526 {527 if (!TryEnter(p, fromState))528 {529 // Delegate KillAsync to current state, because it has already changed since530 // transition to this state was initiated.531 return p._currentState.KillAsync(p);532 }533 try534 {535 if (!p.Process.HasExited)536 {537 p.Process.Kill();538 }539 }540 catch (InvalidOperationException)541 {542 // Ignore543 }544 return WaitForExitAsync(p);545 }546 public override Task ExitAsync(ChromiumProcess p, TimeSpan timeout) => WaitForExitAsync(p);547 public override Task KillAsync(ChromiumProcess p) => WaitForExitAsync(p);548 }549 private class ExitedState : State550 {551 public void EnterFrom(ChromiumProcess p, State fromState)552 {553 while (!TryEnter(p, fromState))554 {555 // Current state has changed since transition to this state was requested.556 // Therefore retry transition to this state from the current state. This ensures557 // that Leave() operation of current state is properly called.558 fromState = p._currentState;559 if (fromState == this)560 {561 return;562 }563 }564 p._exitCompletionSource.TrySetResult(true);565 p._tempUserDataDir?.Dispose();566 }567 public override Task ExitAsync(ChromiumProcess p, TimeSpan timeout) => Task.CompletedTask;568 public override Task KillAsync(ChromiumProcess p) => Task.CompletedTask;569 public override Task WaitForExitAsync(ChromiumProcess p) => Task.CompletedTask;570 }571 private class DisposedState : State572 {573 public void EnterFrom(ChromiumProcess p, State fromState)574 {575 if (!TryEnter(p, fromState))576 {577 // Delegate Dispose to current state, because it has already changed since578 // transition to this state was initiated.579 p._currentState.Dispose(p);580 }581 else if (fromState != Exited)582 {583 Kill(p);584 p._exitCompletionSource.TrySetException(new ObjectDisposedException(p.ToString()));585 p._tempUserDataDir?.Dispose();586 }587 }588 public override Task StartAsync(ChromiumProcess p) => throw new ObjectDisposedException(p.ToString());589 public override Task ExitAsync(ChromiumProcess p, TimeSpan timeout) => throw new ObjectDisposedException(p.ToString());590 public override Task KillAsync(ChromiumProcess p) => throw new ObjectDisposedException(p.ToString());591 public override void Dispose(ChromiumProcess p)592 {593 // Nothing to do594 }595 }596 #endregion597 }598 #endregion599 }600}...
LauncherBase.cs
Source:LauncherBase.cs
...101 /// Kills the Base process if it has not exited within this period.102 /// </summary>103 /// <param name="timeout">The maximum waiting time for a graceful process exit.</param>104 /// <returns></returns>105 public Task EnsureExitAsync(TimeSpan? timeout) => timeout.HasValue106 ? _currentState.ExitAsync(this, timeout.Value)107 : _currentState.KillAsync(this);108 /// <summary>109 /// Asynchronously kills Base process.110 /// </summary>111 /// <returns></returns>112 public Task KillAsync() => _currentState.KillAsync(this);113 /// <summary>114 /// Waits for Base process exit within a given timeout.115 /// </summary>116 /// <param name="timeout">The maximum wait period.</param>117 /// <returns><c>true</c> if Base process has exited within the given <paramref name="timeout"/>,118 /// or <c>false</c> otherwise.</returns>119 public async Task<bool> WaitForExitAsync(TimeSpan? timeout)120 {121 if (timeout.HasValue)122 {123 bool taskCompleted = true;124 await _exitCompletionSource.Task.WithTimeout(125 () =>126 {127 taskCompleted = false;128 }, timeout.Value).ConfigureAwait(false);129 return taskCompleted;130 }131 await _exitCompletionSource.Task.ConfigureAwait(false);132 return true;133 }134 #endregion135 #region Private methods136 /// <summary>137 /// Set Env Variables138 /// </summary>139 /// <param name="environment">The environment.</param>140 /// <param name="customEnv">The customEnv.</param>141 /// <param name="realEnv">The realEnv.</param>142 protected static void SetEnvVariables(IDictionary<string, string> environment, IDictionary<string, string> customEnv, IDictionary realEnv)143 {144 foreach (DictionaryEntry item in realEnv)145 {146 environment[item.Key.ToString()] = item.Value.ToString();147 }148 if (customEnv != null)149 {150 foreach (var item in customEnv)151 {152 environment[item.Key] = item.Value;153 }154 }155 }156 #endregion157 #region State machine158 /// <summary>159 /// Represents state machine for Base process instances. The happy path runs along the160 /// following state transitions: <see cref="Initial"/>161 /// -> <see cref="Starting"/>162 /// -> <see cref="Started"/>163 /// -> <see cref="Exiting"/>164 /// -> <see cref="Exited"/>.165 /// -> <see cref="Disposed"/>.166 /// </summary>167 /// <remarks>168 /// <para>169 /// This state machine implements the following state transitions:170 /// <code>171 /// State Event Target State Action172 /// ======== =================== ============ ==========================================================173 /// Initial --StartAsync------> Starting Start process and wait for endpoint174 /// Initial --ExitAsync-------> Exited Cleanup temp user data175 /// Initial --KillAsync-------> Exited Cleanup temp user data176 /// Initial --Dispose---------> Disposed Cleanup temp user data177 /// Starting --StartAsync------> Starting -178 /// Starting --ExitAsync-------> Exiting Wait for process exit179 /// Starting --KillAsync-------> Killing Kill process180 /// Starting --Dispose---------> Disposed Kill process; Cleanup temp user data; throw ObjectDisposedException on outstanding async operations;181 /// Starting --endpoint ready--> Started Complete StartAsync successfully; Log process start182 /// Starting --process exit----> Exited Complete StartAsync with exception; Cleanup temp user data183 /// Started --StartAsync------> Started -184 /// Started --EnsureExitAsync-> Exiting Start exit timer; Log process exit185 /// Started --KillAsync-------> Killing Kill process; Log process exit186 /// Started --Dispose---------> Disposed Kill process; Log process exit; Cleanup temp user data; throw ObjectDisposedException on outstanding async operations;187 /// Started --process exit----> Exited Log process exit; Cleanup temp user data188 /// Exiting --StartAsync------> Exiting - (StartAsync throws InvalidOperationException)189 /// Exiting --ExitAsync-------> Exiting -190 /// Exiting --KillAsync-------> Killing Kill process191 /// Exiting --Dispose---------> Disposed Kill process; Cleanup temp user data; throw ObjectDisposedException on outstanding async operations;192 /// Exiting --exit timeout----> Killing Kill process193 /// Exiting --process exit----> Exited Cleanup temp user data; complete outstanding async operations;194 /// Killing --StartAsync------> Killing - (StartAsync throws InvalidOperationException)195 /// Killing --KillAsync-------> Killing -196 /// Killing --Dispose---------> Disposed Cleanup temp user data; throw ObjectDisposedException on outstanding async operations;197 /// Killing --process exit----> Exited Cleanup temp user data; complete outstanding async operations;198 /// Exited --StartAsync------> Killing - (StartAsync throws InvalidOperationException)199 /// Exited --KillAsync-------> Exited -200 /// Exited --Dispose---------> Disposed -201 /// Disposed --StartAsync------> Disposed -202 /// Disposed --KillAsync-------> Disposed -203 /// Disposed --Dispose---------> Disposed -204 /// </code>205 /// </para>206 /// </remarks>207 protected abstract class State208 {209 #region Predefined states210 /// <summary>211 /// Set initial state.212 /// </summary>213 public static readonly State Initial = new InitialState();214 private static readonly StartingState Starting = new StartingState();215 private static readonly StartedState Started = new StartedState();216 private static readonly ExitingState Exiting = new ExitingState();217 private static readonly KillingState Killing = new KillingState();218 private static readonly ExitedState Exited = new ExitedState();219 private static readonly DisposedState Disposed = new DisposedState();220 #endregion221 #region Properties222 /// <summary>223 /// Get If process exists.224 /// </summary>225 public bool IsExiting => this == Killing || this == Exiting;226 /// <summary>227 /// Get If process is exited.228 /// </summary>229 public bool IsExited => this == Exited || this == Disposed;230 #endregion231 #region Methods232 /// <summary>233 /// Attempts thread-safe transitions from a given state to this state.234 /// </summary>235 /// <param name="p">The Base process</param>236 /// <param name="fromState">The state from which state transition takes place</param>237 /// <returns>Returns <c>true</c> if transition is successful, or <c>false</c> if transition238 /// cannot be made because current state does not equal <paramref name="fromState"/>.</returns>239 protected bool TryEnter(LauncherBase p, State fromState)240 {241 if (Interlocked.CompareExchange(ref p._currentState, this, fromState) == fromState)242 {243 fromState.Leave(p);244 return true;245 }246 return false;247 }248 /// <summary>249 /// Notifies that state machine is about to transition to another state.250 /// </summary>251 /// <param name="p">The Base process</param>252 protected virtual void Leave(LauncherBase p)253 {254 }255 /// <summary>256 /// Handles process start request.257 /// </summary>258 /// <param name="p">The Base process</param>259 /// <returns></returns>260 public virtual Task StartAsync(LauncherBase p) => Task.FromException(InvalidOperation("start"));261 /// <summary>262 /// Handles process exit request.263 /// </summary>264 /// <param name="p">The Base process</param>265 /// <param name="timeout">The maximum waiting time for a graceful process exit.</param>266 /// <returns></returns>267 public virtual Task ExitAsync(LauncherBase p, TimeSpan timeout) => Task.FromException(InvalidOperation("exit"));268 /// <summary>269 /// Handles process kill request.270 /// </summary>271 /// <param name="p">The Base process</param>272 /// <returns></returns>273 public virtual Task KillAsync(LauncherBase p) => Task.FromException(InvalidOperation("kill"));274 /// <summary>275 /// Handles wait for process exit request.276 /// </summary>277 /// <param name="p">The Base process</param>278 /// <returns></returns>279 public virtual Task WaitForExitAsync(LauncherBase p) => p._exitCompletionSource.Task;280 /// <summary>281 /// Handles disposal of process and temporary user directory282 /// </summary>283 /// <param name="p"></param>284 public virtual void Dispose(LauncherBase p) => Disposed.EnterFrom(p, this);285 /// <inheritdoc />286 public override string ToString()287 {288 string name = GetType().Name;289 return name.Substring(0, name.Length - "State".Length);290 }291 private Exception InvalidOperation(string operationName)292 => new InvalidOperationException($"Cannot {operationName} in state {this}");293 /// <summary>294 /// Kills process if it is still alive.295 /// </summary>296 /// <param name="p"></param>297 private static void Kill(LauncherBase p)298 {299 try300 {301 if (!p.Process.HasExited)302 {303 p.Process.Kill();304 }305 }306 catch (InvalidOperationException)307 {308 // Ignore309 }310 }311 #endregion312 #region Concrete state classes313 private class InitialState : State314 {315 public override Task StartAsync(LauncherBase p) => Starting.EnterFromAsync(p, this);316 public override Task ExitAsync(LauncherBase p, TimeSpan timeout)317 {318 Exited.EnterFrom(p, this);319 return Task.CompletedTask;320 }321 public override Task KillAsync(LauncherBase p)322 {323 Exited.EnterFrom(p, this);324 return Task.CompletedTask;325 }326 public override Task WaitForExitAsync(LauncherBase p) => Task.FromException(InvalidOperation("wait for exit"));327 }328 private class StartingState : State329 {330 public Task EnterFromAsync(LauncherBase p, State fromState)331 {332 if (!TryEnter(p, fromState))333 {334 // Delegate StartAsync to current state, because it has already changed since335 // transition to this state was initiated.336 return p._currentState.StartAsync(p);337 }338 return StartCoreAsync(p);339 }340 public override Task StartAsync(LauncherBase p) => p._startCompletionSource.Task;341 public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => Exiting.EnterFromAsync(p, this, timeout);342 public override Task KillAsync(LauncherBase p) => Killing.EnterFromAsync(p, this);343 public override void Dispose(LauncherBase p)344 {345 p._startCompletionSource.TrySetException(new ObjectDisposedException(p.ToString()));346 base.Dispose(p);347 }348 private async Task StartCoreAsync(LauncherBase p)349 {350 var output = new StringBuilder();351 void OnProcessDataReceivedWhileStarting(object sender, DataReceivedEventArgs e)352 {353 if (e.Data != null)354 {355 output.AppendLine(e.Data);356 var match = Regex.Match(e.Data, "^DevTools listening on (ws:\\/\\/.*)");357 if (match.Success)358 {359 p._startCompletionSource.TrySetResult(match.Groups[1].Value);360 }361 }362 }363 void OnProcessExitedWhileStarting(object sender, EventArgs e)364 => p._startCompletionSource.TrySetException(new ProcessException($"Failed to launch Base! {output}"));365 void OnProcessExited(object sender, EventArgs e) => Exited.EnterFrom(p, p._currentState);366 p.Process.ErrorDataReceived += OnProcessDataReceivedWhileStarting;367 p.Process.Exited += OnProcessExitedWhileStarting;368 p.Process.Exited += OnProcessExited;369 CancellationTokenSource cts = null;370 try371 {372 p.Process.Start();373 await Started.EnterFromAsync(p, this).ConfigureAwait(false);374 p.Process.BeginErrorReadLine();375 int timeout = p._options.Timeout;376 if (timeout > 0)377 {378 cts = new CancellationTokenSource(timeout);379 cts.Token.Register(() => p._startCompletionSource.TrySetException(380 new ProcessException($"Timed out after {timeout} ms while trying to connect to Base!")));381 }382 try383 {384 await p._startCompletionSource.Task.ConfigureAwait(false);385 await Started.EnterFromAsync(p, this).ConfigureAwait(false);386 }387 catch388 {389 await Killing.EnterFromAsync(p, this).ConfigureAwait(false);390 throw;391 }392 }393 finally394 {395 cts?.Dispose();396 p.Process.Exited -= OnProcessExitedWhileStarting;397 p.Process.ErrorDataReceived -= OnProcessDataReceivedWhileStarting;398 }399 }400 }401 private class StartedState : State402 {403 public Task EnterFromAsync(LauncherBase p, State fromState)404 {405 if (TryEnter(p, fromState))406 {407 }408 return Task.CompletedTask;409 }410 protected override void Leave(LauncherBase p) { }411 public override Task StartAsync(LauncherBase p) => Task.CompletedTask;412 public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => Exiting.EnterFromAsync(p, this, timeout);413 public override Task KillAsync(LauncherBase p) => Killing.EnterFromAsync(p, this);414 }415 private class ExitingState : State416 {417 public Task EnterFromAsync(LauncherBase p, State fromState, TimeSpan timeout)418 => !TryEnter(p, fromState) ? p._currentState.ExitAsync(p, timeout) : ExitAsync(p, timeout);419 public override async Task ExitAsync(LauncherBase p, TimeSpan timeout)420 {421 var waitForExitTask = WaitForExitAsync(p);422 await waitForExitTask.WithTimeout(423 async () =>424 {425 await Killing.EnterFromAsync(p, this).ConfigureAwait(false);426 await waitForExitTask.ConfigureAwait(false);427 },428 timeout,429 CancellationToken.None).ConfigureAwait(false);430 }431 public override Task KillAsync(LauncherBase p) => Killing.EnterFromAsync(p, this);432 }433 private class KillingState : State434 {435 public async Task EnterFromAsync(LauncherBase p, State fromState)436 {437 if (!TryEnter(p, fromState))438 {439 // Delegate KillAsync to current state, because it has already changed since440 // transition to this state was initiated.441 await p._currentState.KillAsync(p).ConfigureAwait(false);442 }443 try444 {445 if (!p.Process.HasExited)446 {447 p.Process.Kill();448 }449 }450 catch (InvalidOperationException)451 {452 // Ignore453 return;454 }455 await WaitForExitAsync(p).ConfigureAwait(false);456 }457 public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => WaitForExitAsync(p);458 public override Task KillAsync(LauncherBase p) => WaitForExitAsync(p);459 }460 private class ExitedState : State461 {462 public void EnterFrom(LauncherBase p, State fromState)463 {464 while (!TryEnter(p, fromState))465 {466 // Current state has changed since transition to this state was requested.467 // Therefore retry transition to this state from the current state. This ensures468 // that Leave() operation of current state is properly called.469 fromState = p._currentState;470 if (fromState == this)471 {472 return;473 }474 }475 p._exitCompletionSource.TrySetResult(true);476 p.TempUserDataDir?.Dispose();477 }478 public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => Task.CompletedTask;479 public override Task KillAsync(LauncherBase p) => Task.CompletedTask;480 public override Task WaitForExitAsync(LauncherBase p) => Task.CompletedTask;481 }482 private class DisposedState : State483 {484 public void EnterFrom(LauncherBase p, State fromState)485 {486 if (!TryEnter(p, fromState))487 {488 // Delegate Dispose to current state, because it has already changed since489 // transition to this state was initiated.490 p._currentState.Dispose(p);491 }492 else if (fromState != Exited)493 {494 Kill(p);495 p._exitCompletionSource.TrySetException(new ObjectDisposedException(p.ToString()));496 p.TempUserDataDir?.Dispose();497 }498 }499 public override Task StartAsync(LauncherBase p) => throw new ObjectDisposedException(p.ToString());500 public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => throw new ObjectDisposedException(p.ToString());501 public override Task KillAsync(LauncherBase p) => throw new ObjectDisposedException(p.ToString());502 public override void Dispose(LauncherBase p)503 {504 // Nothing to do505 }506 }507 #endregion508 }509 #endregion510 }511}...
ExitingState.cs
Source:ExitingState.cs
...9 public ExitingState(StateManager stateManager) : base(stateManager)10 {11 }12 public override Task EnterFromAsync(LauncherBase p, State fromState, TimeSpan timeout)13 => !StateManager.TryEnter(p, fromState, this) ? StateManager.CurrentState.ExitAsync(p, timeout) : ExitAsync(p, timeout);14 public override async Task ExitAsync(LauncherBase p, TimeSpan timeout)15 {16 var waitForExitTask = WaitForExitAsync(p);17 await waitForExitTask.WithTimeout(18 async () =>19 {20 await StateManager.Killing.EnterFromAsync(p, this, timeout).ConfigureAwait(false);21 await waitForExitTask.ConfigureAwait(false);22 },23 timeout,24 CancellationToken.None).ConfigureAwait(false);25 }26 public override Task KillAsync(LauncherBase p) => StateManager.Killing.EnterFromAsync(p, this);27 }28}...
StartedState.cs
Source:StartedState.cs
...12 StateManager.TryEnter(p, fromState, this);13 return Task.CompletedTask;14 }15 public override Task StartAsync(LauncherBase p) => Task.CompletedTask;16 public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => new ExitingState(StateManager).EnterFromAsync(p, this, timeout);17 public override Task KillAsync(LauncherBase p) => new KillingState(StateManager).EnterFromAsync(p, this);18 }19}...
ExitAsync
Using AI Code Generation
1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5 static async Task Main(string[] args)6 {7 var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = false });8 var page = await browser.NewPageAsync();9 await page.ClickAsync("input[name='q']");10 await page.Keyboard.TypeAsync("Puppeteer");11 await page.Keyboard.PressAsync("Enter");12 await page.WaitForNavigationAsync();13 await page.CloseAsync();14 await browser.CloseAsync();15 }16}17using System;18using System.Threading.Tasks;19using PuppeteerSharp;20{21 static async Task Main(string[] args)22 {23 var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = false });24 var page = await browser.NewPageAsync();25 await page.ClickAsync("input[name='q']");26 await page.Keyboard.TypeAsync("Puppeteer");27 await page.Keyboard.PressAsync("Enter");28 await page.WaitForNavigationAsync();29 await page.CloseAsync();30 await browser.ExitAsync();31 }32}33using System;34using System.Threading.Tasks;35using PuppeteerSharp;36{37 static async Task Main(string[] args)38 {39 var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = false });40 var page = await browser.NewPageAsync();41 await page.ClickAsync("input[name='q']");42 await page.Keyboard.TypeAsync("Puppeteer");43 await page.Keyboard.PressAsync("Enter");44 await page.WaitForNavigationAsync();45 await page.CloseAsync();46 await browser.ExitAsync();47 }48}49using System;50using System.Threading.Tasks;51using PuppeteerSharp;52{53 static async Task Main(string[] args)54 {55 var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = false });
ExitAsync
Using AI Code Generation
1using System;2using System.Text;3using System.Threading.Tasks;4using PuppeteerSharp;5{6 {7 static async Task Main(string[] args)8 {9 var browser = await Puppeteer.LaunchAsync(new LaunchOptions10 {11 });12 var page = await browser.NewPageAsync();13 await page.WaitForSelectorAsync("input[title='Search']");14 await page.TypeAsync("input[title='Search']", "Hello World!");15 await page.ClickAsync("input[type='submit']");16 await page.WaitForNavigationAsync();17 await page.WaitForSelectorAsync("div#resultStats");18 var resultStats = await page.QuerySelectorAsync("div#resultStats");19 var resultStatsText = await page.EvaluateFunctionAsync<string>("element => element.textContent", resultStats);20 Console.WriteLine(resultStatsText);21 await browser.CloseAsync();22 }23 }24}25using System;26using System.Text;27using System.Threading.Tasks;28using PuppeteerSharp;29{30 {31 static async Task Main(string[] args)32 {33 var browser = await Puppeteer.LaunchAsync(new LaunchOptions34 {35 });36 var page = await browser.NewPageAsync();37 await page.WaitForSelectorAsync("input[title='Search']");38 await page.TypeAsync("input[title='Search']", "Hello World!");39 await page.ClickAsync("input[type='submit']");40 await page.WaitForNavigationAsync();41 await page.WaitForSelectorAsync("div#resultStats");42 var resultStats = await page.QuerySelectorAsync("div#resultStats");43 var resultStatsText = await page.EvaluateFunctionAsync<string>("element => element.textContent", resultStats);44 Console.WriteLine(resultStatsText);45 await browser.ExitAsync();46 }47 }48}49using System;50using System.Text;51using System.Threading.Tasks;52using PuppeteerSharp;53{54 {
ExitAsync
Using AI Code Generation
1using PuppeteerSharp.States;2using System;3using System.Threading.Tasks;4{5 {6 static async Task Main(string[] args)7 {8 var browser = await Puppeteer.LaunchAsync();9 var page = await browser.NewPageAsync();10 var state = new ExitingState();11 await state.ExitAsync(browser);12 }13 }14}15using PuppeteerSharp.States;16using System;17using System.Threading.Tasks;18{19 {20 static async Task Main(string[] args)21 {22 var browser = await Puppeteer.LaunchAsync();23 var page = await browser.NewPageAsync();24 var state = new ExitingState();25 await state.ExitAsync(browser);26 }27 }28}29using PuppeteerSharp.States;30using System;31using System.Threading.Tasks;32{33 {34 static async Task Main(string[] args)35 {36 var browser = await Puppeteer.LaunchAsync();37 var page = await browser.NewPageAsync();38 var state = new ExitingState();39 await state.ExitAsync(browser);40 }41 }42}43using PuppeteerSharp.States;44using System;45using System.Threading.Tasks;46{47 {48 static async Task Main(string[] args)49 {50 var browser = await Puppeteer.LaunchAsync();51 var page = await browser.NewPageAsync();52 var state = new ExitingState();53 await state.ExitAsync(browser);54 }55 }56}57using PuppeteerSharp.States;58using System;59using System.Threading.Tasks;
ExitAsync
Using AI Code Generation
1await browser.CloseAsync();2await browser.CloseAsync();3await browser.CloseAsync();4await browser.CloseAsync();5await browser.CloseAsync();6await browser.CloseAsync();7await browser.CloseAsync();8await browser.CloseAsync();9await browser.CloseAsync();10await browser.CloseAsync();11await browser.CloseAsync();12await browser.CloseAsync();13await browser.CloseAsync();14await browser.CloseAsync();
ExitAsync
Using AI Code Generation
1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5 {6 public override async Task ExitAsync(Browser browser)7 {8 await browser.CloseAsync();9 }10 }11}12using System;13using System.Threading.Tasks;14using PuppeteerSharp;15{16 {17 public override async Task ExitAsync(Browser browser)18 {19 await browser.CloseAsync();20 }21 }22}23using System;24using System.Threading.Tasks;25using PuppeteerSharp;26{27 {28 public override async Task ExitAsync(Browser browser)29 {30 await browser.CloseAsync();31 }32 }33}34using System;35using System.Threading.Tasks;36using PuppeteerSharp;37{38 {39 public override async Task ExitAsync(Browser browser)40 {41 await browser.CloseAsync();42 }43 }44}45using System;46using System.Threading.Tasks;47using PuppeteerSharp;48{49 {50 public override async Task ExitAsync(Browser browser)51 {52 await browser.CloseAsync();53 }54 }55}56using System;57using System.Threading.Tasks;58using PuppeteerSharp;59{60 {61 public override async Task ExitAsync(Browser browser)62 {63 await browser.CloseAsync();64 }65 }66}67using System;68using System.Threading.Tasks;
ExitAsync
Using AI Code Generation
1var browser = await Puppeteer.LaunchAsync(new LaunchOptions());2var page = await browser.NewPageAsync();3await page.CloseAsync();4await browser.CloseAsync();5var browser = await Puppeteer.LaunchAsync(new LaunchOptions());6var page = await browser.NewPageAsync();7await browser.CloseAsync();8var browser = await Puppeteer.LaunchAsync(new LaunchOptions());9var page = await browser.NewPageAsync();10await page.CloseAsync();11await page.CloseAsync();12await browser.CloseAsync();13var browser = await Puppeteer.LaunchAsync(new LaunchOptions());14var page = await browser.NewPageAsync();15await page.CloseAsync();16await browser.CloseAsync();17await page.CloseAsync();18var browser = await Puppeteer.LaunchAsync(new LaunchOptions());19var page = await browser.NewPageAsync();20await browser.CloseAsync();21await page.CloseAsync();22var browser = await Puppeteer.LaunchAsync(new LaunchOptions());23var page = await browser.NewPageAsync();24await page.CloseAsync();25await browser.CloseAsync();26await browser.CloseAsync();27var browser = await Puppeteer.LaunchAsync(new LaunchOptions());28var page = await browser.NewPageAsync();29await page.CloseAsync();30await browser.CloseAsync();31await page.CloseAsync();32await browser.CloseAsync();
ExitAsync
Using AI Code Generation
1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5 {6 static async Task Main(string[] args)7 {8 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);9 var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = false });10 var page = await browser.NewPageAsync();11 await page.ScreenshotAsync("google.png");12 await browser.CloseAsync();13 Console.WriteLine("Browser closed");14 }15 }16}17Recommended Posts: PuppeteerSharp | BrowserFetcher.DownloadAsync() Method18PuppeteerSharp | BrowserFetcher.RevisionInfo() Method19PuppeteerSharp | BrowserFetcher.LocalRevisions() Method20PuppeteerSharp | BrowserFetcher.DownloadAsync() Method21PuppeteerSharp | BrowserFetcher.RevisionInfo() Method22PuppeteerSharp | BrowserFetcher.LocalRevisions() Method23PuppeteerSharp | BrowserFetcher.DownloadAsync() Method24PuppeteerSharp | BrowserFetcher.RevisionInfo() Method25PuppeteerSharp | BrowserFetcher.LocalRevisions() Method26PuppeteerSharp | BrowserFetcher.DownloadAsync() Method27PuppeteerSharp | BrowserFetcher.RevisionInfo() Method28PuppeteerSharp | BrowserFetcher.LocalRevisions() Method29PuppeteerSharp | BrowserFetcher.DownloadAsync() Method30PuppeteerSharp | BrowserFetcher.RevisionInfo() Method31PuppeteerSharp | BrowserFetcher.LocalRevisions() Method32PuppeteerSharp | BrowserFetcher.DownloadAsync() Method33PuppeteerSharp | BrowserFetcher.RevisionInfo() Method
ExitAsync
Using AI Code Generation
1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5 {6 static void Main(string[] args)7 {8 MainAsync().GetAwaiter().GetResult();9 }10 static async Task MainAsync()11 {12 var options = new LaunchOptions { Headless = false };13 using (var browser = await Puppeteer.LaunchAsync(options))14 using (var page = await browser.NewPageAsync())15 {16 await page.WaitForSelectorAsync("h1");17 await page.PdfAsync("example.pdf");18 }19 }20 }21}22using System;23using System.Threading.Tasks;24using PuppeteerSharp;25{26 {27 static void Main(string[] args)28 {29 MainAsync().GetAwaiter().GetResult();30 }31 static async Task MainAsync()32 {33 var options = new LaunchOptions { Headless = false };34 using (var browser = await Puppeteer.LaunchAsync(options))35 using (var page = await browser.NewPageAsync())36 {37 await page.WaitForSelectorAsync("h1");38 await page.PdfAsync("example.pdf");39 await browser.CloseAsync();40 }41 }42 }43}44using System;45using System.Threading.Tasks;46using PuppeteerSharp;47{48 {49 static void Main(string[] args)50 {51 MainAsync().GetAwaiter().GetResult();52 }53 static async Task MainAsync()54 {55 var options = new LaunchOptions { Headless = false };56 using (var browser = await Puppeteer.LaunchAsync(options))57 using (var page = await browser.NewPageAsync())58 {59 await page.WaitForSelectorAsync("h1");60 await page.PdfAsync("example.pdf");61 await browser.ExitAsync();62 }63 }
ExitAsync
Using AI Code Generation
1await page.CloseAsync();2await page.WaitForNavigationAsync();3await page.CloseAsync();4await page.WaitForNavigationAsync();5await page.CloseAsync();6await page.WaitForNavigationAsync();7await page.CloseAsync();8await page.WaitForNavigationAsync();9await page.CloseAsync();10await page.WaitForNavigationAsync();11await page.CloseAsync();12await page.WaitForNavigationAsync();13await page.CloseAsync();14await page.WaitForNavigationAsync();15await page.CloseAsync();16await page.WaitForNavigationAsync();17await page.CloseAsync();18await page.WaitForNavigationAsync();19await page.CloseAsync();20await page.WaitForNavigationAsync();21await page.CloseAsync();22await page.WaitForNavigationAsync();23await page.CloseAsync();24await page.WaitForNavigationAsync();25await page.CloseAsync();26await page.WaitForNavigationAsync();27await page.CloseAsync();28await page.WaitForNavigationAsync();29await page.CloseAsync();30await page.WaitForNavigationAsync();31await page.CloseAsync();32await page.WaitForNavigationAsync();33await page.CloseAsync();34await page.WaitForNavigationAsync();35await page.CloseAsync();36await page.WaitForNavigationAsync();37await page.CloseAsync();38await page.WaitForNavigationAsync();39await page.CloseAsync();40await page.WaitForNavigationAsync();41await page.CloseAsync();42await page.WaitForNavigationAsync();
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!