Skip to content

Commit

Permalink
Define SwitchToFrame, SwitchToParentFrame, and SwitchToWindow WebDriv…
Browse files Browse the repository at this point in the history
…er endpoints. (#424)
  • Loading branch information
mtrea authored Sep 7, 2021
1 parent fcb3b3f commit 99ec27d
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 0 deletions.
3 changes: 3 additions & 0 deletions go/webdriver/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ go_library(
importpath = "github.com/bazelbuild/rules_webtesting/go/webdriver",
visibility = ["//go:__subpackages__"],
deps = [
"//go/bazel:go_default_library",
"//go/errors:go_default_library",
"//go/healthreporter:go_default_library",
"//go/metadata/capabilities:go_default_library",
"//go/portpicker:go_default_library",
],
)

Expand All @@ -43,6 +45,7 @@ go_web_test_suite(
"//browsers/sauce:chrome-win10",
"//browsers/sauce:chrome-win10-connect",
],
data = ["//testdata"],
embed = [":go_default_library"],
deps = ["//go/webtest:go_default_library"],
)
36 changes: 36 additions & 0 deletions go/webdriver/webdriver.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,17 @@ type WebDriver interface {
WindowHandles(context.Context) ([]string, error)
// CurrentWindowHandle returns the handle of the active window.
CurrentWindowHandle(context.Context) (string, error)
// SwitchToFrame switches the current browsing context to:
// nil: the top window (first frame)
// int: the frame with the given index
// WebElement: not yet supported
SwitchToFrame(ctx context.Context, frame interface{}) error
// SwitchToParentFrame switches the current browsing context to the parent of
// the current browsing context.
SwitchToParentFrame(ctx context.Context) error
// SwitchToWindow switches the current browsing context to the window with
// the given handle.
SwitchToWindow(ctx context.Context, handle string) error
// ElementFromID returns a new WebElement object for the given id.
ElementFromID(string) WebElement
// ElementFromMap returns a new WebElement from a map representing a JSON object.
Expand Down Expand Up @@ -440,6 +451,31 @@ func (d *webDriver) CurrentWindowHandle(ctx context.Context) (string, error) {
return value, nil
}

func (d *webDriver) SwitchToFrame(ctx context.Context, frame interface{}) error {
body := map[string]interface{}{}
switch f := frame.(type) {
case int, nil:
body["id"] = f
default:
return fmt.Errorf("invalid type %T", frame)
}
return d.post(ctx, "frame", body, nil)
}

func (d *webDriver) SwitchToParentFrame(ctx context.Context) error {
return d.post(ctx, "frame/parent", map[string]interface{}{}, nil)
}

func (d *webDriver) SwitchToWindow(ctx context.Context, handle string) error {
body := make(map[string]string)
if d.W3C() {
body["handle"] = handle
} else {
body["name"] = handle
}
return d.post(ctx, "window", body, nil)
}

func (d *webDriver) GetWindowRect(ctx context.Context) (result Rectangle, err error) {
if d.W3C() {
err = d.get(ctx, "window/rect", &result)
Expand Down
138 changes: 138 additions & 0 deletions go/webdriver/webdriver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,43 @@ package webdriver

import (
"context"
"fmt"
"log"
"net/http"
"net/url"
"os"
"strings"
"testing"
"time"

"github.com/bazelbuild/rules_webtesting/go/bazel"
"github.com/bazelbuild/rules_webtesting/go/metadata/capabilities"
"github.com/bazelbuild/rules_webtesting/go/portpicker"
"github.com/bazelbuild/rules_webtesting/go/webtest"
)

var testURL *url.URL

func TestMain(m *testing.M) {
port, err := portpicker.PickUnusedPort()
if err != nil {
log.Fatal(err)
}

dir, err := bazel.Runfile("testdata/")
if err != nil {
log.Fatal(err)
}

go func() {
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), http.FileServer(http.Dir(dir))))
}()

testURL, _ = url.Parse(fmt.Sprintf("http://localhost:%d/webdriver.html", port))

os.Exit(m.Run())
}

func TestCreateSessionAndQuit(t *testing.T) {
ctx := context.Background()

Expand Down Expand Up @@ -597,6 +624,117 @@ func TestSetWindowPosition(t *testing.T) {
}
}

func TestSwitchToFrame(t *testing.T) {
ctx := context.Background()

d, err := CreateSession(ctx, wdAddress(), 3, nil)
if err != nil {
t.Fatal(err)
}
defer d.Quit(ctx)

if err := d.NavigateTo(ctx, testURL); err != nil {
t.Fatal(err)
}

// Initial context
assertInFrame(ctx, t, d, false)

// Switch to default content from initial context
if err := d.SwitchToFrame(ctx, nil); err != nil {
t.Fatal(err)
}
assertInFrame(ctx, t, d, false)

// Switch to frame by index from initial context
if err := d.SwitchToFrame(ctx, 0); err != nil {
t.Fatal(err)
}
assertInFrame(ctx, t, d, true)

// Switch to default content from frame
if err := d.SwitchToFrame(ctx, nil); err != nil {
t.Fatal(err)
}
assertInFrame(ctx, t, d, false)

// Switch to frame by index (again) from initial context
if err := d.SwitchToFrame(ctx, 0); err != nil {
t.Fatal(err)
}
assertInFrame(ctx, t, d, true)

// Switch to default content which is the parent of the current frame
if err := d.SwitchToParentFrame(ctx); err != nil {
t.Fatal(err)
}
assertInFrame(ctx, t, d, false)
}

func assertInFrame(ctx context.Context, t *testing.T, d WebDriver, want bool) {
top := false
if err := d.ExecuteScript(ctx, "return window.self === window.top;", nil, &top); err != nil {
t.Fatal(err)
}
if top == want {
t.Errorf("inFrame = %t, but want %t", !top, want)
}
}

func TestSwitchToWindow(t *testing.T) {
ctx := context.Background()

d, err := CreateSession(ctx, wdAddress(), 3, nil)
if err != nil {
t.Fatal(err)
}
defer d.Quit(ctx)

if err := d.NavigateTo(ctx, testURL); err != nil {
t.Fatal(err)
}

handle, err := d.CurrentWindowHandle(ctx)
if err != nil {
t.Fatal(err)
}

// Open a new window.
if err := d.ExecuteScript(ctx, "window.open();", nil, nil); err != nil {
t.Fatal(err)
}

// Get the handle of the new window.
handles, err := d.WindowHandles(ctx)
if err != nil {
t.Fatal(err)
}
newHandle := ""
for _, h := range handles {
if h != handle {
newHandle = h
break
}
}
if newHandle == "" {
t.Fatal("got no new handle, but want new handle")
}

// Switch the context to the new window.
if err := d.SwitchToWindow(ctx, newHandle); err != nil {
t.Fatal(err)
}

// Verify the expected context switch has occurred.
handle, err = d.CurrentWindowHandle(ctx)
if err != nil {
t.Fatal(err)
}
if handle != newHandle {
t.Errorf("driver.CurrentWindowHandle = %s, but want %s", handle, newHandle)
}
}

func wdAddress() string {
addr := os.Getenv("WEB_TEST_WEBDRIVER_SERVER")
if !strings.HasSuffix(addr, "/") {
Expand Down
25 changes: 25 additions & 0 deletions testdata/webdriver.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<!--
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<title>WebDriver</title>
</head>
<body>
<iframe id="iframe" src="testpage.html" title="Test Page">
</iframe>
</body>
</html>

0 comments on commit 99ec27d

Please sign in to comment.