Skip to content

Commit

Permalink
Roll to Playwright v1.38.1 (#373)
Browse files Browse the repository at this point in the history
* chore: roll to playwright v1.38.1
* fix: GetByRole options etc.
* feat: uninstall driver and browsers
  • Loading branch information
canstand committed Oct 9, 2023
1 parent 8575a75 commit c3d215b
Show file tree
Hide file tree
Showing 25 changed files with 846 additions and 146 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
[![PkgGoDev](https://pkg.go.dev/badge/github.com/playwright-community/playwright-go)](https://pkg.go.dev/github.com/playwright-community/playwright-go)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](http://opensource.org/licenses/MIT)
[![Go Report Card](https://goreportcard.com/badge/github.com/playwright-community/playwright-go)](https://goreportcard.com/report/github.com/playwright-community/playwright-go) ![Build Status](https://github.com/playwright-community/playwright-go/workflows/Go/badge.svg)
[![Join Slack](https://img.shields.io/badge/join-slack-infomational)](https://aka.ms/playwright-slack) [![Coverage Status](https://coveralls.io/repos/github/playwright-community/playwright-go/badge.svg?branch=main)](https://coveralls.io/github/playwright-community/playwright-go?branch=main) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-116.0.5845.82-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-115.0-blue.svg?logo=mozilla-firefox)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[![WebKit version](https://img.shields.io/badge/webkit-17.0-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop -->
[![Join Slack](https://img.shields.io/badge/join-slack-infomational)](https://aka.ms/playwright-slack) [![Coverage Status](https://coveralls.io/repos/github/playwright-community/playwright-go/badge.svg?branch=main)](https://coveralls.io/github/playwright-community/playwright-go?branch=main) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-117.0.5938.62-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-117.0-blue.svg?logo=mozilla-firefox)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[![WebKit version](https://img.shields.io/badge/webkit-17.0-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop -->

[API reference](https://playwright.dev/docs/api/class-playwright) | [Example recipes](https://github.com/playwright-community/playwright-go/tree/main/examples)

Playwright is a Go library to automate [Chromium](https://www.chromium.org/Home), [Firefox](https://www.mozilla.org/en-US/firefox/new/) and [WebKit](https://webkit.org/) 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 <!-- GEN:chromium-version -->116.0.5845.82<!-- GEN:stop --> ||||
| Chromium <!-- GEN:chromium-version -->117.0.5938.62<!-- GEN:stop --> ||||
| WebKit <!-- GEN:webkit-version -->17.0<!-- GEN:stop --> ||||
| Firefox <!-- GEN:firefox-version -->115.0<!-- GEN:stop --> ||||
| Firefox <!-- GEN:firefox-version -->117.0<!-- GEN:stop --> ||||

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

Expand Down
8 changes: 8 additions & 0 deletions browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ func (b *browserImpl) NewContext(options ...BrowserNewContextOptions) (BrowserCo
if len(options) == 1 {
option = options[0]
}
if option.AcceptDownloads != nil {
if *option.AcceptDownloads {
overrides["acceptDownloads"] = "accept"
} else {
overrides["acceptDownloads"] = "deny"
}
options[0].AcceptDownloads = nil
}
if option.ExtraHttpHeaders != nil {
overrides["extraHTTPHeaders"] = serializeMapToNameAndValue(options[0].ExtraHttpHeaders)
options[0].ExtraHttpHeaders = nil
Expand Down
21 changes: 20 additions & 1 deletion browser_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ func (b *browserContextImpl) onClose() {
b.Emit("close", b)
}

func (b *browserContextImpl) onPage(page *pageImpl) {
func (b *browserContextImpl) onPage(page Page) {
b.Lock()
b.pages = append(b.pages, page)
b.Unlock()
Expand All @@ -454,6 +454,7 @@ func (b *browserContextImpl) onRoute(route *routeImpl) {
go func() {
b.Lock()
defer b.Unlock()
route.context = b
routes := make([]*routeHandlerEntry, len(b.routes))
copy(routes, b.routes)

Expand Down Expand Up @@ -578,10 +579,15 @@ func (b *browserContextImpl) OnResponse(fn func(Response)) {
b.On("response", fn)
}

func (b *browserContextImpl) OnWebError(fn func(WebError)) {
b.On("weberror", fn)
}

func newBrowserContext(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *browserContextImpl {
bt := &browserContextImpl{
timeoutSettings: newTimeoutSettings(nil),
pages: make([]Page, 0),
backgroundPages: make([]Page, 0),
routes: make([]*routeHandlerEntry, 0),
bindings: make(map[string]BindingCallFunction),
harRecorders: make(map[string]harRecordingMetadata),
Expand Down Expand Up @@ -639,6 +645,19 @@ func newBrowserContext(parent *channelOwner, objectType string, guid string, ini
}
}()
})
bt.channel.On(
"pageError", func(ev map[string]interface{}) {
err := &Error{}
remapMapToStruct(ev["error"].(map[string]interface{})["error"], err)
page := fromNullableChannel(ev["page"])
if page != nil {
bt.Emit("weberror", newWebError(page.(*pageImpl), err))
page.(*pageImpl).Emit("pageerror", err)
} else {
bt.Emit("weberror", newWebError(nil, err))
}
},
)
bt.channel.On("request", func(ev map[string]interface{}) {
request := fromChannel(ev["request"]).(*requestImpl)
page := fromNullableChannel(ev["page"])
Expand Down
8 changes: 8 additions & 0 deletions browser_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ func (b *browserTypeImpl) LaunchPersistentContext(userDataDir string, options ..
if err != nil {
return nil, fmt.Errorf("can not convert options: %w", err)
}
if options[0].AcceptDownloads != nil {
if *options[0].AcceptDownloads {
overrides["acceptDownloads"] = "accept"
} else {
overrides["acceptDownloads"] = "deny"
}
options[0].AcceptDownloads = nil
}
if options[0].ExtraHttpHeaders != nil {
overrides["extraHTTPHeaders"] = serializeMapToNameAndValue(options[0].ExtraHttpHeaders)
options[0].ExtraHttpHeaders = nil
Expand Down
2 changes: 1 addition & 1 deletion examples/end-to-end-testing/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func main() {

// Adding a todo entry (click in the input, enter the todo title and press the Enter key)
assertErrorToNilf("could not click: %v", page.Locator("input.new-todo").Click())
assertErrorToNilf("could not type: %v", page.Locator("input.new-todo").Type(todoName))
assertErrorToNilf("could not type: %v", page.Locator("input.new-todo").Fill(todoName))
assertErrorToNilf("could not press: %v", page.Locator("input.new-todo").Press("Enter"))

// After adding 1 there should be 1 entry in the list
Expand Down
32 changes: 27 additions & 5 deletions frame.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package playwright

import (
"errors"
"fmt"
"os"
"sync"
Expand Down Expand Up @@ -138,7 +139,10 @@ func (f *frameImpl) waitForLoadStateImpl(state string, timeout *float64, cb func
if f.loadStates.Has(state) {
return nil
}
waiter := f.setNavigationWaiter(timeout)
waiter, err := f.setNavigationWaiter(timeout)
if err != nil {
return err
}
waiter.WaitForEvent(f, "loadstate", func(payload interface{}) bool {
gotState := payload.(string)
return gotState == state
Expand All @@ -153,6 +157,9 @@ func (f *frameImpl) waitForLoadStateImpl(state string, timeout *float64, cb func
}

func (f *frameImpl) WaitForURL(url interface{}, options ...FrameWaitForURLOptions) error {
if f.page == nil {
return errors.New("frame is detached")
}
matcher := newURLMatcher(url, f.page.browserContext.options.BaseURL)
if matcher.Matches(f.URL()) {
state := "load"
Expand All @@ -179,6 +186,9 @@ func (f *frameImpl) WaitForURL(url interface{}, options ...FrameWaitForURLOption
}

func (f *frameImpl) ExpectNavigation(cb func() error, options ...FrameExpectNavigationOptions) (Response, error) {
if f.page == nil {
return nil, errors.New("frame is detached")
}
option := FrameExpectNavigationOptions{}
if len(options) == 1 {
option = options[0]
Expand All @@ -201,7 +211,10 @@ func (f *frameImpl) ExpectNavigation(cb func() error, options ...FrameExpectNavi
}
return matcher == nil || matcher.Matches(ev["url"].(string))
}
waiter := f.setNavigationWaiter(option.Timeout)
waiter, err := f.setNavigationWaiter(option.Timeout)
if err != nil {
return nil, err
}

eventData, err := waiter.WaitForEvent(f, "navigated", predicate).RunAndWait(cb)
if err != nil || eventData == nil {
Expand All @@ -223,7 +236,10 @@ func (f *frameImpl) ExpectNavigation(cb func() error, options ...FrameExpectNavi
return nil, nil
}

func (f *frameImpl) setNavigationWaiter(timeout *float64) *waiter {
func (f *frameImpl) setNavigationWaiter(timeout *float64) (*waiter, error) {
if f.page == nil {
return nil, errors.New("page does not exist")
}
waiter := newWaiter()
if timeout != nil {
waiter.WithTimeout(*timeout)
Expand All @@ -239,7 +255,7 @@ func (f *frameImpl) setNavigationWaiter(timeout *float64) *waiter {
}
return false
})
return waiter
return waiter, nil
}

func (f *frameImpl) onFrameNavigated(ev map[string]interface{}) {
Expand All @@ -248,7 +264,8 @@ func (f *frameImpl) onFrameNavigated(ev map[string]interface{}) {
f.name = ev["name"].(string)
f.Unlock()
f.Emit("navigated", ev)
if f.page != nil {
_, ok := ev["error"]
if !ok && f.page != nil {
f.page.Emit("framenavigated", f)
}
}
Expand All @@ -258,6 +275,11 @@ func (f *frameImpl) onLoadState(ev map[string]interface{}) {
add := ev["add"].(string)
f.loadStates.Add(add)
f.Emit("loadstate", add)
if f.parentFrame == nil && f.page != nil {
if add == "load" || add == "domcontentloaded" {
f.Page().Emit(add, f.page)
}
}
} else if ev["remove"] != nil {
remove := ev["remove"].(string)
f.loadStates.Remove(remove)
Expand Down
60 changes: 47 additions & 13 deletions generated-interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ type BrowserContext interface {
// most cases).
OnPage(fn func(Page))

// Emitted when exception is unhandled in any of the pages in this context. To listen for errors from a particular
// page, use [Page.OnPageError] instead.
OnWebError(fn func(WebError))

// Emitted when a request is issued from any pages created through this context. The [request] object is read-only. To
// only listen for requests from a particular page, use [Page.OnRequest].
// In order to intercept and mutate requests, see [BrowserContext.Route] or [Page.Route].
Expand Down Expand Up @@ -585,7 +589,7 @@ type Dialog interface {

// [Download] objects are dispatched by page via the [Page.OnDownload] event.
// All the downloaded files belonging to the browser context are deleted when the browser context is closed.
// Download event is emitted once the download starts. Download path becomes available once download completes:
// Download event is emitted once the download starts. Download path becomes available once download completes.
type Download interface {
// Cancels a download. Will not fail if the download is already finished or canceled. Upon successful cancellations,
// `download.failure()` would resolve to `canceled`.
Expand Down Expand Up @@ -746,7 +750,7 @@ type ElementHandle interface {
// error. However, if the element is inside the `<label>` element that has an associated
// [control], the control will be filled
// instead.
// To send fine-grained keyboard events, use [ElementHandle.Type].
// To send fine-grained keyboard events, use [Locator.PressSequentially].
//
// value: Value to set for the `<input>`, `<textarea>` or `[contenteditable]` element.
//
Expand Down Expand Up @@ -946,6 +950,8 @@ type ElementHandle interface {
// text.
// To press a special key, like `Control` or `ArrowDown`, use [ElementHandle.Press].
//
// Deprecated: In most cases, you should use [Locator.Fill] instead. You only need to press keys one by one if there is special keyboard handling on the page - in this case use [Locator.PressSequentially].
//
// text: A text to type into a focused element.
Type(text string, options ...ElementHandleTypeOptions) error

Expand Down Expand Up @@ -1191,7 +1197,7 @@ type Frame interface {
// error. However, if the element is inside the `<label>` element that has an associated
// [control], the control will be filled
// instead.
// To send fine-grained keyboard events, use [Frame.Type].
// To send fine-grained keyboard events, use [Locator.PressSequentially].
//
// Deprecated: Use locator-based [Locator.Fill] instead. Read more about [locators].
//
Expand Down Expand Up @@ -1621,13 +1627,11 @@ type Frame interface {
// to send fine-grained keyboard events. To fill values in form fields, use [Frame.Fill].
// To press a special key, like `Control` or `ArrowDown`, use [Keyboard.Press].
//
// Deprecated: Use locator-based [Locator.Type] instead. Read more about [locators].
// Deprecated: In most cases, you should use [Locator.Fill] instead. You only need to press keys one by one if there is special keyboard handling on the page - in this case use [Locator.PressSequentially].
//
// 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
// used.
// 2. text: A text to type into a focused element.
//
// [locators]: https://playwright.dev/docs/locators
Type(selector string, text string, options ...FrameTypeOptions) error

// This method checks an element matching “selector” by performing the following steps:
Expand Down Expand Up @@ -1904,6 +1908,7 @@ type Keyboard interface {
// text: Sets input to the specified text value.
InsertText(text string) error

// **NOTE** In most cases, you should use [Locator.Press] instead.
// “key” can specify the intended
// [keyboardEvent.Key] value or a single character
// to generate the text for. A superset of the “key” values can be found
Expand All @@ -1924,6 +1929,8 @@ type Keyboard interface {
// [here]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
Press(key string, options ...KeyboardPressOptions) error

// **NOTE** In most cases, you should use [Locator.Fill] instead. You only need to press keys one by one if there is
// special keyboard handling on the page - in this case use [Locator.PressSequentially].
// Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text.
// To press a special key, like `Control` or `ArrowDown`, use [Keyboard.Press].
//
Expand Down Expand Up @@ -2164,7 +2171,7 @@ type Locator interface {
// error. However, if the element is inside the `<label>` element that has an associated
// [control], the control will be filled
// instead.
// To send fine-grained keyboard events, use [Locator.Type].
// To send fine-grained keyboard events, use [Locator.PressSequentially].
//
// value: Value to set for the `<input>`, `<textarea>` or `[contenteditable]` element.
//
Expand Down Expand Up @@ -2380,6 +2387,15 @@ type Locator interface {
// [here]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
Press(key string, options ...LocatorPressOptions) error

// **NOTE** In most cases, you should use [Locator.Fill] instead. You only need to press keys one by one if there is
// special keyboard handling on the page.
// Focuses the element, and then sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the
// text.
// To press a special key, like `Control` or `ArrowDown`, use [Locator.Press].
//
// text: String of characters to sequentially press into a focused element.
PressSequentially(text string, options ...LocatorPressSequentiallyOptions) error

// Take a screenshot of the element matching the locator.
//
// # Details
Expand Down Expand Up @@ -2487,12 +2503,12 @@ type Locator interface {
// [`node.textContent`]: https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent
TextContent(options ...LocatorTextContentOptions) (string, error)

// **NOTE** In most cases, you should use [Locator.Fill] instead. You only need to type characters if there is special
// keyboard handling on the page.
// Focuses the element, and then sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the
// text.
// To press a special key, like `Control` or `ArrowDown`, use [Locator.Press].
//
// Deprecated: In most cases, you should use [Locator.Fill] instead. You only need to press keys one by one if there is special keyboard handling on the page - in this case use [Locator.PressSequentially].
//
// text: A text to type into a focused element.
Type(text string, options ...LocatorTypeOptions) error

Expand Down Expand Up @@ -2977,7 +2993,7 @@ type Page interface {
// error. However, if the element is inside the `<label>` element that has an associated
// [control], the control will be filled
// instead.
// To send fine-grained keyboard events, use [Page.Type].
// To send fine-grained keyboard events, use [Locator.PressSequentially].
//
// Deprecated: Use locator-based [Locator.Fill] instead. Read more about [locators].
//
Expand Down Expand Up @@ -3512,13 +3528,11 @@ type Page interface {
// send fine-grained keyboard events. To fill values in form fields, use [Page.Fill].
// To press a special key, like `Control` or `ArrowDown`, use [Keyboard.Press].
//
// Deprecated: Use locator-based [Locator.Type] instead. Read more about [locators].
// Deprecated: In most cases, you should use [Locator.Fill] instead. You only need to press keys one by one if there is special keyboard handling on the page - in this case use [Locator.PressSequentially].
//
// 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be
// used.
// 2. text: A text to type into a focused element.
//
// [locators]: https://playwright.dev/docs/locators
Type(selector string, text string, options ...PageTypeOptions) error

// This method unchecks an element matching “selector” by performing the following steps:
Expand Down Expand Up @@ -3746,6 +3760,14 @@ type Request interface {
Failure() error

// Returns the [Frame] that initiated this request.
//
// # Details
//
// Note that in some cases the frame is not available, and this method will throw.
// - When request originates in the Service Worker. You can use `request.serviceWorker()` to check that.
// - When navigation request is issued before the corresponding frame is created. You can use
// [Request.IsNavigationRequest] to check that.
// Here is an example that handles all the cases:
Frame() Frame

// An object with the request HTTP headers. The header names are lower-cased. Note that this method does not return
Expand All @@ -3763,6 +3785,8 @@ type Request interface {
HeaderValue(name string) (string, error)

// Whether this request is driving frame's navigation.
// Some navigation requests are issued before the corresponding frame is created, and therefore do not have
// [Request.Frame] available.
IsNavigationRequest() bool

// Request's method (GET, POST, etc.)
Expand Down Expand Up @@ -3982,6 +4006,16 @@ type Video interface {
SaveAs(path string) error
}

// [WebError] class represents an unhandled exeception thrown in the page. It is dispatched via the
// [BrowserContext.OnWebError] event.
type WebError interface {
// The page that produced this unhandled exception, if any.
Page() Page

// Unhandled error that was thrown.
Error() error
}

// The [WebSocket] class represents websocket connections in the page.
type WebSocket interface {
// Fired when the websocket closes.
Expand Down

0 comments on commit c3d215b

Please sign in to comment.