Skip to content

Commit 67b851e

Browse files
authored
feat: roll to Playwright v1.41.1 (#407)
1 parent 8b2bd7b commit 67b851e

31 files changed

+1455
-304
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
[![PkgGoDev](https://pkg.go.dev/badge/github.com/playwright-community/playwright-go)](https://pkg.go.dev/github.com/playwright-community/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/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)
8-
[![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-120.0.6099.28-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-119.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.4-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/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-121.0.6167.57-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-121.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.4-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/playwright-community/playwright-go/tree/main/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 -->120.0.6099.28<!-- GEN:stop --> ||||
16+
| Chromium <!-- GEN:chromium-version -->121.0.6167.57<!-- GEN:stop --> ||||
1717
| WebKit <!-- GEN:webkit-version -->17.4<!-- GEN:stop --> ||||
18-
| Firefox <!-- GEN:firefox-version -->119.0<!-- GEN:stop --> ||||
18+
| Firefox <!-- GEN:firefox-version -->121.0<!-- GEN:stop --> ||||
1919

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

assertions.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package playwright
22

33
import (
4+
"errors"
45
"fmt"
56
"reflect"
67
"regexp"
@@ -103,7 +104,7 @@ func toExpectedTextValues(
103104
matchSubstring bool,
104105
normalizeWhiteSpace bool,
105106
ignoreCase *bool,
106-
) []expectedTextValue {
107+
) ([]expectedTextValue, error) {
107108
var out []expectedTextValue
108109
for _, item := range items {
109110
switch item := item.(type) {
@@ -123,9 +124,11 @@ func toExpectedTextValues(
123124
NormalizeWhiteSpace: Bool(normalizeWhiteSpace),
124125
IgnoreCase: ignoreCase,
125126
})
127+
default:
128+
return nil, errors.New("value must be a string or regexp")
126129
}
127130
}
128-
return out
131+
return out, nil
129132
}
130133

131134
func convertToInterfaceList(v interface{}) []interface{} {

browser_context.go

Lines changed: 96 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,29 @@ import (
77
"log"
88
"os"
99
"strings"
10+
"sync"
11+
12+
"golang.org/x/exp/slices"
1013
)
1114

1215
type browserContextImpl struct {
1316
channelOwner
14-
timeoutSettings *timeoutSettings
15-
isClosedOrClosing bool
16-
options *BrowserNewContextOptions
17-
pages []Page
18-
routes []*routeHandlerEntry
19-
ownedPage Page
20-
browser *browserImpl
21-
serviceWorkers []Worker
22-
backgroundPages []Page
23-
bindings map[string]BindingCallFunction
24-
tracing *tracingImpl
25-
request *apiRequestContextImpl
26-
harRecorders map[string]harRecordingMetadata
27-
closed chan struct{}
28-
closeReason *string
17+
timeoutSettings *timeoutSettings
18+
closeWasCalled bool
19+
options *BrowserNewContextOptions
20+
pages []Page
21+
routes []*routeHandlerEntry
22+
ownedPage Page
23+
browser *browserImpl
24+
serviceWorkers []Worker
25+
backgroundPages []Page
26+
bindings map[string]BindingCallFunction
27+
tracing *tracingImpl
28+
request *apiRequestContextImpl
29+
harRecorders map[string]harRecordingMetadata
30+
closed chan struct{}
31+
closeReason *string
32+
harRouters []*harRouter
2933
}
3034

3135
func (b *browserContextImpl) SetDefaultNavigationTimeout(timeout float64) {
@@ -210,21 +214,56 @@ func (b *browserContextImpl) ExposeFunction(name string, binding ExposedFunction
210214
}
211215

212216
func (b *browserContextImpl) Route(url interface{}, handler routeHandler, times ...int) error {
213-
b.routes = append(b.routes, newRouteHandlerEntry(newURLMatcher(url, b.options.BaseURL), handler, times...))
217+
b.Lock()
218+
defer b.Unlock()
219+
b.routes = slices.Insert(b.routes, 0, newRouteHandlerEntry(newURLMatcher(url, b.options.BaseURL), handler, times...))
214220
return b.updateInterceptionPatterns()
215221
}
216222

217223
func (b *browserContextImpl) Unroute(url interface{}, handlers ...routeHandler) error {
224+
removed, remaining, err := unroute(b.routes, url, handlers...)
225+
if err != nil {
226+
return err
227+
}
228+
return b.unrouteInternal(removed, remaining, UnrouteBehaviorDefault)
229+
}
230+
231+
func (b *browserContextImpl) unrouteInternal(removed []*routeHandlerEntry, remaining []*routeHandlerEntry, behavior *UnrouteBehavior) error {
218232
b.Lock()
219233
defer b.Unlock()
220-
221-
routes, err := unroute(b.routes, url, handlers...)
222-
if err != nil {
234+
b.routes = remaining
235+
if err := b.updateInterceptionPatterns(); err != nil {
223236
return err
224237
}
225-
b.routes = routes
238+
if behavior == nil || behavior == UnrouteBehaviorDefault {
239+
return nil
240+
}
241+
wg := &sync.WaitGroup{}
242+
for _, entry := range removed {
243+
wg.Add(1)
244+
go func(entry *routeHandlerEntry) {
245+
defer wg.Done()
246+
entry.Stop(string(*behavior))
247+
}(entry)
248+
}
249+
wg.Wait()
250+
return nil
251+
}
226252

227-
return b.updateInterceptionPatterns()
253+
func (b *browserContextImpl) UnrouteAll(options ...BrowserContextUnrouteAllOptions) error {
254+
var behavior *UnrouteBehavior
255+
if len(options) == 1 {
256+
behavior = options[0].Behavior
257+
}
258+
defer b.disposeHarRouters()
259+
return b.unrouteInternal(b.routes, []*routeHandlerEntry{}, behavior)
260+
}
261+
262+
func (b *browserContextImpl) disposeHarRouters() {
263+
for _, router := range b.harRouters {
264+
router.dispose()
265+
}
266+
b.harRouters = make([]*harRouter, 0)
228267
}
229268

230269
func (b *browserContextImpl) Request() APIRequestContext {
@@ -255,6 +294,7 @@ func (b *browserContextImpl) RouteFromHAR(har string, options ...BrowserContextR
255294
notFound = HarNotFoundAbort
256295
}
257296
router := newHarRouter(b.connection.localUtils, har, *notFound, opt.URL)
297+
b.harRouters = append(b.harRouters, router)
258298
return router.addContextRoute(b)
259299
}
260300

@@ -318,15 +358,13 @@ func (b *browserContextImpl) ExpectPage(cb func() error, options ...BrowserConte
318358
}
319359

320360
func (b *browserContextImpl) Close(options ...BrowserContextCloseOptions) error {
321-
if b.isClosedOrClosing {
361+
if b.closeWasCalled {
322362
return nil
323363
}
324364
if len(options) == 1 {
325365
b.closeReason = options[0].Reason
326366
}
327-
b.Lock()
328-
b.isClosedOrClosing = true
329-
b.Unlock()
367+
b.closeWasCalled = true
330368
innerClose := func() (interface{}, error) {
331369
for harId, harMetaData := range b.harRecorders {
332370
overrides := map[string]interface{}{}
@@ -456,6 +494,7 @@ func (b *browserContextImpl) onClose() {
456494
b.browser.contexts = contexts
457495
b.browser.Unlock()
458496
}
497+
b.disposeHarRouters()
459498
b.Emit("close", b)
460499
}
461500

@@ -473,20 +512,15 @@ func (b *browserContextImpl) onPage(page Page) {
473512
func (b *browserContextImpl) onRoute(route *routeImpl) {
474513
go func() {
475514
b.Lock()
476-
defer b.Unlock()
477515
route.context = b
516+
page := route.Request().(*requestImpl).safePage()
478517
routes := make([]*routeHandlerEntry, len(b.routes))
479518
copy(routes, b.routes)
519+
b.Unlock()
480520

481-
url := route.Request().URL()
482-
for i, handlerEntry := range routes {
483-
if !handlerEntry.Matches(url) {
484-
continue
485-
}
486-
if handlerEntry.WillExceed() {
487-
b.routes = append(b.routes[:i], b.routes[i+1:]...)
488-
}
489-
handled := handlerEntry.Handle(route)
521+
checkInterceptionIfNeeded := func() {
522+
b.Lock()
523+
defer b.Unlock()
490524
if len(b.routes) == 0 {
491525
_, err := b.connection.WrapAPICall(func() (interface{}, error) {
492526
err := b.updateInterceptionPatterns()
@@ -496,14 +530,37 @@ func (b *browserContextImpl) onRoute(route *routeImpl) {
496530
log.Printf("could not update interception patterns: %v", err)
497531
}
498532
}
533+
}
534+
535+
url := route.Request().URL()
536+
for _, handlerEntry := range routes {
537+
// If the page or the context was closed we stall all requests right away.
538+
if (page != nil && page.closeWasCalled) || b.closeWasCalled {
539+
return
540+
}
541+
if !handlerEntry.Matches(url) {
542+
continue
543+
}
544+
if !slices.ContainsFunc(b.routes, func(entry *routeHandlerEntry) bool {
545+
return entry == handlerEntry
546+
}) {
547+
continue
548+
}
549+
if handlerEntry.WillExceed() {
550+
b.routes = slices.DeleteFunc(b.routes, func(rhe *routeHandlerEntry) bool {
551+
return rhe == handlerEntry
552+
})
553+
}
554+
handled := handlerEntry.Handle(route)
555+
checkInterceptionIfNeeded()
499556
yes := <-handled
500557
if yes {
501558
return
502559
}
503560
}
504-
if err := route.internalContinue(true); err != nil {
505-
log.Printf("could not continue request: %v", err)
506-
}
561+
// If the page is closed or unrouteAll() was called without waiting and interception disabled,
562+
// the method will throw an error - silence it.
563+
_ = route.internalContinue(true)
507564
}()
508565
}
509566

@@ -624,6 +681,7 @@ func newBrowserContext(parent *channelOwner, objectType string, guid string, ini
624681
bindings: make(map[string]BindingCallFunction),
625682
harRecorders: make(map[string]harRecordingMetadata),
626683
closed: make(chan struct{}, 1),
684+
harRouters: make([]*harRouter, 0),
627685
}
628686
bt.createChannelOwner(bt, parent, objectType, guid, initializer)
629687
if parent.objectType == "Browser" {

examples/end-to-end-testing/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func main() {
3636
assertErrorToNilf("could not create context: %w", err)
3737
page, err := context.NewPage()
3838
assertErrorToNilf("could not create page: %w", err)
39-
_, err = page.Goto("http://todomvc.com/examples/react/")
39+
_, err = page.Goto("https://demo.playwright.dev/todomvc/")
4040
assertErrorToNilf("could not goto: %w", err)
4141

4242
// Helper function to get the amount of todos on the page

frame.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"os"
77
"sync"
88
"time"
9+
10+
mapset "github.com/deckarep/golang-set/v2"
911
)
1012

1113
type frameImpl struct {
@@ -17,15 +19,16 @@ type frameImpl struct {
1719
url string
1820
parentFrame Frame
1921
childFrames []Frame
20-
loadStates *safeStringSet
22+
loadStates mapset.Set[string]
2123
}
2224

2325
func newFrame(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *frameImpl {
24-
var loadStates *safeStringSet
26+
var loadStates mapset.Set[string]
27+
2528
if ls, ok := initializer["loadStates"].([]string); ok {
26-
loadStates = newSafeStringSet(ls)
29+
loadStates = mapset.NewSet[string](ls...)
2730
} else {
28-
loadStates = newSafeStringSet([]string{})
31+
loadStates = mapset.NewSet[string]()
2932
}
3033
bt := &frameImpl{
3134
name: initializer["name"].(string),
@@ -136,7 +139,7 @@ func (f *frameImpl) WaitForLoadState(options ...FrameWaitForLoadStateOptions) er
136139
}
137140

138141
func (f *frameImpl) waitForLoadStateImpl(state string, timeout *float64, cb func() error) error {
139-
if f.loadStates.Has(state) {
142+
if f.loadStates.ContainsOne(state) {
140143
return nil
141144
}
142145
waiter, err := f.setNavigationWaiter(timeout)

generated-enums.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,19 @@ var (
235235
RouteFromHarUpdateContentPolicyAttach = getRouteFromHarUpdateContentPolicy("attach")
236236
)
237237

238+
func getUnrouteBehavior(in string) *UnrouteBehavior {
239+
v := UnrouteBehavior(in)
240+
return &v
241+
}
242+
243+
type UnrouteBehavior string
244+
245+
var (
246+
UnrouteBehaviorWait *UnrouteBehavior = getUnrouteBehavior("wait")
247+
UnrouteBehaviorIgnoreErrors = getUnrouteBehavior("ignoreErrors")
248+
UnrouteBehaviorDefault = getUnrouteBehavior("default")
249+
)
250+
238251
func getMouseButton(in string) *MouseButton {
239252
v := MouseButton(in)
240253
return &v

0 commit comments

Comments
 (0)