Skip to content

Commit 972f9ef

Browse files
chore: roll to tot (playwright-community#205)
1 parent 855d2ff commit 972f9ef

26 files changed

+489
-257
lines changed

.github/workflows/build.yml

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ jobs:
4949
- name: Send coverage
5050
env:
5151
COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52+
continue-on-error: true
5253
run: goveralls -coverprofile=covprofile -service=github -parallel -flagname="${{ matrix.os }}-${{ matrix.browser }}"
5354
finish:
5455
needs: test

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
[![PkgGoDev](https://pkg.go.dev/badge/github.com/mxschmitt/playwright-go)](https://pkg.go.dev/github.com/mxschmitt/playwright-go)
66
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](http://opensource.org/licenses/MIT)
77
[![Go Report Card](https://goreportcard.com/badge/github.com/mxschmitt/playwright-go)](https://goreportcard.com/report/github.com/mxschmitt/playwright-go) ![Build Status](https://github.com/mxschmitt/playwright-go/workflows/Go/badge.svg)
8-
[![Join Slack](https://img.shields.io/badge/join-slack-infomational)](https://aka.ms/playwright-slack) [![Coverage Status](https://coveralls.io/repos/github/mxschmitt/playwright-go/badge.svg?branch=master)](https://coveralls.io/github/mxschmitt/playwright-go?branch=master) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-94.0.4595.0-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-91.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-15.0-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop -->
8+
[![Join Slack](https://img.shields.io/badge/join-slack-infomational)](https://aka.ms/playwright-slack) [![Coverage Status](https://coveralls.io/repos/github/mxschmitt/playwright-go/badge.svg?branch=master)](https://coveralls.io/github/mxschmitt/playwright-go?branch=master) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-96.0.4645.0-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-92.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-15.0-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop -->
99

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

1212
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**.
1313

1414
| | Linux | macOS | Windows |
1515
| :--- | :---: | :---: | :---: |
16-
| Chromium <!-- GEN:chromium-version -->94.0.4595.0<!-- GEN:stop --> ||||
16+
| Chromium <!-- GEN:chromium-version -->96.0.4645.0<!-- GEN:stop --> ||||
1717
| WebKit <!-- GEN:webkit-version -->15.0<!-- GEN:stop --> ||||
18-
| Firefox <!-- GEN:firefox-version -->91.0<!-- GEN:stop --> ||||
18+
| Firefox <!-- GEN:firefox-version -->92.0<!-- GEN:stop --> ||||
1919

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

binding_call.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ type BindingSource struct {
1919
type ExposedFunction = func(args ...interface{}) interface{}
2020

2121
// BindingCallFunction represents the func signature of an exposed binding call func
22-
type BindingCallFunction = func(source *BindingSource, args ...interface{}) interface{}
22+
type BindingCallFunction func(source *BindingSource, args ...interface{}) interface{}
2323

2424
func (b *bindingCallImpl) Call(f BindingCallFunction) {
2525
defer func() {

browser.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,12 @@ func (b *browserImpl) Version() string {
106106

107107
func (b *browserImpl) onClose() {
108108
b.Lock()
109-
b.isConnected = false
110-
b.isClosedOrClosing = true
109+
if !b.isClosedOrClosing {
110+
b.isConnected = false
111+
b.isClosedOrClosing = true
112+
b.Emit("disconnected")
113+
}
111114
b.Unlock()
112-
b.Emit("disconnected")
113115
}
114116

115117
func newBrowser(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *browserImpl {

browser_type.go

+22-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package playwright
22

33
import (
44
"fmt"
5-
"log"
65
)
76

87
type browserTypeImpl struct {
@@ -51,22 +50,17 @@ func (b *browserTypeImpl) LaunchPersistentContext(userDataDir string, options ..
5150
return fromChannel(channel).(*browserContextImpl), nil
5251
}
5352
func (b *browserTypeImpl) Connect(url string, options ...BrowserTypeConnectOptions) (Browser, error) {
54-
transport := newWebSocketTransport(url, options...)
55-
connection := newConnection(transport, func() error { return nil })
56-
go func() {
57-
err := connection.Start()
58-
if err != nil {
59-
log.Fatalf("could not start websocket connection: %v", err)
60-
}
61-
}()
62-
obj, err := connection.CallOnObjectWithKnownName("Playwright")
53+
overrides := map[string]interface{}{
54+
"wsEndpoint": url,
55+
}
56+
pipe, err := b.channel.Send("connect", overrides, options)
6357
if err != nil {
64-
return nil, fmt.Errorf("could not call object: %w", err)
58+
return nil, err
6559
}
66-
playwright := obj.(*Playwright)
67-
browser := fromChannel(playwright.initializer["preLaunchedBrowser"]).(*browserImpl)
68-
browser.isConnectedOverWebSocket = true
69-
transport.(*webSocketTransport).OnClose = func() {
60+
jsonPipe := fromChannel(pipe).(*jsonPipe)
61+
connection := newConnection(jsonPipe.Close)
62+
var browser *browserImpl
63+
pipeClosed := func() {
7064
for _, context := range browser.contexts {
7165
pages := context.(*browserContextImpl).pages
7266
for _, page := range pages {
@@ -76,6 +70,19 @@ func (b *browserTypeImpl) Connect(url string, options ...BrowserTypeConnectOptio
7670
}
7771
browser.onClose()
7872
}
73+
jsonPipe.On("closed", pipeClosed)
74+
connection.onmessage = func(message map[string]interface{}) error {
75+
if err := jsonPipe.Send(message); err != nil {
76+
pipeClosed()
77+
return err
78+
}
79+
return nil
80+
}
81+
jsonPipe.On("message", connection.Dispatch)
82+
connection.Start()
83+
playwright := <-connection.playwright
84+
browser = fromChannel(playwright.initializer["preLaunchedBrowser"]).(*browserImpl)
85+
browser.isConnectedOverWebSocket = true
7986
return browser, nil
8087
}
8188

channel_owner.go

+28-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package playwright
22

3-
import "sync"
3+
import (
4+
"sync"
5+
)
46

57
type channelOwner struct {
68
sync.RWMutex
@@ -33,25 +35,36 @@ func (c *channelOwner) createChannelOwner(self interface{}, parent *channelOwner
3335
c.guid = guid
3436
c.parent = parent
3537
c.objects = make(map[string]*channelOwner)
36-
c.connection = parent.connection
38+
c.initializer = initializer
39+
if c.parent != nil {
40+
c.connection = parent.connection
41+
c.parent.objects[guid] = c
42+
}
43+
if c.connection != nil {
44+
c.connection.objects[guid] = c
45+
}
3746
c.channel = newChannel(c.connection, guid)
3847
c.channel.object = self
39-
c.initializer = initializer
40-
c.connection.objects[guid] = c
41-
c.parent.objects[guid] = c
4248
c.initEventEmitter()
4349
}
4450

45-
func newRootChannelOwner(connection *connection) *channelOwner {
46-
c := &channelOwner{
47-
objectType: "",
48-
guid: "",
49-
connection: connection,
50-
objects: make(map[string]*channelOwner),
51-
channel: newChannel(connection, ""),
51+
type rootChannelOwner struct {
52+
channelOwner
53+
}
54+
55+
func (r *rootChannelOwner) initialize() (*Playwright, error) {
56+
result, err := r.channel.Send("initialize", map[string]interface{}{
57+
"sdkLanguage": "javascript",
58+
})
59+
if err != nil {
60+
return nil, err
5261
}
53-
c.channel.object = c
54-
c.connection.objects[""] = c
55-
c.initEventEmitter()
62+
return fromChannel(result).(*Playwright), nil
63+
}
64+
65+
func newRootChannelOwner(connection *connection) *rootChannelOwner {
66+
c := &rootChannelOwner{}
67+
c.connection = connection
68+
c.createChannelOwner(c, nil, "Root", "", make(map[string]interface{}))
5669
return c
5770
}

connection.go

+44-25
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package playwright
22

33
import (
44
"fmt"
5+
"log"
56
"reflect"
67
"sync"
8+
9+
"github.com/go-stack/stack"
710
)
811

912
type callback struct {
@@ -12,37 +15,33 @@ type callback struct {
1215
}
1316

1417
type connection struct {
15-
transport transport
1618
waitingForRemoteObjectsLock sync.Mutex
1719
waitingForRemoteObjects map[string]chan interface{}
1820
objects map[string]*channelOwner
1921
lastID int
2022
lastIDLock sync.Mutex
21-
rootObject *channelOwner
23+
rootObject *rootChannelOwner
2224
callbacks sync.Map
2325
onClose func() error
26+
playwright chan *Playwright
27+
onmessage func(message map[string]interface{}) error
2428
}
2529

26-
func (c *connection) Start() error {
27-
return c.transport.Start()
30+
func (c *connection) Start() {
31+
go func() {
32+
playwright, err := c.rootObject.initialize()
33+
if err != nil {
34+
log.Fatal(err)
35+
return
36+
}
37+
c.playwright <- playwright
38+
}()
2839
}
2940

3041
func (c *connection) Stop() error {
31-
if err := c.transport.Stop(); err != nil {
32-
return fmt.Errorf("could not stop transport: %w", err)
33-
}
3442
return c.onClose()
3543
}
3644

37-
func (c *connection) CallOnObjectWithKnownName(name string) (interface{}, error) {
38-
if _, ok := c.waitingForRemoteObjects[name]; !ok {
39-
c.waitingForRemoteObjectsLock.Lock()
40-
c.waitingForRemoteObjects[name] = make(chan interface{})
41-
c.waitingForRemoteObjectsLock.Unlock()
42-
}
43-
return <-c.waitingForRemoteObjects[name], nil
44-
}
45-
4645
func (c *connection) Dispatch(msg *message) {
4746
method := msg.Method
4847
if msg.ID != 0 {
@@ -69,7 +68,11 @@ func (c *connection) Dispatch(msg *message) {
6968
object.dispose()
7069
return
7170
}
72-
object.channel.Emit(method, c.replaceGuidsWithChannels(msg.Params))
71+
if object.objectType == "JsonPipe" {
72+
object.channel.Emit(method, msg.Params)
73+
} else {
74+
object.channel.Emit(method, c.replaceGuidsWithChannels(msg.Params))
75+
}
7376
}
7477

7578
func (c *connection) createRemoteObject(parent *channelOwner, objectType string, guid string, initializer interface{}) interface{} {
@@ -143,14 +146,19 @@ func (c *connection) SendMessageToServer(guid string, method string, params inte
143146
c.lastID++
144147
id := c.lastID
145148
c.lastIDLock.Unlock()
149+
stack := serializeCallStack(stack.Trace())
150+
metadata := make(map[string]interface{})
151+
metadata["stack"] = stack
152+
metadata["apiName"] = ""
146153
message := map[string]interface{}{
147-
"id": id,
148-
"guid": guid,
149-
"method": method,
150-
"params": c.replaceChannelsWithGuids(params),
154+
"id": id,
155+
"guid": guid,
156+
"method": method,
157+
"params": c.replaceChannelsWithGuids(params),
158+
"metadata": metadata,
151159
}
152160
cb, _ := c.callbacks.LoadOrStore(id, make(chan callback))
153-
if err := c.transport.Send(message); err != nil {
161+
if err := c.onmessage(message); err != nil {
154162
return nil, fmt.Errorf("could not send message: %w", err)
155163
}
156164
result := <-cb.(chan callback)
@@ -161,15 +169,26 @@ func (c *connection) SendMessageToServer(guid string, method string, params inte
161169
return result.Data, nil
162170
}
163171

164-
func newConnection(t transport, onClose func() error) *connection {
172+
func serializeCallStack(stack stack.CallStack) []map[string]interface{} {
173+
callStack := make([]map[string]interface{}, 0)
174+
for _, s := range stack {
175+
callStack = append(callStack, map[string]interface{}{
176+
"file": s.Frame().File,
177+
"line": s.Frame().Line,
178+
"function": s.Frame().Function,
179+
})
180+
}
181+
return callStack
182+
}
183+
184+
func newConnection(onClose func() error) *connection {
165185
connection := &connection{
166186
waitingForRemoteObjects: make(map[string]chan interface{}),
167187
objects: make(map[string]*channelOwner),
168188
onClose: onClose,
169189
}
170-
connection.transport = t
171-
connection.transport.SetDispatch(connection.Dispatch)
172190
connection.rootObject = newRootChannelOwner(connection)
191+
connection.playwright = make(chan *Playwright, 1)
173192
return connection
174193
}
175194

generated-enums.go

+12
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ var (
2626
ColorSchemeNoPreference = getColorScheme("no-preference")
2727
)
2828

29+
func getForcedColors(in string) *ForcedColors {
30+
v := ForcedColors(in)
31+
return &v
32+
}
33+
34+
type ForcedColors string
35+
36+
var (
37+
ForcedColorsActive *ForcedColors = getForcedColors("active")
38+
ForcedColorsNone = getForcedColors("none")
39+
)
40+
2941
func getReducedMotion(in string) *ReducedMotion {
3042
v := ReducedMotion(in)
3143
return &v

0 commit comments

Comments
 (0)