Skip to content

Commit 64e0326

Browse files
authored
chore: roll to Playwright v1.52.0 (#540)
1 parent c6ac7e7 commit 64e0326

20 files changed

+546
-103
lines changed

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/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-134.0.6998.35-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-135.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.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-136.0.7103.25-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-137.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.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 -->134.0.6998.35<!-- GEN:stop --> ||||
16+
| Chromium <!-- GEN:chromium-version -->136.0.7103.25<!-- GEN:stop --> ||||
1717
| WebKit <!-- GEN:webkit-version -->18.4<!-- GEN:stop --> ||||
18-
| Firefox <!-- GEN:firefox-version -->135.0<!-- GEN:stop --> ||||
18+
| Firefox <!-- GEN:firefox-version -->137.0<!-- GEN:stop --> ||||
1919

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

generated-interfaces.go

+26-9
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,8 @@ type BrowserContext interface {
382382
// [this] issue. We recommend disabling Service Workers when
383383
// using request interception by setting “[object Object]” to `block`.
384384
//
385-
// 1. url: A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a “[object Object]” via the
386-
// context options was provided and the passed URL is a path, it gets merged via the
385+
// 1. url: A glob pattern, regex pattern, or predicate that receives a [URL] to match during routing. If “[object Object]” is
386+
// set in the context options and the provided URL is a string that does not start with `*`, it is resolved using the
387387
// [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor.
388388
// 2. handler: handler function to route the request.
389389
//
@@ -529,11 +529,15 @@ type BrowserType interface {
529529
// Launches browser that uses persistent storage located at “[object Object]” and returns the only context. Closing
530530
// this context will automatically close the browser.
531531
//
532-
// userDataDir: Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for
532+
// userDataDir: Path to a User Data Directory, which stores browser session data like cookies and local storage. Pass an empty
533+
// string to create a temporary directory.
534+
//
535+
// More details for
533536
// [Chromium](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md#introduction) and
534-
// [Firefox](https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options#User_Profile). Note that Chromium's
535-
// user data directory is the **parent** directory of the "Profile Path" seen at `chrome://version`. Pass an empty
536-
// string to use a temporary directory instead.
537+
// [Firefox](https://wiki.mozilla.org/Firefox/CommandLineOptions#User_profile). Chromium's user data directory is the
538+
// **parent** directory of the "Profile Path" seen at `chrome://version`.
539+
//
540+
// Note that browsers do not allow launching multiple instances with the same User Data Directory.
537541
LaunchPersistentContext(userDataDir string, options ...BrowserTypeLaunchPersistentContextOptions) (BrowserContext, error)
538542

539543
// Returns browser name. For example: `chromium`, `webkit` or `firefox`.
@@ -2906,6 +2910,16 @@ type LocatorAssertions interface {
29062910
// [visible]: https://playwright.dev/docs/actionability#visible
29072911
ToBeVisible(options ...LocatorAssertionsToBeVisibleOptions) error
29082912

2913+
// Ensures the [Locator] points to an element with given CSS classes. All classes from the asserted value, separated
2914+
// by spaces, must be present in the
2915+
// [Element.ClassList] in any order.
2916+
//
2917+
// expected: A string containing expected class names, separated by spaces, or a list of such strings to assert multiple
2918+
// elements.
2919+
//
2920+
// [Element.ClassList]: https://developer.mozilla.org/en-US/docs/Web/API/Element/classList
2921+
ToContainClass(expected interface{}, options ...LocatorAssertionsToContainClassOptions) error
2922+
29092923
// Ensures the [Locator] points to an element that contains the given text. All nested elements will be considered
29102924
// when computing the text content of the element. You can use regular expressions for the value as well.
29112925
//
@@ -2948,7 +2962,7 @@ type LocatorAssertions interface {
29482962
ToHaveAttribute(name string, value interface{}, options ...LocatorAssertionsToHaveAttributeOptions) error
29492963

29502964
// Ensures the [Locator] points to an element with given CSS classes. When a string is provided, it must fully match
2951-
// the element's `class` attribute. To match individual classes or perform partial matches, use a regular expression:
2965+
// the element's `class` attribute. To match individual classes use [LocatorAssertions.ToContainClass].
29522966
//
29532967
// expected: Expected class or RegExp or a list of those.
29542968
ToHaveClass(expected interface{}, options ...LocatorAssertionsToHaveClassOptions) error
@@ -3796,8 +3810,8 @@ type Page interface {
37963810
// using request interception by setting “[object Object]” to `block`.
37973811
// **NOTE** [Page.Route] will not intercept the first request of a popup page. Use [BrowserContext.Route] instead.
37983812
//
3799-
// 1. url: A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a “[object Object]” via the
3800-
// context options was provided and the passed URL is a path, it gets merged via the
3813+
// 1. url: A glob pattern, regex pattern, or predicate that receives a [URL] to match during routing. If “[object Object]” is
3814+
// set in the context options and the provided URL is a string that does not start with `*`, it is resolved using the
38013815
// [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor.
38023816
// 2. handler: handler function to route the request.
38033817
//
@@ -4376,6 +4390,9 @@ type Route interface {
43764390
// over to redirected requests.
43774391
// [Route.Continue] will immediately send the request to the network, other matching handlers won't be invoked. Use
43784392
// [Route.Fallback] If you want next matching handler in the chain to be invoked.
4393+
// **NOTE** The `Cookie` header cannot be overridden using this method. If a value is provided, it will be ignored,
4394+
// and the cookie will be loaded from the browser's cookie store. To set custom cookies, use
4395+
// [BrowserContext.AddCookies].
43794396
Continue(options ...RouteContinueOptions) error
43804397

43814398
// Continues route's request with optional overrides. The method is similar to [Route.Continue] with the difference

generated-structs.go

+18-6
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ type APIRequestNewContextOptions struct {
3535
HttpCredentials *HttpCredentials `json:"httpCredentials"`
3636
// Whether to ignore HTTPS errors when sending network requests. Defaults to `false`.
3737
IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"`
38+
// Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
39+
// exceeded. Defaults to `20`. Pass `0` to not follow redirects. This can be overwritten for each request
40+
// individually.
41+
MaxRedirects *int `json:"maxRedirects"`
3842
// Network proxy settings.
3943
Proxy *Proxy `json:"proxy"`
4044
// Populates context with given storage state. This option can be used to initialize context with logged-in
@@ -858,7 +862,7 @@ type BrowserTypeLaunchOptions struct {
858862
// “[object Object]” option is `true`.
859863
//
860864
// [Chromium]: https://developers.google.com/web/updates/2017/04/headless-chrome
861-
// [Firefox]: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode
865+
// [Firefox]: https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/
862866
Headless *bool `json:"headless"`
863867
// If `true`, Playwright does not pass its own configurations args and only uses the ones from “[object Object]”.
864868
// Dangerous option; use with care. Defaults to `false`.
@@ -977,7 +981,7 @@ type BrowserTypeLaunchPersistentContextOptions struct {
977981
// “[object Object]” option is `true`.
978982
//
979983
// [Chromium]: https://developers.google.com/web/updates/2017/04/headless-chrome
980-
// [Firefox]: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode
984+
// [Firefox]: https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/
981985
Headless *bool `json:"headless"`
982986
// Credentials for [HTTP authentication]. If no
983987
// origin is specified, the username and password are sent to any servers upon unauthorized responses.
@@ -2254,6 +2258,9 @@ type KeyboardTypeOptions struct {
22542258
}
22552259

22562260
type LocatorAriaSnapshotOptions struct {
2261+
// Generate symbolic reference for each element. One can use `aria-ref=<ref>` locator immediately after capturing the
2262+
// snapshot to perform actions on the element.
2263+
Ref *bool `json:"ref"`
22572264
// Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can
22582265
// be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods.
22592266
Timeout *float64 `json:"timeout"`
@@ -2413,14 +2420,14 @@ type LocatorElementHandleOptions struct {
24132420
}
24142421

24152422
type LocatorEvaluateOptions struct {
2416-
// Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can
2417-
// be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods.
2423+
// Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved,
2424+
// evaluation itself is not limited by the timeout. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
24182425
Timeout *float64 `json:"timeout"`
24192426
}
24202427

24212428
type LocatorEvaluateHandleOptions struct {
2422-
// Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can
2423-
// be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods.
2429+
// Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved,
2430+
// evaluation itself is not limited by the timeout. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
24242431
Timeout *float64 `json:"timeout"`
24252432
}
24262433

@@ -2940,6 +2947,11 @@ type LocatorAssertionsToBeVisibleOptions struct {
29402947
Visible *bool `json:"visible"`
29412948
}
29422949

2950+
type LocatorAssertionsToContainClassOptions struct {
2951+
// Time to retry the assertion for in milliseconds. Defaults to `5000`.
2952+
Timeout *float64 `json:"timeout"`
2953+
}
2954+
29432955
type LocatorAssertionsToContainTextOptions struct {
29442956
// Whether to perform case-insensitive match. “[object Object]” option takes precedence over the corresponding regular
29452957
// expression flag if specified.

glob.go

+85-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package playwright
22

33
import (
4+
"net/url"
45
"regexp"
6+
"strconv"
57
"strings"
68
)
79

@@ -59,12 +61,6 @@ func globMustToRegex(glob string) *regexp.Regexp {
5961
}
6062
} else {
6163
switch c {
62-
case '?':
63-
tokens = append(tokens, ".")
64-
case '[':
65-
tokens = append(tokens, "[")
66-
case ']':
67-
tokens = append(tokens, "]")
6864
case '{':
6965
inGroup = true
7066
tokens = append(tokens, "(")
@@ -75,7 +71,7 @@ func globMustToRegex(glob string) *regexp.Regexp {
7571
if inGroup {
7672
tokens = append(tokens, "|")
7773
} else {
78-
tokens = append(tokens, string(c))
74+
tokens = append(tokens, "\\"+string(c))
7975
}
8076
default:
8177
if _, ok := escapedChars[c]; ok {
@@ -90,3 +86,85 @@ func globMustToRegex(glob string) *regexp.Regexp {
9086
tokens = append(tokens, "$")
9187
return regexp.MustCompile(strings.Join(tokens, ""))
9288
}
89+
90+
func resolveGlobToRegex(baseURL *string, glob string, isWebSocketUrl bool) *regexp.Regexp {
91+
if isWebSocketUrl {
92+
baseURL = toWebSocketBaseURL(baseURL)
93+
}
94+
glob = resolveGlobBase(baseURL, glob)
95+
return globMustToRegex(glob)
96+
}
97+
98+
func resolveGlobBase(baseURL *string, match string) string {
99+
if strings.HasPrefix(match, "*") {
100+
return match
101+
}
102+
103+
tokenMap := make(map[string]string)
104+
mapToken := func(original string, replacement string) string {
105+
if len(original) == 0 {
106+
return ""
107+
}
108+
tokenMap[replacement] = original
109+
return replacement
110+
}
111+
// Escaped `\\?` behaves the same as `?` in our glob patterns.
112+
match = strings.ReplaceAll(match, `\\?`, "?")
113+
// Glob symbols may be escaped in the URL and some of them such as ? affect resolution,
114+
// so we replace them with safe components first.
115+
relativePath := strings.Split(match, "/")
116+
for i, token := range relativePath {
117+
if token == "." || token == ".." || token == "" {
118+
continue
119+
}
120+
// Handle special case of http*://, note that the new schema has to be
121+
// a web schema so that slashes are properly inserted after domain.
122+
if i == 0 && strings.HasSuffix(token, ":") {
123+
relativePath[i] = mapToken(token, "http:")
124+
} else {
125+
questionIndex := strings.Index(token, "?")
126+
if questionIndex == -1 {
127+
relativePath[i] = mapToken(token, "$_"+strconv.Itoa(i)+"_$")
128+
} else {
129+
newPrefix := mapToken(token[:questionIndex], "$_"+strconv.Itoa(i)+"_$")
130+
newSuffix := mapToken(token[questionIndex:], "?$"+strconv.Itoa(i)+"_$")
131+
relativePath[i] = newPrefix + newSuffix
132+
}
133+
}
134+
}
135+
resolved := constructURLBasedOnBaseURL(baseURL, strings.Join(relativePath, "/"))
136+
for token, original := range tokenMap {
137+
resolved = strings.ReplaceAll(resolved, token, original)
138+
}
139+
return resolved
140+
}
141+
142+
func constructURLBasedOnBaseURL(baseURL *string, givenURL string) string {
143+
u, err := url.Parse(givenURL)
144+
if err != nil {
145+
return givenURL
146+
}
147+
if baseURL != nil {
148+
base, err := url.Parse(*baseURL)
149+
if err != nil {
150+
return givenURL
151+
}
152+
u = base.ResolveReference(u)
153+
}
154+
if u.Path == "" { // In Node.js, new URL('http://localhost') returns 'http://localhost/'.
155+
u.Path = "/"
156+
}
157+
return u.String()
158+
}
159+
160+
func toWebSocketBaseURL(baseURL *string) *string {
161+
if baseURL == nil {
162+
return nil
163+
}
164+
165+
// Allow http(s) baseURL to match ws(s) urls.
166+
re := regexp.MustCompile(`(?m)^http(s?://)`)
167+
wsBaseURL := re.ReplaceAllString(*baseURL, "ws$1")
168+
169+
return &wsBaseURL
170+
}

glob_test.go

+53-9
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,6 @@ func Test_globMustToRegex(t *testing.T) {
5151
},
5252
want: true,
5353
},
54-
{
55-
args: args{
56-
glob: "http://localhost:8080/?imple/path.js",
57-
target: "http://localhost:8080/simple/path.js",
58-
},
59-
want: true,
60-
},
6154
{
6255
args: args{
6356
glob: "**/{a,b}.js",
@@ -137,7 +130,35 @@ func Test_globMustToRegex(t *testing.T) {
137130
},
138131
{
139132
args: args{
140-
glob: "**/three-columns/settings.html?**id=[a-z]**",
133+
glob: "**/api/v[0-9]",
134+
target: "http://example.com/api/v[0-9]",
135+
},
136+
want: true,
137+
},
138+
{
139+
args: args{
140+
glob: "**/api/v[0-9]",
141+
target: "http://example.com/api/version",
142+
},
143+
want: false,
144+
},
145+
{
146+
args: args{
147+
glob: "**/api\\?param",
148+
target: "http://example.com/api?param",
149+
},
150+
want: true,
151+
},
152+
{
153+
args: args{
154+
glob: "**/api\\?param",
155+
target: "http://example.com/api-param",
156+
},
157+
want: false,
158+
},
159+
{
160+
args: args{
161+
glob: "**/three-columns/settings.html\\?**id=settings-**",
141162
target: "http://mydomain:8080/blah/blah/three-columns/settings.html?id=settings-e3c58efe-02e9-44b0-97ac-dd138100cf7c&blah",
142163
},
143164
want: true,
@@ -155,6 +176,29 @@ func Test_globMustToRegex(t *testing.T) {
155176
require.Equal(t, globMustToRegex("\\").String(), `^\\$`)
156177
require.Equal(t, globMustToRegex("\\\\").String(), `^\\$`)
157178
require.Equal(t, globMustToRegex("\\[").String(), `^\[$`)
158-
require.Equal(t, globMustToRegex("[a-z]").String(), `^[a-z]$`)
179+
require.Equal(t, globMustToRegex("[a-z]").String(), `^\[a-z\]$`)
159180
require.Equal(t, globMustToRegex("$^+.\\*()|\\?\\{\\}\\[\\]").String(), `^\$\^\+\.\*\(\)\|\?\{\}\[\]$`)
160181
}
182+
183+
func TestURLMatches(t *testing.T) {
184+
require.True(t, newURLMatcher("http://playwright.dev", nil).Matches("http://playwright.dev/"))
185+
require.True(t, newURLMatcher("http://playwright.dev?a=b", nil).Matches("http://playwright.dev/?a=b"))
186+
require.True(t, newURLMatcher("h*://playwright.dev", nil).Matches("http://playwright.dev/"))
187+
require.True(t, newURLMatcher("http://*.playwright.dev?x=y", nil).Matches("http://api.playwright.dev/?x=y"))
188+
require.True(t, newURLMatcher("**/foo/**", nil).Matches("http://playwright.dev/foo/bar"))
189+
require.True(t, newURLMatcher("?x=y", String("http://playwright.dev")).Matches("http://playwright.dev/?x=y"))
190+
require.True(t, newURLMatcher("./bar?x=y", String("http://playwright.dev/foo/")).Matches("http://playwright.dev/foo/bar?x=y"))
191+
192+
// This is not supported, we treat ? as a query separator.
193+
require.False(t, globMustToRegex("http://localhost:8080/?imple/path.js").MatchString("http://localhost:8080/Simple/path.js"))
194+
require.False(t, newURLMatcher("http://playwright.?ev", nil).Matches("http://playwright.dev/"))
195+
require.True(t, newURLMatcher("http://playwright.?ev", nil).Matches("http://playwright./?ev"))
196+
require.False(t, newURLMatcher("http://playwright.dev/f??", nil).Matches("http://playwright.dev/foo"))
197+
require.True(t, newURLMatcher("http://playwright.dev/f??", nil).Matches("http://playwright.dev/f??"))
198+
require.True(t, newURLMatcher("http://playwright.dev\\?x=y", nil).Matches("http://playwright.dev/?x=y"))
199+
require.True(t, newURLMatcher("http://playwright.dev/\\?x=y", nil).Matches("http://playwright.dev/?x=y"))
200+
require.True(t, newURLMatcher("?bar", String("http://playwright.dev/foo")).Matches("http://playwright.dev/foo?bar"))
201+
require.True(t, newURLMatcher("\\\\?bar", String("http://playwright.dev/foo")).Matches("http://playwright.dev/foo?bar"))
202+
require.True(t, newURLMatcher("**/foo", String("http://first.host/")).Matches("http://second.host/foo"))
203+
require.True(t, newURLMatcher("*//localhost/", String("http://playwright.dev/")).Matches("http://localhost/"))
204+
}

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ go 1.22
44

55
require (
66
github.com/coder/websocket v1.8.12
7-
github.com/deckarep/golang-set/v2 v2.6.0
8-
github.com/go-jose/go-jose/v3 v3.0.3
7+
github.com/deckarep/golang-set/v2 v2.7.0
8+
github.com/go-jose/go-jose/v3 v3.0.4
99
github.com/go-stack/stack v1.8.1
1010
github.com/h2non/filetype v1.1.3
1111
github.com/mitchellh/go-ps v1.0.0

0 commit comments

Comments
 (0)