Playwright for Go a browser automation library to control Chromium, Firefox and WebKit with a single API.

🎭 Playwright for

PkgGoDev License Go Report Card Build Status Join Slack Coverage Status Chromium version Firefox version WebKit version

API reference | Example recipes

Playwright is a Go library to automate Chromium, Firefox and WebKit with a single API. Playwright is built to enable cross-browser web automation that is ever-green, capable, reliable and fast.

Linux macOS Windows
Chromium 90.0.4392.0
WebKit 14.1
Firefox 85.0b5

Headless execution is supported for all the browsers on all platforms.

Installation

go get github.com/mxschmitt/playwright-go

Capabilities

Playwright is built to automate the broad and growing set of web browser capabilities used by Single Page Apps and Progressive Web Apps.

  • Scenarios that span multiple page, domains and iframes
  • Auto-wait for elements to be ready before executing actions (like click, fill)
  • Intercept network activity for stubbing and mocking network requests
  • Emulate mobile devices, geolocation, permissions
  • Support for web components via shadow-piercing selectors
  • Native input events for mouse and keyboard
  • Upload and download files

Example

The following example crawls the current top voted items from Hacker News.

package main

import (
	"fmt"
	"log"

	"github.com/mxschmitt/playwright-go"
)

func main() {
	pw, err := playwright.Run()
	if err != nil {
		log.Fatalf("could not start playwright: %v", err)
	}
	browser, err := pw.Chromium.Launch()
	if err != nil {
		log.Fatalf("could not launch browser: %v", err)
	}
	page, err := browser.NewPage()
	if err != nil {
		log.Fatalf("could not create page: %v", err)
	}
	if _, err = page.Goto("https://news.ycombinator.com"); err != nil {
		log.Fatalf("could not goto: %v", err)
	}
	entries, err := page.QuerySelectorAll(".athing")
	if err != nil {
		log.Fatalf("could not get entries: %v", err)
	}
	for i, entry := range entries {
		titleElement, err := entry.QuerySelector("td.title > a")
		if err != nil {
			log.Fatalf("could not get title element: %v", err)
		}
		title, err := titleElement.TextContent()
		if err != nil {
			log.Fatalf("could not get text content: %v", err)
		}
		fmt.Printf("%d: %s\n", i+1, title)
	}
	if err = browser.Close(); err != nil {
		log.Fatalf("could not close browser: %v", err)
	}
	if err = pw.Stop(); err != nil {
		log.Fatalf("could not stop Playwright: %v", err)
	}
}

More examples

How does it work?

Playwright is a Node.js library which uses:

  • Chrome DevTools Protocol to communicate with Chromium
  • Patched Firefox to communicate with Firefox
  • Patched WebKit to communicate with WebKit

These patches are based on the original sources of the browsers and don't modify the browser behaviour so the browsers are basically the same (see here) as you see them in the wild. The support for different programming languages is based on exposing a RPC server in the Node.js land which can be used to allow other languages to use Playwright without implementing all the custom logic:

The bridge between Node.js and the other languages is basically a Node.js runtime combined with Playwright which gets shipped for each of these languages (around 50MB) and then communicates over stdio to send the relevant commands. This will also download the pre-compiled browsers.

Is Playwright for Go ready?

We are ready for your feedback, but we are still covering Playwright Go with the tests.

Resources

Owner
Max Schmitt
Open Source enthusiast, security researcher and full stack web developer.
Max Schmitt
Comments
  • Feedback needed for future development

    Feedback needed for future development

    Hello,

    (upvote this https://github.com/microsoft/playwright/issues/6856 instead)

    since I've joined @Microsoft we are considering moving this package over to the organisation. By that we would ensure that all features form the original Playwright project are integrate and bugs are fixed. Currently since it was a private project it got unfortunately not that much attention since my time was limited. For that we are currently evaluating what the use-cases are and how many people in which scenarios are using it.

    Would be awesome if you could give us some feedback so you could help us with the decision. In more detail, answer the following questions:

    • For what are you using Playwright for Go?
    • Are you using it for personal use or in a company?
    • Do you have any future plans to extend the usage in the future?
    • Do you have any suggestions in terms of API design and if something should be changed for version 1.0?
    • What other libraries did you consider instead of Playwright for Go?
    • Where do you run it? e.g. Docker, Kubernetes, as a script etc.

    Thank you!

    (Thumbs up if you are interested in it)

  • response.Body does not return the byte array

    response.Body does not return the byte array

    This is issue might relates to #141

    The following is an example to reproduce this bug.

    package main
    
    import (
    	"fmt"
    	"log"
    	"time"
    
    	"github.com/mxschmitt/playwright-go"
    )
    
    func main() {
    	pw, err := playwright.Run()
    	if err != nil {
    		log.Fatalf("could not start playwright: %v", err)
    	}
    	browser, err := pw.Chromium.Launch(playwright.BrowserTypeLaunchOptions{Headless: playwright.Bool(false)})
    	if err != nil {
    		log.Fatalf("could not launch browser: %v", err)
    	}
    	page, err := browser.NewPage()
    	if err != nil {
    		log.Fatalf("could not create page: %v", err)
    	}
    	eventsChan := make(chan string)
    	go func(eventsChan chan string) {
    		for c := range eventsChan {
    			fmt.Println(c)
    		}
    	}(eventsChan)
    	page.On("response", func(response playwright.Response) {
    		// the following code block causes the problem
    		// body, err := response.Body()
    		// if err != nil {
    		// 	log.Fatalf("get body failed: %v", err)
    		// }
    		// fmt.Println("body len: ", len(body))
    
    		eventsChan <- fmt.Sprintf("%d %s", response.Status(), response.URL())
    	})
    	if _, err = page.Goto("https://news.ycombinator.com"); err != nil {
    		log.Fatalf("could not goto: %v", err)
    	}
    
    	time.Sleep(3 * time.Second)
    	if err = browser.Close(); err != nil {
    		log.Fatalf("could not close browser: %v", err)
    	}
    	if err = pw.Stop(); err != nil {
    		log.Fatalf("could not stop Playwright: %v", err)
    	}
    }
    
    

    Tested version go.mod

    go 1.16
    
    require github.com/mxschmitt/playwright-go v0.1100.0 // indirect
    
  • Version Packages

    Version Packages

    @kumaraditya303 Thanks for your great work and all your contributions to this repository. For your commit "roll to 1.14" that matches the latest version of Playwright, do you have any plan to version it or publish the release?

  • Improve versioning with Git tags / GH releases.

    Improve versioning with Git tags / GH releases.

    Hello, thanks for the lib It works great! I faced with some limitations:

    • I would like to avoid downloading https://github.com/mxschmitt/playwright-go/blob/c9d1531e0354a7f267237b3ac55595a8f18170e4/run.go#L29 after every container start. I assumed that playwright is already installed on the official mcr.microsoft.com/playwright:bionic images.

    • It looks like that playwright is installed from an external source https://github.com/mxschmitt/playwright-go/blob/c9d1531e0354a7f267237b3ac55595a8f18170e4/run.go#L15 not the official ones.

    • How can I install a different playwright version? The current is 1.7

  • [Feature Question] BrowserContext.backgroundPages() doesn't exist? :)

    [Feature Question] BrowserContext.backgroundPages() doesn't exist? :)

    BrowserContext in this example: https://playwright.dev/docs/chrome-extensions/ (from JavaScript) supports "backgroundPages", a way to get handles on extensions.

    Is this supported in Playwright? It isn't from what I can see at the moment from examining the "Generated structs".

    Do you know if this will get added or if there are plans for it to be added?

    Many thanks & appreciate your work, Neil

  • Missing types for page error events.

    Missing types for page error events.

    Hi, I can't see the type definition of the page errors. For example:

    page, _ := browserContext.NewPage()
    page.Once("pageerror", func(err ???) {
    	c.Logger().Errorf("an error on the page was detected: %s", err)
    })
    

    I also recommend using custom function types e.g

    type RequestFailedEventHandler = func(request *Request)
    
  • Getting fatal panic after upgrading to latest commit from release version

    Getting fatal panic after upgrading to latest commit from release version

    Hi,

    We are getting a fatal panic when going to a specific site, that we didn't get on v0.1400.0 Release, and also a commit version after that specified below.

    Latest commit tested that did not have this issue: 7e45483

    All commits we test that are after this commit, we end up with a fatal panic, which did not happen on the same site prior to this. A big difference I can see is that you go from Playwright 1.14.1 -> 1.16.0-next.. So maybe the problem is there?

    Here is the full panic message:

    events.js:377
          throw er; // Unhandled 'error' event
          ^
    
    Error: EPIPE: broken pipe, write
        at Socket._write (internal/net.js:55:25)
        at writeOrBuffer (internal/streams/writable.js:358:12)
        at Socket.Writable.write (internal/streams/writable.js:303:10)
        at Transport.send (C:\Users\osterman01\AppData\Local\ms-playwright-go\1.16.0-next-1631944242000\package\lib\protocol\transport.js:54:21)
        at DispatcherConnection.dispatcherConnection.onmessage (C:\Users\osterman01\AppData\Local\ms-playwright-go\1.16.0-next-1631944242000\package\lib\cli\driver.js:67:57)
        at DispatcherConnection.sendMessageToClient (C:\Users\osterman01\AppData\Local\ms-playwright-go\1.16.0-next-1631944242000\package\lib\dispatchers\dispatcher.js:186:10)
        at BrowserContextDispatcher._dispatchEvent (C:\Users\osterman01\AppData\Local\ms-playwright-go\1.16.0-next-1631944242000\package\lib\dispatchers\dispatcher.js:108:22)
        at CRBrowserContext.<anonymous> (C:\Users\osterman01\AppData\Local\ms-playwright-go\1.16.0-next-1631944242000\package\lib\dispatchers\browserContextDispatcher.js:102:81)
        at CRBrowserContext.emit (events.js:400:28)
        at FrameManager.requestReceivedResponse (C:\Users\osterman01\AppData\Local\ms-playwright-go\1.16.0-next-1631944242000\package\lib\server\frames.js:295:32)
    Emitted 'error' event on Socket instance at:
        at emitErrorNT (internal/streams/destroy.js:106:8)
        at errorOrDestroy (internal/streams/destroy.js:168:7)
        at onwriteError (internal/streams/writable.js:391:3)
        at processTicksAndRejections (internal/process/task_queues.js:84:21)
        at runNextTicks (internal/process/task_queues.js:64:3)
        at processImmediate (internal/timers.js:437:9) {
      errno: -4047,
      syscall: 'write',
      code: 'EPIPE'
    }
    
    Debugger finished with the exit code 0
    
  • Add missing functionality/methods

    Add missing functionality/methods

    Current report (node scripts/validate-interfaces.js):

    Missing API interface functions:

    • [x] BrowserContext.SetHTTPCredentials
    • [x] BrowserContext.StorageState
    • [x] ElementHandle.WaitForElementState
    • [x] ElementHandle.WaitForSelector
  • Always downloading Playwright driver

    Always downloading Playwright driver

    I noticed that in the current master branch it was always downloading the driver. I found the issue, in PlaywrightDriver.isUpToDateDriver It's checking the output of PW, for example:

    /Users/sam/Library/Caches/ms-playwright-go/1.16.0-next-1634703014000/playwright.sh --version
    Version 1.16.0-next
    

    With the constant:

    const playwrightCliVersion = "1.16.0-next-1634703014000"
    

    Using:

    	if bytes.Contains(output, []byte(d.Version)) {
    		return true, nil
    	}
    

    The extra -1634703014000 on the constant is the issue. I've fixed it locally by adding this to the end of isUpToDateDriver:

    	if strings.HasPrefix(string(output), "Version ") {
    		// Get rid of trailing new line
    		outputStr := strings.TrimSpace(string(output))
    		if len(outputStr) > 8 && strings.Contains(d.Version, outputStr[8:]) {
    			return true, nil
    		}
    	}
    

    I'll submit a PR with the change.

    If you have any suggestions for changes I'm happy to change.

  • [internal]: fix that there is XML in the doc comments

    [internal]: fix that there is XML in the doc comments

    • [ ] fix that there is XML in the doc comments -> it should not be there (was not correct since a few months)
    • [x] fix that there are csharp examples in the generated_interfaces.go
    • [x] Re-introduce EmulateMedia
  • Interface vs Struct

    Interface vs Struct

    Thanks for this great library and your hardwork to make it great.

    From https://pkg.go.dev/github.com/mxschmitt/playwright-go#pkg-index, the methods show out if the type is struct(like Playwright):

    type Playwright
        func Run(options ...*RunOptions) (*Playwright, error)
        func (c *Playwright) Dispose()
        func (p *Playwright) Stop() error
    

    But No method shows out if the type is defined as interface(like Page), we need to go to the type definition to find the available methods.

    type Page
    

    Is it possible to define the Page as struct?

    type Page struct {
        // non export fields
    }
    
    func (*Page) Click(selector string, options ...PageClickOptions) error
    func (*Page) Fill(selector, text string, options ...FrameFillOptions) error
    ... ...
    

    What do you think about it? Thanks.

  • How to keep browser opening by the end of the code running?

    How to keep browser opening by the end of the code running?

    Is there any way to make browser stay open after a test is finished? (Chromium MacOS ARM version) Even i use page.Pause() or other WaitFor method, browser still auto close after about 1 min.

    Update: use local Chrome or Edge on MacOS ARM will NOT auto close. Also chromium works fine on Windows. it may some kind of bug on Chromium MacOS arm version.

  • how to waiting multiple api responsed in go-playwright ,like javascript promise.all

    how to waiting multiple api responsed in go-playwright ,like javascript promise.all

    I wirte an go function to waiting some api responsed and then to do something,here is my code

    func waitResponse(dashboardIds []int, page playwright.Page) {
    	responses := [5]playwright.Response{}
    	wg := sync.WaitGroup{}
    	baseUrl := "https://example.com"
    	for index, v := range dashboardIds {
    		wg.Add(1)
    		url := fmt.Sprintf("%s/%d?dashboard_id=114", baseUrl, v)
    		idx := index
    		v := v
    		go func() {
    			log.Printf("start request %s\n", url) // 1
    			response := page.WaitForResponse(url)
    			log.Printf("goroutine get response from %s, index is %d\n", url,idx) // 2
    			resBody, _ := response.Body()
    			responses[idx] = response
    			defer wg.Done()
    		}()
    		page.On("response", func(res playwright.Response) {
    			if res.URL() == url {
    				log.Printf("listen get response from %s", url) //3
    			}
    		})
    	}
    	wg.Wait()
    	log.Printf("all url responded") // 4
    }
    

    after run this function,I find 1、3 print every time,but 2 is only print one time(idx is 0), is there something wrong in my code?pls help me,thinks!

    I want comment 4 could print

  • could not download driver

    could not download driver

    trying to install the browsers and OS dependencies: % playwright install --with-deps
    2022/11/28 16:08:57 could not download driver: could not check if driver is up2date: could not run driver: exit status 1

    it seems the baseURL get 404. baseURL = "https://playwright.azureedge.net/builds/driver"

    any idea?

  • Audio not being muted in browser?

    Audio not being muted in browser?

    Hi everyone,

    Maybe this is a dumb question, but isn't audio supposed to be muted in browser instances launched by Playwright by default? Whenever video playback occurs during automation, I can still hear the audio channels for it.

    Is there a special way to disable this audio, if it isn't done automatically for us?

Generate PlantUML diagrams from Chrome or Firefox network inspections

hoofli Generate PlantUML diagrams from Chrome or Firefox network inspections This tool reads browser HAR files stored on your local disk and transform

Nov 15, 2022
End to end functional test and automation framework
End to end functional test and automation framework

Declarative end to end functional testing (endly) This library is compatible with Go 1.12+ Please refer to CHANGELOG.md if you encounter breaking chan

Jan 6, 2023
A Devtools driver for web automation and scraping

Overview Documentation | API reference Rod is a high-level driver directly based on DevTools Protocol. It's designed for web automation and scraping.

Dec 30, 2022
Ritchie CLI is an open-source tool that allows to create, store and share any kind of automation, executing them through command lines, to run operations or start workflows ⚙️ 🖥 💡
Ritchie CLI is an open-source tool that allows to create, store and share any kind of automation, executing them through command lines, to run operations or start workflows ⚙️ 🖥 💡

Table of contents 1. About 2. Getting Started i. Installation ii. Initialize rit locally iii. Add your first formulas repository iv. Run the Hello Wor

Dec 29, 2022
Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go.
Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go.

GoConvey is awesome Go testing Welcome to GoConvey, a yummy Go testing tool for gophers. Works with go test. Use it in the terminal or browser accordi

Dec 30, 2022
Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go.
Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go.

GoConvey is awesome Go testing Welcome to GoConvey, a yummy Go testing tool for gophers. Works with go test. Use it in the terminal or browser accordi

Dec 30, 2022
Selenium Hub successor running browsers within containers. Scalable, immutable, self hosted Selenium-Grid on any platform with single binary.
Selenium Hub successor running browsers within containers. Scalable, immutable, self hosted Selenium-Grid on any platform with single binary.

Selenoid Selenoid is a powerful implementation of Selenium hub using Docker containers to launch browsers. Features One-command Installation Start bro

Jan 5, 2023
fuzzer for a single http parameter which checks if the response does/does not contain a certain given string

single http parameter fuzzer DISCLAIMER: ONLY USE THIS PROGRAM ON TARGETS YOU HAVE PERMISSION TO FUZZ! Initially used as a "poor man's" http fuzzer fo

Dec 19, 2021
A Go library help testing your RESTful API application

RESTit A Go micro-framework to help writing RESTful API integration test Package RESTit provides helps to those who want to write an integration test

Oct 28, 2022
Fortio load testing library, command line tool, advanced echo server and web UI in go (golang). Allows to specify a set query-per-second load and record latency histograms and other useful stats.
Fortio load testing library, command line tool, advanced echo server and web UI in go (golang). Allows to specify a set query-per-second load and record latency histograms and other useful stats.

Fortio Fortio (Φορτίο) started as, and is, Istio's load testing tool and now graduated to be its own project. Fortio is also used by, among others, Me

Jan 2, 2023
End-to-end HTTP and REST API testing for Go.

httpexpect Concise, declarative, and easy to use end-to-end HTTP and REST API testing for Go (golang). Basically, httpexpect is a set of chainable bui

Jan 5, 2023
Lightweight service virtualization/API simulation tool for developers and testers
Lightweight service virtualization/API simulation tool for developers and testers

API simulations for development and testing Hoverfly is a lightweight, open source API simulation tool. Using Hoverfly, you can create realistic simul

Dec 28, 2022
This repository includes consumer driven contract test for provider, unit test and counter api.

This repository includes consumer driven contract test for provider, unit test and counter api.

Feb 1, 2022
A toolkit with common assertions and mocks that plays nicely with the standard library

Testify - Thou Shalt Write Tests ℹ️ We are working on testify v2 and would love to hear what you'd like to see in it, have your say here: https://cutt

Dec 30, 2022
HTTP load testing tool and library. It's over 9000!
HTTP load testing tool and library. It's over 9000!

Vegeta Vegeta is a versatile HTTP load testing tool built out of a need to drill HTTP services with a constant request rate. It can be used both as a

Jan 7, 2023
A library for generating fake data such as names, addresses, and phone numbers.

faker Faker is a library for generating fake data such as names, addresses, and phone numbers. It is a (mostly) API-compatible port of Ruby Faker gem

Jan 4, 2023
A WebDriver client and acceptance testing library for Go
A WebDriver client and acceptance testing library for Go

Agouti Agouti is a library for writing browser-based acceptance tests in Google Go. It provides Gomega matchers and plays nicely with Ginkgo or Spec.

Dec 26, 2022
A simple and expressive HTTP server mocking library for end-to-end tests in Go.

mockhttp A simple and expressive HTTP server mocking library for end-to-end tests in Go. Installation go get -d github.com/americanas-go/mockhttp Exa

Dec 19, 2021
Expressive end-to-end HTTP API testing made easy in Go

baloo Expressive and versatile end-to-end HTTP API testing made easy in Go (golang), built on top of gentleman HTTP client toolkit. Take a look to the

Dec 13, 2022