177 lines
5.1 KiB
Go
177 lines
5.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
. "github.com/aandryashin/matchers"
|
|
. "github.com/aandryashin/matchers/httpresp"
|
|
"github.com/gorilla/websocket"
|
|
"github.com/mafredri/cdp"
|
|
"github.com/mafredri/cdp/protocol/target"
|
|
"github.com/mafredri/cdp/rpcc"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
srv *httptest.Server
|
|
devtoolsSrv *httptest.Server
|
|
)
|
|
|
|
func init() {
|
|
srv = httptest.NewServer(root())
|
|
listen = srv.Listener.Addr().String()
|
|
devtoolsSrv = httptest.NewServer(mockDevtoolsMux())
|
|
defaultDevtoolsHost = devtoolsSrv.Listener.Addr().String()
|
|
}
|
|
|
|
func mockDevtoolsMux() http.Handler {
|
|
mux := http.NewServeMux()
|
|
version := func(w http.ResponseWriter, _ *http.Request) {
|
|
w.Header().Add("Content-Type", "application/json")
|
|
w.Write([]byte(fmt.Sprintf(`{
|
|
"Browser": "Chrome/72.0.3601.0",
|
|
"Protocol-Version": "1.3",
|
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3601.0 Safari/537.36",
|
|
"V8-Version": "7.2.233",
|
|
"WebKit-Version": "537.36 (@cfede9db1d154de0468cb0538479f34c0755a0f4)",
|
|
"webSocketDebuggerUrl": "ws://%s/devtools/browser/b0b8a4fb-bb17-4359-9533-a8d9f3908bd8"
|
|
}`, defaultDevtoolsHost)))
|
|
}
|
|
mux.HandleFunc("/json/version", version)
|
|
listTargets := func(w http.ResponseWriter, _ *http.Request) {
|
|
w.Header().Add("Content-Type", "application/json")
|
|
w.Write([]byte(fmt.Sprintf(`[ {
|
|
"description": "",
|
|
"devtoolsFrontendUrl": "/devtools/inspector.html?ws=localhost:9222/devtools/page/one",
|
|
"id": "one",
|
|
"title": "Aerokube",
|
|
"type": "page",
|
|
"url": "https://www.aerokube.com/",
|
|
"webSocketDebuggerUrl": "ws://%s/devtools/page/one"
|
|
}, {
|
|
"description": "",
|
|
"devtoolsFrontendUrl": "/devtools/inspector.html?ws=localhost:9222/devtools/page/two",
|
|
"id": "two",
|
|
"title": "Aerokube Selenoid",
|
|
"type": "page",
|
|
"url": "https://selenoid.aerokube.com/",
|
|
"webSocketDebuggerUrl": "ws://%s/devtools/page/two"
|
|
} ]`, defaultDevtoolsHost, defaultDevtoolsHost)))
|
|
|
|
}
|
|
mux.HandleFunc("/json/list", listTargets)
|
|
mux.HandleFunc("/json", listTargets)
|
|
|
|
mux.HandleFunc("/json/protocol", func(w http.ResponseWriter, _ *http.Request) {
|
|
w.Header().Add("Content-Type", "application/json")
|
|
w.Write([]byte("{}"))
|
|
})
|
|
|
|
upgrader := websocket.Upgrader{
|
|
CheckOrigin: func(_ *http.Request) bool {
|
|
return true
|
|
},
|
|
}
|
|
|
|
devtoolsEcho := func(w http.ResponseWriter, r *http.Request) {
|
|
//Echo request ID but omit Method
|
|
c, err := upgrader.Upgrade(w, r, nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer c.Close()
|
|
for {
|
|
mt, message, err := c.ReadMessage()
|
|
if err != nil {
|
|
break
|
|
}
|
|
var req rpcc.Request
|
|
err = json.Unmarshal(message, &req)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
resp := rpcc.Response{
|
|
ID: req.ID,
|
|
}
|
|
if req.Method == "Target.getTargets" {
|
|
result := target.GetTargetsReply{
|
|
TargetInfos: []target.Info{
|
|
{TargetID: "one", Type: "page"},
|
|
{TargetID: "two", Type: "page"},
|
|
},
|
|
}
|
|
resBytes, _ := json.Marshal(result)
|
|
resp.Result = json.RawMessage(resBytes)
|
|
}
|
|
output, err := json.Marshal(resp)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
err = c.WriteMessage(mt, output)
|
|
if err != nil {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
mux.HandleFunc("/devtools/browser/", devtoolsEcho)
|
|
mux.HandleFunc("/devtools/page/", devtoolsEcho)
|
|
return mux
|
|
}
|
|
|
|
func TestProtocol(t *testing.T) {
|
|
u := fmt.Sprintf("http://%s/json/protocol", srv.Listener.Addr().String())
|
|
resp, err := http.Get(u)
|
|
AssertThat(t, err, Is{nil})
|
|
AssertThat(t, resp, Code{200})
|
|
}
|
|
|
|
func TestDevtools(t *testing.T) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
|
|
defer cancel()
|
|
|
|
browserWs := fmt.Sprintf("ws://%s/", srv.Listener.Addr().String())
|
|
browserConn, err := rpcc.DialContext(ctx, browserWs)
|
|
AssertThat(t, err, Is{nil})
|
|
defer browserConn.Close()
|
|
|
|
browserClient := cdp.NewClient(browserConn)
|
|
targets, err := browserClient.Target.GetTargets(ctx)
|
|
AssertThat(t, err, Is{nil})
|
|
AssertThat(t, len(targets.TargetInfos), EqualTo{2})
|
|
|
|
defaultPageWs := fmt.Sprintf("ws://%s/page", srv.Listener.Addr().String())
|
|
defaultPageConn, err := rpcc.DialContext(ctx, defaultPageWs)
|
|
AssertThat(t, err, Is{nil})
|
|
defer defaultPageConn.Close()
|
|
defaultPageClient := cdp.NewClient(defaultPageConn)
|
|
err = defaultPageClient.Page.Enable(ctx)
|
|
AssertThat(t, err, Is{nil})
|
|
|
|
selectedPageWs := fmt.Sprintf("ws://%s/page/%s", srv.Listener.Addr().String(), targets.TargetInfos[1].TargetID)
|
|
selectedPageConn, err := rpcc.DialContext(ctx, selectedPageWs)
|
|
AssertThat(t, err, Is{nil})
|
|
defer selectedPageConn.Close()
|
|
selectedPageClient := cdp.NewClient(selectedPageConn)
|
|
err = selectedPageClient.Page.Enable(ctx)
|
|
AssertThat(t, err, Is{nil})
|
|
}
|
|
|
|
func TestDetectDevtoolsHost(t *testing.T) {
|
|
name, _ := ioutil.TempDir("", "devtools")
|
|
defer os.RemoveAll(name)
|
|
profilePath := filepath.Join(name, ".org.chromium.Chromium.deadbee")
|
|
os.MkdirAll(profilePath, os.ModePerm)
|
|
portFile := filepath.Join(profilePath, "DevToolsActivePort")
|
|
ioutil.WriteFile(portFile, []byte("12345\n/devtools/browser/6f37c7fe-a0a6-4346-a6e2-80c5da0687f0"), 0644)
|
|
|
|
AssertThat(t, detectDevtoolsHost(name), EqualTo{"127.0.0.1:12345"})
|
|
}
|