diff --git a/internal/seleniumtest/seleniumtest.go b/internal/seleniumtest/seleniumtest.go
new file mode 100644
index 0000000..a567704
--- /dev/null
+++ b/internal/seleniumtest/seleniumtest.go
@@ -0,0 +1,1701 @@
+// Package seleniumtest provides tests to exercise package selenium. These
+// tests are in a separate package to allow other test harnesses to validate
+// their behavior.
+package seleniumtest
+
+import (
+ "context"
+ "fmt"
+ "math"
+ "net"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "reflect"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+
+ socks5 "github.com/armon/go-socks5"
+ "github.com/blang/semver"
+ "github.com/google/go-cmp/cmp"
+ "github.com/tebeka/selenium"
+ "github.com/tebeka/selenium/chrome"
+ "github.com/tebeka/selenium/firefox"
+ "github.com/tebeka/selenium/log"
+ "github.com/tebeka/selenium/sauce"
+)
+
+type Config struct {
+ Addr, Browser, Path, ServerURL string
+ Sauce *sauce.Capabilities
+ SeleniumVersion semver.Version
+ ServiceOptions []selenium.ServiceOption
+ Headless bool
+ SkipProxy bool
+}
+
+func runTest(f func(*testing.T, Config), c Config) func(*testing.T) {
+ return func(t *testing.T) {
+ f(t, c)
+ }
+}
+
+var NewRemote = func(_ *testing.T, caps selenium.Capabilities, addr string) (selenium.WebDriver, error) {
+ return selenium.NewRemote(caps, addr)
+}
+
+func newRemote(t *testing.T, caps selenium.Capabilities, c Config) selenium.WebDriver {
+ wd, err := NewRemote(t, caps, c.Addr)
+ if err != nil {
+ t.Fatalf("NewRemote(%+v, %q) returned error: %v", caps, c.Addr, err)
+ }
+ return wd
+}
+
+func newTestCapabilities(t *testing.T, c Config) selenium.Capabilities {
+ caps := selenium.Capabilities{
+ "browserName": c.Browser,
+ }
+ switch c.Browser {
+ case "chrome":
+ chrCaps := chrome.Capabilities{
+ Path: c.Path,
+ Args: []string{
+ // This flag is needed to test against Chrome binaries that are not the
+ // default installation. The sandbox requires a setuid binary.
+ "--no-sandbox",
+ },
+ W3C: true,
+ }
+ if c.Headless {
+ chrCaps.Args = append(chrCaps.Args, "--headless")
+ }
+ caps.AddChrome(chrCaps)
+ case "firefox":
+ f := firefox.Capabilities{}
+ if c.Path != "" {
+ p, err := filepath.Abs(c.Path)
+ if err != nil {
+ panic(err)
+ }
+ f.Binary = p
+ }
+ if testing.Verbose() {
+ f.Log = &firefox.Log{
+ Level: firefox.Trace,
+ }
+ }
+ if c.Headless {
+ f.Args = append(f.Args, "-headless")
+ }
+ caps.AddFirefox(f)
+ case "htmlunit":
+ caps["javascriptEnabled"] = true
+ }
+
+ if c.Sauce != nil {
+ m, err := c.Sauce.ToMap()
+ if err != nil {
+ t.Fatalf("Error obtaining map for sauce.Capabilities: %s", err)
+ }
+ for k, v := range m {
+ caps[k] = v
+ }
+ if c.SeleniumVersion.Major > 0 {
+ caps["seleniumVersion"] = c.SeleniumVersion.String()
+ }
+ caps["name"] = t.Name()
+ }
+
+ return caps
+}
+
+func quitRemote(t *testing.T, wd selenium.WebDriver) {
+ if err := wd.Quit(); err != nil {
+ t.Errorf("wd.Quit() returned error: %v", err)
+ }
+}
+
+func RunCommonTests(t *testing.T, c Config) {
+ t.Run("Status", runTest(testStatus, c))
+ t.Run("DeleteSession", runTest(testDeleteSession, c))
+ t.Run("Error", runTest(testError, c))
+ t.Run("Capabilities", runTest(testCapabilities, c))
+ t.Run("SetAsyncScriptTimeout", runTest(testSetAsyncScriptTimeout, c))
+ t.Run("SetImplicitWaitTimeout", runTest(testSetImplicitWaitTimeout, c))
+ t.Run("SetPageLoadTimeout", runTest(testSetPageLoadTimeout, c))
+ t.Run("Windows", runTest(testWindows, c))
+ t.Run("Get", runTest(testGet, c))
+ t.Run("Navigation", runTest(testNavigation, c))
+ t.Run("Title", runTest(testTitle, c))
+ t.Run("PageSource", runTest(testPageSource, c))
+ t.Run("FindElement", runTest(testFindElement, c))
+ t.Run("FindElements", runTest(testFindElements, c))
+ t.Run("SendKeys", runTest(testSendKeys, c))
+ t.Run("Click", runTest(testClick, c))
+ t.Run("GetCookies", runTest(testGetCookies, c))
+ t.Run("GetCookie", runTest(testGetCookie, c))
+ t.Run("AddCookie", runTest(testAddCookie, c))
+ t.Run("DeleteCookie", runTest(testDeleteCookie, c))
+ t.Run("Location", runTest(testLocation, c))
+ t.Run("LocationInView", runTest(testLocationInView, c))
+ t.Run("Size", runTest(testSize, c))
+ t.Run("ExecuteScript", runTest(testExecuteScript, c))
+ t.Run("ExecuteScriptOnElement", runTest(testExecuteScriptOnElement, c))
+ t.Run("ExecuteScriptWithNilArgs", runTest(testExecuteScriptWithNilArgs, c))
+ t.Run("Screenshot", runTest(testScreenshot, c))
+ t.Run("Log", runTest(testLog, c))
+ t.Run("IsSelected", runTest(testIsSelected, c))
+ t.Run("IsDisplayed", runTest(testIsDisplayed, c))
+ t.Run("GetAttributeNotFound", runTest(testGetAttributeNotFound, c))
+ t.Run("KeyDownUp", runTest(testKeyDownUp, c))
+ t.Run("CSSProperty", runTest(testCSSProperty, c))
+ if !c.SkipProxy {
+ t.Run("Proxy", runTest(testProxy, c))
+ }
+ t.Run("SwitchFrame", runTest(testSwitchFrame, c))
+ t.Run("Wait", runTest(testWait, c))
+ t.Run("ActiveElement", runTest(testActiveElement, c))
+ t.Run("AcceptAlert", runTest(testAcceptAlert, c))
+ t.Run("DismissAlert", runTest(testDismissAlert, c))
+}
+
+func testStatus(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ status, err := wd.Status()
+ if err != nil {
+ t.Fatalf("wd.Status() returned error: %v", err)
+ }
+
+ if c.Sauce == nil {
+ if len(status.OS.Name) == 0 && status.Message == "" {
+ t.Fatalf("OS.Name or Message not provided: %+v", status)
+ }
+ } else if status.Build.Version != "Sauce Labs" {
+ t.Fatalf("status.Build.Version = %q, expected 'Sauce Labs'", status.Build.Version)
+ }
+}
+
+func testDeleteSession(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ if err := selenium.DeleteSession(c.Addr, wd.SessionID()); err != nil {
+ t.Fatalf("DeleteSession(%s, %s) returned error: %v", c.Addr, wd.SessionID(), err)
+ }
+}
+
+func testError(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ _, err := wd.FindElement(selenium.ByID, "no-such-element")
+ if err == nil {
+ t.Fatal("wd.FindElement(selenium.ByID, 'no-such-element') did not return an error as expected")
+ }
+
+ e, ok := err.(*selenium.Error)
+ if !ok {
+ if c.SeleniumVersion.Major > 0 {
+ // t.Skipf("Selenium does not support W3C-style errors.")
+ } else {
+ t.Fatalf("wd.FindElement(selenium.ByID, 'no-such-element') returned an error that is not an *Error: %v", err)
+ }
+ }
+ if want := "no such element"; e.Err != want {
+ t.Errorf("wd.FindElement(selenium.ByID, 'no-such-element'); err.Err = %q, want %q", e.Err, want)
+ }
+
+ // Chrome returns 404 in W3C-compatibility mode, but 200 otherwise. Firefox
+ // returns 404, but HTMLUnit returns a 500.
+ switch e.HTTPCode {
+ case 200, 404, 500:
+ default:
+ t.Errorf("wd.FindElement(selenium.ByID, 'no-such-element'); err.HTTPCode = %d, want non-zero", e.HTTPCode)
+ }
+}
+
+// TODO(ekg): does this method work anymore in any browser? It is not part of
+// the W3C standard.
+func testCapabilities(t *testing.T, c Config) {
+ if c.Browser == "firefox" {
+ t.Skip("This method is not supported by Geckodriver.")
+ }
+ t.Skip("This method crashes Chrome?")
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ caps, err := wd.Capabilities()
+ if err != nil {
+ t.Fatalf("wd.Capabilities() returned error: %v", err)
+ }
+
+ if strings.ToLower(caps["browserName"].(string)) != c.Browser {
+ t.Fatalf("bad browser name - %s (should be %s)", caps["browserName"], c.Browser)
+ }
+}
+
+func testSetAsyncScriptTimeout(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.SetAsyncScriptTimeout(200); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testSetImplicitWaitTimeout(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.SetImplicitWaitTimeout(200); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testSetPageLoadTimeout(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.SetPageLoadTimeout(200); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testWindows(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+
+ firstHandle, err := wd.CurrentWindowHandle()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(firstHandle) == 0 {
+ t.Fatal("Empty handle")
+ }
+
+ const linkText = "other page"
+ link, err := wd.FindElement(selenium.ByLinkText, linkText)
+ if err != nil {
+ t.Fatalf("wd.FindElement(%q, %q) returned error: %v", selenium.ByLinkText, linkText, err)
+ }
+
+ switch c.Browser {
+ case "firefox":
+ // Firefox+Geckodriver doesn't handle control characters without appending
+ // a terminating null key.
+ // https://github.com/mozilla/geckodriver/issues/665
+ newWindowModifier := selenium.ShiftKey + selenium.NullKey
+ if err := wd.SendModifier(newWindowModifier /*isDown=*/, true); err != nil {
+ t.Fatalf("wd.SendModifer(selenium.ShiftKey) returned error: %v", err)
+ }
+ // Firefox and Geckodriver doesn't handle clicking on an element.
+ //
+ // https://github.com/mozilla/geckodriver/issues/1007
+ if err := link.SendKeys(selenium.EnterKey); err != nil {
+ t.Fatalf("link.SendKeys(selenium.EnterKey) returned error: %v", err)
+ }
+ if err := wd.SendModifier(newWindowModifier /*isDown=*/, false); err != nil {
+ t.Fatalf("wd.SendKeys(selenium.ShiftKey) returned error: %v", err)
+ }
+ case "htmlunit":
+ newWindowModifier := selenium.ShiftKey
+ if err := wd.SendModifier(newWindowModifier /*isDown=*/, true); err != nil {
+ t.Fatalf("wd.SendModifer(selenium.ShiftKey) returned error: %v", err)
+ }
+ if err := link.Click(); err != nil {
+ t.Fatalf("link.Click() returned error: %v", err)
+ }
+ if err := wd.SendModifier(newWindowModifier /*isDown=*/, false); err != nil {
+ t.Fatalf("wd.SendKeys(selenium.ShiftKey) returned error: %v", err)
+ }
+ case "chrome":
+ // Chrome doesn't support handling key events at the browser level.
+ // https://crbug.com/chromedriver/30
+ otherURL := path.Join(c.ServerURL, "other")
+ if _, err := wd.ExecuteScript(fmt.Sprintf("window.open(%q)", otherURL), nil); err != nil {
+ t.Fatalf("opening a new window via Javascript returned error: %v", err)
+ }
+ }
+
+ // Starting a new window can take a while. Try a few times before failing.
+ var handles []string
+ tries := 5
+ for {
+ handles, err = wd.WindowHandles()
+ if err != nil {
+ t.Fatalf("wd.WindowHandles() returned error: %v", err)
+ }
+ if len(handles) == 2 {
+ break
+ }
+ tries--
+ if tries == 0 {
+ break
+ }
+ time.Sleep(time.Second)
+ }
+ if len(handles) != 2 {
+ t.Fatalf("len(wd.WindowHandles()) = %d, expected 2", len(handles))
+ }
+ var found bool
+ var otherHandle string
+ for _, h := range handles {
+ if h == firstHandle {
+ found = true
+ } else {
+ otherHandle = h
+ }
+ }
+ if !found {
+ t.Fatalf("wd.WindowHandles() returned %v, expected to include %q", handles, firstHandle)
+ }
+
+ t.Run("SwitchWindow", func(t *testing.T) {
+ if err := wd.SwitchWindow(otherHandle); err != nil {
+ t.Fatalf("wd.SwitchWindow(firstHandle) returned error: %v", err)
+ }
+ if _, err := wd.FindElement(selenium.ByLinkText, linkText); err == nil {
+ t.Fatalf("wd.FindElement(%q, %q) (after opening a new window) returned nil, expected error", selenium.ByLinkText, linkText)
+ }
+ if err := wd.SwitchWindow(firstHandle); err != nil {
+ t.Fatalf("wd.SwitchWindow(firstHandle) returned error: %v", err)
+ }
+ if _, err := wd.FindElement(selenium.ByLinkText, linkText); err != nil {
+ t.Fatalf("wd.FindElement(%q, %q) (after switching to the original window) returned error: %v", selenium.ByLinkText, linkText, err)
+ }
+ })
+
+ t.Run("MaximizeWindow", func(t *testing.T) {
+ if err := wd.MaximizeWindow(otherHandle); err != nil {
+ t.Fatalf("error maximizing window: %s", err)
+ }
+ })
+
+ t.Run("ResizeWindow", func(t *testing.T) {
+ if err := wd.ResizeWindow(otherHandle, 100, 100); err != nil {
+ t.Fatalf("error resizing window: %s", err)
+ }
+ })
+
+ t.Run("CloseWindow", func(t *testing.T) {
+ if err := wd.CloseWindow(otherHandle); err != nil {
+ t.Fatalf("wd.CloseWindow(otherHandle) returned error: %v", err)
+ }
+ handles, err := wd.WindowHandles()
+ if err != nil {
+ t.Fatalf("wd.WindowHandles() returned error: %v", err)
+ }
+ if len(handles) != 1 {
+ t.Fatalf("len(wd.WindowHandles()) = %d, expected 1", len(handles))
+ }
+ })
+}
+
+func testGet(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatal(err)
+ }
+
+ newURL, err := wd.CurrentURL()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if newURL != c.ServerURL+"/" {
+ t.Fatalf("%s != %s", newURL, c.ServerURL)
+ }
+}
+
+func testNavigation(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ url1 := c.ServerURL
+ if err := wd.Get(url1); err != nil {
+ t.Fatal(err)
+ }
+
+ url2 := c.ServerURL + "/other"
+ if err := wd.Get(url2); err != nil {
+ t.Fatal(err)
+ }
+
+ if err := wd.Back(); err != nil {
+ t.Fatal(err)
+ }
+ url, err := wd.CurrentURL()
+ if err != nil {
+ t.Fatalf("wd.CurrentURL() returned error: %v", err)
+ }
+ if url != url1+"/" {
+ t.Fatalf("back got me to %s (expected %s/)", url, url1)
+ }
+ if err := wd.Forward(); err != nil {
+ t.Fatal(err)
+ }
+ url, err = wd.CurrentURL()
+ if err != nil {
+ t.Fatalf("wd.CurrentURL() returned error: %v", err)
+ }
+ if url != url2 {
+ t.Fatalf("forward got me to %s (expected %s)", url, url2)
+ }
+
+ if err := wd.Refresh(); err != nil {
+ t.Fatal(err)
+ }
+ url, err = wd.CurrentURL()
+ if err != nil {
+ t.Fatalf("wd.CurrentURL() returned error: %v", err)
+ }
+ if url != url2 {
+ t.Fatalf("refresh got me to %s (expected %s)", url, url2)
+ }
+}
+
+func testTitle(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+
+ title, err := wd.Title()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ expectedTitle := "Go Selenium Test Suite"
+ if title != expectedTitle {
+ t.Fatalf("Bad title %s, should be %s", title, expectedTitle)
+ }
+}
+
+func testPageSource(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatal(err)
+ }
+
+ source, err := wd.PageSource()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !strings.Contains(source, "The home page.") {
+ t.Fatalf("Bad source\n%s", source)
+ }
+}
+
+func testFindElement(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ for _, tc := range []struct {
+ by, query string
+ }{
+ {selenium.ByName, "submit"},
+ {selenium.ByCSSSelector, "input[name=submit]"},
+ {selenium.ByXPATH, "/html/body/form/input[2]"},
+ {selenium.ByLinkText, "search"},
+ } {
+ t.Run(tc.by, func(t *testing.T) {
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ elem, err := wd.FindElement(tc.by, tc.query)
+ if err != nil {
+ t.Fatalf("wd.FindElement(%q, %q) returned error: %v", tc.by, tc.query, err)
+ }
+ evaluateElement(t, wd, elem)
+ })
+ }
+}
+
+func evaluateElement(t *testing.T, wd selenium.WebDriver, elem selenium.WebElement) {
+ if err := elem.Click(); err != nil {
+ t.Fatalf("wd.FindElement().Click() returned error: %v", err)
+ }
+
+ u, err := wd.CurrentURL()
+ if err != nil {
+ t.Fatalf("wd.CurrentURL() returned error: %v", err)
+ }
+
+ if !strings.Contains(u, "/search") {
+ t.Fatalf("After element click, got URL %q, want /search", u)
+ }
+}
+
+func testFindElements(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ elems, err := wd.FindElements(selenium.ByName, "submit")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(elems) != 1 {
+ t.Fatalf("Wrong number of elements %d (should be 1)", len(elems))
+ }
+
+ evaluateElement(t, wd, elems[0])
+}
+
+func testSendKeys(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ input, err := wd.FindElement(selenium.ByName, "q")
+ if err != nil {
+ t.Fatal(err)
+ }
+ const query = "golang"
+ if err := input.SendKeys(query + selenium.EnterKey); err != nil {
+ t.Fatal(err)
+ }
+
+ time.Sleep(500 * time.Millisecond)
+
+ source, err := wd.PageSource()
+ if err != nil {
+ t.Fatalf("wd.PageSource() returned error: %v", err)
+ }
+
+ if !strings.Contains(source, searchContents) {
+ t.Fatalf("Can't find %q on page after searching for %q", searchContents, query)
+ }
+
+ if !strings.Contains(source, query) {
+ t.Fatalf("Can't find search query %q in source", query)
+ }
+}
+
+func testClick(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ const searchBoxName = "q"
+ input, err := wd.FindElement(selenium.ByName, searchBoxName)
+ if err != nil {
+ t.Fatalf("wd.FindElement(%q, %q) returned error: %v", selenium.ByName, searchBoxName, err)
+ }
+ const query = "golang"
+ if err = input.SendKeys(query); err != nil {
+ t.Fatalf("input.SendKeys(%q) returned error: %v", query, err)
+ }
+
+ const selectTag = "select"
+ sel, err := wd.FindElement(selenium.ByCSSSelector, selectTag)
+ if err != nil {
+ t.Fatalf("wd.FindElement(%q, %q) returned error: %v", selenium.ByCSSSelector, selectTag, err)
+ }
+ if err = sel.Click(); err != nil {
+ t.Fatalf("input.Click() returned error: %v", err)
+ }
+ time.Sleep(2 * time.Second)
+ option, err := sel.FindElement(selenium.ByID, "secondValue")
+ if err != nil {
+ t.Fatalf("input.FindElement(%q, %q) returned error: %v", selenium.ByID, "secondValue", err)
+ }
+ if err = option.Click(); err != nil {
+ t.Fatalf("option.Click() returned error: %v", err)
+ }
+ if c.Browser == "firefox" {
+ // Click anywhere else to de-focus the drop-down menu.
+ if err = input.Click(); err != nil {
+ t.Fatalf("wd.Click() returned error: %v", err)
+ }
+ }
+
+ const buttonID = "submit"
+ button, err := wd.FindElement(selenium.ByID, buttonID)
+ if err != nil {
+ t.Fatalf("wd.FindElement(%q, %q) returned error: %v", selenium.ByID, buttonID, err)
+ }
+ if err := wd.SetPageLoadTimeout(2 * time.Second); err != nil {
+ t.Fatalf("wd.SetImplicitWaitTimeout() returned error: %v", err)
+ }
+ if err = button.Click(); err != nil {
+ t.Fatalf("wd.Click() returned error: %v", err)
+ }
+
+ // The page load timeout for Firefox and Selenium 3 seems to not work for
+ // clicking form buttons. Sleep a bit to reduce impact of a flaky test.
+ if c.Browser == "firefox" && c.SeleniumVersion.Major == 3 {
+ time.Sleep(2 * time.Second)
+ }
+ source, err := wd.PageSource()
+ if err != nil {
+ t.Fatalf("wd.PageSource() returned error: %v", err)
+ }
+
+ if !strings.Contains(source, searchContents) {
+ t.Fatalf("Can't find %q on page after searching for %q", searchContents, query)
+ }
+}
+
+func testGetCookie(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ cookies, err := wd.GetCookies()
+ if err != nil {
+ t.Fatalf("wd.GetCookies() returned error: %v", err)
+ }
+
+ if len(cookies) == 0 {
+ t.Fatal("wd.GetCookies() returned no cookies")
+ }
+
+ if len(cookies[0].Name) == 0 {
+ t.Fatalf("Empty cookie name: %+v", cookies[0])
+ }
+
+ got, err := wd.GetCookie(cookies[0].Name)
+ if err != nil {
+ t.Fatalf("wd.GetCookie(%q) returned error: %v", cookies[0].Name, err)
+ }
+ if !reflect.DeepEqual(got, cookies[0]) {
+ t.Fatalf("wd.GetCookie(%q) = %+v, want %+v", cookies[0].Name, cookies[0], got)
+ }
+}
+
+func testGetCookies(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ cookies, err := wd.GetCookies()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(cookies) == 0 {
+ t.Fatal("No cookies")
+ }
+
+ if len(cookies[0].Name) == 0 {
+ t.Fatal("Empty cookie")
+ }
+}
+
+func v(s string) semver.Version {
+ return semver.MustParse(s)
+}
+
+func testAddCookie(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ want := &selenium.Cookie{
+ Name: "the nameless cookie",
+ Value: "I have nothing",
+ Expiry: math.MaxUint32,
+ Domain: "127.0.0.1", // Unlike real browsers, htmlunit requires this to be set.
+ }
+ if err := wd.AddCookie(want); err != nil {
+ t.Fatal(err)
+ }
+
+ // These fields are added implicitly by the browser.
+ want.Domain = "127.0.0.1"
+ want.Path = "/"
+
+ // Firefox and Geckodriver now returns an empty string for the path.
+ if c.Browser == "firefox" {
+ want.Path = ""
+ }
+
+ cookies, err := wd.GetCookies()
+ if err != nil {
+ t.Fatal(err)
+ }
+ var got *selenium.Cookie
+ for _, cookie := range cookies {
+ if cookie.Name == want.Name {
+ got = &cookie
+ break
+ }
+ }
+ if got == nil {
+ t.Fatalf("wd.GetCookies() = %v, missing cookie %q", cookies, want.Name)
+ }
+
+ if diff := cmp.Diff(want, got); diff != "" {
+ t.Fatalf("wd.GetCookies() returned diff (-want/+got):\n%s", diff)
+ }
+}
+
+func testDeleteCookie(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ cookies, err := wd.GetCookies()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(cookies) == 0 {
+ t.Fatal("No cookies")
+ }
+ if err := wd.DeleteCookie(cookies[0].Name); err != nil {
+ t.Fatal(err)
+ }
+ newCookies, err := wd.GetCookies()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(newCookies) != len(cookies)-1 {
+ t.Fatal("Cookie not deleted")
+ }
+
+ for _, c := range newCookies {
+ if c.Name == cookies[0].Name {
+ t.Fatal("Deleted cookie found")
+ }
+ }
+}
+
+func testLocation(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ button, err := wd.FindElement(selenium.ByID, "submit")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ loc, err := button.Location()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if loc.X == 0 || loc.Y == 0 {
+ t.Fatalf("Bad location: %v\n", loc)
+ }
+}
+
+func testLocationInView(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ button, err := wd.FindElement(selenium.ByID, "submit")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ loc, err := button.LocationInView()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if loc.X == 0 || loc.Y == 0 {
+ t.Fatalf("Bad location: %v\n", loc)
+ }
+}
+
+func testSize(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ button, err := wd.FindElement(selenium.ByID, "submit")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ size, err := button.Size()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if size.Width == 0 || size.Height == 0 {
+ t.Fatalf("Bad size: %v\n", size)
+ }
+}
+
+func testExecuteScript(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ script := "return arguments[0] + arguments[1]"
+ args := []interface{}{1, 2}
+ reply, err := wd.ExecuteScript(script, args)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ result, ok := reply.(float64)
+ if !ok {
+ t.Fatal("Not an int reply")
+ }
+
+ if result != 3 {
+ t.Fatalf("Bad result %d (expected 3)", int(result))
+ }
+}
+
+func testExecuteScriptWithNilArgs(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+
+ script := "return document.readyState"
+ if _, err := wd.ExecuteScript(script, nil); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testExecuteScriptOnElement(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+
+ input, err := wd.FindElement(selenium.ByName, "q")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ const query = "golang"
+ if err := input.SendKeys(query); err != nil {
+ t.Fatal(err)
+ }
+
+ we, err := wd.FindElement(selenium.ByXPATH, "//input[@type='submit']")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ script := "arguments[0].click()"
+ args := []interface{}{we}
+
+ if _, err = wd.ExecuteScript(script, args); err != nil {
+ t.Fatal(err)
+ }
+
+ time.Sleep(500 * time.Millisecond)
+
+ source, err := wd.PageSource()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !strings.Contains(source, searchContents) {
+ t.Fatalf("Can't find %q on page after searching for %q", searchContents, query)
+ }
+}
+
+func testScreenshot(t *testing.T, c Config) {
+ if c.Browser == "htmlunit" {
+ t.Skip("Skipping on htmlunit")
+ }
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ data, err := wd.Screenshot()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(data) == 0 {
+ t.Fatal("Empty reply")
+ }
+}
+
+func testLog(t *testing.T, c Config) {
+ switch {
+ case c.Browser == "htmlunit":
+ t.Skip("Skipping on htmlunit")
+ case c.Browser == "firefox" && (c.SeleniumVersion.Major == 3 || c.SeleniumVersion.Major == 0):
+ // Log is not supported on Firefox with Selenium 3.
+ // https://github.com/w3c/webdriver/issues/406
+ // https://github.com/mozilla/geckodriver/issues/284
+ t.Skip("The log interface is not supported on Firefox, since it is not yet part of the W3C spec.")
+ }
+ caps := newTestCapabilities(t, c)
+ caps.SetLogLevel(log.Browser, log.All)
+ if c.Browser == "chrome" {
+ caps.SetLogLevel(log.Performance, log.All)
+ }
+
+ wd := newRemote(t, caps, c)
+ defer quitRemote(t, wd)
+
+ url := c.ServerURL + "/log"
+ if err := wd.Get(url); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", url, err)
+ }
+ logs, err := wd.Log(log.Browser)
+ if err != nil {
+ t.Fatalf("wd.Log(Browser) returned error: %v", err)
+ }
+ if len(logs) == 0 {
+ t.Fatalf("empty reply from wd.Log(Browser)")
+ } else {
+ for _, l := range logs {
+ if len(l.Level) == 0 || l.Timestamp.Unix() == 0 || len(l.Message) == 0 {
+ t.Errorf("wd.Log(Browser) returned malformed message: %+v", l)
+ }
+ }
+ }
+
+ if c.Browser == "chrome" {
+ logs, err = wd.Log(log.Performance)
+ if err != nil {
+ t.Fatalf("wd.Log(Performance) returned error: %v", err)
+ }
+ if len(logs) == 0 {
+ t.Fatal("empty reply from wd.Log(Performance)")
+ } else {
+ for _, l := range logs {
+ if len(l.Level) == 0 || l.Timestamp.Unix() == 0 || len(l.Message) == 0 {
+ t.Errorf("wd.Log(Browser) returned malformed message: %+v", l)
+ }
+ // Make sure the timestamp conversion is vaguely correct. In
+ // practice, this difference should be in the milliseconds range.
+ if time.Now().Sub(l.Timestamp) > time.Hour {
+ t.Errorf("Message has timestamp %s > 1 hour ago: %v", l.Timestamp, l)
+ }
+ }
+ }
+ }
+}
+
+func testIsSelected(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ elem, err := wd.FindElement(selenium.ByID, "chuk")
+ if err != nil {
+ t.Fatal("Can't find element")
+ }
+ selected, err := elem.IsSelected()
+ if err != nil {
+ t.Fatal("Can't get selection")
+ }
+
+ if selected {
+ t.Fatal("Already selected")
+ }
+
+ if err := elem.Click(); err != nil {
+ t.Fatal("Can't click")
+ }
+
+ selected, err = elem.IsSelected()
+ if err != nil {
+ t.Fatal("Can't get selection")
+ }
+
+ if !selected {
+ t.Fatal("Not selected")
+ }
+}
+
+func testIsDisplayed(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ const id = "chuk"
+ elem, err := wd.FindElement(selenium.ByID, id)
+ if err != nil {
+ t.Fatalf("wd.FindElement(selenium.ByID, %s) return error %v", id, err)
+ }
+ displayed, err := elem.IsDisplayed()
+ if err != nil {
+ t.Fatalf("elem.IsDisplayed() returned error: %v", err)
+ }
+
+ if !displayed {
+ t.Fatal("Not displayed")
+ }
+}
+
+func testGetAttributeNotFound(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ elem, err := wd.FindElement(selenium.ByID, "chuk")
+ if err != nil {
+ t.Fatal("Can't find element")
+ }
+
+ if _, err = elem.GetAttribute("no-such-attribute"); err == nil {
+ t.Fatal("Got non existing attribute")
+ }
+}
+
+func testActiveElement(t *testing.T, c Config) {
+ if c.Browser == "htmlunit" {
+ // TODO(minusnine): figure out why ActiveElement doesn't work in HTMLUnit.
+ t.Skip("ActiveElement does not work in HTMLUnit")
+ }
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+
+ e, err := wd.ActiveElement()
+ if err != nil {
+ t.Fatalf("wd.ActiveElement() returned error: %v", err)
+ }
+ name, err := e.GetAttribute("name")
+ if err != nil {
+ t.Fatalf("wd.ActiveElement().GetAttribute() returned error: %v", err)
+ }
+ if name != "q" {
+ t.Fatalf("wd.ActiveElement().GetAttribute() returned element with name = %q, expected name = 'q'", name)
+ }
+}
+
+func testKeyDownUp(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+
+ e, err := wd.FindElement(selenium.ByLinkText, "other page")
+ if err != nil {
+ t.Fatalf("error finding other page link: %v", err)
+ }
+
+ if err := wd.KeyDown(selenium.ControlKey); err != nil {
+ t.Fatalf("error pressing control key down: %v", err)
+ }
+ if err := e.Click(); err != nil {
+ t.Fatalf("error clicking the other page link: %v", err)
+ }
+ if err := wd.KeyUp(selenium.ControlKey); err != nil {
+ t.Fatalf("error releasing control key: %v", err)
+ }
+}
+
+func testCSSProperty(t *testing.T, c Config) {
+ if c.Browser == "htmlunit" {
+ t.Skip("Skipping on htmlunit")
+ }
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+
+ e, err := wd.FindElement(selenium.ByLinkText, "other page")
+ if err != nil {
+ t.Fatalf("error finding other page link: %v", err)
+ }
+
+ color, err := e.CSSProperty("color")
+ if err != nil {
+ t.Fatalf(`e.CSSProperty("color") returned error: %v`, err)
+ }
+
+ // Later versions of Firefox and HTMLUnit return the "rgb" version.
+ wantColors := []string{"rgba(0, 0, 238, 1)", "rgb(0, 0, 238)"}
+ for _, wantColor := range wantColors {
+ if color == wantColor {
+ return
+ }
+ }
+ t.Fatalf(`e.CSSProperty("color") = %q, want one of %q`, color, wantColors)
+}
+
+const proxyPageContents = "You are viewing a proxied page"
+
+// addrRewriter rewrites all requsted addresses to the one specified by the
+// URL.
+type addrRewriter struct{ u *url.URL }
+
+func (a *addrRewriter) Rewrite(ctx context.Context, _ *socks5.Request) (context.Context, *socks5.AddrSpec) {
+ port, err := strconv.Atoi(a.u.Port())
+ if err != nil {
+ panic(err)
+ }
+ return ctx, &socks5.AddrSpec{
+ FQDN: a.u.Hostname(),
+ Port: port,
+ }
+}
+
+func testProxy(t *testing.T, c Config) {
+ if c.Sauce != nil {
+ t.Skip("Testing a proxy on Sauce Labs doesn't work.")
+ }
+
+ // Create a different web server that should be used if HTTP proxying is enabled.
+ s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ fmt.Fprintf(w, proxyPageContents)
+ }))
+ defer s.Close()
+
+ u, err := url.Parse(s.URL)
+ if err != nil {
+ t.Fatalf("url.Parse(%q) returned error: %v", s.URL, err)
+ }
+
+ t.Run("HTTP", func(t *testing.T) {
+ caps := newTestCapabilities(t, c)
+ caps.AddProxy(selenium.Proxy{
+ Type: selenium.Manual,
+ HTTP: u.Host,
+ })
+ runTestProxy(t, c, caps)
+ })
+
+ t.Run("SOCKS", func(t *testing.T) {
+ if c.SeleniumVersion.Major == 3 {
+ // Selenium 3 fails when converting SOCKSVersion with: "unknown error:
+ // java.lang.Long cannot be cast to java.lang.Integer"
+ // The fix for this is committed, but not yet in a release.
+ //
+ // https://github.com/SeleniumHQ/selenium/issues/6917
+ t.Skip("Selenium 3 throws an exception with SOCKSVersion type conversion")
+ }
+ socks, err := socks5.New(&socks5.Config{
+ Rewriter: &addrRewriter{u},
+ })
+ if err != nil {
+ t.Fatalf("socks5.New(_) returned error: %v", err)
+ }
+ l, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("net.Listen(_, _) return error: %v", err)
+ }
+
+ // Start serving SOCKS connections, but don't fail the test once the
+ // listener is closed at the end of execution.
+ done := make(chan struct{})
+ go func() {
+ err := socks.Serve(l)
+ select {
+ case <-done:
+ return
+ default:
+ }
+ if err != nil {
+ t.Fatalf("s.ListenAndServe(_) returned error: %v", err)
+ }
+ }()
+ defer func() {
+ close(done)
+ l.Close()
+ }()
+
+ caps := newTestCapabilities(t, c)
+ caps.AddProxy(selenium.Proxy{
+ Type: selenium.Manual,
+ SOCKS: l.Addr().String(),
+ SOCKSVersion: 5,
+ })
+
+ runTestProxy(t, c, caps)
+ })
+}
+
+func runTestProxy(t *testing.T, c Config, caps selenium.Capabilities) {
+ allowProxyForLocalhost(c.Browser, caps)
+
+ wd := newRemote(t, caps, c)
+ defer quitRemote(t, wd)
+
+ // Request the original server URL.
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ source, err := wd.PageSource()
+ if err != nil {
+ t.Fatalf("wd.PageSource() returned error: %v", err)
+ }
+
+ if !strings.Contains(source, proxyPageContents) {
+ if strings.Contains(source, "Go Selenium Test Suite") {
+ t.Fatal("Got non-proxied page.")
+ }
+ t.Fatalf("Got page: %s\n\nExpected: %q", source, proxyPageContents)
+ }
+}
+
+func allowProxyForLocalhost(browser string, caps selenium.Capabilities) {
+ switch browser {
+ case "firefox":
+ // By default, Firefox explicitly does not use a proxy for connection to
+ // localhost and 127.0.0.1. Clear this preference to reach our test proxy.
+ ff := caps[firefox.CapabilitiesKey].(firefox.Capabilities)
+ if ff.Prefs == nil {
+ ff.Prefs = make(map[string]interface{})
+ }
+ ff.Prefs["network.proxy.no_proxies_on"] = ""
+ ff.Prefs["network.proxy.allow_hijacking_localhost"] = true
+ caps.AddFirefox(ff)
+
+ case "chrome":
+ ch := caps[chrome.CapabilitiesKey].(chrome.Capabilities)
+ // Allow Chrome to use the specified proxy for localhost, which is
+ // needed for the Proxy test. https://crbug.com/899126
+ ch.Args = append(ch.Args, "--proxy-bypass-list=<-loopback>")
+ caps.AddChrome(ch)
+ }
+}
+
+func testSwitchFrame(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ if err := wd.Get(c.ServerURL + "/frame"); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+
+ const (
+ iframeID = "iframeID"
+ insideFrameID = "chuk"
+ outsideDivID = "outsideOfFrame"
+ )
+
+ // Test with the ID of the iframe.
+ if err := wd.SwitchFrame(iframeID); err != nil {
+ t.Fatalf("wd.SwitchToFrame(%q) returned error: %v", iframeID, err)
+ }
+ if _, err := wd.FindElement(selenium.ByID, insideFrameID); err != nil {
+ t.Fatalf("After switching frames using an ID, wd.FindElement(selenium.ByID, %q) returned error: %v", insideFrameID, err)
+ }
+ if _, err := wd.FindElement(selenium.ByID, outsideDivID); err == nil {
+ t.Fatalf("After switching frames using an ID, wd.FindElement(selenium.ByID, %q) returned nil, expected an error", outsideDivID)
+ }
+
+ // Test with nil, to return to the top-level context.
+ if err := wd.SwitchFrame(nil); err != nil {
+ t.Fatalf("wd.SwitchToFrame(nil) returned error: %v", err)
+ }
+ if _, err := wd.FindElement(selenium.ByID, outsideDivID); err != nil {
+ t.Fatalf("After switching frames using nil, wd.FindElement(selenium.ByID, %q) returned error: %v", outsideDivID, err)
+ }
+
+ // Test with a WebElement.
+ iframe, err := wd.FindElement(selenium.ByID, iframeID)
+ if err != nil {
+ t.Fatalf("error finding iframe: %v", err)
+ }
+ if err := wd.SwitchFrame(iframe); err != nil {
+ t.Fatalf("wd.SwitchToFrame(nil) returned error: %v", err)
+ }
+ if _, err := wd.FindElement(selenium.ByID, insideFrameID); err != nil {
+ t.Fatalf("After switching frames using a WebElement, wd.FindElement(selenium.ByID, %q) returned error: %v", insideFrameID, err)
+ }
+ if _, err := wd.FindElement(selenium.ByID, outsideDivID); err == nil {
+ t.Fatalf("After switching frames using a WebElement, wd.FindElement(selenium.ByID, %q) returned nil, expected an error", outsideDivID)
+ }
+
+ // Test with the empty string, to return to the top-level context.
+ if err := wd.SwitchFrame(""); err != nil {
+ t.Fatalf(`wd.SwitchToFrame("") returned error: %v`, err)
+ }
+ if _, err := wd.FindElement(selenium.ByID, outsideDivID); err != nil {
+ t.Fatalf(`After switching frames using "", wd.FindElement(selenium.ByID, %q) returned error: %v`, outsideDivID, err)
+ }
+}
+
+func testWait(t *testing.T, c Config) {
+ const newTitle = "Title changed."
+ titleChangeCondition := func(wd selenium.WebDriver) (bool, error) {
+ title, err := wd.Title()
+ if err != nil {
+ return false, err
+ }
+
+ return title == newTitle, nil
+ }
+
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ titleURL := c.ServerURL + "/title"
+
+ if err := wd.Get(titleURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", titleURL, err)
+ }
+
+ // Testing when the title should change.
+ if err := wd.Wait(titleChangeCondition); err != nil {
+ t.Fatalf("wd.Wait(titleChangeCondition) returned error: %v", err)
+ }
+
+ // Reloading the page.
+ if err := wd.Get(titleURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", titleURL, err)
+ }
+
+ // Testing when the Wait() should error the timeout..
+ if err := wd.WaitWithTimeout(titleChangeCondition, 500*time.Millisecond); err == nil {
+ t.Fatalf("wd.Wait(titleChangeCondition) should returned error, but it didn't.")
+ }
+}
+
+func testAcceptAlert(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ alertPageURL := c.ServerURL + "/alert"
+
+ if err := wd.Get(alertPageURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", alertPageURL, err)
+ }
+
+ alertText, err := wd.AlertText()
+ if err != nil {
+ t.Fatalf("wd.AlertText() returned error: %v", err)
+ }
+
+ if alertText != "Hello world" {
+ t.Fatalf("Expected 'Hello world' but got '%s'", alertText)
+ }
+
+ if err := wd.AcceptAlert(); err != nil {
+ t.Fatalf("wd.AcceptAlert() returned error: %v", err)
+ }
+}
+
+func testDismissAlert(t *testing.T, c Config) {
+ wd := newRemote(t, newTestCapabilities(t, c), c)
+ defer quitRemote(t, wd)
+
+ alertPageURL := c.ServerURL + "/alert"
+
+ if err := wd.Get(alertPageURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", alertPageURL, err)
+ }
+
+ if err := wd.DismissAlert(); err != nil {
+ t.Fatalf("wd.DismissAlert() returned error: %v", err)
+ }
+}
+
+var homePage = `
+
+
+ Go Selenium Test Suite
+
+
+ The home page.
+
+ Link to the other page.
+
+ тест
+ search
+
+
+`
+
+var otherPage = `
+
+
+ Go Selenium Test Suite - Other Page
+
+
+ The other page.
+
+
+`
+
+const searchContents = "The Go Proramming Language"
+
+var searchPage = `
+
+
+ Go Selenium Test Suite - Search Page
+
+
+ You searched for "%s". I'll pretend I've found:
+
+ "` + searchContents + `"
+
+ Select value is: %s
+
+
+`
+
+var logPage = `
+
+
+ Go Selenium Test Suite - Log Page
+
+
+
+ Log test page.
+
+
+`
+
+var framePage = `
+
+
+ Go Selenium Test Suite - Frame Page
+
+
+ This page contains a frame.
+
+
+
+
+
+`
+
+var titleChangePage = `
+
+
+ Go Selenium Test Suite - Title Change Page
+
+
+ This page will change a title after 1 second.
+
+
+
+
+`
+
+var alertPage = `
+
+
+ Go Selenium Test Suite - Alert Appear Page
+
+
+ An alert will popup.
+
+
+
+
+`
+
+var Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ path := r.URL.Path
+ page, ok := map[string]string{
+ "/": homePage,
+ "/other": otherPage,
+ "/search": searchPage,
+ "/log": logPage,
+ "/frame": framePage,
+ "/title": titleChangePage,
+ "/alert": alertPage,
+ }[path]
+ if !ok {
+ http.NotFound(w, r)
+ return
+ }
+
+ if path == "/search" {
+ r.ParseForm()
+ if len(r.Form) > 0 {
+ page = fmt.Sprintf(page, r.Form["q"][0], r.Form["s"][0])
+ }
+ }
+ // Some cookies for the tests
+ for i := 0; i < 3; i++ {
+ http.SetCookie(w, &http.Cookie{
+ Name: fmt.Sprintf("cookie-%d", i),
+ Value: fmt.Sprintf("value-%d", i),
+ })
+ }
+ fmt.Fprintf(w, page)
+})
+
+func RunFirefoxTests(t *testing.T, c Config) {
+ // Firefox-specific tests.
+ t.Run("Preferences", runTest(testFirefoxPreferences, c))
+ t.Run("Profile", runTest(testFirefoxProfile, c))
+}
+
+func testFirefoxPreferences(t *testing.T, c Config) {
+ if c.SeleniumVersion.Major == 2 {
+ t.Skip("This test is known to fail for Selenium 2 and Firefox 47.")
+ }
+ caps := newTestCapabilities(t, c)
+ f, ok := caps[firefox.CapabilitiesKey].(firefox.Capabilities)
+ if !ok || f.Prefs == nil {
+ f.Prefs = make(map[string]interface{})
+ }
+ f.Prefs["browser.startup.homepage"] = c.ServerURL
+ f.Prefs["browser.startup.page"] = "1"
+ caps.AddFirefox(f)
+
+ wd := newRemote(t, caps, c)
+ defer quitRemote(t, wd)
+
+ // TODO(minusnine): use the upcoming Wait API for this.
+ var u string
+ for i := 0; i < 5; i++ {
+ var err error
+ u, err = wd.CurrentURL()
+ if err != nil {
+ t.Fatalf("wd.Current() returned error: %v", err)
+ }
+ if u == c.ServerURL+"/" {
+ return
+ }
+ time.Sleep(time.Second)
+ }
+ t.Fatalf("wd.Current() = %q, want %q", u, c.ServerURL+"/")
+}
+
+func testFirefoxProfile(t *testing.T, c Config) {
+ if c.SeleniumVersion.Major == 2 {
+ t.Skip("This test is known to fail for Selenium 2 and Firefox 47.")
+ }
+ caps := newTestCapabilities(t, c)
+ f := caps[firefox.CapabilitiesKey].(firefox.Capabilities)
+ const path = "testing/firefox_profile"
+ if err := f.SetProfile(path); err != nil {
+ t.Fatalf("f.SetProfile(%q) returned error: %v", path, err)
+ }
+ caps.AddFirefox(f)
+
+ wd := newRemote(t, caps, c)
+ defer quitRemote(t, wd)
+
+ u, err := wd.CurrentURL()
+ if err != nil {
+ t.Fatalf("wd.Current() returned error: %v", err)
+ }
+ const wantURL = "about:config"
+ if u != wantURL {
+ t.Fatalf("wd.Current() = %q, want %q", u, wantURL)
+ }
+}
+
+func testChromeExtension(t *testing.T, c Config) {
+ caps := newTestCapabilities(t, c)
+ co := caps[chrome.CapabilitiesKey].(chrome.Capabilities)
+ cmd := exec.Command("pwd")
+ cmd.Stdout = os.Stdout
+ cmd.Run()
+
+ cmd = exec.Command("ls")
+ cmd.Stdout = os.Stdout
+ cmd.Run()
+ const path = "testing/chrome_extension/css_page_red"
+ if err := co.AddUnpackedExtension(path); err != nil {
+ t.Fatalf("co.AddExtension(%q) returned error: %v", path, err)
+ }
+ caps[chrome.CapabilitiesKey] = co
+
+ wd, err := NewRemote(t, caps, c.Addr)
+ if err != nil {
+ t.Fatalf("newRemote(_, _) returned error: %v", err)
+ }
+ defer wd.Quit()
+
+ if c.Headless {
+ // https://crbug.com/706008
+ t.Skip("Chrome does not support extensions in headless mode.")
+ }
+
+ if err := wd.Get(c.ServerURL); err != nil {
+ t.Fatalf("wd.Get(%q) returned error: %v", c.ServerURL, err)
+ }
+ e, err := wd.FindElement(selenium.ByCSSSelector, "body")
+ if err != nil {
+ t.Fatalf("error finding body: %v", err)
+ }
+
+ const property = "background-color"
+ color, err := e.CSSProperty(property)
+ if err != nil {
+ t.Fatalf(`e.CSSProperty(%q) returned error: %v`, property, err)
+ }
+
+ const wantColor = "rgba(255, 0, 0, 1)"
+ if color != wantColor {
+ t.Fatalf("body background has color %q, want %q", color, wantColor)
+ }
+}
+
+func RunChromeTests(t *testing.T, c Config) {
+ // Chrome-specific tests.
+ t.Run("Extension", runTest(testChromeExtension, c))
+}
diff --git a/remote_test.go b/remote_test.go
index 62d56c1..7578d33 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -1,33 +1,21 @@
-package selenium
+package selenium_test
import (
- "context"
"flag"
"fmt"
- "math"
"net"
- "net/http"
"net/http/httptest"
- "net/url"
"os"
"os/exec"
- "path"
"path/filepath"
- "reflect"
"sort"
- "strconv"
"strings"
"testing"
- "time"
- socks5 "github.com/armon/go-socks5"
"github.com/blang/semver"
"github.com/golang/glog"
- "github.com/google/go-cmp/cmp"
- "github.com/tebeka/selenium/chrome"
- "github.com/tebeka/selenium/firefox"
- "github.com/tebeka/selenium/log"
- "github.com/tebeka/selenium/sauce"
+ "github.com/tebeka/selenium"
+ "github.com/tebeka/selenium/internal/seleniumtest"
)
var (
@@ -46,8 +34,6 @@ var (
startFrameBuffer = flag.Bool("start_frame_buffer", false, "If true, start an Xvfb subprocess and run the browsers in that X server.")
headless = flag.Bool("headless", true, "If true, run Chrome and Firefox in headless mode, not requiring a frame buffer.")
-
- serverURL string
)
func TestMain(m *testing.M) {
@@ -56,10 +42,6 @@ func TestMain(m *testing.M) {
fmt.Fprint(os.Stderr, fmt.Sprintf("Exiting early: unable to get the driver paths -- %s", err.Error()))
os.Exit(1)
}
-
- s := httptest.NewServer(http.HandlerFunc(handler))
- serverURL = s.URL
- defer s.Close()
os.Exit(m.Run())
}
@@ -125,13 +107,6 @@ func pickUnusedPort() (int, error) {
return port, nil
}
-type config struct {
- addr, browser, path string
- sauce *sauce.Capabilities
- seleniumVersion semver.Version
- serviceOptions []ServiceOption
-}
-
func TestChrome(t *testing.T) {
if *useDocker {
t.Skip("Skipping Chrome tests because they will be run under a Docker container")
@@ -148,98 +123,61 @@ func TestChrome(t *testing.T) {
}
t.Run("Chromedriver", func(t *testing.T) {
- runChromeTests(t, config{
- path: *chromeBinary,
+ runChromeTests(t, seleniumtest.Config{
+ Path: *chromeBinary,
})
})
t.Run("Selenium3", func(t *testing.T) {
- runChromeTests(t, config{
- path: *chromeBinary,
- seleniumVersion: semver.MustParse("3.0.0"),
+ runChromeTests(t, seleniumtest.Config{
+ Path: *chromeBinary,
+ SeleniumVersion: semver.MustParse("3.0.0"),
})
})
}
-func runChromeTests(t *testing.T, c config) {
- c.browser = "chrome"
+func runChromeTests(t *testing.T, c seleniumtest.Config) {
+ c.Browser = "chrome"
+ c.Headless = *headless
- var opts []ServiceOption
+ var opts []selenium.ServiceOption
if *startFrameBuffer {
- opts = append(opts, StartFrameBuffer())
+ opts = append(opts, selenium.StartFrameBuffer())
}
if testing.Verbose() {
- SetDebug(true)
- opts = append(opts, Output(os.Stderr))
+ selenium.SetDebug(true)
+ opts = append(opts, selenium.Output(os.Stderr))
}
port, err := pickUnusedPort()
if err != nil {
t.Fatalf("pickUnusedPort() returned error: %v", err)
}
- c.addr = fmt.Sprintf("http://127.0.0.1:%d/wd/hub", port)
+ c.Addr = fmt.Sprintf("http://127.0.0.1:%d/wd/hub", port)
- var s *Service
- if c.seleniumVersion.Major == 3 {
- c.serviceOptions = append(c.serviceOptions, ChromeDriver(*chromeDriverPath))
- s, err = NewSeleniumService(*selenium3Path, port, c.serviceOptions...)
+ var s *selenium.Service
+ if c.SeleniumVersion.Major == 3 {
+ c.ServiceOptions = append(c.ServiceOptions, selenium.ChromeDriver(*chromeDriverPath))
+ s, err = selenium.NewSeleniumService(*selenium3Path, port, c.ServiceOptions...)
} else {
- s, err = NewChromeDriverService(*chromeDriverPath, port, c.serviceOptions...)
+ s, err = selenium.NewChromeDriverService(*chromeDriverPath, port, c.ServiceOptions...)
}
if err != nil {
t.Fatalf("Error starting the server: %v", err)
}
- runTests(t, c)
+ hs := httptest.NewServer(seleniumtest.Handler)
+ defer hs.Close()
+ c.ServerURL = hs.URL
- // Chrome-specific tests.
- t.Run("Extension", runTest(testChromeExtension, c))
+ seleniumtest.RunCommonTests(t, c)
+ seleniumtest.RunChromeTests(t, c)
if err := s.Stop(); err != nil {
t.Fatalf("Error stopping the ChromeDriver service: %v", err)
}
}
-func testChromeExtension(t *testing.T, c config) {
- caps := newTestCapabilities(t, c)
- co := caps[chrome.CapabilitiesKey].(chrome.Capabilities)
- const path = "testing/chrome_extension/css_page_red"
- if err := co.AddUnpackedExtension(path); err != nil {
- t.Fatalf("co.AddExtension(%q) returned error: %v", path, err)
- }
- caps[chrome.CapabilitiesKey] = co
-
- wd, err := NewRemote(caps, c.addr)
- if err != nil {
- t.Fatalf("NewRemote(_, _) returned error: %v", err)
- }
- defer wd.Quit()
-
- if *headless {
- // https://crbug.com/706008
- t.Skip("Chrome does not support extensions in headless mode.")
- }
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- e, err := wd.FindElement(ByCSSSelector, "body")
- if err != nil {
- t.Fatalf("error finding body: %v", err)
- }
-
- const property = "background-color"
- color, err := e.CSSProperty(property)
- if err != nil {
- t.Fatalf(`e.CSSProperty(%q) returned error: %v`, property, err)
- }
-
- const wantColor = "rgba(255, 0, 0, 1)"
- if color != wantColor {
- t.Fatalf("body background has color %q, want %q", color, wantColor)
- }
-}
-
func TestFirefox(t *testing.T) {
if *useDocker {
t.Skip("Skipping tests because they will be run under a Docker container")
@@ -257,15 +195,15 @@ func TestFirefox(t *testing.T) {
}
t.Run("Selenium3", func(t *testing.T) {
- runFirefoxTests(t, *selenium3Path, config{
- seleniumVersion: semver.MustParse("3.0.0"),
- serviceOptions: []ServiceOption{GeckoDriver(*geckoDriverPath)},
- path: *firefoxBinarySelenium3,
+ runFirefoxTests(t, *selenium3Path, seleniumtest.Config{
+ SeleniumVersion: semver.MustParse("3.0.0"),
+ ServiceOptions: []selenium.ServiceOption{selenium.GeckoDriver(*geckoDriverPath)},
+ Path: *firefoxBinarySelenium3,
})
})
t.Run("Geckodriver", func(t *testing.T) {
- runFirefoxTests(t, *geckoDriverPath, config{
- path: *firefoxBinarySelenium3,
+ runFirefoxTests(t, *geckoDriverPath, seleniumtest.Config{
+ Path: *firefoxBinarySelenium3,
})
})
}
@@ -282,44 +220,48 @@ func TestHTMLUnit(t *testing.T) {
}
if testing.Verbose() {
- SetDebug(true)
+ selenium.SetDebug(true)
}
- c := config{
- browser: "htmlunit",
- seleniumVersion: semver.MustParse("3.0.0"),
- serviceOptions: []ServiceOption{HTMLUnit(*htmlUnitDriverPath)},
+ c := seleniumtest.Config{
+ Browser: "htmlunit",
+ SeleniumVersion: semver.MustParse("3.0.0"),
+ ServiceOptions: []selenium.ServiceOption{selenium.HTMLUnit(*htmlUnitDriverPath)},
}
port, err := pickUnusedPort()
if err != nil {
t.Fatalf("pickUnusedPort() returned error: %v", err)
}
- s, err := NewSeleniumService(*selenium3Path, port, c.serviceOptions...)
+ s, err := selenium.NewSeleniumService(*selenium3Path, port, c.ServiceOptions...)
if err != nil {
t.Fatalf("Error starting the WebDriver server with binary %q: %v", *selenium3Path, err)
}
- c.addr = fmt.Sprintf("http://127.0.0.1:%d/wd/hub", port)
+ c.Addr = fmt.Sprintf("http://127.0.0.1:%d/wd/hub", port)
+
+ hs := httptest.NewServer(seleniumtest.Handler)
+ defer hs.Close()
+ c.ServerURL = hs.URL
- runTests(t, c)
+ seleniumtest.RunCommonTests(t, c)
if err := s.Stop(); err != nil {
t.Fatalf("Error stopping the Selenium service: %v", err)
}
}
-func runFirefoxTests(t *testing.T, webDriverPath string, c config) {
- c.browser = "firefox"
+func runFirefoxTests(t *testing.T, webDriverPath string, c seleniumtest.Config) {
+ c.Browser = "firefox"
if *startFrameBuffer {
- c.serviceOptions = append(c.serviceOptions, StartFrameBuffer())
+ c.ServiceOptions = append(c.ServiceOptions, selenium.StartFrameBuffer())
}
if testing.Verbose() {
- SetDebug(true)
- c.serviceOptions = append(c.serviceOptions, Output(os.Stderr))
+ selenium.SetDebug(true)
+ c.ServiceOptions = append(c.ServiceOptions, selenium.Output(os.Stderr))
}
if *javaPath != "" {
- c.serviceOptions = append(c.serviceOptions, JavaPath(*javaPath))
+ c.ServiceOptions = append(c.ServiceOptions, selenium.JavaPath(*javaPath))
}
port, err := pickUnusedPort()
@@ -327,116 +269,39 @@ func runFirefoxTests(t *testing.T, webDriverPath string, c config) {
t.Fatalf("pickUnusedPort() returned error: %v", err)
}
- var s *Service
- if c.seleniumVersion.Major == 0 {
- c.addr = fmt.Sprintf("http://127.0.0.1:%d", port)
- s, err = NewGeckoDriverService(webDriverPath, port, c.serviceOptions...)
+ var s *selenium.Service
+ if c.SeleniumVersion.Major == 0 {
+ c.Addr = fmt.Sprintf("http://127.0.0.1:%d", port)
+ s, err = selenium.NewGeckoDriverService(webDriverPath, port, c.ServiceOptions...)
} else {
- c.addr = fmt.Sprintf("http://127.0.0.1:%d/wd/hub", port)
+ c.Addr = fmt.Sprintf("http://127.0.0.1:%d/wd/hub", port)
if _, err := os.Stat(*selenium3Path); err != nil {
t.Skipf("Skipping Firefox tests using Selenium 3 because Selenium WebDriver JAR not found at path %q", *selenium3Path)
}
- s, err = NewSeleniumService(webDriverPath, port, c.serviceOptions...)
+ s, err = selenium.NewSeleniumService(webDriverPath, port, c.ServiceOptions...)
}
if err != nil {
t.Fatalf("Error starting the WebDriver server with binary %q: %v", webDriverPath, err)
}
- runFirefoxSubTests(t, c)
-
- if err := s.Stop(); err != nil {
- t.Fatalf("Error stopping the Selenium service: %v", err)
- }
-}
-
-func runFirefoxSubTests(t *testing.T, c config) {
- runTests(t, c)
-
- // Firefox-specific tests.
- t.Run("Preferences", runTest(testFirefoxPreferences, c))
- t.Run("Profile", runTest(testFirefoxProfile, c))
-}
-
-func testFirefoxPreferences(t *testing.T, c config) {
- if c.seleniumVersion.Major == 2 {
- t.Skip("This test is known to fail for Selenium 2 and Firefox 47.")
- }
- caps := newTestCapabilities(t, c)
- f, ok := caps[firefox.CapabilitiesKey].(firefox.Capabilities)
- if !ok || f.Prefs == nil {
- f.Prefs = make(map[string]interface{})
- }
- f.Prefs["browser.startup.homepage"] = serverURL
- f.Prefs["browser.startup.page"] = "1"
- caps.AddFirefox(f)
-
- wd := &remoteWD{
- capabilities: caps,
- urlPrefix: c.addr,
- }
- defer func() {
- if err := wd.Quit(); err != nil {
- t.Errorf("wd.Quit() returned error: %v", err)
- }
- }()
-
- if _, err := wd.NewSession(); err != nil {
- t.Fatalf("error in new session - %s", err)
- }
-
- // TODO(minusnine): use the upcoming Wait API for this.
- var u string
- for i := 0; i < 5; i++ {
- var err error
- u, err = wd.CurrentURL()
- if err != nil {
- t.Fatalf("wd.Current() returned error: %v", err)
- }
- if u == serverURL+"/" {
- return
- }
- time.Sleep(time.Second)
- }
- t.Fatalf("wd.Current() = %q, want %q", u, serverURL+"/")
-}
+ hs := httptest.NewServer(seleniumtest.Handler)
+ defer hs.Close()
+ c.ServerURL = hs.URL
-func testFirefoxProfile(t *testing.T, c config) {
- if c.seleniumVersion.Major == 2 {
- t.Skip("This test is known to fail for Selenium 2 and Firefox 47.")
- }
- caps := newTestCapabilities(t, c)
- f := caps[firefox.CapabilitiesKey].(firefox.Capabilities)
- const path = "testing/firefox_profile"
- if err := f.SetProfile(path); err != nil {
- t.Fatalf("f.SetProfile(%q) returned error: %v", path, err)
+ if c.SeleniumVersion.Major == 0 {
+ c.Addr = fmt.Sprintf("http://127.0.0.1:%d", port)
+ } else {
+ c.Addr = fmt.Sprintf("http://127.0.0.1:%d/wd/hub", port)
}
- caps.AddFirefox(f)
- wd := &remoteWD{
- capabilities: caps,
- urlPrefix: c.addr,
- }
- if _, err := wd.NewSession(); err != nil {
- t.Fatalf("wd.NewSession() returned error: %v", err)
- }
- defer quitRemote(t, wd)
+ c.Headless = *headless
- u, err := wd.CurrentURL()
- if err != nil {
- t.Fatalf("wd.Current() returned error: %v", err)
- }
- const wantURL = "about:config"
- if u != wantURL {
- t.Fatalf("wd.Current() = %q, want %q", u, wantURL)
- }
+ seleniumtest.RunCommonTests(t, c)
+ seleniumtest.RunFirefoxTests(t, c)
- // Test that the old Firefox profile location gets migrated for W3C
- // compatibility.
- caps = newW3CCapabilities(map[string]interface{}{"firefox_profile": "base64-encoded Firefox profile goes here"})
- f = caps["alwaysMatch"].(Capabilities)[firefox.CapabilitiesKey].(firefox.Capabilities)
- if f.Profile == "" {
- t.Fatalf("Capability 'firefox_profile' was not migrated to 'moz:firefoxOptions.profile': %+v", caps)
+ if err := s.Stop(); err != nil {
+ t.Fatalf("Error stopping the Selenium service: %v", err)
}
}
@@ -470,1647 +335,3 @@ func TestDocker(t *testing.T) {
t.Fatalf("docker run failed: %v", err)
}
}
-
-func newTestCapabilities(t *testing.T, c config) Capabilities {
- caps := Capabilities{
- "browserName": c.browser,
- }
- switch c.browser {
- case "chrome":
- chrCaps := chrome.Capabilities{
- Path: c.path,
- Args: []string{
- // This flag is needed to test against Chrome binaries that are not the
- // default installation. The sandbox requires a setuid binary.
- "--no-sandbox",
- },
- W3C: true,
- }
- if *headless {
- chrCaps.Args = append(chrCaps.Args, "--headless")
- }
- caps.AddChrome(chrCaps)
- case "firefox":
- f := firefox.Capabilities{}
- if c.path != "" {
- // Selenium 2 uses this option to specify the path to the Firefox binary.
- //caps["firefox_binary"] = c.path
- p, err := filepath.Abs(c.path)
- if err != nil {
- panic(err)
- }
- f.Binary = p
- }
- if testing.Verbose() {
- f.Log = &firefox.Log{
- Level: firefox.Trace,
- }
- }
- if *headless {
- f.Args = append(f.Args, "-headless")
- }
- caps.AddFirefox(f)
- case "htmlunit":
- caps["javascriptEnabled"] = true
- }
-
- if c.sauce != nil {
- m, err := c.sauce.ToMap()
- if err != nil {
- t.Fatalf("Error obtaining map for sauce.Capabilities: %s", err)
- }
- for k, v := range m {
- caps[k] = v
- }
- if c.seleniumVersion.Major > 0 {
- caps["seleniumVersion"] = c.seleniumVersion.String()
- }
- caps["name"] = t.Name()
- }
-
- return caps
-}
-
-func newRemote(t *testing.T, c config) WebDriver {
- caps := newTestCapabilities(t, c)
- wd, err := NewRemote(caps, c.addr)
- if err != nil {
- t.Fatalf("NewRemote(%+v, %q) returned error: %v", caps, c.addr, err)
- }
- return wd
-}
-
-func quitRemote(t *testing.T, wd WebDriver) {
- if err := wd.Quit(); err != nil {
- t.Errorf("wd.Quit() returned error: %v", err)
- }
-}
-
-func runTest(f func(*testing.T, config), c config) func(*testing.T) {
- return func(t *testing.T) {
- f(t, c)
- }
-}
-
-func runTests(t *testing.T, c config) {
- t.Run("Status", runTest(testStatus, c))
- t.Run("NewSession", runTest(testNewSession, c))
- t.Run("DeleteSession", runTest(testDeleteSession, c))
- t.Run("Error", runTest(testError, c))
- t.Run("ExtendedErrorMessage", runTest(testExtendedErrorMessage, c))
- t.Run("Capabilities", runTest(testCapabilities, c))
- t.Run("SetAsyncScriptTimeout", runTest(testSetAsyncScriptTimeout, c))
- t.Run("SetImplicitWaitTimeout", runTest(testSetImplicitWaitTimeout, c))
- t.Run("SetPageLoadTimeout", runTest(testSetPageLoadTimeout, c))
- t.Run("Windows", runTest(testWindows, c))
- t.Run("Get", runTest(testGet, c))
- t.Run("Navigation", runTest(testNavigation, c))
- t.Run("Title", runTest(testTitle, c))
- t.Run("PageSource", runTest(testPageSource, c))
- t.Run("FindElement", runTest(testFindElement, c))
- t.Run("FindElements", runTest(testFindElements, c))
- t.Run("SendKeys", runTest(testSendKeys, c))
- t.Run("Click", runTest(testClick, c))
- t.Run("GetCookies", runTest(testGetCookies, c))
- t.Run("GetCookie", runTest(testGetCookie, c))
- t.Run("AddCookie", runTest(testAddCookie, c))
- t.Run("DeleteCookie", runTest(testDeleteCookie, c))
- t.Run("Location", runTest(testLocation, c))
- t.Run("LocationInView", runTest(testLocationInView, c))
- t.Run("Size", runTest(testSize, c))
- t.Run("ExecuteScript", runTest(testExecuteScript, c))
- t.Run("ExecuteScriptOnElement", runTest(testExecuteScriptOnElement, c))
- t.Run("ExecuteScriptWithNilArgs", runTest(testExecuteScriptWithNilArgs, c))
- t.Run("Screenshot", runTest(testScreenshot, c))
- t.Run("Log", runTest(testLog, c))
- t.Run("IsSelected", runTest(testIsSelected, c))
- t.Run("IsDisplayed", runTest(testIsDisplayed, c))
- t.Run("GetAttributeNotFound", runTest(testGetAttributeNotFound, c))
- t.Run("KeyDownUp", runTest(testKeyDownUp, c))
- t.Run("CSSProperty", runTest(testCSSProperty, c))
- t.Run("Proxy", runTest(testProxy, c))
- t.Run("SwitchFrame", runTest(testSwitchFrame, c))
- t.Run("Wait", runTest(testWait, c))
- t.Run("ActiveElement", runTest(testActiveElement, c))
- t.Run("AcceptAlert", runTest(testAcceptAlert, c))
- t.Run("DismissAlert", runTest(testDismissAlert, c))
-}
-
-func testStatus(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- status, err := wd.Status()
- if err != nil {
- t.Fatalf("wd.Status() returned error: %v", err)
- }
-
- if c.sauce == nil {
- if len(status.OS.Name) == 0 && status.Message == "" {
- t.Fatalf("OS.Name or Message not provided: %+v", status)
- }
- } else if status.Build.Version != "Sauce Labs" {
- t.Fatalf("status.Build.Version = %q, expected 'Sauce Labs'", status.Build.Version)
- }
-}
-
-func testNewSession(t *testing.T, c config) {
- // Bypass NewRemote which itself calls NewSession internally.
- wd := &remoteWD{
- capabilities: newTestCapabilities(t, c),
- urlPrefix: c.addr,
- }
- defer func() {
- if err := wd.Quit(); err != nil {
- t.Errorf("wd.Quit() returned error: %v", err)
- }
- }()
-
- sid, err := wd.NewSession()
- if err != nil {
- t.Fatalf("error in new session - %s", err)
- }
-
- if len(sid) == 0 {
- t.Fatal("Empty session id")
- }
-
- if wd.id != sid {
- t.Fatal("Session id mismatch")
- }
-
- if wd.SessionID() != sid {
- t.Fatalf("Got session id mismatch %s != %s", sid, wd.SessionID())
- }
-
- if c.browser != "htmlunit" && wd.browserVersion.Major == 0 {
- t.Fatalf("wd.browserVersion.Major = %d, expected > 0", wd.browserVersion.Major)
- }
-}
-
-func testDeleteSession(t *testing.T, c config) {
- wd := newRemote(t, c)
- if err := DeleteSession(c.addr, wd.SessionID()); err != nil {
- t.Fatalf("DeleteSession(%s, %s) returned error: %v", c.addr, wd.SessionID(), err)
- }
-}
-
-func testError(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- _, err := wd.FindElement(ByID, "no-such-element")
- if err == nil {
- t.Fatal("wd.FindElement(ByID, 'no-such-element') did not return an error as expected")
- }
-
- e, ok := err.(*Error)
- if !ok {
- if c.seleniumVersion.Major > 0 {
- // t.Skipf("Selenium does not support W3C-style errors.")
- } else {
- t.Fatalf("wd.FindElement(ByID, 'no-such-element') returned an error that is not an *Error: %v", err)
- }
- }
- if want := "no such element"; e.Err != want {
- t.Errorf("wd.FindElement(ByID, 'no-such-element'); err.Err = %q, want %q", e.Err, want)
- }
-
- var wantCode, wantLegacyCode int
- switch c.browser {
- case "chrome":
- if wd.(*remoteWD).w3cCompatible {
- wantCode = 404
- wantLegacyCode = 0
- } else {
- wantCode = 200
- wantLegacyCode = 7
- }
- case "firefox":
- wantCode = 404
- case "htmlunit":
- wantCode = 500
- wantLegacyCode = 7
- }
- if e.HTTPCode != wantCode {
- t.Errorf("wd.FindElement(ByID, 'no-such-element'); err.HTTPCode = %d, want %d", e.HTTPCode, wantCode)
- }
- if e.LegacyCode != wantLegacyCode {
- t.Errorf("wd.FindElement(ByID, 'no-such-element'); err.LegacyCode = %d, want %d", e.LegacyCode, wantLegacyCode)
- }
-}
-
-func testExtendedErrorMessage(t *testing.T, c config) {
- // Bypass NewRemote which itself calls NewSession internally.
- wd := &remoteWD{
- capabilities: newTestCapabilities(t, c),
- urlPrefix: c.addr,
- }
-
- var want string
- switch {
- case c.sauce != nil:
- want = "404 Not Found"
- case c.seleniumVersion.Major == 3:
- want = "invalid session id:"
- case c.browser == "firefox" && c.seleniumVersion.Major == 2:
- want = "unknown error:"
- case c.browser == "firefox" && c.seleniumVersion.Major == 0:
- want = "unknown command"
- case c.browser == "chrome":
- want = "invalid session id:"
- default:
- want = "invalid session ID:"
- }
- if err := wd.Close(); err == nil || !strings.HasPrefix(err.Error(), want) {
- t.Fatalf("Got error %q, expected error to start with %q", err, want)
- }
-}
-
-// TODO(ekg): does this method work anymore in any browser? It is not part of
-// the W3C standard.
-func testCapabilities(t *testing.T, c config) {
- if c.browser == "firefox" {
- t.Skip("This method is not supported by Geckodriver.")
- }
- t.Skip("This method crashes Chrome?")
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- caps, err := wd.Capabilities()
- if err != nil {
- t.Fatalf("wd.Capabilities() returned error: %v", err)
- }
-
- if strings.ToLower(caps["browserName"].(string)) != c.browser {
- t.Fatalf("bad browser name - %s (should be %s)", caps["browserName"], c.browser)
- }
-}
-
-func testSetAsyncScriptTimeout(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.SetAsyncScriptTimeout(200); err != nil {
- t.Fatal(err)
- }
-}
-
-func testSetImplicitWaitTimeout(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.SetImplicitWaitTimeout(200); err != nil {
- t.Fatal(err)
- }
-}
-
-func testSetPageLoadTimeout(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.SetPageLoadTimeout(200); err != nil {
- t.Fatal(err)
- }
-}
-
-func testWindows(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
-
- firstHandle, err := wd.CurrentWindowHandle()
- if err != nil {
- t.Fatal(err)
- }
-
- if len(firstHandle) == 0 {
- t.Fatal("Empty handle")
- }
-
- const linkText = "other page"
- link, err := wd.FindElement(ByLinkText, linkText)
- if err != nil {
- t.Fatalf("wd.FindElement(%q, %q) returned error: %v", ByLinkText, linkText, err)
- }
-
- switch c.browser {
- case "firefox":
- // Firefox+Geckodriver doesn't handle control characters without appending
- // a terminating null key.
- // https://github.com/mozilla/geckodriver/issues/665
- newWindowModifier := ShiftKey + NullKey
- if err := wd.SendModifier(newWindowModifier /*isDown=*/, true); err != nil {
- t.Fatalf("wd.SendModifer(ShiftKey) returned error: %v", err)
- }
- // Firefox and Geckodriver doesn't handle clicking on an element.
- //
- // https://github.com/mozilla/geckodriver/issues/1007
- if err := link.SendKeys(EnterKey); err != nil {
- t.Fatalf("link.SendKeys(EnterKey) returned error: %v", err)
- }
- if err := wd.SendModifier(newWindowModifier /*isDown=*/, false); err != nil {
- t.Fatalf("wd.SendKeys(ShiftKey) returned error: %v", err)
- }
- case "htmlunit":
- newWindowModifier := ShiftKey
- if err := wd.SendModifier(newWindowModifier /*isDown=*/, true); err != nil {
- t.Fatalf("wd.SendModifer(ShiftKey) returned error: %v", err)
- }
- if err := link.Click(); err != nil {
- t.Fatalf("link.Click() returned error: %v", err)
- }
- if err := wd.SendModifier(newWindowModifier /*isDown=*/, false); err != nil {
- t.Fatalf("wd.SendKeys(ShiftKey) returned error: %v", err)
- }
- case "chrome":
- // Chrome doesn't support handling key events at the browser level.
- // https://crbug.com/chromedriver/30
- otherURL := path.Join(serverURL, "other")
- if _, err := wd.ExecuteScript(fmt.Sprintf("window.open(%q)", otherURL), nil); err != nil {
- t.Fatalf("opening a new window via Javascript returned error: %v", err)
- }
- }
-
- // Starting a new window can take a while. Try a few times before failing.
- var handles []string
- tries := 5
- for {
- handles, err = wd.WindowHandles()
- if err != nil {
- t.Fatalf("wd.WindowHandles() returned error: %v", err)
- }
- if len(handles) == 2 {
- break
- }
- tries--
- if tries == 0 {
- break
- }
- time.Sleep(time.Second)
- }
- if len(handles) != 2 {
- t.Fatalf("len(wd.WindowHandles()) = %d, expected 2", len(handles))
- }
- var found bool
- var otherHandle string
- for _, h := range handles {
- if h == firstHandle {
- found = true
- } else {
- otherHandle = h
- }
- }
- if !found {
- t.Fatalf("wd.WindowHandles() returned %v, expected to include %q", handles, firstHandle)
- }
-
- t.Run("SwitchWindow", func(t *testing.T) {
- if err := wd.SwitchWindow(otherHandle); err != nil {
- t.Fatalf("wd.SwitchWindow(firstHandle) returned error: %v", err)
- }
- if _, err := wd.FindElement(ByLinkText, linkText); err == nil {
- t.Fatalf("wd.FindElement(%q, %q) (after opening a new window) returned nil, expected error", ByLinkText, linkText)
- }
- if err := wd.SwitchWindow(firstHandle); err != nil {
- t.Fatalf("wd.SwitchWindow(firstHandle) returned error: %v", err)
- }
- if _, err := wd.FindElement(ByLinkText, linkText); err != nil {
- t.Fatalf("wd.FindElement(%q, %q) (after switching to the original window) returned error: %v", ByLinkText, linkText, err)
- }
- })
-
- t.Run("MaximizeWindow", func(t *testing.T) {
- if err := wd.MaximizeWindow(otherHandle); err != nil {
- t.Fatalf("error maximizing window: %s", err)
- }
- })
-
- t.Run("ResizeWindow", func(t *testing.T) {
- if err := wd.ResizeWindow(otherHandle, 100, 100); err != nil {
- t.Fatalf("error resizing window: %s", err)
- }
- })
-
- t.Run("CloseWindow", func(t *testing.T) {
- if err := wd.CloseWindow(otherHandle); err != nil {
- t.Fatalf("wd.CloseWindow(otherHandle) returned error: %v", err)
- }
- handles, err := wd.WindowHandles()
- if err != nil {
- t.Fatalf("wd.WindowHandles() returned error: %v", err)
- }
- if len(handles) != 1 {
- t.Fatalf("len(wd.WindowHandles()) = %d, expected 1", len(handles))
- }
- })
-}
-
-func testGet(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatal(err)
- }
-
- newURL, err := wd.CurrentURL()
- if err != nil {
- t.Fatal(err)
- }
-
- if newURL != serverURL+"/" {
- t.Fatalf("%s != %s", newURL, serverURL)
- }
-}
-
-func testNavigation(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- url1 := serverURL
- if err := wd.Get(url1); err != nil {
- t.Fatal(err)
- }
-
- url2 := serverURL + "/other"
- if err := wd.Get(url2); err != nil {
- t.Fatal(err)
- }
-
- if err := wd.Back(); err != nil {
- t.Fatal(err)
- }
- url, err := wd.CurrentURL()
- if err != nil {
- t.Fatalf("wd.CurrentURL() returned error: %v", err)
- }
- if url != url1+"/" {
- t.Fatalf("back got me to %s (expected %s/)", url, url1)
- }
- if err := wd.Forward(); err != nil {
- t.Fatal(err)
- }
- url, err = wd.CurrentURL()
- if err != nil {
- t.Fatalf("wd.CurrentURL() returned error: %v", err)
- }
- if url != url2 {
- t.Fatalf("forward got me to %s (expected %s)", url, url2)
- }
-
- if err := wd.Refresh(); err != nil {
- t.Fatal(err)
- }
- url, err = wd.CurrentURL()
- if err != nil {
- t.Fatalf("wd.CurrentURL() returned error: %v", err)
- }
- if url != url2 {
- t.Fatalf("refresh got me to %s (expected %s)", url, url2)
- }
-}
-
-func testTitle(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
-
- title, err := wd.Title()
- if err != nil {
- t.Fatal(err)
- }
-
- expectedTitle := "Go Selenium Test Suite"
- if title != expectedTitle {
- t.Fatalf("Bad title %s, should be %s", title, expectedTitle)
- }
-}
-
-func testPageSource(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatal(err)
- }
-
- source, err := wd.PageSource()
- if err != nil {
- t.Fatal(err)
- }
-
- if !strings.Contains(source, "The home page.") {
- t.Fatalf("Bad source\n%s", source)
- }
-}
-
-func testFindElement(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
-
- for _, tc := range []struct {
- by, query string
- }{
- {ByName, "q"},
- {ByCSSSelector, "input[name=q]"},
- {ByXPATH, "/html/body/form/input[1]"},
- {ByLinkText, "тест"},
- } {
- elem, err := wd.FindElement(tc.by, tc.query)
- if err != nil {
- t.Errorf("wd.FindElement(%q, %q) returned error: %v", tc.by, tc.query, err)
- continue
- }
-
- we, ok := elem.(*remoteWE)
- if !ok {
- t.Errorf("wd.FindElement(%q, %q) = %T, want a *remoteWE", tc.by, tc.query, elem)
- continue
- }
-
- if len(we.id) == 0 {
- t.Errorf("wd.FindElement(%q, %q) returned an empty element", tc.by, tc.query)
- continue
- }
-
- if we.parent != wd {
- t.Errorf("wd.FindElement(%q, %q) returned the wrong parent", tc.by, tc.query)
- continue
- }
- }
-}
-
-func testFindElements(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- elems, err := wd.FindElements(ByName, "q")
- if err != nil {
- t.Fatal(err)
- }
-
- if len(elems) != 1 {
- t.Fatalf("Wrong number of elements %d (should be 1)", len(elems))
- }
-
- we, ok := elems[0].(*remoteWE)
- if !ok {
- t.Fatal("Can't convert to *remoteWE")
- }
-
- if len(we.id) == 0 {
- t.Fatal("Empty element")
- }
-
- if we.parent != wd {
- t.Fatal("Bad parent")
- }
-}
-
-func testSendKeys(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- input, err := wd.FindElement(ByName, "q")
- if err != nil {
- t.Fatal(err)
- }
- const query = "golang"
- if err := input.SendKeys(query + EnterKey); err != nil {
- t.Fatal(err)
- }
-
- time.Sleep(500 * time.Millisecond)
-
- source, err := wd.PageSource()
- if err != nil {
- t.Fatalf("wd.PageSource() returned error: %v", err)
- }
-
- if !strings.Contains(source, searchContents) {
- t.Fatalf("Can't find %q on page after searching for %q", searchContents, query)
- }
-
- if !strings.Contains(source, query) {
- t.Fatalf("Can't find search query %q in source", query)
- }
-}
-
-func testClick(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- const searchBoxName = "q"
- input, err := wd.FindElement(ByName, searchBoxName)
- if err != nil {
- t.Fatalf("wd.FindElement(%q, %q) returned error: %v", ByName, searchBoxName, err)
- }
- const query = "golang"
- if err = input.SendKeys(query); err != nil {
- t.Fatalf("input.SendKeys(%q) returned error: %v", query, err)
- }
-
- const selectTag = "select"
- sel, err := wd.FindElement(ByCSSSelector, selectTag)
- if err != nil {
- t.Fatalf("wd.FindElement(%q, %q) returned error: %v", ByCSSSelector, selectTag, err)
- }
- if err = sel.Click(); err != nil {
- t.Fatalf("input.Click() returned error: %v", err)
- }
- time.Sleep(2 * time.Second)
- option, err := sel.FindElement(ByID, "secondValue")
- if err != nil {
- t.Fatalf("input.FindElement(%q, %q) returned error: %v", ByID, "secondValue", err)
- }
- if err = option.Click(); err != nil {
- t.Fatalf("option.Click() returned error: %v", err)
- }
- if c.browser == "firefox" {
- // Click anywhere else to de-focus the drop-down menu.
- if err = input.Click(); err != nil {
- t.Fatalf("wd.Click() returned error: %v", err)
- }
- }
-
- const buttonID = "submit"
- button, err := wd.FindElement(ByID, buttonID)
- if err != nil {
- t.Fatalf("wd.FindElement(%q, %q) returned error: %v", ByID, buttonID, err)
- }
- if err := wd.SetPageLoadTimeout(2 * time.Second); err != nil {
- t.Fatalf("wd.SetImplicitWaitTimeout() returned error: %v", err)
- }
- if err = button.Click(); err != nil {
- t.Fatalf("wd.Click() returned error: %v", err)
- }
-
- // The page load timeout for Firefox and Selenium 3 seems to not work for
- // clicking form buttons. Sleep a bit to reduce impact of a flaky test.
- if c.browser == "firefox" && c.seleniumVersion.Major == 3 {
- time.Sleep(2 * time.Second)
- }
- source, err := wd.PageSource()
- if err != nil {
- t.Fatalf("wd.PageSource() returned error: %v", err)
- }
-
- if !strings.Contains(source, searchContents) {
- t.Fatalf("Can't find %q on page after searching for %q", searchContents, query)
- }
-}
-
-func testGetCookie(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- cookies, err := wd.GetCookies()
- if err != nil {
- t.Fatalf("wd.GetCookies() returned error: %v", err)
- }
-
- if len(cookies) == 0 {
- t.Fatal("wd.GetCookies() returned no cookies")
- }
-
- if len(cookies[0].Name) == 0 {
- t.Fatalf("Empty cookie name: %+v", cookies[0])
- }
-
- got, err := wd.GetCookie(cookies[0].Name)
- if err != nil {
- t.Fatalf("wd.GetCookie(%q) returned error: %v", cookies[0].Name, err)
- }
- if !reflect.DeepEqual(got, cookies[0]) {
- t.Fatalf("wd.GetCookie(%q) = %+v, want %+v", cookies[0].Name, cookies[0], got)
- }
-}
-
-func testGetCookies(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- cookies, err := wd.GetCookies()
- if err != nil {
- t.Fatal(err)
- }
-
- if len(cookies) == 0 {
- t.Fatal("No cookies")
- }
-
- if len(cookies[0].Name) == 0 {
- t.Fatal("Empty cookie")
- }
-}
-
-func v(s string) semver.Version {
- return semver.MustParse(s)
-}
-
-func testAddCookie(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- want := &Cookie{
- Name: "the nameless cookie",
- Value: "I have nothing",
- Expiry: math.MaxUint32,
- Domain: "127.0.0.1", // Unlike real browsers, htmlunit requires this to be set.
- }
- if err := wd.AddCookie(want); err != nil {
- t.Fatal(err)
- }
-
- // These fields are added implicitly by the browser.
- want.Domain = "127.0.0.1"
- want.Path = "/"
-
- // Firefox and Geckodriver now returns an empty string for the path.
- if c.browser == "firefox" {
- want.Path = ""
- }
-
- cookies, err := wd.GetCookies()
- if err != nil {
- t.Fatal(err)
- }
- var got *Cookie
- for _, cookie := range cookies {
- if cookie.Name == want.Name {
- got = &cookie
- break
- }
- }
- if got == nil {
- t.Fatalf("wd.GetCookies() = %v, missing cookie %q", cookies, want.Name)
- }
-
- if diff := cmp.Diff(want, got); diff != "" {
- t.Fatalf("wd.GetCookies() returned diff (-want/+got):\n%s", diff)
- }
-}
-
-func testDeleteCookie(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- cookies, err := wd.GetCookies()
- if err != nil {
- t.Fatal(err)
- }
- if len(cookies) == 0 {
- t.Fatal("No cookies")
- }
- if err := wd.DeleteCookie(cookies[0].Name); err != nil {
- t.Fatal(err)
- }
- newCookies, err := wd.GetCookies()
- if err != nil {
- t.Fatal(err)
- }
- if len(newCookies) != len(cookies)-1 {
- t.Fatal("Cookie not deleted")
- }
-
- for _, c := range newCookies {
- if c.Name == cookies[0].Name {
- t.Fatal("Deleted cookie found")
- }
- }
-}
-
-func testLocation(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- button, err := wd.FindElement(ByID, "submit")
- if err != nil {
- t.Fatal(err)
- }
-
- loc, err := button.Location()
- if err != nil {
- t.Fatal(err)
- }
-
- if loc.X == 0 || loc.Y == 0 {
- t.Fatalf("Bad location: %v\n", loc)
- }
-}
-
-func testLocationInView(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- button, err := wd.FindElement(ByID, "submit")
- if err != nil {
- t.Fatal(err)
- }
-
- loc, err := button.LocationInView()
- if err != nil {
- t.Fatal(err)
- }
-
- if loc.X == 0 || loc.Y == 0 {
- t.Fatalf("Bad location: %v\n", loc)
- }
-}
-
-func testSize(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- button, err := wd.FindElement(ByID, "submit")
- if err != nil {
- t.Fatal(err)
- }
-
- size, err := button.Size()
- if err != nil {
- t.Fatal(err)
- }
-
- if size.Width == 0 || size.Height == 0 {
- t.Fatalf("Bad size: %v\n", size)
- }
-}
-
-func testExecuteScript(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- script := "return arguments[0] + arguments[1]"
- args := []interface{}{1, 2}
- reply, err := wd.ExecuteScript(script, args)
- if err != nil {
- t.Fatal(err)
- }
-
- result, ok := reply.(float64)
- if !ok {
- t.Fatal("Not an int reply")
- }
-
- if result != 3 {
- t.Fatalf("Bad result %d (expected 3)", int(result))
- }
-}
-
-func testExecuteScriptWithNilArgs(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
-
- script := "return document.readyState"
- if _, err := wd.ExecuteScript(script, nil); err != nil {
- t.Fatal(err)
- }
-}
-
-func testExecuteScriptOnElement(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
-
- input, err := wd.FindElement(ByName, "q")
- if err != nil {
- t.Fatal(err)
- }
-
- const query = "golang"
- if err := input.SendKeys(query); err != nil {
- t.Fatal(err)
- }
-
- we, err := wd.FindElement(ByXPATH, "//input[@type='submit']")
- if err != nil {
- t.Fatal(err)
- }
-
- script := "arguments[0].click()"
- args := []interface{}{we}
-
- if _, err = wd.ExecuteScript(script, args); err != nil {
- t.Fatal(err)
- }
-
- time.Sleep(500 * time.Millisecond)
-
- source, err := wd.PageSource()
- if err != nil {
- t.Fatal(err)
- }
-
- if !strings.Contains(source, searchContents) {
- t.Fatalf("Can't find %q on page after searching for %q", searchContents, query)
- }
-}
-
-func testScreenshot(t *testing.T, c config) {
- if c.browser == "htmlunit" {
- t.Skip("Skipping on htmlunit")
- }
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- data, err := wd.Screenshot()
- if err != nil {
- t.Fatal(err)
- }
-
- if len(data) == 0 {
- t.Fatal("Empty reply")
- }
-}
-
-func testLog(t *testing.T, c config) {
- switch {
- case c.browser == "htmlunit":
- t.Skip("Skipping on htmlunit")
- case c.browser == "firefox" && (c.seleniumVersion.Major == 3 || c.seleniumVersion.Major == 0):
- // Log is not supported on Firefox with Selenium 3.
- // https://github.com/w3c/webdriver/issues/406
- // https://github.com/mozilla/geckodriver/issues/284
- t.Skip("The log interface is not supported on Firefox, since it is not yet part of the W3C spec.")
- }
- caps := newTestCapabilities(t, c)
- caps.SetLogLevel(log.Browser, log.All)
- if c.browser == "chrome" {
- caps.SetLogLevel(log.Performance, log.All)
- }
-
- wd := &remoteWD{
- capabilities: caps,
- urlPrefix: c.addr,
- }
- if _, err := wd.NewSession(); err != nil {
- t.Fatalf("wd.NewSession() returned error: %v", err)
- }
- defer quitRemote(t, wd)
-
- url := serverURL + "/log"
- if err := wd.Get(url); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", url, err)
- }
- logs, err := wd.Log(log.Browser)
- if err != nil {
- t.Fatalf("wd.Log(Browser) returned error: %v", err)
- }
- if len(logs) == 0 {
- t.Fatalf("empty reply from wd.Log(Browser)")
- } else {
- for _, l := range logs {
- if len(l.Level) == 0 || l.Timestamp.Unix() == 0 || len(l.Message) == 0 {
- t.Errorf("wd.Log(Browser) returned malformed message: %+v", l)
- }
- }
- }
-
- if c.browser == "chrome" {
- logs, err = wd.Log(log.Performance)
- if err != nil {
- t.Fatalf("wd.Log(Performance) returned error: %v", err)
- }
- if len(logs) == 0 {
- t.Fatal("empty reply from wd.Log(Performance)")
- } else {
- for _, l := range logs {
- if len(l.Level) == 0 || l.Timestamp.Unix() == 0 || len(l.Message) == 0 {
- t.Errorf("wd.Log(Browser) returned malformed message: %+v", l)
- }
- // Make sure the timestamp conversion is vaguely correct. In
- // practice, this difference should be in the milliseconds range.
- if time.Now().Sub(l.Timestamp) > time.Hour {
- t.Errorf("Message has timestamp %s > 1 hour ago: %v", l.Timestamp, l)
- }
- }
- }
- }
-}
-
-func testIsSelected(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- elem, err := wd.FindElement(ByID, "chuk")
- if err != nil {
- t.Fatal("Can't find element")
- }
- selected, err := elem.IsSelected()
- if err != nil {
- t.Fatal("Can't get selection")
- }
-
- if selected {
- t.Fatal("Already selected")
- }
-
- if err := elem.Click(); err != nil {
- t.Fatal("Can't click")
- }
-
- selected, err = elem.IsSelected()
- if err != nil {
- t.Fatal("Can't get selection")
- }
-
- if !selected {
- t.Fatal("Not selected")
- }
-}
-
-func testIsDisplayed(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- const id = "chuk"
- elem, err := wd.FindElement(ByID, id)
- if err != nil {
- t.Fatalf("wd.FindElement(ByID, %s) return error %v", id, err)
- }
- displayed, err := elem.IsDisplayed()
- if err != nil {
- t.Fatalf("elem.IsDisplayed() returned error: %v", err)
- }
-
- if !displayed {
- t.Fatal("Not displayed")
- }
-}
-
-func testGetAttributeNotFound(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- elem, err := wd.FindElement(ByID, "chuk")
- if err != nil {
- t.Fatal("Can't find element")
- }
-
- if _, err = elem.GetAttribute("no-such-attribute"); err == nil {
- t.Fatal("Got non existing attribute")
- }
-}
-
-func testActiveElement(t *testing.T, c config) {
- if c.browser == "htmlunit" {
- // TODO(minusnine): figure out why ActiveElement doesn't work in HTMLUnit.
- t.Skip("ActiveElement does not work in HTMLUnit")
- }
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
-
- e, err := wd.ActiveElement()
- if err != nil {
- t.Fatalf("wd.ActiveElement() returned error: %v", err)
- }
- name, err := e.GetAttribute("name")
- if err != nil {
- t.Fatalf("wd.ActiveElement().GetAttribute() returned error: %v", err)
- }
- if name != "q" {
- t.Fatalf("wd.ActiveElement().GetAttribute() returned element with name = %q, expected name = 'q'", name)
- }
-}
-
-func testKeyDownUp(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
-
- e, err := wd.FindElement(ByLinkText, "other page")
- if err != nil {
- t.Fatalf("error finding other page link: %v", err)
- }
-
- if err := wd.KeyDown(ControlKey); err != nil {
- t.Fatalf("error pressing control key down: %v", err)
- }
- if err := e.Click(); err != nil {
- t.Fatalf("error clicking the other page link: %v", err)
- }
- if err := wd.KeyUp(ControlKey); err != nil {
- t.Fatalf("error releasing control key: %v", err)
- }
-}
-
-func testCSSProperty(t *testing.T, c config) {
- if c.browser == "htmlunit" {
- t.Skip("Skipping on htmlunit")
- }
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
-
- e, err := wd.FindElement(ByLinkText, "other page")
- if err != nil {
- t.Fatalf("error finding other page link: %v", err)
- }
-
- color, err := e.CSSProperty("color")
- if err != nil {
- t.Fatalf(`e.CSSProperty("color") returned error: %v`, err)
- }
-
- // Later versions of Firefox and HTMLUnit return the "rgb" version.
- wantColors := []string{"rgba(0, 0, 238, 1)", "rgb(0, 0, 238)"}
- for _, wantColor := range wantColors {
- if color == wantColor {
- return
- }
- }
- t.Fatalf(`e.CSSProperty("color") = %q, want one of %q`, color, wantColors)
-}
-
-const proxyPageContents = "You are viewing a proxied page"
-
-// addrRewriter rewrites all requsted addresses to the one specified by the
-// URL.
-type addrRewriter struct{ u *url.URL }
-
-func (a *addrRewriter) Rewrite(ctx context.Context, _ *socks5.Request) (context.Context, *socks5.AddrSpec) {
- port, err := strconv.Atoi(a.u.Port())
- if err != nil {
- panic(err)
- }
- return ctx, &socks5.AddrSpec{
- FQDN: a.u.Hostname(),
- Port: port,
- }
-}
-
-func testProxy(t *testing.T, c config) {
- if c.sauce != nil {
- t.Skip("Testing a proxy on Sauce Labs doesn't work.")
- }
-
- // Create a different web server that should be used if HTTP proxying is enabled.
- s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
- fmt.Fprintf(w, proxyPageContents)
- }))
- defer s.Close()
-
- u, err := url.Parse(s.URL)
- if err != nil {
- t.Fatalf("url.Parse(%q) returned error: %v", s.URL, err)
- }
-
- t.Run("HTTP", func(t *testing.T) {
- caps := newTestCapabilities(t, c)
- caps.AddProxy(Proxy{
- Type: Manual,
- HTTP: u.Host,
- })
- runTestProxy(t, c, caps)
- })
-
- t.Run("SOCKS", func(t *testing.T) {
- if c.seleniumVersion.Major == 3 {
- // Selenium 3 fails when converting SOCKSVersion with: "unknown error:
- // java.lang.Long cannot be cast to java.lang.Integer"
- // The fix for this is committed, but not yet in a release.
- //
- // https://github.com/SeleniumHQ/selenium/issues/6917
- t.Skip("Selenium 3 throws an exception with SOCKSVersion type conversion")
- }
- socks, err := socks5.New(&socks5.Config{
- Rewriter: &addrRewriter{u},
- })
- if err != nil {
- t.Fatalf("socks5.New(_) returned error: %v", err)
- }
- l, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("net.Listen(_, _) return error: %v", err)
- }
-
- // Start serving SOCKS connections, but don't fail the test once the
- // listener is closed at the end of execution.
- done := make(chan struct{})
- go func() {
- err := socks.Serve(l)
- select {
- case <-done:
- return
- default:
- }
- if err != nil {
- t.Fatalf("s.ListenAndServe(_) returned error: %v", err)
- }
- }()
- defer func() {
- close(done)
- l.Close()
- }()
-
- caps := newTestCapabilities(t, c)
- caps.AddProxy(Proxy{
- Type: Manual,
- SOCKS: l.Addr().String(),
- SOCKSVersion: 5,
- })
-
- runTestProxy(t, c, caps)
- })
-}
-
-func runTestProxy(t *testing.T, c config, caps Capabilities) {
- allowProxyForLocalhost(c.browser, caps)
-
- wd := &remoteWD{
- capabilities: caps,
- urlPrefix: c.addr,
- }
- defer func() {
- if err := wd.Quit(); err != nil {
- t.Fatalf("wd.Quit() returned error: %v", err)
- }
- }()
- if _, err := wd.NewSession(); err != nil {
- t.Fatalf("wd.NewSession() returned error: %v", err)
- }
-
- // Request the original server URL.
- if err := wd.Get(serverURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
- source, err := wd.PageSource()
- if err != nil {
- t.Fatalf("wd.PageSource() returned error: %v", err)
- }
-
- if !strings.Contains(source, proxyPageContents) {
- if strings.Contains(source, "Go Selenium Test Suite") {
- t.Fatal("Got non-proxied page.")
- }
- t.Fatalf("Got page: %s\n\nExpected: %q", source, proxyPageContents)
- }
-}
-
-func allowProxyForLocalhost(browser string, caps Capabilities) {
- switch browser {
- case "firefox":
- // By default, Firefox explicitly does not use a proxy for connection to
- // localhost and 127.0.0.1. Clear this preference to reach our test proxy.
- ff := caps[firefox.CapabilitiesKey].(firefox.Capabilities)
- if ff.Prefs == nil {
- ff.Prefs = make(map[string]interface{})
- }
- ff.Prefs["network.proxy.no_proxies_on"] = ""
- ff.Prefs["network.proxy.allow_hijacking_localhost"] = true
- caps.AddFirefox(ff)
-
- case "chrome":
- ch := caps[chrome.CapabilitiesKey].(chrome.Capabilities)
- // Allow Chrome to use the specified proxy for localhost, which is
- // needed for the Proxy test. https://crbug.com/899126
- ch.Args = append(ch.Args, "--proxy-bypass-list=<-loopback>")
- caps.AddChrome(ch)
- }
-}
-
-func testSwitchFrame(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- if err := wd.Get(serverURL + "/frame"); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
- }
-
- const (
- iframeID = "iframeID"
- insideFrameID = "chuk"
- outsideDivID = "outsideOfFrame"
- )
-
- // Test with the ID of the iframe.
- if err := wd.SwitchFrame(iframeID); err != nil {
- t.Fatalf("wd.SwitchToFrame(%q) returned error: %v", iframeID, err)
- }
- if _, err := wd.FindElement(ByID, insideFrameID); err != nil {
- t.Fatalf("After switching frames using an ID, wd.FindElement(ByID, %q) returned error: %v", insideFrameID, err)
- }
- if _, err := wd.FindElement(ByID, outsideDivID); err == nil {
- t.Fatalf("After switching frames using an ID, wd.FindElement(ByID, %q) returned nil, expected an error", outsideDivID)
- }
-
- // Test with nil, to return to the top-level context.
- if err := wd.SwitchFrame(nil); err != nil {
- t.Fatalf("wd.SwitchToFrame(nil) returned error: %v", err)
- }
- if _, err := wd.FindElement(ByID, outsideDivID); err != nil {
- t.Fatalf("After switching frames using nil, wd.FindElement(ByID, %q) returned error: %v", outsideDivID, err)
- }
-
- // Test with a WebElement.
- iframe, err := wd.FindElement(ByID, iframeID)
- if err != nil {
- t.Fatalf("error finding iframe: %v", err)
- }
- if err := wd.SwitchFrame(iframe); err != nil {
- t.Fatalf("wd.SwitchToFrame(nil) returned error: %v", err)
- }
- if _, err := wd.FindElement(ByID, insideFrameID); err != nil {
- t.Fatalf("After switching frames using a WebElement, wd.FindElement(ByID, %q) returned error: %v", insideFrameID, err)
- }
- if _, err := wd.FindElement(ByID, outsideDivID); err == nil {
- t.Fatalf("After switching frames using a WebElement, wd.FindElement(ByID, %q) returned nil, expected an error", outsideDivID)
- }
-
- // Test with the empty string, to return to the top-level context.
- if err := wd.SwitchFrame(""); err != nil {
- t.Fatalf(`wd.SwitchToFrame("") returned error: %v`, err)
- }
- if _, err := wd.FindElement(ByID, outsideDivID); err != nil {
- t.Fatalf(`After switching frames using "", wd.FindElement(ByID, %q) returned error: %v`, outsideDivID, err)
- }
-}
-
-func testWait(t *testing.T, c config) {
- const newTitle = "Title changed."
- titleChangeCondition := func(wd WebDriver) (bool, error) {
- title, err := wd.Title()
- if err != nil {
- return false, err
- }
-
- return title == newTitle, nil
- }
-
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- titleURL := serverURL + "/title"
-
- if err := wd.Get(titleURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", titleURL, err)
- }
-
- // Testing when the title should change.
- if err := wd.Wait(titleChangeCondition); err != nil {
- t.Fatalf("wd.Wait(titleChangeCondition) returned error: %v", err)
- }
-
- // Reloading the page.
- if err := wd.Get(titleURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", titleURL, err)
- }
-
- // Testing when the Wait() should error the timeout..
- if err := wd.WaitWithTimeout(titleChangeCondition, 500*time.Millisecond); err == nil {
- t.Fatalf("wd.Wait(titleChangeCondition) should returned error, but it didn't.")
- }
-}
-
-func testAcceptAlert(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- alertPageURL := serverURL + "/alert"
-
- if err := wd.Get(alertPageURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", alertPageURL, err)
- }
-
- alertText, err := wd.AlertText()
- if err != nil {
- t.Fatalf("wd.AlertText() returned error: %v", err)
- }
-
- if alertText != "Hello world" {
- t.Fatalf("Expected 'Hello world' but got '%s'", alertText)
- }
-
- if err := wd.AcceptAlert(); err != nil {
- t.Fatalf("wd.AcceptAlert() returned error: %v", err)
- }
-}
-
-func testDismissAlert(t *testing.T, c config) {
- wd := newRemote(t, c)
- defer quitRemote(t, wd)
-
- alertPageURL := serverURL + "/alert"
-
- if err := wd.Get(alertPageURL); err != nil {
- t.Fatalf("wd.Get(%q) returned error: %v", alertPageURL, err)
- }
-
- if err := wd.DismissAlert(); err != nil {
- t.Fatalf("wd.DismissAlert() returned error: %v", err)
- }
-}
-
-var homePage = `
-
-
- Go Selenium Test Suite
-
-
- The home page.
-
- Link to the other page.
-
- тест
-
-
-`
-
-var otherPage = `
-
-
- Go Selenium Test Suite - Other Page
-
-
- The other page.
-
-
-`
-
-const searchContents = "The Go Proramming Language"
-
-var searchPage = `
-
-
- Go Selenium Test Suite - Search Page
-
-
- You searched for "%s". I'll pretend I've found:
-
- "` + searchContents + `"
-
- Select value is: %s
-
-
-`
-
-var logPage = `
-
-
- Go Selenium Test Suite - Log Page
-
-
-
- Log test page.
-
-
-`
-
-var framePage = `
-
-
- Go Selenium Test Suite - Frame Page
-
-
- This page contains a frame.
-
-
-
-
-
-`
-
-var titleChangePage = `
-
-
- Go Selenium Test Suite - Title Change Page
-
-
- This page will change a title after 1 second.
-
-
-
-
-`
-
-var alertPage = `
-
-
- Go Selenium Test Suite - Alert Appear Page
-
-
- An alert will popup.
-
-
-
-
-`
-
-func handler(w http.ResponseWriter, r *http.Request) {
- path := r.URL.Path
- page, ok := map[string]string{
- "/": homePage,
- "/other": otherPage,
- "/search": searchPage,
- "/log": logPage,
- "/frame": framePage,
- "/title": titleChangePage,
- "/alert": alertPage,
- }[path]
- if !ok {
- http.NotFound(w, r)
- return
- }
-
- if path == "/search" {
- r.ParseForm()
- page = fmt.Sprintf(page, r.Form["q"][0], r.Form["s"][0])
- }
- // Some cookies for the tests
- for i := 0; i < 3; i++ {
- http.SetCookie(w, &http.Cookie{
- Name: fmt.Sprintf("cookie-%d", i),
- Value: fmt.Sprintf("value-%d", i),
- })
- }
- fmt.Fprintf(w, page)
-}
diff --git a/sauce_test.go b/sauce_test.go
index b825727..784fb8a 100644
--- a/sauce_test.go
+++ b/sauce_test.go
@@ -1,4 +1,4 @@
-package selenium
+package selenium_test
import (
"flag"
@@ -7,6 +7,8 @@ import (
"testing"
"github.com/blang/semver"
+ "github.com/tebeka/selenium"
+ "github.com/tebeka/selenium/internal/seleniumtest"
"github.com/tebeka/selenium/sauce"
)
@@ -22,7 +24,7 @@ func TestSauce(t *testing.T) {
t.Skip("Skipping Sauce tests. Enable via --experimental_sauce_tests")
}
if testing.Verbose() {
- SetDebug(true)
+ selenium.SetDebug(true)
}
if *sauceUserName == "" {
t.Fatalf("--sauce_user_name is required.")
@@ -69,17 +71,19 @@ func TestSauce(t *testing.T) {
browser, version := strings.ToLower(browser), strings.ToLower(tc.version)
t.Run(name, func(t *testing.T) {
- runFirefoxSubTests(t, config{
- browser: browser,
- seleniumVersion: semver.MustParse(tc.selenium),
- sauce: &sauce.Capabilities{
+ c := seleniumtest.Config{
+ Browser: browser,
+ SeleniumVersion: semver.MustParse(tc.selenium),
+ Sauce: &sauce.Capabilities{
Browser: browser,
Version: version,
Platform: tc.platform,
SeleniumVersion: tc.selenium,
},
- addr: addr,
- })
+ Addr: addr,
+ }
+ seleniumtest.RunCommonTests(t, c)
+ seleniumtest.RunFirefoxTests(t, c)
})
}
}