2017-02-09 15:01:40 +00:00
|
|
|
package chromedp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-03-05 13:14:50 +00:00
|
|
|
"fmt"
|
2019-04-08 10:33:08 +00:00
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
2017-02-09 15:01:40 +00:00
|
|
|
"os"
|
2017-12-27 02:30:28 +00:00
|
|
|
"path"
|
2019-04-08 10:33:08 +00:00
|
|
|
"runtime"
|
2017-02-09 15:01:40 +00:00
|
|
|
"testing"
|
2019-04-08 10:33:08 +00:00
|
|
|
"time"
|
2017-02-09 15:01:40 +00:00
|
|
|
)
|
|
|
|
|
2017-12-18 00:11:42 +00:00
|
|
|
var (
|
|
|
|
testdataDir string
|
|
|
|
|
2019-04-01 13:20:41 +00:00
|
|
|
browserCtx context.Context
|
2017-12-18 00:11:42 +00:00
|
|
|
|
2019-04-17 04:17:01 +00:00
|
|
|
// allocOpts is filled in TestMain
|
|
|
|
allocOpts []ExecAllocatorOption
|
2017-12-18 00:11:42 +00:00
|
|
|
)
|
2017-02-09 15:01:40 +00:00
|
|
|
|
2019-03-05 13:14:50 +00:00
|
|
|
func testAllocate(t *testing.T, path string) (_ context.Context, cancel func()) {
|
2019-04-01 13:20:41 +00:00
|
|
|
// Same browser, new tab; not needing to start new chrome browsers for
|
|
|
|
// each test gives a huge speed-up.
|
2019-04-09 11:03:00 +00:00
|
|
|
ctx, _ := NewContext(browserCtx)
|
2017-02-09 15:01:40 +00:00
|
|
|
|
2019-03-20 16:56:03 +00:00
|
|
|
// Only navigate if we want a path, otherwise leave the blank page.
|
|
|
|
if path != "" {
|
|
|
|
if err := Run(ctx, Navigate(testdataDir+"/"+path)); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-02-12 07:08:40 +00:00
|
|
|
}
|
|
|
|
|
2019-04-08 16:52:14 +00:00
|
|
|
cancelErr := func() {
|
2019-04-09 11:03:00 +00:00
|
|
|
if err := Cancel(ctx); err != nil {
|
2019-04-08 16:52:14 +00:00
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ctx, cancelErr
|
2017-02-09 15:01:40 +00:00
|
|
|
}
|
2017-02-12 04:59:33 +00:00
|
|
|
|
2017-02-15 14:46:07 +00:00
|
|
|
func TestMain(m *testing.M) {
|
2017-12-27 02:30:28 +00:00
|
|
|
wd, err := os.Getwd()
|
|
|
|
if err != nil {
|
2019-03-05 13:14:50 +00:00
|
|
|
panic(fmt.Sprintf("could not get working directory: %v", err))
|
2017-12-27 02:30:28 +00:00
|
|
|
}
|
|
|
|
testdataDir = "file://" + path.Join(wd, "testdata")
|
2017-02-15 14:46:07 +00:00
|
|
|
|
2019-04-17 04:17:01 +00:00
|
|
|
// build on top of the default options
|
|
|
|
allocOpts = append(allocOpts, DefaultExecAllocatorOptions...)
|
|
|
|
|
|
|
|
// disabling the GPU helps portability with some systems like Travis,
|
|
|
|
// and can slightly speed up the tests on other systems
|
|
|
|
allocOpts = append(allocOpts, DisableGPU)
|
|
|
|
|
2019-03-05 13:14:50 +00:00
|
|
|
// it's worth noting that newer versions of chrome (64+) run much faster
|
2017-12-18 00:11:42 +00:00
|
|
|
// than older ones -- same for headless_shell ...
|
2019-03-05 13:14:50 +00:00
|
|
|
if execPath := os.Getenv("CHROMEDP_TEST_RUNNER"); execPath != "" {
|
|
|
|
allocOpts = append(allocOpts, ExecPath(execPath))
|
2017-12-18 00:11:42 +00:00
|
|
|
}
|
|
|
|
// not explicitly needed to be set, as this vastly speeds up unit tests
|
|
|
|
if noSandbox := os.Getenv("CHROMEDP_NO_SANDBOX"); noSandbox != "false" {
|
2019-03-05 13:14:50 +00:00
|
|
|
allocOpts = append(allocOpts, NoSandbox)
|
2017-12-18 00:11:42 +00:00
|
|
|
}
|
|
|
|
|
2019-04-08 10:10:59 +00:00
|
|
|
allocCtx, cancel := NewExecAllocator(context.Background(), allocOpts...)
|
2019-04-01 13:20:41 +00:00
|
|
|
|
|
|
|
// start the browser
|
|
|
|
browserCtx, _ = NewContext(allocCtx)
|
2019-04-01 16:12:17 +00:00
|
|
|
if err := Run(browserCtx); err != nil {
|
2019-04-01 13:20:41 +00:00
|
|
|
panic(err)
|
|
|
|
}
|
2017-02-15 14:46:07 +00:00
|
|
|
|
|
|
|
code := m.Run()
|
|
|
|
|
2019-03-05 13:14:50 +00:00
|
|
|
cancel()
|
2017-02-15 14:46:07 +00:00
|
|
|
os.Exit(code)
|
2017-02-12 04:59:33 +00:00
|
|
|
}
|
2019-04-08 10:33:08 +00:00
|
|
|
|
|
|
|
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.
|
2019-04-17 04:29:11 +00:00
|
|
|
ctx2, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
|
|
defer cancel()
|
2019-04-08 10:33:08 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2019-04-08 16:52:14 +00:00
|
|
|
|
|
|
|
func TestCancelError(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
ctx1, cancel1 := NewContext(context.Background())
|
|
|
|
defer cancel1()
|
|
|
|
if err := Run(ctx1); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open and close a target normally; no error.
|
|
|
|
ctx2, cancel2 := NewContext(ctx1)
|
|
|
|
defer cancel2()
|
|
|
|
if err := Run(ctx2); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2019-04-09 11:03:00 +00:00
|
|
|
if err := Cancel(ctx2); err != nil {
|
2019-04-08 16:52:14 +00:00
|
|
|
t.Fatalf("expected a nil error, got %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make "cancel" close the wrong target; error.
|
|
|
|
ctx3, cancel3 := NewContext(ctx1)
|
|
|
|
defer cancel3()
|
|
|
|
if err := Run(ctx3); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
FromContext(ctx3).Target.TargetID = "wrong"
|
2019-04-09 11:03:00 +00:00
|
|
|
if err := Cancel(ctx3); err == nil {
|
2019-04-08 16:52:14 +00:00
|
|
|
t.Fatalf("expected a non-nil error, got %v", err)
|
|
|
|
}
|
|
|
|
}
|
2019-04-18 06:07:33 +00:00
|
|
|
|
|
|
|
func TestPrematureCancel(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// Cancel before the browser is allocated.
|
|
|
|
ctx, cancel := NewContext(context.Background())
|
|
|
|
cancel()
|
|
|
|
if err := Run(ctx); err != context.Canceled {
|
|
|
|
t.Fatalf("wanted canceled context error, got %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPrematureCancelTab(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
ctx1, cancel := NewContext(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
if err := Run(ctx1); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cancel after the browser is allocated, but before we've created a new
|
|
|
|
// tab.
|
|
|
|
ctx2, cancel := NewContext(ctx1)
|
|
|
|
cancel()
|
|
|
|
Run(ctx2)
|
|
|
|
}
|