Adding SetUploadFiles and changing SendKeys behavior
Added high level action SetUploadFiles to set the upload files for a input[type="file"] node, and modified SendKeys to recognize the nodes. Additionally, added unit test for both, and updated the examples/upload/main.go to use the SendKeys variant.
This commit is contained in:
parent
0b9790e5a8
commit
df490a3025
|
@ -10,8 +10,6 @@ import (
|
|||
"os"
|
||||
|
||||
cdp "github.com/knq/chromedp"
|
||||
cdptypes "github.com/knq/chromedp/cdp"
|
||||
"github.com/knq/chromedp/cdp/dom"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -97,14 +95,9 @@ func main() {
|
|||
}
|
||||
|
||||
func upload(filepath string, sz *string) cdp.Tasks {
|
||||
var ids []cdptypes.NodeID
|
||||
return cdp.Tasks{
|
||||
cdp.Navigate(fmt.Sprintf("http://localhost:%d", *flagPort)),
|
||||
cdp.WaitVisible(`input[name="upload"]`),
|
||||
cdp.NodeIDs(`input[name="upload"]`, &ids, cdp.NodeVisible),
|
||||
cdp.ActionFunc(func(ctxt context.Context, h cdptypes.Handler) error {
|
||||
return dom.SetFileInputFiles(ids[0], []string{filepath}).Do(ctxt, h)
|
||||
}),
|
||||
cdp.SendKeys(`input[name="upload"]`, filepath, cdp.NodeVisible),
|
||||
cdp.Click(`input[name="submit"]`),
|
||||
cdp.Text(`#result`, sz, cdp.ByID, cdp.NodeVisible),
|
||||
}
|
||||
|
|
6
input.go
6
input.go
|
@ -147,8 +147,10 @@ func ClickCount(n int) MouseOption {
|
|||
// KeyAction will synthesize a keyDown, char, and keyUp event for each rune
|
||||
// contained in keys along with any supplied key options.
|
||||
//
|
||||
// Note: only well known, "printable" characters will have "char" events
|
||||
// synthesized.
|
||||
// Only well-known, "printable" characters will have char events synthesized.
|
||||
//
|
||||
// Please see the chromedp/kb package for implementation details and the list
|
||||
// of well-known keys.
|
||||
func KeyAction(keys string, opts ...KeyOption) Action {
|
||||
return ActionFunc(func(ctxt context.Context, h cdp.Handler) error {
|
||||
var err error
|
||||
|
|
35
query.go
35
query.go
|
@ -329,15 +329,48 @@ func DoubleClick(sel interface{}, opts ...QueryOption) Action {
|
|||
|
||||
// SendKeys synthesizes the key up, char, and down events as needed for the
|
||||
// runes in v, sending them to the first node matching the selector.
|
||||
//
|
||||
// Note: when selector matches a input[type="file"] node, then dom.SetFileInputFiles
|
||||
// is used to set the upload path of the input node to v.
|
||||
func SendKeys(sel interface{}, v string, opts ...QueryOption) Action {
|
||||
return QueryAfter(sel, func(ctxt context.Context, h cdp.Handler, nodes ...*cdp.Node) error {
|
||||
if len(nodes) < 1 {
|
||||
return fmt.Errorf("selector `%s` did not return any nodes", sel)
|
||||
}
|
||||
return KeyActionNode(nodes[0], v).Do(ctxt, h)
|
||||
|
||||
n := nodes[0]
|
||||
|
||||
// grab type attribute from node
|
||||
typ, attrs := "", n.Attributes
|
||||
n.RLock()
|
||||
for i := 0; i < len(attrs); i += 2 {
|
||||
if attrs[i] == "type" {
|
||||
typ = attrs[i+1]
|
||||
}
|
||||
}
|
||||
n.RUnlock()
|
||||
|
||||
// when working with input[type="file"], call dom.SetFileInputFiles
|
||||
if n.NodeName == "INPUT" && typ == "file" {
|
||||
return dom.SetFileInputFiles(n.NodeID, []string{v}).Do(ctxt, h)
|
||||
}
|
||||
|
||||
return KeyActionNode(n, v).Do(ctxt, h)
|
||||
}, append(opts, NodeVisible)...)
|
||||
}
|
||||
|
||||
// SetUploadFiles sets the files to upload (ie, for a input[type="file"] node)
|
||||
// for the first node matching the selector.
|
||||
func SetUploadFiles(sel interface{}, files []string, opts ...QueryOption) Action {
|
||||
return QueryAfter(sel, func(ctxt context.Context, h cdp.Handler, nodes ...*cdp.Node) error {
|
||||
if len(nodes) < 1 {
|
||||
return fmt.Errorf("selector `%s` did not return any nodes", sel)
|
||||
}
|
||||
|
||||
return dom.SetFileInputFiles(nodes[0].NodeID, files).Do(ctxt, h)
|
||||
}, opts...)
|
||||
}
|
||||
|
||||
// Screenshot takes a screenshot of the first node matching the selector.
|
||||
func Screenshot(sel interface{}, picbuf *[]byte, opts ...QueryOption) Action {
|
||||
if picbuf == nil {
|
||||
|
|
|
@ -2,6 +2,10 @@ package chromedp
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -853,3 +857,96 @@ func TestMatchedStyle(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileUpload(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// create test server
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprintf(res, uploadHTML)
|
||||
})
|
||||
mux.HandleFunc("/upload", func(res http.ResponseWriter, req *http.Request) {
|
||||
f, _, err := req.FormFile("upload")
|
||||
if err != nil {
|
||||
http.Error(res, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
buf, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
http.Error(res, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(res, resultHTML, len(buf))
|
||||
})
|
||||
s := httptest.NewServer(mux)
|
||||
defer s.Close()
|
||||
|
||||
// create temporary file on disk
|
||||
tmpfile, err := ioutil.TempFile("", "chromedp-upload-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(tmpfile.Name())
|
||||
if _, err = tmpfile.WriteString(uploadHTML); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = tmpfile.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := testAllocate(t, "")
|
||||
defer c.Release()
|
||||
|
||||
tests := []struct {
|
||||
a Action
|
||||
}{
|
||||
{SendKeys(`input[name="upload"]`, tmpfile.Name(), NodeVisible)},
|
||||
{SetUploadFiles(`input[name="upload"]`, []string{tmpfile.Name()}, NodeVisible)},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) {
|
||||
test = test
|
||||
|
||||
c := testAllocate(t, "")
|
||||
defer c.Release()
|
||||
|
||||
var result string
|
||||
err = c.Run(defaultContext, Tasks{
|
||||
Navigate(s.URL),
|
||||
test.a,
|
||||
Click(`input[name="submit"]`),
|
||||
Text(`#result`, &result, ByID, NodeVisible),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("test %d expected no error, got: %v", i, err)
|
||||
}
|
||||
if result != fmt.Sprintf("%d", len(uploadHTML)) {
|
||||
t.Errorf("test %d expected result to be %d, got: %s", i, len(uploadHTML), result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
uploadHTML = `<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
<form method="POST" action="/upload" enctype="multipart/form-data">
|
||||
<input name="upload" type="file"/>
|
||||
<input name="submit" type="submit"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
resultHTML = `<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
<div id="result">%d</div>
|
||||
</body>
|
||||
</html>`
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user