diff --git a/browser.go b/browser.go index 3aa6b87..304713e 100644 --- a/browser.go +++ b/browser.go @@ -1,9 +1,3 @@ -// Package chromedp is a high level Chrome DevTools Protocol client that -// simplifies driving browsers for scraping, unit testing, or profiling web -// pages using the CDP. -// -// chromedp requires no third-party dependencies, implementing the async Chrome -// DevTools Protocol entirely in Go. package chromedp import ( diff --git a/context.go b/chromedp.go similarity index 95% rename from context.go rename to chromedp.go index bfcce48..15412f9 100644 --- a/context.go +++ b/chromedp.go @@ -1,3 +1,9 @@ +// Package chromedp is a high level Chrome DevTools Protocol client that +// simplifies driving browsers for scraping, unit testing, or profiling web +// pages using the CDP. +// +// chromedp requires no third-party dependencies, implementing the async Chrome +// DevTools Protocol entirely in Go. package chromedp import ( diff --git a/chromedp_test.go b/chromedp_test.go index 57e2f63..9a1530c 100644 --- a/chromedp_test.go +++ b/chromedp_test.go @@ -3,9 +3,13 @@ package chromedp import ( "context" "fmt" + "net/http" + "net/http/httptest" "os" "path" + "runtime" "testing" + "time" ) var ( @@ -66,3 +70,91 @@ func TestMain(m *testing.M) { cancel() os.Exit(code) } + +func TestTargets(t *testing.T) { + t.Parallel() + + // Start one browser with one tab. + ctx1, cancel1 := NewContext(context.Background()) + defer cancel1() + if err := Run(ctx1); err != nil { + t.Fatal(err) + } + + wantTargets := func(ctx context.Context, want int) { + t.Helper() + infos, err := Targets(ctx) + if err != nil { + t.Fatal(err) + } + if got := len(infos); want != got { + t.Fatalf("want %d targets, got %d", want, got) + } + } + wantTargets(ctx1, 1) + + // Start a second tab on the same browser. + ctx2, cancel2 := NewContext(ctx1) + defer cancel2() + if err := Run(ctx2); err != nil { + t.Fatal(err) + } + wantTargets(ctx2, 2) + + // The first context should also see both targets. + wantTargets(ctx1, 2) + + // Cancelling the second context should close the second tab alone. + cancel2() + wantTargets(ctx1, 1) + + // We used to have a bug where Run would reset the first context as if + // it weren't the first, breaking its cancellation. + if err := Run(ctx1); err != nil { + t.Fatal(err) + } +} + +func TestBrowserQuit(t *testing.T) { + t.Parallel() + if runtime.GOOS == "windows" { + t.Skip("os.Interrupt isn't supported on Windows") + } + + // Simulate a scenario where we navigate to a page that's slow to + // respond, and the browser is closed before we can finish the + // navigation. + serve := make(chan bool, 1) + close := make(chan bool, 1) + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + close <- true + <-serve + fmt.Fprintf(w, "response") + })) + defer s.Close() + + ctx, cancel := NewContext(context.Background()) + defer cancel() + if err := Run(ctx); err != nil { + t.Fatal(err) + } + + go func() { + <-close + b := FromContext(ctx).Browser + if err := b.process.Signal(os.Interrupt); err != nil { + t.Error(err) + } + serve <- true + }() + + // Run should error with something other than "deadline exceeded" in + // much less than 5s. + ctx2, _ := context.WithTimeout(ctx, 5*time.Second) + switch err := Run(ctx2, Navigate(s.URL)); err { + case nil: + t.Fatal("did not expect a nil error") + case context.DeadlineExceeded: + t.Fatalf("did not expect a standard context error: %v", err) + } +} diff --git a/context_test.go b/context_test.go deleted file mode 100644 index fa6ae3a..0000000 --- a/context_test.go +++ /dev/null @@ -1,100 +0,0 @@ -package chromedp - -import ( - "context" - "fmt" - "net/http" - "net/http/httptest" - "os" - "runtime" - "testing" - "time" -) - -func TestTargets(t *testing.T) { - t.Parallel() - - // Start one browser with one tab. - ctx1, cancel1 := NewContext(context.Background()) - defer cancel1() - if err := Run(ctx1); err != nil { - t.Fatal(err) - } - - wantTargets := func(ctx context.Context, want int) { - t.Helper() - infos, err := Targets(ctx) - if err != nil { - t.Fatal(err) - } - if got := len(infos); want != got { - t.Fatalf("want %d targets, got %d", want, got) - } - } - wantTargets(ctx1, 1) - - // Start a second tab on the same browser. - ctx2, cancel2 := NewContext(ctx1) - defer cancel2() - if err := Run(ctx2); err != nil { - t.Fatal(err) - } - wantTargets(ctx2, 2) - - // The first context should also see both targets. - wantTargets(ctx1, 2) - - // Cancelling the second context should close the second tab alone. - cancel2() - wantTargets(ctx1, 1) - - // We used to have a bug where Run would reset the first context as if - // it weren't the first, breaking its cancellation. - if err := Run(ctx1); err != nil { - t.Fatal(err) - } -} - -func TestBrowserQuit(t *testing.T) { - t.Parallel() - if runtime.GOOS == "windows" { - t.Skip("os.Interrupt isn't supported on Windows") - } - - // Simulate a scenario where we navigate to a page that's slow to - // respond, and the browser is closed before we can finish the - // navigation. - serve := make(chan bool, 1) - close := make(chan bool, 1) - s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - close <- true - <-serve - fmt.Fprintf(w, "response") - })) - defer s.Close() - - ctx, cancel := NewContext(context.Background()) - defer cancel() - if err := Run(ctx); err != nil { - t.Fatal(err) - } - - go func() { - <-close - b := FromContext(ctx).Browser - if err := b.process.Signal(os.Interrupt); err != nil { - t.Error(err) - } - serve <- true - }() - - // Run should error with something other than "deadline exceeded" in - // much less than 5s. - ctx2, _ := context.WithTimeout(ctx, 5*time.Second) - switch err := Run(ctx2, Navigate(s.URL)); err { - case nil: - t.Fatal("did not expect a nil error") - case context.DeadlineExceeded: - t.Fatalf("did not expect a standard context error: %v", err) - } -}