Increasing unit test coverage on query.go
This commit is contained in:
parent
dc08ecc727
commit
0db7a9ee72
|
@ -116,14 +116,14 @@ func (c *CDP) AddTarget(ctxt context.Context, t client.Target) {
|
|||
// create target manager
|
||||
h, err := NewTargetHandler(t, c.logf, c.debugf, c.errorf)
|
||||
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
|
||||
}
|
||||
|
||||
// run
|
||||
err = h.Run(ctxt)
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -4,18 +4,63 @@ import (
|
|||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var pool *Pool
|
||||
|
||||
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) {
|
||||
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 {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -29,51 +74,3 @@ func TestMain(m *testing.M) {
|
|||
|
||||
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()
|
||||
}
|
||||
|
|
50
handler.go
50
handler.go
|
@ -50,7 +50,7 @@ type TargetHandler struct {
|
|||
lastm sync.Mutex
|
||||
|
||||
// res is the id->result channel map.
|
||||
res map[int64]chan easyjson.RawMessage
|
||||
res map[int64]chan *cdp.Message
|
||||
resrw sync.RWMutex
|
||||
|
||||
// logging funcs
|
||||
|
@ -87,7 +87,7 @@ func (h *TargetHandler) Run(ctxt context.Context) error {
|
|||
h.qcmd = make(chan *cdp.Message)
|
||||
h.qres = 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.pageWaitGroup = 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)
|
||||
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
|
||||
tree, err := page.GetResourceTree().Do(ctxt, h)
|
||||
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
|
||||
|
@ -182,19 +182,19 @@ func (h *TargetHandler) run(ctxt context.Context) {
|
|||
case ev := <-h.qevents:
|
||||
err = h.processEvent(ctxt, ev)
|
||||
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:
|
||||
err = h.processResult(res)
|
||||
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:
|
||||
err = h.processCommand(cmd)
|
||||
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():
|
||||
|
@ -271,7 +271,7 @@ func (h *TargetHandler) processEvent(ctxt context.Context, msg *cdp.Message) err
|
|||
func (h *TargetHandler) documentUpdated(ctxt context.Context) {
|
||||
f, err := h.WaitFrame(ctxt, EmptyFrameID)
|
||||
if err != nil {
|
||||
h.errorf("could not get current frame, got: %v", err)
|
||||
h.errorf("could not get current frame: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -286,7 +286,7 @@ func (h *TargetHandler) documentUpdated(ctxt context.Context) {
|
|||
f.Nodes = make(map[cdp.NodeID]*cdp.Node)
|
||||
f.Root, err = dom.GetDocument().WithPierce(true).Do(ctxt, h)
|
||||
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
|
||||
}
|
||||
f.Root.Invalidated = make(chan struct{})
|
||||
|
@ -304,11 +304,7 @@ func (h *TargetHandler) processResult(msg *cdp.Message) error {
|
|||
}
|
||||
defer close(ch)
|
||||
|
||||
if msg.Error != nil {
|
||||
return msg.Error
|
||||
}
|
||||
|
||||
ch <- msg.Result
|
||||
ch <- msg
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -346,7 +342,7 @@ func (h *TargetHandler) Execute(ctxt context.Context, commandType cdp.MethodType
|
|||
id := h.next()
|
||||
|
||||
// save channel
|
||||
ch := make(chan easyjson.RawMessage, 1)
|
||||
ch := make(chan *cdp.Message, 1)
|
||||
h.resrw.Lock()
|
||||
h.res[id] = ch
|
||||
h.resrw.Unlock()
|
||||
|
@ -364,8 +360,15 @@ func (h *TargetHandler) Execute(ctxt context.Context, commandType cdp.MethodType
|
|||
|
||||
select {
|
||||
case msg := <-ch:
|
||||
if res != nil {
|
||||
errch <- easyjson.Unmarshal(msg, res)
|
||||
switch {
|
||||
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():
|
||||
|
@ -559,7 +562,7 @@ func (h *TargetHandler) pageEvent(ctxt context.Context, ev interface{}) {
|
|||
|
||||
f, err := h.WaitFrame(ctxt, id)
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -579,7 +582,7 @@ func (h *TargetHandler) domEvent(ctxt context.Context, ev interface{}) {
|
|||
// wait current frame
|
||||
f, err := h.WaitFrame(ctxt, EmptyFrameID)
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -643,12 +646,15 @@ func (h *TargetHandler) domEvent(ctxt context.Context, ev interface{}) {
|
|||
return
|
||||
}
|
||||
|
||||
s := strings.TrimPrefix(strings.TrimSuffix(runtime.FuncForPC(reflect.ValueOf(op).Pointer()).Name(), ".func1"), "github.com/knq/chromedp.")
|
||||
|
||||
// retrieve node
|
||||
n, err := h.WaitNode(ctxt, f, id)
|
||||
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
|
||||
}
|
||||
|
||||
|
|
41
nav_test.go
Normal file
41
nav_test.go
Normal 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
602
query_test.go
Normal 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
20
testdata/form.html
vendored
Normal 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
7
testdata/image.html
vendored
Normal 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
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
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
34
testdata/table.html
vendored
Normal 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>
|
Loading…
Reference in New Issue
Block a user