Increasing unit test coverage on query.go

This commit is contained in:
Randy Cahyana 2017-02-15 21:46:07 +07:00 committed by Kenneth Shaw
parent dc08ecc727
commit 0db7a9ee72
10 changed files with 782 additions and 75 deletions

View File

@ -116,14 +116,14 @@ func (c *CDP) AddTarget(ctxt context.Context, t client.Target) {
// create target manager // create target manager
h, err := NewTargetHandler(t, c.logf, c.debugf, c.errorf) h, err := NewTargetHandler(t, c.logf, c.debugf, c.errorf)
if err != nil { if err != nil {
c.errorf("could not create handler for %s, got: %v", t, err) c.errorf("could not create handler for %s: %v", t, err)
return return
} }
// run // run
err = h.Run(ctxt) err = h.Run(ctxt)
if err != nil { if err != nil {
c.errorf("could not start handler for %s, got: %v", t, err) c.errorf("could not start handler for %s: %v", t, err)
return return
} }

View File

@ -4,18 +4,63 @@ import (
"context" "context"
"log" "log"
"os" "os"
"strings"
"testing" "testing"
) )
var pool *Pool var pool *Pool
var defaultContext = context.Background() var defaultContext = context.Background()
var testdataDir string
func testAllocate(t *testing.T, path string) *Res {
c, err := pool.Allocate(defaultContext)
if err != nil {
t.Fatalf("could not allocate from pool: %v", err)
}
err = WithLogf(t.Logf)(c.c)
if err != nil {
t.Fatalf("could not set logf: %v", err)
}
err = WithDebugf(t.Logf)(c.c)
if err != nil {
t.Fatalf("could not set debugf: %v", err)
}
err = WithErrorf(t.Errorf)(c.c)
if err != nil {
t.Fatalf("could not set errorf: %v", err)
}
h := c.c.GetHandlerByIndex(0)
th, ok := h.(*TargetHandler)
if !ok {
t.Fatalf("handler is invalid type")
}
th.logf = t.Logf
th.debugf = t.Logf
th.errorf = func(s string, v ...interface{}) {
t.Logf("target handler error: "+s, v...)
}
if path != "" {
err = c.Run(defaultContext, Navigate(testdataDir+"/"+path))
if err != nil {
t.Fatalf("could not navigate to testdata/%s: %v", path, err)
}
}
return c
}
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
var err error var err error
pool, err = NewPool(PoolLog(log.Printf, log.Printf, log.Printf)) testdataDir = "file:" + os.Getenv("GOPATH") + "/src/github.com/knq/chromedp/testdata"
//pool, err = NewPool(PoolLog(log.Printf, log.Printf, log.Printf))
pool, err = NewPool()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -29,51 +74,3 @@ func TestMain(m *testing.M) {
os.Exit(code) os.Exit(code)
} }
func TestNavigate(t *testing.T) {
var err error
c, err := pool.Allocate(defaultContext)
if err != nil {
t.Fatal(err)
}
defer c.Release()
err = c.Run(defaultContext, Navigate("https://www.google.com/"))
if err != nil {
t.Fatal(err)
}
err = c.Run(defaultContext, WaitVisible(`#hplogo`, ByID))
if err != nil {
t.Fatal(err)
}
var urlstr string
err = c.Run(defaultContext, Location(&urlstr))
if err != nil {
t.Fatal(err)
}
if !strings.HasPrefix(urlstr, "https://www.google.") {
t.Errorf("expected to be on google domain, at: %s", urlstr)
}
var title string
err = c.Run(defaultContext, Title(&title))
if err != nil {
t.Fatal(err)
}
if !strings.Contains(strings.ToLower(title), "google") {
t.Errorf("expected title to contain google, instead title is: %s", title)
}
}
func TestSendKeys(t *testing.T) {
var err error
c, err := pool.Allocate(defaultContext)
if err != nil {
t.Fatal(err)
}
defer c.Release()
}

View File

@ -50,7 +50,7 @@ type TargetHandler struct {
lastm sync.Mutex lastm sync.Mutex
// res is the id->result channel map. // res is the id->result channel map.
res map[int64]chan easyjson.RawMessage res map[int64]chan *cdp.Message
resrw sync.RWMutex resrw sync.RWMutex
// logging funcs // logging funcs
@ -87,7 +87,7 @@ func (h *TargetHandler) Run(ctxt context.Context) error {
h.qcmd = make(chan *cdp.Message) h.qcmd = make(chan *cdp.Message)
h.qres = make(chan *cdp.Message) h.qres = make(chan *cdp.Message)
h.qevents = make(chan *cdp.Message) h.qevents = make(chan *cdp.Message)
h.res = make(map[int64]chan easyjson.RawMessage) h.res = make(map[int64]chan *cdp.Message)
h.detached = make(chan *inspector.EventDetached) h.detached = make(chan *inspector.EventDetached)
h.pageWaitGroup = new(sync.WaitGroup) h.pageWaitGroup = new(sync.WaitGroup)
h.domWaitGroup = new(sync.WaitGroup) h.domWaitGroup = new(sync.WaitGroup)
@ -108,7 +108,7 @@ func (h *TargetHandler) Run(ctxt context.Context) error {
} { } {
err = a.Do(ctxt, h) err = a.Do(ctxt, h)
if err != nil { if err != nil {
return fmt.Errorf("unable to execute %s, got: %v", reflect.TypeOf(a), err) return fmt.Errorf("unable to execute %s: %v", reflect.TypeOf(a), err)
} }
} }
@ -117,7 +117,7 @@ func (h *TargetHandler) Run(ctxt context.Context) error {
// get page resources // get page resources
tree, err := page.GetResourceTree().Do(ctxt, h) tree, err := page.GetResourceTree().Do(ctxt, h)
if err != nil { if err != nil {
return fmt.Errorf("unable to get resource tree, got: %v", err) return fmt.Errorf("unable to get resource tree: %v", err)
} }
h.frames[tree.Frame.ID] = tree.Frame h.frames[tree.Frame.ID] = tree.Frame
@ -182,19 +182,19 @@ func (h *TargetHandler) run(ctxt context.Context) {
case ev := <-h.qevents: case ev := <-h.qevents:
err = h.processEvent(ctxt, ev) err = h.processEvent(ctxt, ev)
if err != nil { if err != nil {
h.errorf("could not process event %s, got: %v", ev.Method, err) h.errorf("could not process event %s: %v", ev.Method, err)
} }
case res := <-h.qres: case res := <-h.qres:
err = h.processResult(res) err = h.processResult(res)
if err != nil { if err != nil {
h.errorf("could not process result for message %d, got: %v", res.ID, err) h.errorf("could not process result for message %d: %v", res.ID, err)
} }
case cmd := <-h.qcmd: case cmd := <-h.qcmd:
err = h.processCommand(cmd) err = h.processCommand(cmd)
if err != nil { if err != nil {
h.errorf("could not process command message %d, got: %v", cmd.ID, err) h.errorf("could not process command message %d: %v", cmd.ID, err)
} }
case <-ctxt.Done(): case <-ctxt.Done():
@ -271,7 +271,7 @@ func (h *TargetHandler) processEvent(ctxt context.Context, msg *cdp.Message) err
func (h *TargetHandler) documentUpdated(ctxt context.Context) { func (h *TargetHandler) documentUpdated(ctxt context.Context) {
f, err := h.WaitFrame(ctxt, EmptyFrameID) f, err := h.WaitFrame(ctxt, EmptyFrameID)
if err != nil { if err != nil {
h.errorf("could not get current frame, got: %v", err) h.errorf("could not get current frame: %v", err)
return return
} }
@ -286,7 +286,7 @@ func (h *TargetHandler) documentUpdated(ctxt context.Context) {
f.Nodes = make(map[cdp.NodeID]*cdp.Node) f.Nodes = make(map[cdp.NodeID]*cdp.Node)
f.Root, err = dom.GetDocument().WithPierce(true).Do(ctxt, h) f.Root, err = dom.GetDocument().WithPierce(true).Do(ctxt, h)
if err != nil { if err != nil {
h.errorf("could not retrieve document root for %s, got: %v", f.ID, err) h.errorf("could not retrieve document root for %s: %v", f.ID, err)
return return
} }
f.Root.Invalidated = make(chan struct{}) f.Root.Invalidated = make(chan struct{})
@ -304,11 +304,7 @@ func (h *TargetHandler) processResult(msg *cdp.Message) error {
} }
defer close(ch) defer close(ch)
if msg.Error != nil { ch <- msg
return msg.Error
}
ch <- msg.Result
return nil return nil
} }
@ -346,7 +342,7 @@ func (h *TargetHandler) Execute(ctxt context.Context, commandType cdp.MethodType
id := h.next() id := h.next()
// save channel // save channel
ch := make(chan easyjson.RawMessage, 1) ch := make(chan *cdp.Message, 1)
h.resrw.Lock() h.resrw.Lock()
h.res[id] = ch h.res[id] = ch
h.resrw.Unlock() h.resrw.Unlock()
@ -364,8 +360,15 @@ func (h *TargetHandler) Execute(ctxt context.Context, commandType cdp.MethodType
select { select {
case msg := <-ch: case msg := <-ch:
if res != nil { switch {
errch <- easyjson.Unmarshal(msg, res) case msg == nil:
errch <- cdp.ErrChannelClosed
case msg.Error != nil:
errch <- msg.Error
case res != nil:
errch <- easyjson.Unmarshal(msg.Result, res)
} }
case <-ctxt.Done(): case <-ctxt.Done():
@ -559,7 +562,7 @@ func (h *TargetHandler) pageEvent(ctxt context.Context, ev interface{}) {
f, err := h.WaitFrame(ctxt, id) f, err := h.WaitFrame(ctxt, id)
if err != nil { if err != nil {
h.errorf("could not get frame %s, got: %v", id, err) h.errorf("could not get frame %s: %v", id, err)
return return
} }
@ -579,7 +582,7 @@ func (h *TargetHandler) domEvent(ctxt context.Context, ev interface{}) {
// wait current frame // wait current frame
f, err := h.WaitFrame(ctxt, EmptyFrameID) f, err := h.WaitFrame(ctxt, EmptyFrameID)
if err != nil { if err != nil {
h.errorf("error processing DOM event %s: error waiting for frame, got: %v", reflect.TypeOf(ev), err) h.errorf("could not process DOM event %s: %v", reflect.TypeOf(ev), err)
return return
} }
@ -643,12 +646,15 @@ func (h *TargetHandler) domEvent(ctxt context.Context, ev interface{}) {
return return
} }
s := strings.TrimPrefix(strings.TrimSuffix(runtime.FuncForPC(reflect.ValueOf(op).Pointer()).Name(), ".func1"), "github.com/knq/chromedp.")
// retrieve node // retrieve node
n, err := h.WaitNode(ctxt, f, id) n, err := h.WaitNode(ctxt, f, id)
if err != nil { if err != nil {
h.errorf("error could not perform (%s) operation on node %d (wait node error), got: %v", s, id, err) s := strings.TrimSuffix(runtime.FuncForPC(reflect.ValueOf(op).Pointer()).Name(), ".func1")
i := strings.LastIndex(s, ".")
if i != -1 {
s = s[i+1:]
}
h.errorf("could not perform (%s) operation on node %d (wait node): %v", s, id, err)
return return
} }

41
nav_test.go Normal file
View File

@ -0,0 +1,41 @@
package chromedp
import (
"strings"
"testing"
)
func TestNavigate(t *testing.T) {
var err error
c := testAllocate(t, "")
defer c.Release()
err = c.Run(defaultContext, Navigate("https://www.google.com/"))
if err != nil {
t.Fatal(err)
}
err = c.Run(defaultContext, WaitVisible(`#hplogo`, ByID))
if err != nil {
t.Fatal(err)
}
var urlstr string
err = c.Run(defaultContext, Location(&urlstr))
if err != nil {
t.Fatal(err)
}
if !strings.HasPrefix(urlstr, "https://www.google.") {
t.Errorf("expected to be on google domain, at: %s", urlstr)
}
var title string
err = c.Run(defaultContext, Title(&title))
if err != nil {
t.Fatal(err)
}
if !strings.Contains(strings.ToLower(title), "google") {
t.Errorf("expected title to contain google, instead title is: %s", title)
}
}

602
query_test.go Normal file
View File

@ -0,0 +1,602 @@
package chromedp
import (
"reflect"
"testing"
"time"
"github.com/knq/chromedp/cdp"
"github.com/knq/chromedp/cdp/dom"
"github.com/knq/chromedp/kb"
)
func TestNodes(t *testing.T) {
c := testAllocate(t, "table.html")
defer c.Release()
tests := []struct {
sel string
by QueryOption
len int
}{
{"/html/body/table/tbody[1]/tr[2]/td", BySearch, 3},
{"body > table > tbody:nth-child(2) > tr:nth-child(2) > td:not(:last-child)", ByQueryAll, 2},
{"body > table > tbody:nth-child(2) > tr:nth-child(2) > td", ByQuery, 1},
{"#footer", ByID, 1},
}
var err error
for i, test := range tests {
var nodes []*cdp.Node
err = c.Run(defaultContext, Nodes(test.sel, &nodes, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if len(nodes) != test.len {
t.Errorf("test %d expected to have %d nodes: got %d", i, test.len, len(nodes))
}
}
}
// TODO:
// NodeIDs
// Focus
// Blur
func TestDimensions(t *testing.T) {
c := testAllocate(t, "image.html")
defer c.Release()
tests := []struct {
sel string
by QueryOption
width int64
height int64
}{
{"/html/body/img", BySearch, 239, 239},
{"img", ByQueryAll, 239, 239},
{"img", ByQuery, 239, 239},
{"#icon-github", ByID, 120, 120},
}
var err error
for i, test := range tests {
var model *dom.BoxModel
err = c.Run(defaultContext, Dimensions(test.sel, &model))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if model.Height != test.height || model.Width != test.width {
t.Errorf("test %d expected %dx%d, got: %dx%d", i, test.width, test.height, model.Height, model.Width)
}
}
}
func TestText(t *testing.T) {
c := testAllocate(t, "form.html")
defer c.Release()
tests := []struct {
sel string
by QueryOption
exp string
}{
{"#foo", ByID, "insert"},
{"body > form > span", ByQueryAll, "insert"},
{"body > form > span:nth-child(2)", ByQuery, "keyword"},
{"/html/body/form/span[2]", BySearch, "keyword"},
}
var err error
for i, test := range tests {
var text string
err = c.Run(defaultContext, Text(test.sel, &text, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if text != test.exp {
t.Errorf("test %d expected `%s`, got: %s", i, test.exp, text)
}
}
}
func TestClear(t *testing.T) {
tests := []struct {
sel string
by QueryOption
}{
// input fields
{`//*[@id="form"]/input[1]`, BySearch},
{`#form > input[type="text"]:nth-child(4)`, ByQuery},
{`#form > input[type="text"]`, ByQueryAll},
{`#keyword`, ByID},
// textarea fields
{`//*[@id="bar"]`, BySearch},
{`#form > textarea`, ByQuery},
{`#form > textarea`, ByQueryAll},
{`#bar`, ByID},
// input + textarea fields
{`//*[@id="form"]/input`, BySearch},
{`#form > input[type="text"]`, ByQueryAll},
}
var err error
for i, test := range tests {
c := testAllocate(t, "form.html")
defer c.Release()
var val string
err = c.Run(defaultContext, Value(test.sel, &val, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if val == "" {
t.Errorf("test %d expected `%s` to have non empty value", i, test.sel)
}
err = c.Run(defaultContext, Clear(test.sel, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
err = c.Run(defaultContext, Value(test.sel, &val, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if val != "" {
t.Errorf("test %d expected empty value for `%s`, got: %s", i, test.sel, val)
}
}
}
func TestReset(t *testing.T) {
tests := []struct {
sel string
by QueryOption
value string
exp string
}{
{`//*[@id="keyword"]`, BySearch, "foobar", "chromedp"},
{`#form > input[type="text"]:nth-child(6)`, ByQuery, "foobar", "foo"},
{`#form > input[type="text"]`, ByQueryAll, "foobar", "chromedp"},
{"#bar", ByID, "foobar", "bar"},
}
var err error
for i, test := range tests {
c := testAllocate(t, "form.html")
defer c.Release()
err = c.Run(defaultContext, SetValue(test.sel, test.value, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
err = c.Run(defaultContext, Reset(test.sel, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
var value string
err = c.Run(defaultContext, Value(test.sel, &value, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if value != test.exp {
t.Errorf("test %d expected value after reset is %s, got: '%s'", i, test.exp, value)
}
}
}
func TestValue(t *testing.T) {
c := testAllocate(t, "form.html")
defer c.Release()
tests := []struct {
sel string
by QueryOption
}{
{`//*[@id="form"]/input[1]`, BySearch},
{`#form > input[type="text"]:nth-child(4)`, ByQuery},
{`#form > input[type="text"]`, ByQueryAll},
{`#keyword`, ByID},
}
var err error
for i, test := range tests {
var value string
err = c.Run(defaultContext, Value(test.sel, &value, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if value != "chromedp" {
t.Errorf("test %d expected `chromedp`, got: %s", i, value)
}
}
}
func TestSetValue(t *testing.T) {
c := testAllocate(t, "form.html")
defer c.Release()
tests := []struct {
sel string
by QueryOption
}{
{`//*[@id="form"]/input[1]`, BySearch},
{`#form > input[type="text"]:nth-child(4)`, ByQuery},
{`#form > input[type="text"]`, ByQueryAll},
{`#bar`, ByID},
}
var err error
for i, test := range tests {
if i != 0 {
err = c.Run(defaultContext, Reload())
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
time.Sleep(50 * time.Millisecond)
}
err = c.Run(defaultContext, SetValue(test.sel, "FOOBAR", test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
var value string
err = c.Run(defaultContext, Value(test.sel, &value, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if value != "FOOBAR" {
t.Errorf("test %d expected `FOOBAR`, got: %s", i, value)
}
}
}
func TestAttributes(t *testing.T) {
c := testAllocate(t, "image.html")
defer c.Release()
tests := []struct {
sel string
by QueryOption
exp map[string]string
}{
{`//*[@id="icon-brankas"]`, BySearch,
map[string]string{
"alt": "Brankas - Easy Money Management",
"id": "icon-brankas",
"src": "images/brankas.png",
}},
{"body > img:first-child", ByQuery,
map[string]string{
"alt": "Brankas - Easy Money Management",
"id": "icon-brankas",
"src": "images/brankas.png",
}},
{"body > img:nth-child(2)", ByQueryAll,
map[string]string{
"alt": `How people build software`,
"id": "icon-github",
"src": "images/github.png",
}},
{"#icon-github", ByID,
map[string]string{
"alt": "How people build software",
"id": "icon-github",
"src": "images/github.png",
}},
}
var err error
for i, test := range tests {
var attrs map[string]string
err = c.Run(defaultContext, Attributes(test.sel, &attrs, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if !reflect.DeepEqual(test.exp, attrs) {
t.Errorf("test %d expected %v, got: %v", i, test.exp, attrs)
}
}
}
func TestSetAttributes(t *testing.T) {
tests := []struct {
sel string
by QueryOption
attrs map[string]string
exp map[string]string
}{
{`//*[@id="icon-brankas"]`, BySearch,
map[string]string{"data-url": "brankas"},
map[string]string{
"alt": "Brankas - Easy Money Management",
"id": "icon-brankas",
"src": "images/brankas.png",
"data-url": "brankas"}},
{"body > img:first-child", ByQuery,
map[string]string{"data-url": "brankas"},
map[string]string{
"alt": "Brankas - Easy Money Management",
"id": "icon-brankas",
"src": "images/brankas.png",
"data-url": "brankas",
}},
{"body > img:nth-child(2)", ByQueryAll,
map[string]string{"width": "100", "height": "200"},
map[string]string{
"alt": `How people build software`,
"id": "icon-github",
"src": "images/github.png",
"width": "100",
"height": "200",
}},
{"#icon-github", ByID,
map[string]string{"width": "100", "height": "200"},
map[string]string{
"alt": "How people build software",
"id": "icon-github",
"src": "images/github.png",
"width": "100",
"height": "200",
}},
}
var err error
for i, test := range tests {
c := testAllocate(t, "image.html")
defer c.Release()
err = c.Run(defaultContext, SetAttributes(test.sel, test.attrs, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
var attrs map[string]string
err = c.Run(defaultContext, Attributes(test.sel, &attrs, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if !reflect.DeepEqual(test.exp, attrs) {
t.Errorf("test %d expected %v, got: %v", i, test.exp, attrs)
}
}
}
func TestAttributeValue(t *testing.T) {
c := testAllocate(t, "image.html")
defer c.Release()
tests := []struct {
sel string
by QueryOption
attr string
exp string
}{
{`//*[@id="icon-brankas"]`, BySearch, "alt", "Brankas - Easy Money Management"},
{"body > img:first-child", ByQuery, "alt", "Brankas - Easy Money Management"},
{"body > img:nth-child(2)", ByQueryAll, "alt", "How people build software"},
{"#icon-github", ByID, "alt", "How people build software"},
}
var err error
for i, test := range tests {
var value string
var ok bool
err = c.Run(defaultContext, AttributeValue(test.sel, test.attr, &value, &ok, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if !ok {
t.Fatalf("test %d failed to get attribute %s on %s", i, test.attr, test.sel)
}
if value != test.exp {
t.Errorf("test %d expected %s to be %s, got: %s", i, test.attr, test.exp, value)
}
}
}
func TestSetAttributeValue(t *testing.T) {
tests := []struct {
sel string
by QueryOption
attr string
exp string
}{
{`//*[@id="keyword"]`, BySearch, "foo", "bar"},
{`#form > input[type="text"]:nth-child(6)`, ByQuery, "foo", "bar"},
{`#form > input[type="text"]`, ByQueryAll, "foo", "bar"},
{"#bar", ByID, "foo", "bar"},
}
var err error
for i, test := range tests {
c := testAllocate(t, "form.html")
defer c.Release()
err = c.Run(defaultContext, SetAttributeValue(test.sel, test.attr, test.exp, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
var value string
var ok bool
err = c.Run(defaultContext, AttributeValue(test.sel, test.attr, &value, &ok, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if !ok {
t.Fatalf("test %d failed to get attribute %s on %s", i, test.attr, test.sel)
}
if value != test.exp {
t.Errorf("test %d expected %s to be %s, got: %s", i, test.attr, test.exp, value)
}
}
}
func TestRemoveAttribute(t *testing.T) {
c := testAllocate(t, "image.html")
defer c.Release()
tests := []struct {
sel string
by QueryOption
attr string
}{
{"/html/body/img", BySearch, "alt"},
{"img", ByQueryAll, "alt"},
{"img", ByQuery, "alt"},
{"#icon-github", ByID, "alt"},
}
var err error
for i, test := range tests {
if i != 0 {
err = c.Run(defaultContext, Reload())
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
time.Sleep(50 * time.Millisecond)
}
err = c.Run(defaultContext, RemoveAttribute(test.sel, test.attr))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
var value string
var ok bool
err = c.Run(defaultContext, AttributeValue(test.sel, test.attr, &value, &ok, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if ok || value != "" {
t.Fatalf("test %d expected attribute %s removed from element %s", i, test.attr, test.sel)
}
}
}
func TestClick(t *testing.T) {
tests := []struct {
sel string
by QueryOption
}{
{`//*[@id="form"]/input[4]`, BySearch},
{`#form > input[type="submit"]:nth-child(11)`, ByQuery},
{`#form > input[type="submit"]:nth-child(11)`, ByQueryAll},
{"#btn2", ByID},
}
var err error
for i, test := range tests {
c := testAllocate(t, "form.html")
defer c.Release()
err = c.Run(defaultContext, Click(test.sel, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
err = c.Run(defaultContext, Sleep(time.Second*2))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
var title string
err = c.Run(defaultContext, Title(&title))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if title != "chromedp - Google Search" {
t.Errorf("test %d expected title to be 'chromedp - Google Search', got: '%s'", i, title)
}
}
}
// DoubleClick
func TestSendKeys(t *testing.T) {
tests := []struct {
sel string
by QueryOption
keys string
exp string
}{
{`//*[@id="input1"]`, BySearch, "INSERT ", "INSERT some value"},
{`#box4 > input:nth-child(1)`, ByQuery, "insert ", "insert some value"},
{`#box4 > textarea`, ByQueryAll, "prefix " + kb.End + "\b\b SUFFIX\n", "prefix textar SUFFIX\n"},
{"#textarea1", ByID, "insert ", "insert textarea"},
{"#textarea1", ByID, kb.End + "\b\b\n\naoeu\n\nfoo\n\nbar\n\n", "textar\n\naoeu\n\nfoo\n\nbar\n\n"},
{"#select1", ByID, kb.ArrowDown + kb.ArrowDown, "three"},
}
var err error
for i, test := range tests {
c := testAllocate(t, "visible.html")
defer c.Release()
err = c.Run(defaultContext, SendKeys(test.sel, test.keys, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
var val string
err = c.Run(defaultContext, Value(test.sel, &val, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if val != test.exp {
t.Errorf("test %d expected value %s, got: %s", i, test.exp, val)
}
}
}
func TestSubmit(t *testing.T) {
tests := []struct {
sel string
by QueryOption
}{
{`//*[@id="keyword"]`, BySearch},
{`#form > input[type="text"]:nth-child(4)`, ByQuery},
{`#form > input[type="text"]`, ByQueryAll},
{"#form", ByID},
}
var err error
for i, test := range tests {
c := testAllocate(t, "form.html")
defer c.Release()
err = c.Run(defaultContext, Submit(test.sel, test.by))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
err = c.Run(defaultContext, Sleep(time.Second*2))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
var title string
err = c.Run(defaultContext, Title(&title))
if err != nil {
t.Fatalf("test %d got error: %v", i, err)
}
if title != "chromedp - Google Search" {
t.Errorf("test %d expected title to be 'chromedp - Google Search', got: '%s'", i, title)
}
}
}
// ComputedStyle
// MatchedStyle

20
testdata/form.html vendored Normal file
View File

@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<style>
input, textarea {
margin-top: 5px
}
</style>
</head>
<body>
<form id="form" action="https://www.google.com/search" name="form">
<span id="foo">insert</span> <span>keyword</span><br>
<input id="keyword" type="text" name="q" value="chromedp"/><br>
<input id="foo" type="text" name="foo" value="foo"/><br>
<textarea id="bar" rows="4" cols="50">bar</textarea><br>
<input id="btn1" type="reset" value="Reset">
<input id="btn2" type="submit" value="Submit">
</form>
</body>
</html>

7
testdata/image.html vendored Normal file
View File

@ -0,0 +1,7 @@
<!doctype html>
<html>
<body style="background-color: #41a1e1">
<img id="icon-brankas" src="images/brankas.png" alt="Brankas - Easy Money Management">
<img id="icon-github" src="images/github.png" alt="How people build software">
</body>
</html>

BIN
testdata/images/brankas.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
testdata/images/github.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

34
testdata/table.html vendored Normal file
View File

@ -0,0 +1,34 @@
<!doctype html>
<html>
<head>
<title>table</title>
</head>
<body>
<table>
<thead>
<tr>
<th>row 1 header</th>
<th>row 2 header</th>
<th>row 3 header</th>
</tr>
</thead>
<tbody>
<tr>
<td>1.1</td>
<td>1.2</td>
<td>1.3</td>
</tr>
<tr>
<td>2.1</td>
<td>2.2</td>
<td>2.3</td>
</tr>
<tr id="footer">
<td>3.1</td>
<td>3.2</td>
<td>3.3</td>
</tr>
<tbody>
</table>
</body>
</html>