Selenium WebDriver client for Go

Overview

============================================== go-selenium - Selenium WebDriver client for Go

go-selenium is a Selenium WebDriver client for Go.

Note: the public API is experimental and subject to change until further notice.

Usage

Documentation: go-selenium on Sourcegraph.

Example: see example_test.go:

package selenium_test

import (
	"fmt"
	"sourcegraph.com/sourcegraph/go-selenium"
)

func ExampleFindElement() {
	var webDriver selenium.WebDriver
	var err error
	caps := selenium.Capabilities(map[string]interface{}{"browserName": "firefox"})
	if webDriver, err = selenium.NewRemote(caps, "http://localhost:4444/wd/hub"); err != nil {
		fmt.Printf("Failed to open session: %s\n", err)
		return
	}
	defer webDriver.Quit()

	err = webDriver.Get("https://sourcegraph.com/sourcegraph/go-selenium")
	if err != nil {
		fmt.Printf("Failed to load page: %s\n", err)
		return
	}

	if title, err := webDriver.Title(); err == nil {
		fmt.Printf("Page title: %s\n", title)
	} else {
		fmt.Printf("Failed to get page title: %s", err)
		return
	}

	var elem selenium.WebElement
	elem, err = webDriver.FindElement(selenium.ByCSSSelector, ".repo .name")
	if err != nil {
		fmt.Printf("Failed to find element: %s\n", err)
		return
	}

	if text, err := elem.Text(); err == nil {
		fmt.Printf("Repository: %s\n", text)
	} else {
		fmt.Printf("Failed to get text of element: %s\n", err)
		return
	}

	// output:
	// Page title: go-selenium - Sourcegraph
	// Repository: go-selenium
}

The WebDriverT and WebElementT interfaces make test code cleaner. Each method in WebDriver and WebElement has a corresponding method in the *T interfaces that omits the error from the return values and instead calls t.Fatalf upon encountering an error. For example:

package mytest

import (
  "sourcegraph.com/sourcegraph/go-selenium"
  "testing"
)

var caps selenium.Capabilities
var executorURL = "http://localhost:4444/wd/hub"

// An example test using the WebDriverT and WebElementT interfaces. If you use the non-*T
// interfaces, you must perform error checking that is tangential to what you are testing,
// and you have to destructure results from method calls.
func TestWithT(t *testing.T) {
  wd, _ := selenium.NewRemote(caps, executor)

  // Call .T(t) to obtain a WebDriverT from a WebDriver (or to obtain a WebElementT from
  // a WebElement).
  wdt := wd.T(t)

  // Calls `t.Fatalf("Get: %s", err)` upon failure.
  wdt.Get("http://example.com")

  // Calls `t.Fatalf("FindElement(by=%q, value=%q): %s", by, value, err)` upon failure.
  elem := wdt.FindElement(selenium.ByCSSSelector, ".foo")

  // Calls `t.Fatalf("Text: %s", err)` if the `.Text()` call fails.
  if elem.Text() != "bar" {
    t.Fatalf("want elem text %q, got %q", "bar", elem.Text())
  }
}

See remote_test.go for more usage examples.

Running tests

Start Selenium WebDriver and run go test. To see all available options, run go test -test.h.

TODO

  • Support Firefox profiles

Contributors

License

go-selenium is distributed under the Eclipse Public License.

Comments
  • ExecuteScript always returns error

    ExecuteScript always returns error "unknown error"

    result, err := webDriver.ExecuteScript("document.readyState", nil)
    if err != nil {
        fmt.Printf("ERROR executing script: %s\n", err)
    }
    

    yields: ERROR executing script: unknown error

    the selenum server log shows 20:29:29.816 WARN - Exception thrown java.lang.NullPointerException at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:191) at com.google.common.collect.Iterables.transform(Iterables.java:708) at org.openqa.selenium.remote.server.handler.ExecuteScript.setJsonParameters(ExecuteScript.java:46) at org.openqa.selenium.remote.server.rest.ResultConfig.setJsonParameters(ResultConfig.java:309) at org.openqa.selenium.remote.server.rest.ResultConfig.handle(ResultConfig.java:193) at org.openqa.selenium.remote.server.JsonHttpRemoteConfig.handleRequest(JsonHttpRemoteConfig.java:192) at org.openqa.selenium.remote.server.DriverServlet.handleRequest(DriverServlet.java:201) at org.openqa.selenium.remote.server.DriverServlet.doPost(DriverServlet.java:167) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at org.openqa.selenium.remote.server.DriverServlet.service(DriverServlet.java:139) at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)

    ChromeDriver (v2.3) selenium-server-standalone-2.35.0.jar Linux Desktop2012 3.10.9-1-ARCH #1 SMP PREEMPT Wed Aug 21 13:49:35 CEST 2013 x86_64 GNU/Linux

    opened by Grant-Murray 6
  • Element Screenshot

    Element Screenshot

    webdriver has define element screenshot, in 18.2: https://www.w3.org/TR/webdriver/#take-element-screenshot

    I have try as this:

    func (elem *remoteWE) ScreenshotElement() ([]byte, error) {
    data, err := elem.parent.stringCommand("/session/%s/element/" + elem.id + "/screenshot")
    if err != nil {
    	return nil, err
    }
    
    return []byte(data), nil
    }
    

    But i cannot work, error is 404 Not found, why?

    opened by guotie 4
  • Add /sessions command

    Add /sessions command

    This adds a WebDriver method Sessions(), which returns an array of active server sessions according to the JsonWireProtocol command “/sessions”. A test for Sessions() is included in remote_test.go.

    No existing code is modified, so nothing breaks when people update.

    opened by carstn 4
  • Test for error handling

    Test for error handling

    Also updated the example test so it passes.

    This PR originally tried to improve on our error handling, but I'm leaving that out for now and just including the related fixes.

    opened by keegancsmith 3
  • GetCookies sometimes fails on chromedriver

    GetCookies sometimes fails on chromedriver

    It seems that when using ChromeDriver (and perhaps other drivers), sometimes the value returned for the cookie's expiry field doesn't deserialize as a uint.

    For example:

    [
      {
        "domain":".typeform.com",
        "expiry":1475462515.303742,
        "httpOnly":false,
        "name":"__insp_slim",
        "path":"/",
        "secure":false,
        "value":"1443926515303"
    },
    ...
    ]
    

    Notice how the expiry field has a period followed by a bunch of digits. I'm guessing this is fractions of a second?

    I changed the type of Expiry to interface{} in my fork to fix the immediate issue. Maybe there is a way to detect this & handle it better though.

    opened by Bowbaq 3
  • Explicitly waiting for new page to load after Click()

    Explicitly waiting for new page to load after Click()

    I'm writing a simple page performance tester. I'm trying to fill in a form, issue a Click() on the submit button, and then gather timing information on the page that's returned by the server after the submission.

    I'm able to fill the form out (FindElement(), SendKeys()) and I can issue the Click() but I haven't figured out how to wait until the resulting new page is rendered before attempting to gather timings. Is this possible in go-selenium?

    opened by chrissnell 2
  • Fix import comment to fix failing in go 1.4

    Fix import comment to fix failing in go 1.4

    Using go 1.4 'go get -u -a' logs the error message:

    package github.com/sourcegraph/go-selenium: code in directory /Users/user/workspace/go/src/github.com/sourcegraph/go-selenium expects import "sourcegraph.com/sourcegraph/go-selenium"

    opened by korzha 2
  • Adding Cookie Before Load?

    Adding Cookie Before Load?

    Currently attempting to load a cookie before the loading of the page / browser but having issues. Is this possible or am I doing this wrong? Rather new to golang.

    cookie := selenium.Cookie{"domain_splash", "1", "/", ".domain.com", false, 0}
    webDriver.AddCookie(&cookie)
    
    opened by lxcodes 2
  • Add support for context.Context automatic Quit()

    Add support for context.Context automatic Quit()

    It's annoying if you interrupt tests to have them leave a browser window open.

    You might have to wait a while before you can run your tests again.

    This adds support for go 1.7's context.Context. It instruments all requests, causing them to cancel the outgoing HTTP request to selenium if the context is canceled.

    In addition, it checks on entry and exit to a HTTP request if the context is canceled, to ensure we notice rapidly.

    If the context is canceled, wd.Quit() is called. For convenience, it's made legal to call quit more than once, so that code which does:

    wd := makeWD()
    defer wd.Quit()
    

    Remains legal.

    An example of use:

    var cancel func()
    ctx, cancel = context.WithCancel(context.Background())
    go func() {
        interrupt := make(chan os.Signal)
        signal.Notify(interrupt, os.Interrupt)
        <-interrupt
        log.Printf("Received interrupt.")
        cancel()
    }()
    
    wd := makeWD()
    wd.SetContext(ctx)
    
    wd.Get(...)
    // ... etc, etc.
    

    The net effect is that interrupting the tests now give X failed: canceled, and the browser window quits.

    opened by pwaller 1
  • Screenshot() returning io.Reader instead of byte[]

    Screenshot() returning io.Reader instead of byte[]

    It would be nice if Screenshot() would give user more control by returning io.Reader instead of byte[]. User can always call ioutil.ReadAll() if needed.

    opened by shicky 1
  • Default handle name in case of empty name.

    Default handle name in case of empty name.

    For several functions such as WindowSize(name string) takes window handle name as argument.

    This can be confusing at times and should support default value of "current" in case empty string is passed as argument.

    // This doesn't work but should work!
    webDriver.WindowSize("") 
    
    opened by shicky 1
  • Doesn't work with IeDriverServer

    Doesn't work with IeDriverServer

    The problem is that StartSession returns empty sessionId. The reason of this behaviour is serialization problem of reply struct. If sessionId is first string of json - it works ok. But IeDriverServer returns it as last param in json, so it not deserialized properly

    opened by spiritofsim 0
  • Failed to open session: unknown error - 33: Unable to create new service: GeckoDriverService

    Failed to open session: unknown error - 33: Unable to create new service: GeckoDriverService

    Selenium server: 3.6.0

    Go error:

    Failed to open session: unknown error - 33: Unable to create new service: GeckoDriverService Build info: version: '3.6.0', revision: '6fbf3ec767', time: '2017-09-27T16:15:40.131Z' System info: host: 'anboo', ip: '127.0.1.1', os.name: 'Linux', os.arch: 'amd64', os.version: '4.10.0-35-generic', java.version: '1.8.0_144' Driver info: driver.version: unknown

    Selenium logs:

    09:53:06.803 INFO - Binding default provider to: org.openqa.selenium.chrome.ChromeDriverService 09:53:06.804 INFO - Found handler: org.openqa.selenium.remote.server.commandhandler.BeginSession@18a73dae 09:53:06.805 INFO - /session: Executing POST on /session (handler: BeginSession) 09:53:06.808 INFO - Capabilities are: Capabilities {browserName=firefox} 09:53:06.809 INFO - Capabilities {browserName=firefox} matched class org.openqa.selenium.remote.server.ServicedSession$Factory (provider: org.openqa.selenium.firefox.GeckoDriverService) 09:53:06.810 INFO - Capabilities {browserName=firefox} matched class org.openqa.selenium.remote.server.ServicedSession$Factory (provider: org.openqa.selenium.chrome.ChromeDriverService)

    Code: `package main

    import ( "fmt" //"sourcegraph.com/sourcegraph/go-selenium" "github.com/tebeka/selenium" )

    func main() { var webDriver selenium.WebDriver var err error caps := selenium.Capabilities(map[string]interface{}{"browserName": "firefox"}) if webDriver, err = selenium.NewRemote(caps, "http://localhost:4444/wd/hub"); err != nil { fmt.Printf("Failed to open session: %s\n", err) return } defer webDriver.Quit()

    err = webDriver.Get("https://sourcegraph.com/sourcegraph/go-selenium")
    if err != nil {
    	fmt.Printf("Failed to load page: %s\n", err)
    	return
    }
    
    if title, err := webDriver.Title(); err == nil {
    	fmt.Printf("Page title: %s\n", title)
    } else {
    	fmt.Printf("Failed to get page title: %s", err)
    	return
    }
    
    var elem selenium.WebElement
    elem, err = webDriver.FindElement(selenium.ByCSSSelector, ".repo .name")
    if err != nil {
    	fmt.Printf("Failed to find element: %s\n", err)
    	return
    }
    
    if text, err := elem.Text(); err == nil {
    	fmt.Printf("Repository: %s\n", text)
    } else {
    	fmt.Printf("Failed to get text of element: %s\n", err)
    	return
    }
    

    }`

    opened by anboo 1
  • Is this project still maintained?

    Is this project still maintained?

    Greetings! It looks like this project is no longer being developed while upstream (tebeka/selenium) is looking very active.

    Are there any plans to develop this package further or is it dead? :confused:

    opened by ivy 3
  • Removing hard coded package URL

    Removing hard coded package URL

    Fixes #29 If not it gives error on build as: cant load package: package github.com/sourcegraph/go-selenium: code in directory $GOPATH/src/github.com/sourcegraph/go-selenium expects import "sourcegraph.com/sourcegraph/go-selenium"

    opened by apoorvam 0
Owner
Sourcegraph
Code search and navigation for teams (self-hosted, OSS)
Sourcegraph
Chief Client Go is a cross platform Krunker client written in Go Lang

Chief Client Go Chief Client Go is a client for Mac and Linux written in GoLang Features Ad Blocker Option to use proxy Installation To install this c

Chief Software 0 Nov 6, 2021
a Go (Golang) MusicBrainz WS2 client library - work in progress

gomusicbrainz a Go (Golang) MusicBrainz WS2 client library - a work in progress. Current state Currently GoMusicBrainz provides methods to perform sea

Michael Wendland 47 Sep 28, 2022
Yubigo is a Yubikey client API library that provides an easy way to integrate the Yubico Yubikey into your existing Go-based user authentication infrastructure.

yubigo Yubigo is a Yubikey client API library that provides an easy way to integrate the Yubikey into any Go application. Installation Installation is

Geert-Johan Riemer 123 Oct 27, 2022
Simple Client Implementation of WebFinger

Go-Webfinger Go client for the Webfinger protocol Go-Webfinger is a Go client for the Webfinger protocol. *It is a work in progress, the API is not fr

Antoine Imbert 17 Nov 18, 2022
An example client implementation written in GO to access the CyberVox platform API

About This is an example client implementation written in GO to access the CyberVox platform API.

Cyberlabs AI 15 Nov 7, 2022
TUI Client for Docker

docui - TUI Client for Docker Written in Go About docui docui is a TUI Client for Docker. It can do the following: image search/pull/remove save/impor

skanehira 2.3k Dec 28, 2022
Elastic is an Elasticsearch client for the Go programming language.

Elastic is an Elasticsearch client for the Go programming language.

Oliver Eilhard 7.1k Jan 9, 2023
Geth client which picks the most profitable blocks to mine using a greedy algorithm

Greeden-Geth Greeden-Geth is a protocol-agnostic client which uses a greedy algorithm to pick the most profitable blocks to submit to the network out

Nathan 75 Nov 16, 2022
A comparison of client tracing APIs

A comparison of client tracing APIs Client Usage Trace Dump go-ethereum View Nethermind View View Erigon View View Besu View Getting Started git clone

Hans Martin 5 Feb 4, 2022
CircleCI API (V2) Client Library in Go

go-circleci This client supports the CircleCI V2 API. Installation Installation can be done with a normal go get: go get -u github.com/grezar/go-circl

Riki Makita 30 Dec 12, 2022
HackerNews client made with Kyoto

HackerNews demo HackerNews demo client, made with kyoto Install Clone repo: git clone https://github.com/yuriizinets/kyoto-hn Go to the cloned directo

Yurii Zinets 9 Jul 2, 2022
Go client library for Geonames Web Services (geonames.org)

geonames Go client library for Geonames Web Services (geonames.org) Usage Register your username at geonames.org Export ENV Var or read the username f

Jakub Jarosz 3 Nov 23, 2022
Golang exaroton API client

Golang exaroton API client This is the unofficial Go implementation of this I'm still learning so expect badly design code PR are appreciated. Code In

Jiternos 2 Dec 14, 2021
Graphical small-internet client for windows, linux, MacOS X and BSDs. Supports gemini, http, https, gopher, finger.

Graphical small-internet client for windows, linux, MacOS X and BSDs. Supports gemini, http, https, gopher, finger.

Felix Queißner 570 Jan 1, 2023
Gore - Simple HTTP client for Go

GoRe (Go Requester) Simple HTTP client for Go Example g := gore.New( gore.With

Hadi Hidayat Hammurabi 8 Jan 21, 2022
The command-line client for Cloudflare Tunnel

Cloudflare Tunnel client Contains the command-line client for Cloudflare Tunnel, a tunneling daemon that proxies traffic from the Cloudflare network t

null 0 Feb 10, 2022
Allows verifying client's phone number

hone verification module for Elling - Elytrium Billing

Elytrium 1 Jun 4, 2022
Arduino Firmata client for golang

go-firmata A Golang wrapper for Firmata on Arduino Installation go get github.com/kraman/go-firmata Usage package main import ( "github.com/kraman/

Krishna Raman 42 Aug 11, 2022
Protocol Buffers to HTTP client code generator/converter

Proto2http Proto2http provides a code generation tool to convert your protocol buffers (.proto) files into invokable HTTP request. Usage proto2http -p

Kodiiing 6 Oct 23, 2022