Skip to content

Commit

Permalink
chore: roll to Playwright v1.48.1 (#500)
Browse files Browse the repository at this point in the history
  • Loading branch information
canstand authored Oct 25, 2024
1 parent e8c12f4 commit 3e8cb5f
Show file tree
Hide file tree
Showing 27 changed files with 1,215 additions and 808 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-129.0.6668.29-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-130.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-18.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-130.0.6723.31-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-131.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-18.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 -->129.0.6668.29<!-- GEN:stop --> ||||
| Chromium <!-- GEN:chromium-version -->130.0.6723.31<!-- GEN:stop --> ||||
| WebKit <!-- GEN:webkit-version -->18.0<!-- GEN:stop --> ||||
| Firefox <!-- GEN:firefox-version -->130.0<!-- GEN:stop --> ||||
| Firefox <!-- GEN:firefox-version -->131.0<!-- GEN:stop --> ||||

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

Expand Down
4 changes: 2 additions & 2 deletions browser_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (b *browserContextImpl) SetDefaultNavigationTimeout(timeout float64) {

func (b *browserContextImpl) setDefaultNavigationTimeoutImpl(timeout *float64) {
b.timeoutSettings.SetDefaultNavigationTimeout(timeout)
b.channel.SendNoReply("setDefaultNavigationTimeoutNoReply", map[string]interface{}{
b.channel.SendNoReply("setDefaultNavigationTimeoutNoReply", true, map[string]interface{}{
"timeout": timeout,
})
}
Expand All @@ -55,7 +55,7 @@ func (b *browserContextImpl) SetDefaultTimeout(timeout float64) {

func (b *browserContextImpl) setDefaultTimeoutImpl(timeout *float64) {
b.timeoutSettings.SetDefaultTimeout(timeout)
b.channel.SendNoReply("setDefaultTimeoutNoReply", map[string]interface{}{
b.channel.SendNoReply("setDefaultTimeoutNoReply", true, map[string]interface{}{
"timeout": timeout,
})
}
Expand Down
6 changes: 3 additions & 3 deletions browser_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (b *browserTypeImpl) Connect(wsEndpoint string, options ...BrowserTypeConne
if err != nil {
return nil, err
}
jsonPipe := fromChannel(pipe.(map[string]interface{})["pipe"]).(*jsonPipe)
jsonPipe := fromChannel(pipe["pipe"]).(*jsonPipe)
connection := newConnection(jsonPipe, localUtils)

playwright, err := connection.Start()
Expand Down Expand Up @@ -146,9 +146,9 @@ func (b *browserTypeImpl) ConnectOverCDP(endpointURL string, options ...BrowserT
if err != nil {
return nil, err
}
browser := fromChannel(response.(map[string]interface{})["browser"]).(*browserImpl)
browser := fromChannel(response["browser"]).(*browserImpl)
b.didLaunchBrowser(browser)
if defaultContext, ok := response.(map[string]interface{})["defaultContext"]; ok {
if defaultContext, ok := response["defaultContext"]; ok {
context := fromChannel(defaultContext).(*browserContextImpl)
b.didCreateContext(context, nil, nil)
}
Expand Down
43 changes: 12 additions & 31 deletions channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,27 @@ func (c *channel) MarshalJSON() ([]byte, error) {

func (c *channel) Send(method string, options ...interface{}) (interface{}, error) {
return c.connection.WrapAPICall(func() (interface{}, error) {
return c.innerSend(method, false, options...)
}, false)
return c.innerSend(method, options...).GetResultValue()
}, c.owner.isInternalType)
}

func (c *channel) SendReturnAsDict(method string, options ...interface{}) (interface{}, error) {
return c.connection.WrapAPICall(func() (interface{}, error) {
return c.innerSend(method, true, options...)
}, true)
func (c *channel) SendReturnAsDict(method string, options ...interface{}) (map[string]interface{}, error) {
ret, err := c.connection.WrapAPICall(func() (interface{}, error) {
return c.innerSend(method, options...).GetResult()
}, c.owner.isInternalType)
return ret.(map[string]interface{}), err
}

func (c *channel) innerSend(method string, returnAsDict bool, options ...interface{}) (interface{}, error) {
func (c *channel) innerSend(method string, options ...interface{}) *protocolCallback {
params := transformOptions(options...)
callback, err := c.connection.sendMessageToServer(c.owner, method, params, false)
if err != nil {
return nil, err
}
result, err := callback.GetResult()
if err != nil {
return nil, err
}
if result == nil {
return nil, nil
}
if returnAsDict {
return result, nil
}
if mapV, ok := result.(map[string]interface{}); ok && len(mapV) <= 1 {
for key := range mapV {
return mapV[key], nil
}
return nil, nil
}
return result, nil
return c.connection.sendMessageToServer(c.owner, method, params, false)
}

func (c *channel) SendNoReply(method string, options ...interface{}) {
func (c *channel) SendNoReply(method string, isInternal bool, options ...interface{}) {
params := transformOptions(options...)
_, err := c.connection.WrapAPICall(func() (interface{}, error) {
return c.connection.sendMessageToServer(c.owner, method, params, true)
}, false)
return c.connection.sendMessageToServer(c.owner, method, params, true).GetResult()
}, isInternal)
if err != nil {
logger.Printf("SendNoReply failed: %v\n", err)
}
Expand Down
11 changes: 8 additions & 3 deletions channel_owner.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type channelOwner struct {
initializer map[string]interface{}
parent *channelOwner
wasCollected bool
isInternalType bool
}

func (c *channelOwner) dispose(reason ...string) {
Expand Down Expand Up @@ -48,7 +49,7 @@ func (c *channelOwner) setEventSubscriptionMapping(mapping map[string]string) {
func (c *channelOwner) updateSubscription(event string, enabled bool) {
protocolEvent, ok := c.eventToSubscriptionMapping[event]
if ok {
c.channel.SendNoReply("updateSubscription", map[string]interface{}{
c.channel.SendNoReply("updateSubscription", true, map[string]interface{}{
"event": protocolEvent,
"enabled": enabled,
})
Expand Down Expand Up @@ -95,18 +96,22 @@ func (c *channelOwner) createChannelOwner(self interface{}, parent *channelOwner
c.eventToSubscriptionMapping = map[string]string{}
}

func (c *channelOwner) markAsInternalType() {
c.isInternalType = true
}

type rootChannelOwner struct {
channelOwner
}

func (r *rootChannelOwner) initialize() (*Playwright, error) {
result, err := r.channel.Send("initialize", map[string]interface{}{
ret, err := r.channel.SendReturnAsDict("initialize", map[string]interface{}{
"sdkLanguage": "javascript",
})
if err != nil {
return nil, err
}
return fromChannel(result).(*Playwright), nil
return fromChannel(ret["playwright"]).(*Playwright), nil
}

func newRootChannelOwner(connection *connection) *rootChannelOwner {
Expand Down
97 changes: 59 additions & 38 deletions connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ var (
apiNameTransform = regexp.MustCompile(`(?U)\(\*(.+)(Impl)?\)`)
)

type result struct {
Data interface{}
Error error
}

type connection struct {
transport transport
apiZone sync.Map
Expand Down Expand Up @@ -102,13 +97,9 @@ func (c *connection) Dispatch(msg *message) {
return
}
if msg.Error != nil {
cb.SetResult(result{
Error: parseError(msg.Error.Error),
})
cb.SetError(parseError(msg.Error.Error))
} else {
cb.SetResult(result{
Data: c.replaceGuidsWithChannels(msg.Result),
})
cb.SetResult(c.replaceGuidsWithChannels(msg.Result).(map[string]interface{}))
}
return
}
Expand Down Expand Up @@ -191,16 +182,20 @@ func (c *connection) replaceGuidsWithChannels(payload interface{}) interface{} {
return payload
}

func (c *connection) sendMessageToServer(object *channelOwner, method string, params interface{}, noReply bool) (*protocolCallback, error) {
func (c *connection) sendMessageToServer(object *channelOwner, method string, params interface{}, noReply bool) (cb *protocolCallback) {
cb = newProtocolCallback(noReply, c.abort)

if err := c.closedError.Get(); err != nil {
return nil, err
cb.SetError(err)
return
}
if object.wasCollected {
return nil, errors.New("The object has been collected to prevent unbounded heap growth.")
cb.SetError(errors.New("The object has been collected to prevent unbounded heap growth."))
return
}

id := c.lastID.Add(1)
cb, _ := c.callbacks.LoadOrStore(id, newProtocolCallback(noReply, c.abort))
c.callbacks.Store(id, cb)
var (
metadata = make(map[string]interface{}, 0)
stack = make([]map[string]interface{}, 0)
Expand All @@ -225,10 +220,11 @@ func (c *connection) sendMessageToServer(object *channelOwner, method string, pa
}

if err := c.transport.Send(message); err != nil {
return nil, fmt.Errorf("could not send message: %w", err)
cb.SetError(fmt.Errorf("could not send message: %w", err))
return
}

return cb, nil
return
}

func (c *connection) setInTracing(isTracing bool) {
Expand Down Expand Up @@ -327,41 +323,66 @@ func fromNullableChannel(v interface{}) interface{} {
}

type protocolCallback struct {
callback chan result
noReply bool
abort <-chan struct{}
done chan struct{}
noReply bool
abort <-chan struct{}
once sync.Once
value map[string]interface{}
err error
}

func (pc *protocolCallback) SetResult(r result) {
func (pc *protocolCallback) setResultOnce(result map[string]interface{}, err error) {
pc.once.Do(func() {
pc.value = result
pc.err = err
close(pc.done)
})
}

func (pc *protocolCallback) waitResult() {
if pc.noReply {
return
}
select {
case <-pc.done: // wait for result
return
case <-pc.abort:
select {
case pc.callback <- r:
case <-pc.done:
return
default:
pc.err = errors.New("Connection closed")
return
}
return
case pc.callback <- r:
}
}

func (pc *protocolCallback) GetResult() (interface{}, error) {
if pc.noReply {
return nil, nil
func (pc *protocolCallback) SetError(err error) {
pc.setResultOnce(nil, err)
}

func (pc *protocolCallback) SetResult(result map[string]interface{}) {
pc.setResultOnce(result, nil)
}

func (pc *protocolCallback) GetResult() (map[string]interface{}, error) {
pc.waitResult()
return pc.value, pc.err
}

// GetResultValue returns value if the map has only one element
func (pc *protocolCallback) GetResultValue() (interface{}, error) {
pc.waitResult()
if len(pc.value) == 0 { // empty map treated as nil
return nil, pc.err
}
select {
case result := <-pc.callback:
return result.Data, result.Error
case <-pc.abort:
select {
case result := <-pc.callback:
return result.Data, result.Error
default:
return nil, errors.New("Connection closed")
if len(pc.value) == 1 {
for key := range pc.value {
return pc.value[key], pc.err
}
}

return pc.value, pc.err
}

func newProtocolCallback(noReply bool, abort <-chan struct{}) *protocolCallback {
Expand All @@ -372,7 +393,7 @@ func newProtocolCallback(noReply bool, abort <-chan struct{}) *protocolCallback
}
}
return &protocolCallback{
callback: make(chan result, 1),
abort: abort,
done: make(chan struct{}),
abort: abort,
}
}
12 changes: 12 additions & 0 deletions event_emitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type EventEmitter interface {
On(name string, handler interface{})
Once(name string, handler interface{})
RemoveListener(name string, handler interface{})
RemoveListeners(name string)
}

type (
Expand All @@ -31,6 +32,10 @@ type (
}
)

func NewEventEmitter() EventEmitter {
return &eventEmitter{}
}

func (e *eventEmitter) Emit(name string, payload ...interface{}) (hasListener bool) {
e.eventsMutex.Lock()
e.init()
Expand Down Expand Up @@ -64,6 +69,13 @@ func (e *eventEmitter) RemoveListener(name string, handler interface{}) {
}
}

func (e *eventEmitter) RemoveListeners(name string) {
e.eventsMutex.Lock()
defer e.eventsMutex.Unlock()
e.init()
delete(e.events, name)
}

// ListenerCount count the listeners by name, count all if name is empty
func (e *eventEmitter) ListenerCount(name string) int {
e.eventsMutex.Lock()
Expand Down
2 changes: 1 addition & 1 deletion fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ func (r *apiResponseImpl) Body() ([]byte, error) {
}
return nil, err
}
body := result.(map[string]interface{})["binary"]
body := result["binary"]
if body == nil {
return nil, errors.New("response has been disposed")
}
Expand Down
Loading

0 comments on commit 3e8cb5f

Please sign in to comment.