fb23c1750a
t.Parallel effectively fires off a goroutine, so we can't use the test range variable directly. That can result in different subtests using the same test case data, causing sporadic failures, or some test cases rarely being actually tested. This was uncovered while stress-testing the test suite for an unrelated refactor. While at it, one test case in TestMouseClickNode was incorrect. contextmenu fires on a right click, so ModifierNone won't fire it. This wasn't caught before, as this test case was almost never ran. After the data race fix, the test case failed consistently, before being fixed.
272 lines
6.3 KiB
Go
272 lines
6.3 KiB
Go
package chromedp
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/chromedp/cdproto/cdp"
|
|
"github.com/chromedp/cdproto/input"
|
|
)
|
|
|
|
const (
|
|
// inViewportJS is a javascript snippet that will get the specified node
|
|
// position relative to the viewport and returns true if the specified node
|
|
// is within the window's viewport.
|
|
inViewportJS = `(function(a) {
|
|
var r = a[0].getBoundingClientRect();
|
|
return r.top >= 0 && r.left >= 0 && r.bottom <= window.innerHeight && r.right <= window.innerWidth;
|
|
})($x('%s'))`
|
|
)
|
|
|
|
func TestMouseClickXY(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx, cancel := testAllocate(t, "input.html")
|
|
defer cancel()
|
|
|
|
if err := Run(ctx, WaitVisible(`#input1`, ByID)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tests := []struct {
|
|
x, y int64
|
|
}{
|
|
{100, 100},
|
|
{0, 0},
|
|
{9999, 100},
|
|
{100, 9999},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
if err := Run(ctx, MouseClickXY(test.x, test.y)); err != nil {
|
|
t.Fatalf("test %d got error: %v", i, err)
|
|
}
|
|
|
|
var xstr, ystr string
|
|
if err := Run(ctx, Value("#input1", &xstr, ByID)); err != nil {
|
|
t.Fatalf("test %d got error: %v", i, err)
|
|
}
|
|
|
|
x, err := strconv.ParseInt(xstr, 10, 64)
|
|
if err != nil {
|
|
t.Fatalf("test %d got error: %v", i, err)
|
|
}
|
|
if x != test.x {
|
|
t.Fatalf("test %d expected x to be: %d, got: %d", i, test.x, x)
|
|
}
|
|
if err := Run(ctx, Value("#input2", &ystr, ByID)); err != nil {
|
|
t.Fatalf("test %d got error: %v", i, err)
|
|
}
|
|
|
|
y, err := strconv.ParseInt(ystr, 10, 64)
|
|
if err != nil {
|
|
t.Fatalf("test %d got error: %v", i, err)
|
|
}
|
|
if y != test.y {
|
|
t.Fatalf("test %d expected y to be: %d, got: %d", i, test.y, y)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMouseClickNode(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
sel, exp string
|
|
opt MouseOption
|
|
by QueryOption
|
|
}{
|
|
{"button2", "foo", ButtonType(input.ButtonNone), ByID},
|
|
{"button2", "bar", ButtonType(input.ButtonLeft), ByID},
|
|
{"button2", "bar-middle", ButtonType(input.ButtonMiddle), ByID},
|
|
{"input3", "foo", ButtonModifiers(input.ModifierNone), ByID},
|
|
{"input3", "bar-right", ButtonType(input.ButtonRight), ByID},
|
|
{"input3", "bar-right", Button("right"), ByID},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) {
|
|
test := test
|
|
t.Parallel()
|
|
|
|
ctx, cancel := testAllocate(t, "input.html")
|
|
defer cancel()
|
|
|
|
var nodes []*cdp.Node
|
|
if err := Run(ctx, Nodes(test.sel, &nodes, test.by)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
if len(nodes) != 1 {
|
|
t.Fatalf("expected nodes to have exactly 1 element, got: %d", len(nodes))
|
|
}
|
|
if err := Run(ctx, MouseClickNode(nodes[0], test.opt)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
var value string
|
|
if err := Run(ctx, Value("#input3", &value, ByID)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
if value != test.exp {
|
|
t.Fatalf("expected to have value %s, got: %s", test.exp, value)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMouseClickOffscreenNode(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
sel string
|
|
exp int
|
|
by QueryOption
|
|
}{
|
|
{"#button3", 0, ByID},
|
|
{"#button3", 2, ByID},
|
|
{"#button3", 10, ByID},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) {
|
|
test := test
|
|
t.Parallel()
|
|
|
|
ctx, cancel := testAllocate(t, "input.html")
|
|
defer cancel()
|
|
|
|
var nodes []*cdp.Node
|
|
if err := Run(ctx, Nodes(test.sel, &nodes, test.by)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
if len(nodes) != 1 {
|
|
t.Fatalf("expected nodes to have exactly 1 element, got: %d", len(nodes))
|
|
}
|
|
|
|
var ok bool
|
|
if err := Run(ctx, EvaluateAsDevTools(fmt.Sprintf(inViewportJS, nodes[0].FullXPath()), &ok)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("expected node to be offscreen")
|
|
}
|
|
|
|
for i := test.exp; i > 0; i-- {
|
|
if err := Run(ctx, MouseClickNode(nodes[0])); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
}
|
|
|
|
var value int
|
|
if err := Run(ctx, Evaluate("window.document.test_i", &value)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
if value != test.exp {
|
|
t.Fatalf("expected to have value %d, got: %d", test.exp, value)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestKeyAction(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
sel, exp string
|
|
by QueryOption
|
|
}{
|
|
{"#input4", "foo", ByID},
|
|
{"#input4", "foo and bar", ByID},
|
|
{"#input4", "1234567890", ByID},
|
|
{"#input4", "~!@#$%^&*()_+=[];'", ByID},
|
|
{"#input4", "你", ByID},
|
|
{"#input4", "\n\nfoo\n\nbar\n\n", ByID},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) {
|
|
test := test
|
|
t.Parallel()
|
|
|
|
ctx, cancel := testAllocate(t, "input.html")
|
|
defer cancel()
|
|
|
|
var nodes []*cdp.Node
|
|
if err := Run(ctx, Nodes(test.sel, &nodes, test.by)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
if len(nodes) != 1 {
|
|
t.Fatalf("expected nodes to have exactly 1 element, got: %d", len(nodes))
|
|
}
|
|
if err := Run(ctx, Focus(test.sel, test.by)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
if err := Run(ctx, KeyAction(test.exp)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
var value string
|
|
if err := Run(ctx, Value(test.sel, &value, test.by)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
if value != test.exp {
|
|
t.Fatalf("expected to have value %s, got: %s", test.exp, value)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestKeyActionNode(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
sel, exp string
|
|
by QueryOption
|
|
}{
|
|
{"#input4", "foo", ByID},
|
|
{"#input4", "foo and bar", ByID},
|
|
{"#input4", "1234567890", ByID},
|
|
{"#input4", "~!@#$%^&*()_+=[];'", ByID},
|
|
{"#input4", "你", ByID},
|
|
{"#input4", "\n\nfoo\n\nbar\n\n", ByID},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) {
|
|
test := test
|
|
t.Parallel()
|
|
|
|
ctx, cancel := testAllocate(t, "input.html")
|
|
defer cancel()
|
|
|
|
var nodes []*cdp.Node
|
|
if err := Run(ctx, Nodes(test.sel, &nodes, test.by)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
if len(nodes) != 1 {
|
|
t.Fatalf("expected nodes to have exactly 1 element, got: %d", len(nodes))
|
|
}
|
|
if err := Run(ctx, KeyActionNode(nodes[0], test.exp)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
var value string
|
|
if err := Run(ctx, Value(test.sel, &value, test.by)); err != nil {
|
|
t.Fatalf("got error: %v", err)
|
|
}
|
|
|
|
if value != test.exp {
|
|
t.Fatalf("expected to have value %s, got: %s", test.exp, value)
|
|
}
|
|
})
|
|
}
|
|
}
|