44using System . IO ;
55using System . Linq ;
66using System . Net ;
7+ using System . Runtime . InteropServices ;
78using System . Threading . Tasks ;
89using Xunit ;
910using Xunit . Abstractions ;
@@ -76,7 +77,7 @@ public async Task ShouldWorkInRealLifeWithOptions()
7677 {
7778 var response = await page . GoToAsync (
7879 "https://www.google.com" ,
79- new NavigationOptions ( )
80+ new NavigationOptions
8081 {
8182 Timeout = 10000 ,
8283 WaitUntil = new [ ] { WaitUntilNavigation . Networkidle0 }
@@ -288,20 +289,9 @@ public void ShouldDumpBrowserProcessStderr()
288289 {
289290 var dumpioTextToLog = "MAGIC_DUMPIO_TEST" ;
290291 var success = false ;
291- var process = new Process ( ) ;
292-
293- #if NETCOREAPP
294- process . StartInfo . WorkingDirectory = GetDumpIOAppDirectory ( ) ;
295- process . StartInfo . FileName = "dotnet" ;
296- process . StartInfo . Arguments = $ "PuppeteerSharp.Tests.DumpIO.dll { dumpioTextToLog } " +
297- $ "\" { new BrowserFetcher ( ) . RevisionInfo ( BrowserFetcher . DefaultRevision ) . ExecutablePath } \" ";
298- #else
299- process . StartInfo . FileName = Path . Combine ( GetDumpIOAppDirectory ( ) , "PuppeteerSharp.Tests.DumpIO.exe" ) ;
300- process . StartInfo . Arguments = $ "{ dumpioTextToLog } " +
301- $ "\" { new BrowserFetcher ( ) . RevisionInfo ( BrowserFetcher . DefaultRevision ) . ExecutablePath } \" ";
302- #endif
303- process . StartInfo . UseShellExecute = false ;
304- process . StartInfo . RedirectStandardError = true ;
292+ var process = GetTestAppProcess (
293+ "PuppeteerSharp.Tests.DumpIO" ,
294+ $ "{ dumpioTextToLog } \" { new BrowserFetcher ( ) . RevisionInfo ( BrowserFetcher . DefaultRevision ) . ExecutablePath } \" ") ;
305295
306296 process . ErrorDataReceived += ( sender , e ) =>
307297 {
@@ -314,28 +304,107 @@ public void ShouldDumpBrowserProcessStderr()
314304 Assert . True ( success ) ;
315305 }
316306
317- private string GetDumpIOAppDirectory ( )
307+ [ Fact ]
308+ public async Task ShouldCloseTheBrowserWhenTheProcessCloses ( )
309+ {
310+ var process = GetTestAppProcess (
311+ "PuppeteerSharp.Tests.CloseMe" ,
312+ $ "\" { new BrowserFetcher ( ) . RevisionInfo ( BrowserFetcher . DefaultRevision ) . ExecutablePath } \" ") ;
313+
314+ var webSocketTaskWrapper = new TaskCompletionSource < string > ( ) ;
315+ var browserClosedTaskWrapper = new TaskCompletionSource < bool > ( ) ;
316+
317+ process . StartInfo . UseShellExecute = false ;
318+ process . StartInfo . RedirectStandardOutput = true ;
319+
320+ process . OutputDataReceived += ( sender , e ) =>
321+ {
322+ if ( ! webSocketTaskWrapper . Task . IsCompleted )
323+ {
324+ webSocketTaskWrapper . SetResult ( e . Data ) ;
325+ }
326+ } ;
327+
328+ process . Start ( ) ;
329+ process . BeginOutputReadLine ( ) ;
330+
331+ var browser = await Puppeteer . ConnectAsync ( new ConnectOptions
332+ {
333+ BrowserWSEndpoint = await webSocketTaskWrapper . Task
334+ } ) ;
335+
336+ browser . Disconnected += ( sender , e ) =>
337+ {
338+ browserClosedTaskWrapper . SetResult ( true ) ;
339+ } ;
340+
341+ KillProcess ( process . Id ) ;
342+
343+ await browserClosedTaskWrapper . Task ;
344+ Assert . True ( process . HasExited ) ;
345+ }
346+
347+ private Process GetTestAppProcess ( string appName , string arguments )
348+ {
349+ var process = new Process ( ) ;
350+
351+ #if NETCOREAPP
352+ process . StartInfo . WorkingDirectory = GetSubprocessWorkingDir ( appName ) ;
353+ process . StartInfo . FileName = "dotnet" ;
354+ process . StartInfo . Arguments = $ "{ appName } .dll { arguments } ";
355+ #else
356+ process . StartInfo . FileName = Path . Combine ( GetSubprocessWorkingDir ( appName ) , $ "{ appName } .exe") ;
357+ process . StartInfo . Arguments = arguments ;
358+ #endif
359+ process . StartInfo . UseShellExecute = false ;
360+ process . StartInfo . RedirectStandardError = true ;
361+ return process ;
362+ }
363+
364+ private string GetSubprocessWorkingDir ( string dir )
318365 {
319366#if DEBUG
320367 var build = "Debug" ;
321368#else
369+
322370 var build = "Release" ;
323371#endif
324372#if NETCOREAPP
325373 return Path . Combine (
326374 TestUtils . FindParentDirectory ( "lib" ) ,
327- "PuppeteerSharp.Tests.DumpIO" ,
375+ dir ,
328376 "bin" ,
329377 build ,
330378 "netcoreapp2.0" ) ;
331379#else
332380 return Path . Combine (
333381 TestUtils . FindParentDirectory ( "lib" ) ,
334- "PuppeteerSharp.Tests.DumpIO" ,
382+ dir ,
335383 "bin" ,
336384 build ,
337385 "net471" ) ;
338386#endif
339387 }
388+
389+ private void KillProcess ( int pid )
390+ {
391+ var process = new Process ( ) ;
392+
393+ //We need to kill the process tree manually
394+ //See: https://github.com/dotnet/corefx/issues/26234
395+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
396+ {
397+ process . StartInfo . FileName = "taskkill" ;
398+ process . StartInfo . Arguments = $ "-pid { pid } -t -f";
399+ }
400+ else
401+ {
402+ process . StartInfo . FileName = "/bin/bash" ;
403+ process . StartInfo . Arguments = $ "-c \" kill -s 9 { pid } \" ";
404+ }
405+
406+ process . Start ( ) ;
407+ process . WaitForExit ( ) ;
408+ }
340409 }
341410}
0 commit comments