don't create an extra tab when starting a browser
Chrome already starts with a blank page, so use that for the first target context instead of creating a new tab. Add the first version of the Targets API, which is useful to test this feature. Fixes #291.
This commit is contained in:
parent
97e80a00d5
commit
b647c708b4
|
@ -124,6 +124,10 @@ func (p *ExecAllocator) Allocate(ctx context.Context) (*Browser, error) {
|
||||||
p.wg.Done()
|
p.wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// force the first page to be blank, instead of the welcome page
|
||||||
|
// TODO: why isn't --no-first-run enough?
|
||||||
|
args = append(args, "about:blank")
|
||||||
|
|
||||||
cmd = exec.CommandContext(ctx, p.execPath, args...)
|
cmd = exec.CommandContext(ctx, p.execPath, args...)
|
||||||
stderr, err := cmd.StderrPipe()
|
stderr, err := cmd.StderrPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
53
context.go
53
context.go
|
@ -65,7 +65,8 @@ func Run(ctx context.Context, actions ...Action) error {
|
||||||
if c == nil || c.Allocator == nil {
|
if c == nil || c.Allocator == nil {
|
||||||
return ErrInvalidContext
|
return ErrInvalidContext
|
||||||
}
|
}
|
||||||
if c.Browser == nil {
|
first := c.Browser == nil
|
||||||
|
if first {
|
||||||
browser, err := c.Allocator.Allocate(ctx)
|
browser, err := c.Allocator.Allocate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -73,24 +74,47 @@ func Run(ctx context.Context, actions ...Action) error {
|
||||||
c.Browser = browser
|
c.Browser = browser
|
||||||
}
|
}
|
||||||
if c.Target == nil {
|
if c.Target == nil {
|
||||||
if err := c.newSession(ctx); err != nil {
|
if err := c.newSession(ctx, first); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Tasks(actions).Do(ctx, c.Target)
|
return Tasks(actions).Do(ctx, c.Target)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) newSession(ctx context.Context) error {
|
func (c *Context) newSession(ctx context.Context, first bool) error {
|
||||||
targetID, err := target.CreateTarget("about:blank").Do(ctx, c.Browser)
|
var targetID target.ID
|
||||||
|
if first {
|
||||||
|
// If we just allocated this browser, and it has a single page
|
||||||
|
// that's blank and not attached, use it.
|
||||||
|
infos, err := target.GetTargets().Do(ctx, c.Browser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
pages := 0
|
||||||
|
for _, info := range infos {
|
||||||
|
if info.Type == "page" && info.URL == "about:blank" && !info.Attached {
|
||||||
|
targetID = info.TargetID
|
||||||
|
pages++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pages > 1 {
|
||||||
|
// Multiple blank pages; just in case, don't use any.
|
||||||
|
targetID = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if targetID == "" {
|
||||||
|
var err error
|
||||||
|
targetID, err = target.CreateTarget("about:blank").Do(ctx, c.Browser)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sessionID, err := target.AttachToTarget(targetID).Do(ctx, c.Browser)
|
sessionID, err := target.AttachToTarget(targetID).Do(ctx, c.Browser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Target = c.Browser.newExecutorForTarget(ctx, sessionID)
|
c.Target = c.Browser.newExecutorForTarget(ctx, sessionID)
|
||||||
|
|
||||||
// enable domains
|
// enable domains
|
||||||
|
@ -111,3 +135,22 @@ func (c *Context) newSession(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContextOption func(*Context)
|
type ContextOption func(*Context)
|
||||||
|
|
||||||
|
// Targets lists all the targets in the browser attached to the given context.
|
||||||
|
func Targets(ctx context.Context) ([]*target.Info, error) {
|
||||||
|
// Don't rely on Run, as that needs to be able to call Targets, and we
|
||||||
|
// don't want cyclic func calls.
|
||||||
|
|
||||||
|
c := FromContext(ctx)
|
||||||
|
if c == nil || c.Allocator == nil {
|
||||||
|
return nil, ErrInvalidContext
|
||||||
|
}
|
||||||
|
if c.Browser == nil {
|
||||||
|
browser, err := c.Allocator.Allocate(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.Browser = browser
|
||||||
|
}
|
||||||
|
return target.GetTargets().Do(ctx, c.Browser)
|
||||||
|
}
|
||||||
|
|
55
context_test.go
Normal file
55
context_test.go
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
package chromedp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTargets(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Start one browser with one tab.
|
||||||
|
ctx1, cancel := NewContext(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
if err := Run(ctx1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
infos, err := Targets(ctx1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if want, got := 1, len(infos); want != got {
|
||||||
|
t.Fatalf("want %d targets, got %d", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a second tab on the same browser
|
||||||
|
ctx2, cancel := NewContext(ctx1)
|
||||||
|
defer cancel()
|
||||||
|
if err := Run(ctx2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
infos, err := Targets(ctx2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if want, got := 2, len(infos); want != got {
|
||||||
|
t.Fatalf("want %d targets, got %d", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first context should also see both targets.
|
||||||
|
{
|
||||||
|
infos, err := Targets(ctx1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if want, got := 2, len(infos); want != got {
|
||||||
|
t.Fatalf("want %d targets, got %d", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user