diff options
Diffstat (limited to 'vendor/github.com/playwright-community/playwright-go')
72 files changed, 22158 insertions, 0 deletions
diff --git a/vendor/github.com/playwright-community/playwright-go/.gitattributes b/vendor/github.com/playwright-community/playwright-go/.gitattributes new file mode 100644 index 0000000..c976050 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/.gitattributes @@ -0,0 +1,3 @@ +# text files must be lf for golden file tests to work +* text=auto eol=lf + diff --git a/vendor/github.com/playwright-community/playwright-go/.gitignore b/vendor/github.com/playwright-community/playwright-go/.gitignore new file mode 100644 index 0000000..83e2355 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/.gitignore @@ -0,0 +1,34 @@ +# Created by https://www.toptal.com/developers/gitignore/api/go +# Edit at https://www.toptal.com/developers/gitignore?templates=go + +### Go ### +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +### Go Patch ### +/vendor/ +/Godeps/ + +# End of https://www.toptal.com/developers/gitignore/api/go +covprofile +.idea/ +.DS_Store + +api.json +_site/ +.jekyll-cache/ + +.vscode/settings.json
\ No newline at end of file diff --git a/vendor/github.com/playwright-community/playwright-go/.gitmodules b/vendor/github.com/playwright-community/playwright-go/.gitmodules new file mode 100644 index 0000000..9ab899d --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/.gitmodules @@ -0,0 +1,3 @@ +[submodule "playwright"] + path = playwright + url = https://github.com/microsoft/playwright diff --git a/vendor/github.com/playwright-community/playwright-go/.golangci.yaml b/vendor/github.com/playwright-community/playwright-go/.golangci.yaml new file mode 100644 index 0000000..1557a3f --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/.golangci.yaml @@ -0,0 +1,6 @@ +--- +linters: + enable-all: false + disable-all: false + enable: + - gofumpt
\ No newline at end of file diff --git a/vendor/github.com/playwright-community/playwright-go/.nojekyll b/vendor/github.com/playwright-community/playwright-go/.nojekyll new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/.nojekyll diff --git a/vendor/github.com/playwright-community/playwright-go/404.html b/vendor/github.com/playwright-community/playwright-go/404.html new file mode 100644 index 0000000..086a5c9 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/404.html @@ -0,0 +1,25 @@ +--- +permalink: /404.html +layout: default +--- + +<style type="text/css" media="screen"> + .container { + margin: 10px auto; + max-width: 600px; + text-align: center; + } + h1 { + margin: 30px 0; + font-size: 4em; + line-height: 1; + letter-spacing: -1px; + } +</style> + +<div class="container"> + <h1>404</h1> + + <p><strong>Page not found :(</strong></p> + <p>The requested page could not be found.</p> +</div> diff --git a/vendor/github.com/playwright-community/playwright-go/CONTRIBUTING.md b/vendor/github.com/playwright-community/playwright-go/CONTRIBUTING.md new file mode 100644 index 0000000..3b11995 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/CONTRIBUTING.md @@ -0,0 +1,39 @@ +# Contributing + +## Code style +The Go code is linted with [golangci-lint](https://golangci-lint.run/) and formatted with [gofumpt](https://github.com/mvdan/gofumpt). Please configure your editor to run the tools while developing and make sure to run the tools before committing any code. + +## Tests + +### Test coverage + +For every Pull Request on GitHub and on the main branch the coverage data will get sent over to [Coveralls](https://coveralls.io/github/playwright-community/playwright-go), this is helpful for finding functions that aren't covered by tests. + +### Running tests + +You can use the `BROWSER` environment variable to use a different browser than Chromium for the tests and use the `HEADLESS` environment variable which is useful for debugging. + +``` +BROWSER=chromium HEADLESS=1 go test -v --race ./... +``` + +### Roll + +1. Find out to which upstream version you want to roll, and change the value of `playwrightCliVersion` in the **run.go** to the new version. +1. Download current version of Playwright driver `go run scripts/install-browsers/main.go` +1. Apply patch `bash scripts/apply-patch.sh` +1. Fix merge conflicts if any, otherwise ignore this step. Once you are happy you can commit the changes `cd playwright; git commit -am "apply patch" && cd ..` +1. Regenerate a new patch `bash scripts/update-patch.sh` +1. Generate go code `go generate ./...` + +To adapt to the new version of Playwright's protocol and feature updates, you may need to modify the patch. Refer to the following steps: + +1. Apply patch `bash scripts/apply-patch.sh` +1. `cd playwright` +1. Revert the patch`git reset HEAD~1` +1. Modify the files under `docs/src/api`, etc. as needed. Available references: + - Protocol `packages/protocol/src/protocol.yml` + - [Playwright python](https://github.com/microsoft/playwright-python) +1. Commit the changes `git commit -am "apply patch"` +1. Regenerate a new patch `bash scripts/update-patch.sh` +1. Generate go code `go generate ./...`. diff --git a/vendor/github.com/playwright-community/playwright-go/Dockerfile.example b/vendor/github.com/playwright-community/playwright-go/Dockerfile.example new file mode 100644 index 0000000..3077cf3 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/Dockerfile.example @@ -0,0 +1,25 @@ +# Stage 1: Modules caching +FROM golang:1.22 as modules +COPY go.mod go.sum /modules/ +WORKDIR /modules +RUN go mod download + +# Stage 2: Build +FROM golang:1.22 as builder +COPY --from=modules /go/pkg /go/pkg +COPY . /workdir +WORKDIR /workdir +# Install playwright cli with right version for later use +RUN PWGO_VER=$(grep -oE "playwright-go v\S+" /workdir/go.mod | sed 's/playwright-go //g') \ + && go install github.com/playwright-community/playwright-go/cmd/playwright@${PWGO_VER} +# Build your app +RUN GOOS=linux GOARCH=amd64 go build -o /bin/myapp + +# Stage 3: Final +FROM ubuntu:noble +COPY --from=builder /go/bin/playwright /bin/myapp / +RUN apt-get update && apt-get install -y ca-certificates tzdata \ + # Install dependencies and all browsers (or specify one) + && /playwright install --with-deps \ + && rm -rf /var/lib/apt/lists/* +CMD ["/myapp"]
\ No newline at end of file diff --git a/vendor/github.com/playwright-community/playwright-go/LICENSE b/vendor/github.com/playwright-community/playwright-go/LICENSE new file mode 100644 index 0000000..d4f29b3 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Max Schmitt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/playwright-community/playwright-go/README.md b/vendor/github.com/playwright-community/playwright-go/README.md new file mode 100644 index 0000000..a9e3dd7 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/README.md @@ -0,0 +1,148 @@ +# 🎭 [Playwright](https://github.com/microsoft/playwright#readme) for <img src="https://user-images.githubusercontent.com/17984549/91302719-343a1d80-e7a7-11ea-8d6a-9448ef598420.png" height="35" /> + +## Looking for maintainers and see [here](https://github.com/playwright-community/playwright-go/issues/122). Thanks! + +[](https://pkg.go.dev/github.com/playwright-community/playwright-go) +[](http://opensource.org/licenses/MIT) +[](https://goreportcard.com/report/github.com/playwright-community/playwright-go)  +[](https://aka.ms/playwright-slack) [](https://coveralls.io/github/playwright-community/playwright-go?branch=main) <!-- GEN:chromium-version-badge -->[](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[](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 -->136.0.7103.25<!-- GEN:stop --> | ✅ | ✅ | ✅ | +| WebKit <!-- GEN:webkit-version -->18.4<!-- GEN:stop --> | ✅ | ✅ | ✅ | +| Firefox <!-- GEN:firefox-version -->137.0<!-- GEN:stop --> | ✅ | ✅ | ✅ | + +Headless execution is supported for all the browsers on all platforms. + +## Installation + +```txt +go get -u github.com/playwright-community/playwright-go +``` + +Install the browsers and OS dependencies: + +```bash +go run github.com/playwright-community/playwright-go/cmd/playwright@latest install --with-deps +# Or +go install github.com/playwright-community/playwright-go/cmd/playwright@latest +playwright install --with-deps +``` + +Alternatively you can do it inside your program via which downloads the driver and browsers: + +```go +err := playwright.Install() +``` + +## Capabilities + +Playwright is built to automate the broad and growing set of web browser capabilities used by Single Page Apps and Progressive Web Apps. + +* Scenarios that span multiple page, domains and iframes +* Auto-wait for elements to be ready before executing actions (like click, fill) +* Intercept network activity for stubbing and mocking network requests +* Emulate mobile devices, geolocation, permissions +* Support for web components via shadow-piercing selectors +* Native input events for mouse and keyboard +* Upload and download files + +## Example + +The following example crawls the current top voted items from [Hacker News](https://news.ycombinator.com). + +```go + +package main + +import ( + "fmt" + "log" + + "github.com/playwright-community/playwright-go" +) + +func main() { + pw, err := playwright.Run() + if err != nil { + log.Fatalf("could not start playwright: %v", err) + } + browser, err := pw.Chromium.Launch() + if err != nil { + log.Fatalf("could not launch browser: %v", err) + } + page, err := browser.NewPage() + if err != nil { + log.Fatalf("could not create page: %v", err) + } + if _, err = page.Goto("https://news.ycombinator.com"); err != nil { + log.Fatalf("could not goto: %v", err) + } + entries, err := page.Locator(".athing").All() + if err != nil { + log.Fatalf("could not get entries: %v", err) + } + for i, entry := range entries { + title, err := entry.Locator("td.title > span > a").TextContent() + if err != nil { + log.Fatalf("could not get text content: %v", err) + } + fmt.Printf("%d: %s\n", i+1, title) + } + if err = browser.Close(); err != nil { + log.Fatalf("could not close browser: %v", err) + } + if err = pw.Stop(); err != nil { + log.Fatalf("could not stop Playwright: %v", err) + } +} +``` + +## Docker +Refer to the [Dockerfile.example](./Dockerfile.example) to build your own docker image. + +## More examples + +* Refer to [helper_test.go](./tests/helper_test.go) for End-To-End testing +* [Downloading files](./examples/download/main.go) +* [End-To-End testing a website](./examples/end-to-end-testing/main.go) +* [Executing JavaScript in the browser](./examples/javascript/main.go) +* [Emulate mobile and geolocation](./examples/mobile-and-geolocation/main.go) +* [Parallel scraping using a WaitGroup](./examples/parallel-scraping/main.go) +* [Rendering a PDF of a website](./examples/pdf/main.go) +* [Scraping HackerNews](./examples/scraping/main.go) +* [Take a screenshot](./examples/screenshot/main.go) +* [Record a video](./examples/video/main.go) +* [Monitor network activity](./examples/network-monitoring/main.go) + +## How does it work? + +Playwright is a Node.js library which uses: + +* Chrome DevTools Protocol to communicate with Chromium +* Patched Firefox to communicate with Firefox +* Patched WebKit to communicate with WebKit + +These patches are based on the original sources of the browsers and don't modify the browser behaviour so the browsers are basically the same (see [here](https://github.com/microsoft/playwright/tree/main/browser_patches)) as you see them in the wild. The support for different programming languages is based on exposing a RPC server in the Node.js land which can be used to allow other languages to use Playwright without implementing all the custom logic: + +* [Playwright for Python](https://github.com/microsoft/playwright-python) +* [Playwright for .NET](https://github.com/microsoft/playwright-sharp) +* [Playwright for Java](https://github.com/microsoft/playwright-java) +* [Playwright for Go](https://github.com/playwright-community/playwright-go) + +The bridge between Node.js and the other languages is basically a Node.js runtime combined with Playwright which gets shipped for each of these languages (around 50MB) and then communicates over stdio to send the relevant commands. This will also download the pre-compiled browsers. + +## Is Playwright for Go ready? + +We are ready for your feedback, but we are still covering Playwright Go with the tests. + +## Resources + +* [Playwright for Go Documentation](https://pkg.go.dev/github.com/playwright-community/playwright-go) +* [Playwright Documentation](https://playwright.dev/docs/api/class-playwright) +* [Example recipes](https://github.com/playwright-community/playwright-go/tree/main/examples) diff --git a/vendor/github.com/playwright-community/playwright-go/_config.yml b/vendor/github.com/playwright-community/playwright-go/_config.yml new file mode 100644 index 0000000..15ec3b2 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/_config.yml @@ -0,0 +1,21 @@ +title: Playwright for Go +email: max@schmitt.mx +description: >- # this means to ignore newlines until "baseurl:" + Playwright is a Node.js library to automate Chromium, Firefox and WebKit with a single API. + Playwright is built to enable cross-browser web automation that is ever-green, capable, reliable and fast. +baseurl: "/playwright-go" +url: "https://playwright-community.github.io/" +twitter_username: maxibanki +github_username: playwright-community +remote_theme: pages-themes/cayman@v0.2.0 +plugins: + - jekyll-remote-theme + - jekyll-optional-front-matter + - jekyll-readme-index +exclude: + - playwright/ +defaults: + - scope: + path: "" # an empty string here means all files in the project + values: + layout: "default" diff --git a/vendor/github.com/playwright-community/playwright-go/apiresponse_assertions.go b/vendor/github.com/playwright-community/playwright-go/apiresponse_assertions.go new file mode 100644 index 0000000..187618e --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/apiresponse_assertions.go @@ -0,0 +1,75 @@ +package playwright + +import ( + "errors" + "fmt" + "regexp" + "strings" +) + +type apiResponseAssertionsImpl struct { + actual APIResponse + isNot bool +} + +func newAPIResponseAssertions(actual APIResponse, isNot bool) *apiResponseAssertionsImpl { + return &apiResponseAssertionsImpl{ + actual: actual, + isNot: isNot, + } +} + +func (ar *apiResponseAssertionsImpl) Not() APIResponseAssertions { + return newAPIResponseAssertions(ar.actual, true) +} + +func (ar *apiResponseAssertionsImpl) ToBeOK() error { + if ar.isNot != ar.actual.Ok() { + return nil + } + message := fmt.Sprintf(`Response status expected to be within [200..299] range, was %v`, ar.actual.Status()) + if ar.isNot { + message = strings.ReplaceAll(message, "expected to", "expected not to") + } + logList, err := ar.actual.(*apiResponseImpl).fetchLog() + if err != nil { + return err + } + log := strings.Join(logList, "\n") + if log != "" { + message += "\nCall log:\n" + log + } + + isTextEncoding := false + contentType, ok := ar.actual.Headers()["content-type"] + if ok { + isTextEncoding = isTexualMimeType(contentType) + } + if isTextEncoding { + text, err := ar.actual.Text() + if err == nil { + message += fmt.Sprintf(`\n Response Text:\n %s`, subString(text, 0, 1000)) + } + } + return errors.New(message) +} + +func isTexualMimeType(mimeType string) bool { + re := regexp.MustCompile(`^(text\/.*?|application\/(json|(x-)?javascript|xml.*?|ecmascript|graphql|x-www-form-urlencoded)|image\/svg(\+xml)?|application\/.*?(\+json|\+xml))(;\s*charset=.*)?$`) + return re.MatchString(mimeType) +} + +func subString(s string, start, length int) string { + if start < 0 { + start = 0 + } + if length < 0 { + length = 0 + } + rs := []rune(s) + end := start + length + if end > len(rs) { + end = len(rs) + } + return string(rs[start:end]) +} diff --git a/vendor/github.com/playwright-community/playwright-go/artifact.go b/vendor/github.com/playwright-community/playwright-go/artifact.go new file mode 100644 index 0000000..c76b892 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/artifact.go @@ -0,0 +1,70 @@ +package playwright + +import ( + "errors" + "fmt" +) + +type artifactImpl struct { + channelOwner +} + +func (a *artifactImpl) AbsolutePath() string { + return a.initializer["absolutePath"].(string) +} + +func (a *artifactImpl) PathAfterFinished() (string, error) { + if a.connection.isRemote { + return "", errors.New("Path is not available when connecting remotely. Use SaveAs() to save a local copy") + } + path, err := a.channel.Send("pathAfterFinished") + return path.(string), err +} + +func (a *artifactImpl) SaveAs(path string) error { + if !a.connection.isRemote { + _, err := a.channel.Send("saveAs", map[string]interface{}{ + "path": path, + }) + return err + } + streamChannel, err := a.channel.Send("saveAsStream") + if err != nil { + return err + } + stream := fromChannel(streamChannel).(*streamImpl) + return stream.SaveAs(path) +} + +func (a *artifactImpl) Failure() error { + reason, err := a.channel.Send("failure") + if reason == nil { + return err + } + return fmt.Errorf("%w: %v", ErrPlaywright, reason) +} + +func (a *artifactImpl) Delete() error { + _, err := a.channel.Send("delete") + return err +} + +func (a *artifactImpl) Cancel() error { + _, err := a.channel.Send("cancel") + return err +} + +func (a *artifactImpl) ReadIntoBuffer() ([]byte, error) { + streamChannel, err := a.channel.Send("stream") + if err != nil { + return nil, err + } + stream := fromChannel(streamChannel) + return stream.(*streamImpl).ReadAll() +} + +func newArtifact(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *artifactImpl { + artifact := &artifactImpl{} + artifact.createChannelOwner(artifact, parent, objectType, guid, initializer) + return artifact +} diff --git a/vendor/github.com/playwright-community/playwright-go/assertions.go b/vendor/github.com/playwright-community/playwright-go/assertions.go new file mode 100644 index 0000000..5e0e710 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/assertions.go @@ -0,0 +1,146 @@ +package playwright + +import ( + "errors" + "fmt" + "reflect" + "regexp" + "strings" +) + +const assertionsDefaultTimeout = 5000 // 5s + +type playwrightAssertionsImpl struct { + defaultTimeout *float64 +} + +// NewPlaywrightAssertions creates a new instance of PlaywrightAssertions +// - timeout: default value is 5000 (ms) +func NewPlaywrightAssertions(timeout ...float64) PlaywrightAssertions { + if len(timeout) > 0 { + return &playwrightAssertionsImpl{Float(timeout[0])} + } + return &playwrightAssertionsImpl{Float(assertionsDefaultTimeout)} +} + +func (pa *playwrightAssertionsImpl) APIResponse(response APIResponse) APIResponseAssertions { + return newAPIResponseAssertions(response, false) +} + +func (pa *playwrightAssertionsImpl) Locator(locator Locator) LocatorAssertions { + return newLocatorAssertions(locator, false, pa.defaultTimeout) +} + +func (pa *playwrightAssertionsImpl) Page(page Page) PageAssertions { + return newPageAssertions(page, false, pa.defaultTimeout) +} + +type expectedTextValue struct { + Str *string `json:"string,omitempty"` + RegexSource *string `json:"regexSource,omitempty"` + RegexFlags *string `json:"regexFlags,omitempty"` + MatchSubstring *bool `json:"matchSubstring,omitempty"` + IgnoreCase *bool `json:"ignoreCase,omitempty"` + NormalizeWhiteSpace *bool `json:"normalizeWhiteSpace,omitempty"` +} + +type frameExpectOptions struct { + ExpressionArg interface{} `json:"expressionArg,omitempty"` + ExpectedText []expectedTextValue `json:"expectedText,omitempty"` + ExpectedNumber *float64 `json:"expectedNumber,omitempty"` + ExpectedValue interface{} `json:"expectedValue,omitempty"` + UseInnerText *bool `json:"useInnerText,omitempty"` + IsNot bool `json:"isNot"` + Timeout *float64 `json:"timeout"` +} + +type frameExpectResult struct { + Matches bool `json:"matches"` + Received interface{} `json:"received,omitempty"` + TimedOut *bool `json:"timedOut,omitempty"` + Log []string `json:"log,omitempty"` +} + +type assertionsBase struct { + actualLocator Locator + isNot bool + defaultTimeout *float64 +} + +func (b *assertionsBase) expect( + expression string, + options frameExpectOptions, + expected interface{}, + message string, +) error { + options.IsNot = b.isNot + if options.Timeout == nil { + options.Timeout = b.defaultTimeout + } + if options.IsNot { + message = strings.ReplaceAll(message, "expected to", "expected not to") + } + result, err := b.actualLocator.(*locatorImpl).expect(expression, options) + if err != nil { + return err + } + + if result.Matches == b.isNot { + actual := result.Received + log := strings.Join(result.Log, "\n") + if log != "" { + log = "\nCall log:\n" + log + } + if expected != nil { + return fmt.Errorf("%s '%v'\nActual value: %v %s", message, expected, actual, log) + } + return fmt.Errorf("%s\nActual value: %v %s", message, actual, log) + } + + return nil +} + +func toExpectedTextValues( + items []interface{}, + matchSubstring bool, + normalizeWhiteSpace bool, + ignoreCase *bool, +) ([]expectedTextValue, error) { + var out []expectedTextValue + for _, item := range items { + switch item := item.(type) { + case string: + out = append(out, expectedTextValue{ + Str: String(item), + MatchSubstring: Bool(matchSubstring), + NormalizeWhiteSpace: Bool(normalizeWhiteSpace), + IgnoreCase: ignoreCase, + }) + case *regexp.Regexp: + pattern, flags := convertRegexp(item) + out = append(out, expectedTextValue{ + RegexSource: String(pattern), + RegexFlags: String(flags), + MatchSubstring: Bool(matchSubstring), + NormalizeWhiteSpace: Bool(normalizeWhiteSpace), + IgnoreCase: ignoreCase, + }) + default: + return nil, errors.New("value must be a string or regexp") + } + } + return out, nil +} + +func convertToInterfaceList(v interface{}) []interface{} { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Slice { + return []interface{}{v} + } + + list := make([]interface{}, rv.Len()) + for i := 0; i < rv.Len(); i++ { + list[i] = rv.Index(i).Interface() + } + return list +} diff --git a/vendor/github.com/playwright-community/playwright-go/binding_call.go b/vendor/github.com/playwright-community/playwright-go/binding_call.go new file mode 100644 index 0000000..8468992 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/binding_call.go @@ -0,0 +1,87 @@ +package playwright + +import ( + "fmt" + "strings" + + "github.com/go-stack/stack" +) + +type BindingCall interface { + Call(f BindingCallFunction) +} + +type bindingCallImpl struct { + channelOwner +} + +// BindingSource is the value passed to a binding call execution +type BindingSource struct { + Context BrowserContext + Page Page + Frame Frame +} + +// ExposedFunction represents the func signature of an exposed function +type ExposedFunction = func(args ...interface{}) interface{} + +// BindingCallFunction represents the func signature of an exposed binding call func +type BindingCallFunction func(source *BindingSource, args ...interface{}) interface{} + +func (b *bindingCallImpl) Call(f BindingCallFunction) { + defer func() { + if r := recover(); r != nil { + if _, err := b.channel.Send("reject", map[string]interface{}{ + "error": serializeError(r.(error)), + }); err != nil { + logger.Error("could not reject BindingCall", "error", err) + } + } + }() + + frame := fromChannel(b.initializer["frame"]).(*frameImpl) + source := &BindingSource{ + Context: frame.Page().Context(), + Page: frame.Page(), + Frame: frame, + } + var result interface{} + if handle, ok := b.initializer["handle"]; ok { + result = f(source, fromChannel(handle)) + } else { + initializerArgs := b.initializer["args"].([]interface{}) + funcArgs := []interface{}{} + for i := 0; i < len(initializerArgs); i++ { + funcArgs = append(funcArgs, parseResult(initializerArgs[i])) + } + result = f(source, funcArgs...) + } + _, err := b.channel.Send("resolve", map[string]interface{}{ + "result": serializeArgument(result), + }) + if err != nil { + logger.Error("could not resolve BindingCall", "error", err) + } +} + +func serializeError(err error) map[string]interface{} { + st := stack.Trace().TrimRuntime() + if len(st) == 0 { // https://github.com/go-stack/stack/issues/27 + st = stack.Trace() + } + return map[string]interface{}{ + "error": &Error{ + Name: "Playwright for Go Error", + Message: err.Error(), + Stack: strings.ReplaceAll(strings.TrimFunc(fmt.Sprintf("%+v", st), func(r rune) bool { + return r == '[' || r == ']' + }), " ", "\n"), + }, + } +} + +func newBindingCall(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *bindingCallImpl { + bt := &bindingCallImpl{} + bt.createChannelOwner(bt, parent, objectType, guid, initializer) + return bt +} diff --git a/vendor/github.com/playwright-community/playwright-go/browser.go b/vendor/github.com/playwright-community/playwright-go/browser.go new file mode 100644 index 0000000..c87540a --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/browser.go @@ -0,0 +1,274 @@ +package playwright + +import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" +) + +type browserImpl struct { + channelOwner + isConnected bool + shouldCloseConnectionOnClose bool + contexts []BrowserContext + browserType BrowserType + chromiumTracingPath *string + closeReason *string +} + +func (b *browserImpl) BrowserType() BrowserType { + return b.browserType +} + +func (b *browserImpl) IsConnected() bool { + b.RLock() + defer b.RUnlock() + return b.isConnected +} + +func (b *browserImpl) NewContext(options ...BrowserNewContextOptions) (BrowserContext, error) { + overrides := map[string]interface{}{} + option := BrowserNewContextOptions{} + 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 + } + if option.ClientCertificates != nil { + certs, err := transformClientCertificate(option.ClientCertificates) + if err != nil { + return nil, err + } + overrides["clientCertificates"] = certs + options[0].ClientCertificates = nil + } + if option.StorageStatePath != nil { + var storageState *OptionalStorageState + storageString, err := os.ReadFile(*options[0].StorageStatePath) + if err != nil { + return nil, fmt.Errorf("could not read storage state file: %w", err) + } + err = json.Unmarshal(storageString, &storageState) + if err != nil { + return nil, fmt.Errorf("could not parse storage state file: %w", err) + } + options[0].StorageState = storageState + options[0].StorageStatePath = nil + } + if option.NoViewport != nil && *options[0].NoViewport { + overrides["noDefaultViewport"] = true + options[0].NoViewport = nil + } + if option.RecordHarPath != nil { + overrides["recordHar"] = prepareRecordHarOptions(recordHarInputOptions{ + Path: *options[0].RecordHarPath, + URL: options[0].RecordHarURLFilter, + Mode: options[0].RecordHarMode, + Content: options[0].RecordHarContent, + OmitContent: options[0].RecordHarOmitContent, + }) + options[0].RecordHarPath = nil + options[0].RecordHarURLFilter = nil + options[0].RecordHarMode = nil + options[0].RecordHarContent = nil + options[0].RecordHarOmitContent = nil + } + channel, err := b.channel.Send("newContext", options, overrides) + if err != nil { + return nil, err + } + context := fromChannel(channel).(*browserContextImpl) + context.browser = b + b.browserType.(*browserTypeImpl).didCreateContext(context, &option, nil) + return context, nil +} + +func (b *browserImpl) NewPage(options ...BrowserNewPageOptions) (Page, error) { + opts := make([]BrowserNewContextOptions, 0) + if len(options) == 1 { + opts = append(opts, BrowserNewContextOptions(options[0])) + } + context, err := b.NewContext(opts...) + if err != nil { + return nil, err + } + page, err := context.NewPage() + if err != nil { + return nil, err + } + page.(*pageImpl).ownedContext = context + context.(*browserContextImpl).ownedPage = page + return page, nil +} + +func (b *browserImpl) NewBrowserCDPSession() (CDPSession, error) { + channel, err := b.channel.Send("newBrowserCDPSession") + if err != nil { + return nil, err + } + + cdpSession := fromChannel(channel).(*cdpSessionImpl) + + return cdpSession, nil +} + +func (b *browserImpl) Contexts() []BrowserContext { + b.Lock() + defer b.Unlock() + return b.contexts +} + +func (b *browserImpl) Close(options ...BrowserCloseOptions) (err error) { + if len(options) == 1 { + b.closeReason = options[0].Reason + } + + if b.shouldCloseConnectionOnClose { + err = b.connection.Stop() + } else if b.closeReason != nil { + _, err = b.channel.Send("close", map[string]interface{}{ + "reason": b.closeReason, + }) + } else { + _, err = b.channel.Send("close") + } + if err != nil && !errors.Is(err, ErrTargetClosed) { + return fmt.Errorf("close browser failed: %w", err) + } + return nil +} + +func (b *browserImpl) Version() string { + return b.initializer["version"].(string) +} + +func (b *browserImpl) StartTracing(options ...BrowserStartTracingOptions) error { + overrides := map[string]interface{}{} + option := BrowserStartTracingOptions{} + if len(options) == 1 { + option = options[0] + } + if option.Page != nil { + overrides["page"] = option.Page.(*pageImpl).channel + option.Page = nil + } + if option.Path != nil { + b.chromiumTracingPath = option.Path + option.Path = nil + } + _, err := b.channel.Send("startTracing", option, overrides) + return err +} + +func (b *browserImpl) StopTracing() ([]byte, error) { + channel, err := b.channel.Send("stopTracing") + if err != nil { + return nil, err + } + artifact := fromChannel(channel).(*artifactImpl) + binary, err := artifact.ReadIntoBuffer() + if err != nil { + return nil, err + } + err = artifact.Delete() + if err != nil { + return binary, err + } + if b.chromiumTracingPath != nil { + err := os.MkdirAll(filepath.Dir(*b.chromiumTracingPath), 0o777) + if err != nil { + return binary, err + } + err = os.WriteFile(*b.chromiumTracingPath, binary, 0o644) + if err != nil { + return binary, err + } + } + return binary, nil +} + +func (b *browserImpl) onClose() { + b.Lock() + if b.isConnected { + b.isConnected = false + b.Unlock() + b.Emit("disconnected", b) + return + } + b.Unlock() +} + +func (b *browserImpl) OnDisconnected(fn func(Browser)) { + b.On("disconnected", fn) +} + +func newBrowser(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *browserImpl { + b := &browserImpl{ + isConnected: true, + contexts: make([]BrowserContext, 0), + } + b.createChannelOwner(b, parent, objectType, guid, initializer) + // convert parent to *browserTypeImpl + b.browserType = newBrowserType(parent.parent, parent.objectType, parent.guid, parent.initializer) + b.channel.On("close", b.onClose) + return b +} + +func transformClientCertificate(clientCertificates []ClientCertificate) ([]map[string]interface{}, error) { + results := make([]map[string]interface{}, 0) + + for _, cert := range clientCertificates { + data := map[string]interface{}{ + "origin": cert.Origin, + "passphrase": cert.Passphrase, + } + if len(cert.Cert) > 0 { + data["cert"] = base64.StdEncoding.EncodeToString(cert.Cert) + } else if cert.CertPath != nil { + content, err := os.ReadFile(*cert.CertPath) + if err != nil { + return nil, err + } + data["cert"] = base64.StdEncoding.EncodeToString(content) + } + + if len(cert.Key) > 0 { + data["key"] = base64.StdEncoding.EncodeToString(cert.Key) + } else if cert.KeyPath != nil { + content, err := os.ReadFile(*cert.KeyPath) + if err != nil { + return nil, err + } + data["key"] = base64.StdEncoding.EncodeToString(content) + } + + if len(cert.Pfx) > 0 { + data["pfx"] = base64.StdEncoding.EncodeToString(cert.Pfx) + } else if cert.PfxPath != nil { + content, err := os.ReadFile(*cert.PfxPath) + if err != nil { + return nil, err + } + data["pfx"] = base64.StdEncoding.EncodeToString(content) + } + + results = append(results, data) + } + if len(results) == 0 { + return nil, nil + } + return results, nil +} diff --git a/vendor/github.com/playwright-community/playwright-go/browser_context.go b/vendor/github.com/playwright-community/playwright-go/browser_context.go new file mode 100644 index 0000000..1d420d3 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/browser_context.go @@ -0,0 +1,914 @@ +package playwright + +import ( + "encoding/json" + "errors" + "fmt" + "os" + "regexp" + "slices" + "strings" + "sync" + + "github.com/playwright-community/playwright-go/internal/safe" +) + +type browserContextImpl struct { + channelOwner + timeoutSettings *timeoutSettings + closeWasCalled bool + options *BrowserNewContextOptions + pages []Page + routes []*routeHandlerEntry + webSocketRoutes []*webSocketRouteHandler + ownedPage Page + browser *browserImpl + serviceWorkers []Worker + backgroundPages []Page + bindings *safe.SyncMap[string, BindingCallFunction] + tracing *tracingImpl + request *apiRequestContextImpl + harRecorders map[string]harRecordingMetadata + closed chan struct{} + closeReason *string + harRouters []*harRouter + clock Clock +} + +func (b *browserContextImpl) Clock() Clock { + return b.clock +} + +func (b *browserContextImpl) SetDefaultNavigationTimeout(timeout float64) { + b.setDefaultNavigationTimeoutImpl(&timeout) +} + +func (b *browserContextImpl) setDefaultNavigationTimeoutImpl(timeout *float64) { + b.timeoutSettings.SetDefaultNavigationTimeout(timeout) + b.channel.SendNoReplyInternal("setDefaultNavigationTimeoutNoReply", map[string]interface{}{ + "timeout": timeout, + }) +} + +func (b *browserContextImpl) SetDefaultTimeout(timeout float64) { + b.setDefaultTimeoutImpl(&timeout) +} + +func (b *browserContextImpl) setDefaultTimeoutImpl(timeout *float64) { + b.timeoutSettings.SetDefaultTimeout(timeout) + b.channel.SendNoReplyInternal("setDefaultTimeoutNoReply", map[string]interface{}{ + "timeout": timeout, + }) +} + +func (b *browserContextImpl) Pages() []Page { + b.Lock() + defer b.Unlock() + return b.pages +} + +func (b *browserContextImpl) Browser() Browser { + return b.browser +} + +func (b *browserContextImpl) Tracing() Tracing { + return b.tracing +} + +func (b *browserContextImpl) NewCDPSession(page interface{}) (CDPSession, error) { + params := map[string]interface{}{} + + if p, ok := page.(*pageImpl); ok { + params["page"] = p.channel + } else if f, ok := page.(*frameImpl); ok { + params["frame"] = f.channel + } else { + return nil, fmt.Errorf("not page or frame: %v", page) + } + + channel, err := b.channel.Send("newCDPSession", params) + if err != nil { + return nil, err + } + + cdpSession := fromChannel(channel).(*cdpSessionImpl) + + return cdpSession, nil +} + +func (b *browserContextImpl) NewPage() (Page, error) { + if b.ownedPage != nil { + return nil, errors.New("Please use browser.NewContext()") + } + channel, err := b.channel.Send("newPage") + if err != nil { + return nil, err + } + return fromChannel(channel).(*pageImpl), nil +} + +func (b *browserContextImpl) Cookies(urls ...string) ([]Cookie, error) { + result, err := b.channel.Send("cookies", map[string]interface{}{ + "urls": urls, + }) + if err != nil { + return nil, err + } + cookies := make([]Cookie, len(result.([]interface{}))) + for i, item := range result.([]interface{}) { + cookie := &Cookie{} + remapMapToStruct(item, cookie) + cookies[i] = *cookie + } + return cookies, nil +} + +func (b *browserContextImpl) AddCookies(cookies []OptionalCookie) error { + _, err := b.channel.Send("addCookies", map[string]interface{}{ + "cookies": cookies, + }) + return err +} + +func (b *browserContextImpl) ClearCookies(options ...BrowserContextClearCookiesOptions) error { + params := map[string]interface{}{} + if len(options) == 1 { + if options[0].Domain != nil { + switch t := options[0].Domain.(type) { + case string: + params["domain"] = t + case *string: + params["domain"] = t + case *regexp.Regexp: + pattern, flag := convertRegexp(t) + params["domainRegexSource"] = pattern + params["domainRegexFlags"] = flag + default: + return errors.New("invalid type for domain, expected string or *regexp.Regexp") + } + } + if options[0].Name != nil { + switch t := options[0].Name.(type) { + case string: + params["name"] = t + case *string: + params["name"] = t + case *regexp.Regexp: + pattern, flag := convertRegexp(t) + params["nameRegexSource"] = pattern + params["nameRegexFlags"] = flag + default: + return errors.New("invalid type for name, expected string or *regexp.Regexp") + } + } + if options[0].Path != nil { + switch t := options[0].Path.(type) { + case string: + params["path"] = t + case *string: + params["path"] = t + case *regexp.Regexp: + pattern, flag := convertRegexp(t) + params["pathRegexSource"] = pattern + params["pathRegexFlags"] = flag + default: + return errors.New("invalid type for path, expected string or *regexp.Regexp") + } + } + } + _, err := b.channel.Send("clearCookies", params) + return err +} + +func (b *browserContextImpl) GrantPermissions(permissions []string, options ...BrowserContextGrantPermissionsOptions) error { + _, err := b.channel.Send("grantPermissions", map[string]interface{}{ + "permissions": permissions, + }, options) + return err +} + +func (b *browserContextImpl) ClearPermissions() error { + _, err := b.channel.Send("clearPermissions") + return err +} + +func (b *browserContextImpl) SetGeolocation(geolocation *Geolocation) error { + _, err := b.channel.Send("setGeolocation", map[string]interface{}{ + "geolocation": geolocation, + }) + return err +} + +func (b *browserContextImpl) ResetGeolocation() error { + _, err := b.channel.Send("setGeolocation", map[string]interface{}{}) + return err +} + +func (b *browserContextImpl) SetExtraHTTPHeaders(headers map[string]string) error { + _, err := b.channel.Send("setExtraHTTPHeaders", map[string]interface{}{ + "headers": serializeMapToNameAndValue(headers), + }) + return err +} + +func (b *browserContextImpl) SetOffline(offline bool) error { + _, err := b.channel.Send("setOffline", map[string]interface{}{ + "offline": offline, + }) + return err +} + +func (b *browserContextImpl) AddInitScript(script Script) error { + var source string + if script.Content != nil { + source = *script.Content + } + if script.Path != nil { + content, err := os.ReadFile(*script.Path) + if err != nil { + return err + } + source = string(content) + } + _, err := b.channel.Send("addInitScript", map[string]interface{}{ + "source": source, + }) + return err +} + +func (b *browserContextImpl) ExposeBinding(name string, binding BindingCallFunction, handle ...bool) error { + needsHandle := false + if len(handle) == 1 { + needsHandle = handle[0] + } + for _, page := range b.Pages() { + if _, ok := page.(*pageImpl).bindings.Load(name); ok { + return fmt.Errorf("Function '%s' has been already registered in one of the pages", name) + } + } + if _, ok := b.bindings.Load(name); ok { + return fmt.Errorf("Function '%s' has been already registered", name) + } + _, err := b.channel.Send("exposeBinding", map[string]interface{}{ + "name": name, + "needsHandle": needsHandle, + }) + if err != nil { + return err + } + b.bindings.Store(name, binding) + return err +} + +func (b *browserContextImpl) ExposeFunction(name string, binding ExposedFunction) error { + return b.ExposeBinding(name, func(source *BindingSource, args ...interface{}) interface{} { + return binding(args...) + }) +} + +func (b *browserContextImpl) Route(url interface{}, handler routeHandler, times ...int) error { + b.Lock() + defer b.Unlock() + b.routes = slices.Insert(b.routes, 0, newRouteHandlerEntry(newURLMatcher(url, b.options.BaseURL), handler, times...)) + return b.updateInterceptionPatterns() +} + +func (b *browserContextImpl) Unroute(url interface{}, handlers ...routeHandler) error { + removed, remaining, err := unroute(b.routes, url, handlers...) + if err != nil { + return err + } + return b.unrouteInternal(removed, remaining, UnrouteBehaviorDefault) +} + +func (b *browserContextImpl) unrouteInternal(removed []*routeHandlerEntry, remaining []*routeHandlerEntry, behavior *UnrouteBehavior) error { + b.Lock() + defer b.Unlock() + b.routes = remaining + if err := b.updateInterceptionPatterns(); err != nil { + return err + } + if behavior == nil || behavior == UnrouteBehaviorDefault { + return nil + } + wg := &sync.WaitGroup{} + for _, entry := range removed { + wg.Add(1) + go func(entry *routeHandlerEntry) { + defer wg.Done() + entry.Stop(string(*behavior)) + }(entry) + } + wg.Wait() + return nil +} + +func (b *browserContextImpl) UnrouteAll(options ...BrowserContextUnrouteAllOptions) error { + var behavior *UnrouteBehavior + if len(options) == 1 { + behavior = options[0].Behavior + } + defer b.disposeHarRouters() + return b.unrouteInternal(b.routes, []*routeHandlerEntry{}, behavior) +} + +func (b *browserContextImpl) disposeHarRouters() { + for _, router := range b.harRouters { + router.dispose() + } + b.harRouters = make([]*harRouter, 0) +} + +func (b *browserContextImpl) Request() APIRequestContext { + return b.request +} + +func (b *browserContextImpl) RouteFromHAR(har string, options ...BrowserContextRouteFromHAROptions) error { + opt := BrowserContextRouteFromHAROptions{} + if len(options) == 1 { + opt = options[0] + } + if opt.Update != nil && *opt.Update { + var updateContent *HarContentPolicy + switch opt.UpdateContent { + case RouteFromHarUpdateContentPolicyAttach: + updateContent = HarContentPolicyAttach + case RouteFromHarUpdateContentPolicyEmbed: + updateContent = HarContentPolicyEmbed + } + return b.recordIntoHar(har, browserContextRecordIntoHarOptions{ + URL: opt.URL, + UpdateContent: updateContent, + UpdateMode: opt.UpdateMode, + }) + } + notFound := opt.NotFound + if notFound == nil { + notFound = HarNotFoundAbort + } + router := newHarRouter(b.connection.localUtils, har, *notFound, opt.URL) + b.harRouters = append(b.harRouters, router) + return router.addContextRoute(b) +} + +func (b *browserContextImpl) WaitForEvent(event string, options ...BrowserContextWaitForEventOptions) (interface{}, error) { + return b.waiterForEvent(event, options...).Wait() +} + +func (b *browserContextImpl) waiterForEvent(event string, options ...BrowserContextWaitForEventOptions) *waiter { + timeout := b.timeoutSettings.Timeout() + var predicate interface{} = nil + if len(options) == 1 { + if options[0].Timeout != nil { + timeout = *options[0].Timeout + } + predicate = options[0].Predicate + } + waiter := newWaiter().WithTimeout(timeout) + waiter.RejectOnEvent(b, "close", ErrTargetClosed) + return waiter.WaitForEvent(b, event, predicate) +} + +func (b *browserContextImpl) ExpectConsoleMessage(cb func() error, options ...BrowserContextExpectConsoleMessageOptions) (ConsoleMessage, error) { + var w *waiter + if len(options) == 1 { + w = b.waiterForEvent("console", BrowserContextWaitForEventOptions{ + Predicate: options[0].Predicate, + Timeout: options[0].Timeout, + }) + } else { + w = b.waiterForEvent("console") + } + ret, err := w.RunAndWait(cb) + if err != nil { + return nil, err + } + return ret.(ConsoleMessage), nil +} + +func (b *browserContextImpl) ExpectEvent(event string, cb func() error, options ...BrowserContextExpectEventOptions) (interface{}, error) { + if len(options) == 1 { + return b.waiterForEvent(event, BrowserContextWaitForEventOptions(options[0])).RunAndWait(cb) + } + return b.waiterForEvent(event).RunAndWait(cb) +} + +func (b *browserContextImpl) ExpectPage(cb func() error, options ...BrowserContextExpectPageOptions) (Page, error) { + var w *waiter + if len(options) == 1 { + w = b.waiterForEvent("page", BrowserContextWaitForEventOptions{ + Predicate: options[0].Predicate, + Timeout: options[0].Timeout, + }) + } else { + w = b.waiterForEvent("page") + } + ret, err := w.RunAndWait(cb) + if err != nil { + return nil, err + } + return ret.(Page), nil +} + +func (b *browserContextImpl) Close(options ...BrowserContextCloseOptions) error { + if b.closeWasCalled { + return nil + } + if len(options) == 1 { + b.closeReason = options[0].Reason + } + b.closeWasCalled = true + + _, err := b.channel.connection.WrapAPICall(func() (interface{}, error) { + return nil, b.request.Dispose(APIRequestContextDisposeOptions{ + Reason: b.closeReason, + }) + }, true) + if err != nil { + return err + } + + innerClose := func() (interface{}, error) { + for harId, harMetaData := range b.harRecorders { + overrides := map[string]interface{}{} + if harId != "" { + overrides["harId"] = harId + } + response, err := b.channel.Send("harExport", overrides) + if err != nil { + return nil, err + } + artifact := fromChannel(response).(*artifactImpl) + // Server side will compress artifact if content is attach or if file is .zip. + needCompressed := strings.HasSuffix(strings.ToLower(harMetaData.Path), ".zip") + if !needCompressed && harMetaData.Content == HarContentPolicyAttach { + tmpPath := harMetaData.Path + ".tmp" + if err := artifact.SaveAs(tmpPath); err != nil { + return nil, err + } + err = b.connection.localUtils.HarUnzip(tmpPath, harMetaData.Path) + if err != nil { + return nil, err + } + } else { + if err := artifact.SaveAs(harMetaData.Path); err != nil { + return nil, err + } + } + if err := artifact.Delete(); err != nil { + return nil, err + } + } + return nil, nil + } + + _, err = b.channel.connection.WrapAPICall(innerClose, true) + if err != nil { + return err + } + + _, err = b.channel.Send("close", map[string]interface{}{ + "reason": b.closeReason, + }) + if err != nil { + return err + } + <-b.closed + return err +} + +type browserContextRecordIntoHarOptions struct { + Page Page + URL interface{} + UpdateContent *HarContentPolicy + UpdateMode *HarMode +} + +func (b *browserContextImpl) recordIntoHar(har string, options ...browserContextRecordIntoHarOptions) error { + overrides := map[string]interface{}{} + harOptions := recordHarInputOptions{ + Path: har, + Content: HarContentPolicyAttach, + Mode: HarModeMinimal, + } + if len(options) == 1 { + if options[0].UpdateContent != nil { + harOptions.Content = options[0].UpdateContent + } + if options[0].UpdateMode != nil { + harOptions.Mode = options[0].UpdateMode + } + harOptions.URL = options[0].URL + overrides["options"] = prepareRecordHarOptions(harOptions) + if options[0].Page != nil { + overrides["page"] = options[0].Page.(*pageImpl).channel + } + } + harId, err := b.channel.Send("harStart", overrides) + if err != nil { + return err + } + b.harRecorders[harId.(string)] = harRecordingMetadata{ + Path: har, + Content: harOptions.Content, + } + return nil +} + +func (b *browserContextImpl) StorageState(paths ...string) (*StorageState, error) { + result, err := b.channel.SendReturnAsDict("storageState") + if err != nil { + return nil, err + } + if len(paths) == 1 { + file, err := os.Create(paths[0]) + if err != nil { + return nil, err + } + if err := json.NewEncoder(file).Encode(result); err != nil { + return nil, err + } + if err := file.Close(); err != nil { + return nil, err + } + } + var storageState StorageState + remapMapToStruct(result, &storageState) + return &storageState, nil +} + +func (b *browserContextImpl) onBinding(binding *bindingCallImpl) { + function, ok := b.bindings.Load(binding.initializer["name"].(string)) + if !ok || function == nil { + return + } + go binding.Call(function) +} + +func (b *browserContextImpl) onClose() { + if b.browser != nil { + contexts := make([]BrowserContext, 0) + b.browser.Lock() + for _, context := range b.browser.contexts { + if context != b { + contexts = append(contexts, context) + } + } + b.browser.contexts = contexts + b.browser.Unlock() + } + b.disposeHarRouters() + b.Emit("close", b) +} + +func (b *browserContextImpl) onPage(page Page) { + b.Lock() + b.pages = append(b.pages, page) + b.Unlock() + b.Emit("page", page) + opener, _ := page.Opener() + if opener != nil && !opener.IsClosed() { + opener.Emit("popup", page) + } +} + +func (b *browserContextImpl) onRoute(route *routeImpl) { + b.Lock() + route.context = b + page := route.Request().(*requestImpl).safePage() + routes := make([]*routeHandlerEntry, len(b.routes)) + copy(routes, b.routes) + b.Unlock() + + checkInterceptionIfNeeded := func() { + b.Lock() + defer b.Unlock() + if len(b.routes) == 0 { + _, err := b.connection.WrapAPICall(func() (interface{}, error) { + err := b.updateInterceptionPatterns() + return nil, err + }, true) + if err != nil { + logger.Error("could not update interception patterns", "error", err) + } + } + } + + url := route.Request().URL() + for _, handlerEntry := range routes { + // If the page or the context was closed we stall all requests right away. + if (page != nil && page.closeWasCalled) || b.closeWasCalled { + return + } + if !handlerEntry.Matches(url) { + continue + } + if !slices.ContainsFunc(b.routes, func(entry *routeHandlerEntry) bool { + return entry == handlerEntry + }) { + continue + } + if handlerEntry.WillExceed() { + b.routes = slices.DeleteFunc(b.routes, func(rhe *routeHandlerEntry) bool { + return rhe == handlerEntry + }) + } + handled := handlerEntry.Handle(route) + checkInterceptionIfNeeded() + yes := <-handled + if yes { + return + } + } + // If the page is closed or unrouteAll() was called without waiting and interception disabled, + // the method will throw an error - silence it. + _ = route.internalContinue(true) +} + +func (b *browserContextImpl) updateInterceptionPatterns() error { + patterns := prepareInterceptionPatterns(b.routes) + _, err := b.channel.Send("setNetworkInterceptionPatterns", map[string]interface{}{ + "patterns": patterns, + }) + return err +} + +func (b *browserContextImpl) pause() <-chan error { + ret := make(chan error, 1) + go func() { + _, err := b.channel.Send("pause") + ret <- err + }() + return ret +} + +func (b *browserContextImpl) onBackgroundPage(ev map[string]interface{}) { + b.Lock() + p := fromChannel(ev["page"]).(*pageImpl) + p.browserContext = b + b.backgroundPages = append(b.backgroundPages, p) + b.Unlock() + b.Emit("backgroundpage", p) +} + +func (b *browserContextImpl) onServiceWorker(worker *workerImpl) { + worker.context = b + b.serviceWorkers = append(b.serviceWorkers, worker) + b.Emit("serviceworker", worker) +} + +func (b *browserContextImpl) setOptions(options *BrowserNewContextOptions, tracesDir *string) { + if options == nil { + options = &BrowserNewContextOptions{} + } + b.options = options + if b.options != nil && b.options.RecordHarPath != nil { + b.harRecorders[""] = harRecordingMetadata{ + Path: *b.options.RecordHarPath, + Content: b.options.RecordHarContent, + } + } + if tracesDir != nil { + b.tracing.tracesDir = *tracesDir + } +} + +func (b *browserContextImpl) BackgroundPages() []Page { + b.Lock() + defer b.Unlock() + return b.backgroundPages +} + +func (b *browserContextImpl) ServiceWorkers() []Worker { + b.Lock() + defer b.Unlock() + return b.serviceWorkers +} + +func (b *browserContextImpl) OnBackgroundPage(fn func(Page)) { + b.On("backgroundpage", fn) +} + +func (b *browserContextImpl) OnClose(fn func(BrowserContext)) { + b.On("close", fn) +} + +func (b *browserContextImpl) OnConsole(fn func(ConsoleMessage)) { + b.On("console", fn) +} + +func (b *browserContextImpl) OnDialog(fn func(Dialog)) { + b.On("dialog", fn) +} + +func (b *browserContextImpl) OnPage(fn func(Page)) { + b.On("page", fn) +} + +func (b *browserContextImpl) OnRequest(fn func(Request)) { + b.On("request", fn) +} + +func (b *browserContextImpl) OnRequestFailed(fn func(Request)) { + b.On("requestfailed", fn) +} + +func (b *browserContextImpl) OnRequestFinished(fn func(Request)) { + b.On("requestfinished", fn) +} + +func (b *browserContextImpl) OnResponse(fn func(Response)) { + b.On("response", fn) +} + +func (b *browserContextImpl) OnWebError(fn func(WebError)) { + b.On("weberror", fn) +} + +func (b *browserContextImpl) RouteWebSocket(url interface{}, handler func(WebSocketRoute)) error { + b.Lock() + defer b.Unlock() + b.webSocketRoutes = slices.Insert(b.webSocketRoutes, 0, newWebSocketRouteHandler(newURLMatcher(url, b.options.BaseURL), handler)) + + return b.updateWebSocketInterceptionPatterns() +} + +func (b *browserContextImpl) onWebSocketRoute(wr WebSocketRoute) { + b.Lock() + index := slices.IndexFunc(b.webSocketRoutes, func(r *webSocketRouteHandler) bool { + return r.Matches(wr.URL()) + }) + if index == -1 { + b.Unlock() + _, err := wr.ConnectToServer() + if err != nil { + logger.Error("could not connect to WebSocket server", "error", err) + } + return + } + handler := b.webSocketRoutes[index] + b.Unlock() + handler.Handle(wr) +} + +func (b *browserContextImpl) updateWebSocketInterceptionPatterns() error { + patterns := prepareWebSocketRouteHandlerInterceptionPatterns(b.webSocketRoutes) + _, err := b.channel.Send("setWebSocketInterceptionPatterns", map[string]interface{}{ + "patterns": patterns, + }) + return err +} + +func (b *browserContextImpl) effectiveCloseReason() *string { + b.Lock() + defer b.Unlock() + if b.closeReason != nil { + return b.closeReason + } + if b.browser != nil { + return b.browser.closeReason + } + return nil +} + +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: safe.NewSyncMap[string, BindingCallFunction](), + harRecorders: make(map[string]harRecordingMetadata), + closed: make(chan struct{}, 1), + harRouters: make([]*harRouter, 0), + } + bt.createChannelOwner(bt, parent, objectType, guid, initializer) + if parent.objectType == "Browser" { + bt.browser = fromChannel(parent.channel).(*browserImpl) + bt.browser.contexts = append(bt.browser.contexts, bt) + } + bt.tracing = fromChannel(initializer["tracing"]).(*tracingImpl) + bt.request = fromChannel(initializer["requestContext"]).(*apiRequestContextImpl) + bt.clock = newClock(bt) + bt.channel.On("bindingCall", func(params map[string]interface{}) { + bt.onBinding(fromChannel(params["binding"]).(*bindingCallImpl)) + }) + + bt.channel.On("close", bt.onClose) + bt.channel.On("page", func(payload map[string]interface{}) { + bt.onPage(fromChannel(payload["page"]).(*pageImpl)) + }) + bt.channel.On("route", func(params map[string]interface{}) { + bt.channel.CreateTask(func() { + bt.onRoute(fromChannel(params["route"]).(*routeImpl)) + }) + }) + bt.channel.On("webSocketRoute", func(params map[string]interface{}) { + bt.channel.CreateTask(func() { + bt.onWebSocketRoute(fromChannel(params["webSocketRoute"]).(*webSocketRouteImpl)) + }) + }) + bt.channel.On("backgroundPage", bt.onBackgroundPage) + bt.channel.On("serviceWorker", func(params map[string]interface{}) { + bt.onServiceWorker(fromChannel(params["worker"]).(*workerImpl)) + }) + bt.channel.On("console", func(ev map[string]interface{}) { + message := newConsoleMessage(ev) + bt.Emit("console", message) + if message.page != nil { + message.page.Emit("console", message) + } + }) + bt.channel.On("dialog", func(params map[string]interface{}) { + dialog := fromChannel(params["dialog"]).(*dialogImpl) + go func() { + hasListeners := bt.Emit("dialog", dialog) + page := dialog.page + if page != nil { + if page.Emit("dialog", dialog) { + hasListeners = true + } + } + if !hasListeners { + // Although we do similar handling on the server side, we still need this logic + // on the client side due to a possible race condition between two async calls: + // a) removing "dialog" listener subscription (client->server) + // b) actual "dialog" event (server->client) + if dialog.Type() == "beforeunload" { + _ = dialog.Accept() + } else { + _ = dialog.Dismiss() + } + } + }() + }) + bt.channel.On( + "pageError", func(ev map[string]interface{}) { + pwErr := &Error{} + remapMapToStruct(ev["error"].(map[string]interface{})["error"], pwErr) + err := parseError(*pwErr) + 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"]) + bt.Emit("request", request) + if page != nil { + page.(*pageImpl).Emit("request", request) + } + }) + bt.channel.On("requestFailed", func(ev map[string]interface{}) { + request := fromChannel(ev["request"]).(*requestImpl) + failureText := ev["failureText"] + if failureText != nil { + request.failureText = failureText.(string) + } + page := fromNullableChannel(ev["page"]) + request.setResponseEndTiming(ev["responseEndTiming"].(float64)) + bt.Emit("requestfailed", request) + if page != nil { + page.(*pageImpl).Emit("requestfailed", request) + } + }) + + bt.channel.On("requestFinished", func(ev map[string]interface{}) { + request := fromChannel(ev["request"]).(*requestImpl) + response := fromNullableChannel(ev["response"]) + page := fromNullableChannel(ev["page"]) + request.setResponseEndTiming(ev["responseEndTiming"].(float64)) + bt.Emit("requestfinished", request) + if page != nil { + page.(*pageImpl).Emit("requestfinished", request) + } + if response != nil { + close(response.(*responseImpl).finished) + } + }) + bt.channel.On("response", func(ev map[string]interface{}) { + response := fromChannel(ev["response"]).(*responseImpl) + page := fromNullableChannel(ev["page"]) + bt.Emit("response", response) + if page != nil { + page.(*pageImpl).Emit("response", response) + } + }) + bt.Once("close", func() { + bt.closed <- struct{}{} + }) + bt.setEventSubscriptionMapping(map[string]string{ + "console": "console", + "dialog": "dialog", + "request": "request", + "response": "response", + "requestfinished": "requestFinished", + "responsefailed": "responseFailed", + }) + return bt +} diff --git a/vendor/github.com/playwright-community/playwright-go/browser_type.go b/vendor/github.com/playwright-community/playwright-go/browser_type.go new file mode 100644 index 0000000..41a8b18 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/browser_type.go @@ -0,0 +1,181 @@ +package playwright + +import ( + "fmt" +) + +type browserTypeImpl struct { + channelOwner + playwright *Playwright +} + +func (b *browserTypeImpl) Name() string { + return b.initializer["name"].(string) +} + +func (b *browserTypeImpl) ExecutablePath() string { + return b.initializer["executablePath"].(string) +} + +func (b *browserTypeImpl) Launch(options ...BrowserTypeLaunchOptions) (Browser, error) { + overrides := map[string]interface{}{} + if len(options) == 1 && options[0].Env != nil { + overrides["env"] = serializeMapToNameAndValue(options[0].Env) + options[0].Env = nil + } + channel, err := b.channel.Send("launch", options, overrides) + if err != nil { + return nil, err + } + browser := fromChannel(channel).(*browserImpl) + b.didLaunchBrowser(browser) + return browser, nil +} + +func (b *browserTypeImpl) LaunchPersistentContext(userDataDir string, options ...BrowserTypeLaunchPersistentContextOptions) (BrowserContext, error) { + overrides := map[string]interface{}{ + "userDataDir": userDataDir, + } + option := &BrowserNewContextOptions{} + var tracesDir *string = nil + if len(options) == 1 { + tracesDir = options[0].TracesDir + err := assignStructFields(option, options[0], true) + 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].ClientCertificates != nil { + certs, err := transformClientCertificate(options[0].ClientCertificates) + if err != nil { + return nil, err + } + overrides["clientCertificates"] = certs + options[0].ClientCertificates = nil + } + if options[0].ExtraHttpHeaders != nil { + overrides["extraHTTPHeaders"] = serializeMapToNameAndValue(options[0].ExtraHttpHeaders) + options[0].ExtraHttpHeaders = nil + } + if options[0].Env != nil { + overrides["env"] = serializeMapToNameAndValue(options[0].Env) + options[0].Env = nil + } + if options[0].NoViewport != nil && *options[0].NoViewport { + overrides["noDefaultViewport"] = true + options[0].NoViewport = nil + } + if options[0].RecordHarPath != nil { + overrides["recordHar"] = prepareRecordHarOptions(recordHarInputOptions{ + Path: *options[0].RecordHarPath, + URL: options[0].RecordHarURLFilter, + Mode: options[0].RecordHarMode, + Content: options[0].RecordHarContent, + OmitContent: options[0].RecordHarOmitContent, + }) + options[0].RecordHarPath = nil + options[0].RecordHarURLFilter = nil + options[0].RecordHarMode = nil + options[0].RecordHarContent = nil + options[0].RecordHarOmitContent = nil + } + } + channel, err := b.channel.Send("launchPersistentContext", options, overrides) + if err != nil { + return nil, err + } + context := fromChannel(channel).(*browserContextImpl) + b.didCreateContext(context, option, tracesDir) + return context, nil +} + +func (b *browserTypeImpl) Connect(wsEndpoint string, options ...BrowserTypeConnectOptions) (Browser, error) { + overrides := map[string]interface{}{ + "wsEndpoint": wsEndpoint, + "headers": map[string]string{ + "x-playwright-browser": b.Name(), + }, + } + if len(options) == 1 { + if options[0].Headers != nil { + for k, v := range options[0].Headers { + overrides["headers"].(map[string]string)[k] = v + } + options[0].Headers = nil + } + } + localUtils := b.connection.LocalUtils() + pipe, err := localUtils.channel.SendReturnAsDict("connect", options, overrides) + if err != nil { + return nil, err + } + jsonPipe := fromChannel(pipe["pipe"]).(*jsonPipe) + connection := newConnection(jsonPipe, localUtils) + + playwright, err := connection.Start() + if err != nil { + return nil, err + } + playwright.setSelectors(b.playwright.Selectors) + browser := fromChannel(playwright.initializer["preLaunchedBrowser"]).(*browserImpl) + browser.shouldCloseConnectionOnClose = true + pipeClosed := func() { + for _, context := range browser.Contexts() { + pages := context.Pages() + for _, page := range pages { + page.(*pageImpl).onClose() + } + context.(*browserContextImpl).onClose() + } + browser.onClose() + connection.cleanup() + } + jsonPipe.On("closed", pipeClosed) + + b.didLaunchBrowser(browser) + return browser, nil +} + +func (b *browserTypeImpl) ConnectOverCDP(endpointURL string, options ...BrowserTypeConnectOverCDPOptions) (Browser, error) { + overrides := map[string]interface{}{ + "endpointURL": endpointURL, + } + if len(options) == 1 { + if options[0].Headers != nil { + overrides["headers"] = serializeMapToNameAndValue(options[0].Headers) + options[0].Headers = nil + } + } + response, err := b.channel.SendReturnAsDict("connectOverCDP", options, overrides) + if err != nil { + return nil, err + } + browser := fromChannel(response["browser"]).(*browserImpl) + b.didLaunchBrowser(browser) + if defaultContext, ok := response["defaultContext"]; ok { + context := fromChannel(defaultContext).(*browserContextImpl) + b.didCreateContext(context, nil, nil) + } + return browser, nil +} + +func (b *browserTypeImpl) didCreateContext(context *browserContextImpl, contextOptions *BrowserNewContextOptions, tracesDir *string) { + context.setOptions(contextOptions, tracesDir) +} + +func (b *browserTypeImpl) didLaunchBrowser(browser *browserImpl) { + browser.browserType = b +} + +func newBrowserType(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *browserTypeImpl { + bt := &browserTypeImpl{} + bt.createChannelOwner(bt, parent, objectType, guid, initializer) + return bt +} diff --git a/vendor/github.com/playwright-community/playwright-go/cdp_session.go b/vendor/github.com/playwright-community/playwright-go/cdp_session.go new file mode 100644 index 0000000..e9bba82 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/cdp_session.go @@ -0,0 +1,38 @@ +package playwright + +type cdpSessionImpl struct { + channelOwner +} + +func (c *cdpSessionImpl) Detach() error { + _, err := c.channel.Send("detach") + return err +} + +func (c *cdpSessionImpl) Send(method string, params map[string]interface{}) (interface{}, error) { + result, err := c.channel.Send("send", map[string]interface{}{ + "method": method, + "params": params, + }) + if err != nil { + return nil, err + } + + return result, err +} + +func (c *cdpSessionImpl) onEvent(params map[string]interface{}) { + c.Emit(params["method"].(string), params["params"]) +} + +func newCDPSession(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *cdpSessionImpl { + bt := &cdpSessionImpl{} + + bt.createChannelOwner(bt, parent, objectType, guid, initializer) + + bt.channel.On("event", func(params map[string]interface{}) { + bt.onEvent(params) + }) + + return bt +} diff --git a/vendor/github.com/playwright-community/playwright-go/channel.go b/vendor/github.com/playwright-community/playwright-go/channel.go new file mode 100644 index 0000000..b0bded4 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/channel.go @@ -0,0 +1,92 @@ +package playwright + +import ( + "encoding/json" + "fmt" +) + +type channel struct { + eventEmitter + guid string + connection *connection + owner *channelOwner // to avoid type conversion + object interface{} // retain type info (for fromChannel needed) +} + +func (c *channel) MarshalJSON() ([]byte, error) { + return json.Marshal(map[string]string{ + "guid": c.guid, + }) +} + +// for catch errors of route handlers etc. +func (c *channel) CreateTask(fn func()) { + go func() { + defer func() { + if e := recover(); e != nil { + err, ok := e.(error) + if ok { + c.connection.err.Set(err) + } else { + c.connection.err.Set(fmt.Errorf("%v", e)) + } + } + }() + fn() + }() +} + +func (c *channel) Send(method string, options ...interface{}) (interface{}, error) { + return c.connection.WrapAPICall(func() (interface{}, error) { + return c.innerSend(method, options...).GetResultValue() + }, c.owner.isInternalType) +} + +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, options ...interface{}) *protocolCallback { + if err := c.connection.err.Get(); err != nil { + c.connection.err.Set(nil) + pc := newProtocolCallback(false, c.connection.abort) + pc.SetError(err) + return pc + } + params := transformOptions(options...) + return c.connection.sendMessageToServer(c.owner, method, params, false) +} + +// SendNoReply ignores return value and errors +// almost equivalent to `send(...).catch(() => {})` +func (c *channel) SendNoReply(method string, options ...interface{}) { + c.innerSendNoReply(method, c.owner.isInternalType, options...) +} + +func (c *channel) SendNoReplyInternal(method string, options ...interface{}) { + c.innerSendNoReply(method, true, options...) +} + +func (c *channel) innerSendNoReply(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).GetResult() + }, isInternal) + if err != nil { + // ignore error actively, log only for debug + logger.Error("SendNoReply failed", "error", err) + } +} + +func newChannel(owner *channelOwner, object interface{}) *channel { + channel := &channel{ + connection: owner.connection, + guid: owner.guid, + owner: owner, + object: object, + } + return channel +} diff --git a/vendor/github.com/playwright-community/playwright-go/channel_owner.go b/vendor/github.com/playwright-community/playwright-go/channel_owner.go new file mode 100644 index 0000000..5159eb2 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/channel_owner.go @@ -0,0 +1,122 @@ +package playwright + +import ( + "sync" +) + +type channelOwner struct { + sync.RWMutex + eventEmitter + objectType string + guid string + channel *channel + objects map[string]*channelOwner + eventToSubscriptionMapping map[string]string + connection *connection + initializer map[string]interface{} + parent *channelOwner + wasCollected bool + isInternalType bool +} + +func (c *channelOwner) dispose(reason ...string) { + // Clean up from parent and connection. + if c.parent != nil { + delete(c.parent.objects, c.guid) + } + c.connection.objects.Delete(c.guid) + if len(reason) > 0 { + c.wasCollected = reason[0] == "gc" + } + + // Dispose all children. + for _, object := range c.objects { + object.dispose(reason...) + } + c.objects = make(map[string]*channelOwner) +} + +func (c *channelOwner) adopt(child *channelOwner) { + delete(child.parent.objects, child.guid) + c.objects[child.guid] = child + child.parent = c +} + +func (c *channelOwner) setEventSubscriptionMapping(mapping map[string]string) { + c.eventToSubscriptionMapping = mapping +} + +func (c *channelOwner) updateSubscription(event string, enabled bool) { + protocolEvent, ok := c.eventToSubscriptionMapping[event] + if ok { + c.channel.SendNoReplyInternal("updateSubscription", map[string]interface{}{ + "event": protocolEvent, + "enabled": enabled, + }) + } +} + +func (c *channelOwner) Once(name string, handler interface{}) { + c.addEvent(name, handler, true) +} + +func (c *channelOwner) On(name string, handler interface{}) { + c.addEvent(name, handler, false) +} + +func (c *channelOwner) addEvent(name string, handler interface{}, once bool) { + if c.ListenerCount(name) == 0 { + c.updateSubscription(name, true) + } + c.eventEmitter.addEvent(name, handler, once) +} + +func (c *channelOwner) RemoveListener(name string, handler interface{}) { + c.eventEmitter.RemoveListener(name, handler) + if c.ListenerCount(name) == 0 { + c.updateSubscription(name, false) + } +} + +func (c *channelOwner) createChannelOwner(self interface{}, parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) { + c.objectType = objectType + c.guid = guid + c.wasCollected = false + c.parent = parent + c.objects = make(map[string]*channelOwner) + c.initializer = initializer + if c.parent != nil { + c.connection = parent.connection + c.parent.objects[guid] = c + } + if c.connection != nil { + c.connection.objects.Store(guid, c) + } + c.channel = newChannel(c, self) + c.eventToSubscriptionMapping = map[string]string{} +} + +func (c *channelOwner) markAsInternalType() { + c.isInternalType = true +} + +type rootChannelOwner struct { + channelOwner +} + +func (r *rootChannelOwner) initialize() (*Playwright, error) { + ret, err := r.channel.SendReturnAsDict("initialize", map[string]interface{}{ + "sdkLanguage": "javascript", + }) + if err != nil { + return nil, err + } + return fromChannel(ret["playwright"]).(*Playwright), nil +} + +func newRootChannelOwner(connection *connection) *rootChannelOwner { + c := &rootChannelOwner{} + c.connection = connection + c.createChannelOwner(c, nil, "Root", "", make(map[string]interface{})) + return c +} diff --git a/vendor/github.com/playwright-community/playwright-go/clock.go b/vendor/github.com/playwright-community/playwright-go/clock.go new file mode 100644 index 0000000..8bab037 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/clock.go @@ -0,0 +1,111 @@ +package playwright + +import ( + "errors" + "time" +) + +type clockImpl struct { + browserCtx *browserContextImpl +} + +func newClock(bCtx *browserContextImpl) Clock { + return &clockImpl{ + browserCtx: bCtx, + } +} + +func (c *clockImpl) FastForward(ticks interface{}) error { + params, err := parseTicks(ticks) + if err != nil { + return err + } + + _, err = c.browserCtx.channel.Send("clockFastForward", params) + return err +} + +func (c *clockImpl) Install(options ...ClockInstallOptions) (err error) { + params := map[string]any{} + if len(options) == 1 { + if options[0].Time != nil { + params, err = parseTime(options[0].Time) + if err != nil { + return err + } + } + } + + _, err = c.browserCtx.channel.Send("clockInstall", params) + + return err +} + +func (c *clockImpl) PauseAt(time interface{}) error { + params, err := parseTime(time) + if err != nil { + return err + } + + _, err = c.browserCtx.channel.Send("clockPauseAt", params) + return err +} + +func (c *clockImpl) Resume() error { + _, err := c.browserCtx.channel.Send("clockResume") + return err +} + +func (c *clockImpl) RunFor(ticks interface{}) error { + params, err := parseTicks(ticks) + if err != nil { + return err + } + + _, err = c.browserCtx.channel.Send("clockRunFor", params) + return err +} + +func (c *clockImpl) SetFixedTime(time interface{}) error { + params, err := parseTime(time) + if err != nil { + return err + } + + _, err = c.browserCtx.channel.Send("clockSetFixedTime", params) + return err +} + +func (c *clockImpl) SetSystemTime(time interface{}) error { + params, err := parseTime(time) + if err != nil { + return err + } + + _, err = c.browserCtx.channel.Send("clockSetSystemTime", params) + return err +} + +func parseTime(t interface{}) (map[string]any, error) { + switch v := t.(type) { + case int, int64: + return map[string]any{"timeNumber": v}, nil + case string: + return map[string]any{"timeString": v}, nil + case time.Time: + return map[string]any{"timeNumber": v.UnixMilli()}, nil + default: + return nil, errors.New("time should be one of: int, int64, string, time.Time") + } +} + +func parseTicks(ticks interface{}) (map[string]any, error) { + switch v := ticks.(type) { + case int, int64: + return map[string]any{"ticksNumber": v}, nil + case string: + return map[string]any{"ticksString": v}, nil + default: + return nil, errors.New("ticks should be one of: int, int64, string") + } +} diff --git a/vendor/github.com/playwright-community/playwright-go/cmd/playwright/main.go b/vendor/github.com/playwright-community/playwright-go/cmd/playwright/main.go new file mode 100644 index 0000000..95e7d85 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/cmd/playwright/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "log" + "os" + + "github.com/playwright-community/playwright-go" +) + +func main() { + driver, err := playwright.NewDriver(&playwright.RunOptions{}) + if err != nil { + log.Fatalf("could not start driver: %v", err) + } + if err = driver.DownloadDriver(); err != nil { + log.Fatalf("could not download driver: %v", err) + } + cmd := driver.Command(os.Args[1:]...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + log.Fatalf("could not run driver: %v", err) + } + os.Exit(cmd.ProcessState.ExitCode()) +} diff --git a/vendor/github.com/playwright-community/playwright-go/connection.go b/vendor/github.com/playwright-community/playwright-go/connection.go new file mode 100644 index 0000000..ba1e365 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/connection.go @@ -0,0 +1,401 @@ +package playwright + +import ( + "errors" + "fmt" + "reflect" + "regexp" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/go-stack/stack" + "github.com/playwright-community/playwright-go/internal/safe" +) + +var ( + pkgSourcePathPattern = regexp.MustCompile(`.+[\\/]playwright-go[\\/][^\\/]+\.go`) + apiNameTransform = regexp.MustCompile(`(?U)\(\*(.+)(Impl)?\)`) +) + +type connection struct { + transport transport + apiZone sync.Map + objects *safe.SyncMap[string, *channelOwner] + lastID atomic.Uint32 + rootObject *rootChannelOwner + callbacks *safe.SyncMap[uint32, *protocolCallback] + afterClose func() + onClose func() error + isRemote bool + localUtils *localUtilsImpl + tracingCount atomic.Int32 + abort chan struct{} + abortOnce sync.Once + err *safeValue[error] // for event listener error + closedError *safeValue[error] +} + +func (c *connection) Start() (*Playwright, error) { + go func() { + for { + msg, err := c.transport.Poll() + if err != nil { + _ = c.transport.Close() + c.cleanup(err) + return + } + c.Dispatch(msg) + } + }() + + c.onClose = func() error { + if err := c.transport.Close(); err != nil { + return err + } + return nil + } + + return c.rootObject.initialize() +} + +func (c *connection) Stop() error { + if err := c.onClose(); err != nil { + return err + } + c.cleanup() + return nil +} + +func (c *connection) cleanup(cause ...error) { + if len(cause) > 0 { + c.closedError.Set(fmt.Errorf("%w: %w", ErrTargetClosed, cause[0])) + } else { + c.closedError.Set(ErrTargetClosed) + } + if c.afterClose != nil { + c.afterClose() + } + c.abortOnce.Do(func() { + select { + case <-c.abort: + default: + close(c.abort) + } + }) +} + +func (c *connection) Dispatch(msg *message) { + if c.closedError.Get() != nil { + return + } + method := msg.Method + if msg.ID != 0 { + cb, _ := c.callbacks.LoadAndDelete(uint32(msg.ID)) + if cb.noReply { + return + } + if msg.Error != nil { + cb.SetError(parseError(msg.Error.Error)) + } else { + cb.SetResult(c.replaceGuidsWithChannels(msg.Result).(map[string]interface{})) + } + return + } + object, _ := c.objects.Load(msg.GUID) + if method == "__create__" { + c.createRemoteObject( + object, msg.Params["type"].(string), msg.Params["guid"].(string), msg.Params["initializer"], + ) + return + } + if object == nil { + return + } + if method == "__adopt__" { + child, ok := c.objects.Load(msg.Params["guid"].(string)) + if !ok { + return + } + object.adopt(child) + return + } + if method == "__dispose__" { + reason, ok := msg.Params["reason"] + if ok { + object.dispose(reason.(string)) + } else { + object.dispose() + } + return + } + if object.objectType == "JsonPipe" { + object.channel.Emit(method, msg.Params) + } else { + object.channel.Emit(method, c.replaceGuidsWithChannels(msg.Params)) + } +} + +func (c *connection) LocalUtils() *localUtilsImpl { + return c.localUtils +} + +func (c *connection) createRemoteObject(parent *channelOwner, objectType string, guid string, initializer interface{}) interface{} { + initializer = c.replaceGuidsWithChannels(initializer) + result := createObjectFactory(parent, objectType, guid, initializer.(map[string]interface{})) + return result +} + +func (c *connection) WrapAPICall(cb func() (interface{}, error), isInternal bool) (interface{}, error) { + if _, ok := c.apiZone.Load("apiZone"); ok { + return cb() + } + c.apiZone.Store("apiZone", serializeCallStack(isInternal)) + return cb() +} + +func (c *connection) replaceGuidsWithChannels(payload interface{}) interface{} { + if payload == nil { + return nil + } + v := reflect.ValueOf(payload) + if v.Kind() == reflect.Slice { + listV := payload.([]interface{}) + for i := 0; i < len(listV); i++ { + listV[i] = c.replaceGuidsWithChannels(listV[i]) + } + return listV + } + if v.Kind() == reflect.Map { + mapV := payload.(map[string]interface{}) + if guid, hasGUID := mapV["guid"]; hasGUID { + if channelOwner, ok := c.objects.Load(guid.(string)); ok { + return channelOwner.channel + } + } + for key := range mapV { + mapV[key] = c.replaceGuidsWithChannels(mapV[key]) + } + return mapV + } + return payload +} + +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 { + cb.SetError(err) + return + } + if object.wasCollected { + cb.SetError(errors.New("The object has been collected to prevent unbounded heap growth.")) + return + } + + id := c.lastID.Add(1) + c.callbacks.Store(id, cb) + var ( + metadata = make(map[string]interface{}, 0) + stack = make([]map[string]interface{}, 0) + ) + apiZone, ok := c.apiZone.LoadAndDelete("apiZone") + if ok { + for k, v := range apiZone.(parsedStackTrace).metadata { + metadata[k] = v + } + stack = append(stack, apiZone.(parsedStackTrace).frames...) + } + metadata["wallTime"] = time.Now().UnixMilli() + message := map[string]interface{}{ + "id": id, + "guid": object.guid, + "method": method, + "params": params, // channel.MarshalJSON will replace channel with guid + "metadata": metadata, + } + if c.tracingCount.Load() > 0 && len(stack) > 0 && object.guid != "localUtils" { + c.LocalUtils().AddStackToTracingNoReply(id, stack) + } + + if err := c.transport.Send(message); err != nil { + cb.SetError(fmt.Errorf("could not send message: %w", err)) + return + } + + return +} + +func (c *connection) setInTracing(isTracing bool) { + if isTracing { + c.tracingCount.Add(1) + } else { + c.tracingCount.Add(-1) + } +} + +type parsedStackTrace struct { + frames []map[string]interface{} + metadata map[string]interface{} +} + +func serializeCallStack(isInternal bool) parsedStackTrace { + st := stack.Trace().TrimRuntime() + if len(st) == 0 { // https://github.com/go-stack/stack/issues/27 + st = stack.Trace() + } + + lastInternalIndex := 0 + for i, s := range st { + if pkgSourcePathPattern.MatchString(s.Frame().File) { + lastInternalIndex = i + } + } + apiName := "" + if !isInternal { + apiName = fmt.Sprintf("%n", st[lastInternalIndex]) + } + st = st.TrimBelow(st[lastInternalIndex]) + + callStack := make([]map[string]interface{}, 0) + for i, s := range st { + if i == 0 { + continue + } + callStack = append(callStack, map[string]interface{}{ + "file": s.Frame().File, + "line": s.Frame().Line, + "column": 0, + "function": s.Frame().Function, + }) + } + metadata := make(map[string]interface{}) + if len(st) > 1 { + metadata["location"] = serializeCallLocation(st[1]) + } + apiName = apiNameTransform.ReplaceAllString(apiName, "$1") + if len(apiName) > 1 { + apiName = strings.ToUpper(apiName[:1]) + apiName[1:] + } + metadata["apiName"] = apiName + metadata["isInternal"] = isInternal + return parsedStackTrace{ + metadata: metadata, + frames: callStack, + } +} + +func serializeCallLocation(caller stack.Call) map[string]interface{} { + line, _ := strconv.Atoi(fmt.Sprintf("%d", caller)) + return map[string]interface{}{ + "file": fmt.Sprintf("%s", caller), + "line": line, + } +} + +func newConnection(transport transport, localUtils ...*localUtilsImpl) *connection { + connection := &connection{ + abort: make(chan struct{}, 1), + callbacks: safe.NewSyncMap[uint32, *protocolCallback](), + objects: safe.NewSyncMap[string, *channelOwner](), + transport: transport, + isRemote: false, + err: &safeValue[error]{}, + closedError: &safeValue[error]{}, + } + if len(localUtils) > 0 { + connection.localUtils = localUtils[0] + connection.isRemote = true + } + connection.rootObject = newRootChannelOwner(connection) + return connection +} + +func fromChannel(v interface{}) interface{} { + return v.(*channel).object +} + +func fromNullableChannel(v interface{}) interface{} { + if v == nil { + return nil + } + return fromChannel(v) +} + +type protocolCallback struct { + done chan struct{} + noReply bool + abort <-chan struct{} + once sync.Once + value map[string]interface{} + err error +} + +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.done: + return + default: + pc.err = errors.New("Connection closed") + return + } + } +} + +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 + } + 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 { + if noReply { + return &protocolCallback{ + noReply: true, + abort: abort, + } + } + return &protocolCallback{ + done: make(chan struct{}, 1), + abort: abort, + } +} diff --git a/vendor/github.com/playwright-community/playwright-go/console_message.go b/vendor/github.com/playwright-community/playwright-go/console_message.go new file mode 100644 index 0000000..4baf3f1 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/console_message.go @@ -0,0 +1,47 @@ +package playwright + +type consoleMessageImpl struct { + event map[string]interface{} + page Page +} + +func (c *consoleMessageImpl) Type() string { + return c.event["type"].(string) +} + +func (c *consoleMessageImpl) Text() string { + return c.event["text"].(string) +} + +func (c *consoleMessageImpl) String() string { + return c.Text() +} + +func (c *consoleMessageImpl) Args() []JSHandle { + args := c.event["args"].([]interface{}) + out := []JSHandle{} + for idx := range args { + out = append(out, fromChannel(args[idx]).(*jsHandleImpl)) + } + return out +} + +func (c *consoleMessageImpl) Location() *ConsoleMessageLocation { + location := &ConsoleMessageLocation{} + remapMapToStruct(c.event["location"], location) + return location +} + +func (c *consoleMessageImpl) Page() Page { + return c.page +} + +func newConsoleMessage(event map[string]interface{}) *consoleMessageImpl { + bt := &consoleMessageImpl{} + bt.event = event + page := fromNullableChannel(event["page"]) + if page != nil { + bt.page = page.(*pageImpl) + } + return bt +} diff --git a/vendor/github.com/playwright-community/playwright-go/dialog.go b/vendor/github.com/playwright-community/playwright-go/dialog.go new file mode 100644 index 0000000..8d13234 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/dialog.go @@ -0,0 +1,48 @@ +package playwright + +type dialogImpl struct { + channelOwner + page Page +} + +func (d *dialogImpl) Type() string { + return d.initializer["type"].(string) +} + +func (d *dialogImpl) Message() string { + return d.initializer["message"].(string) +} + +func (d *dialogImpl) DefaultValue() string { + return d.initializer["defaultValue"].(string) +} + +func (d *dialogImpl) Accept(promptTextInput ...string) error { + var promptText *string + if len(promptTextInput) == 1 { + promptText = &promptTextInput[0] + } + _, err := d.channel.Send("accept", map[string]interface{}{ + "promptText": promptText, + }) + return err +} + +func (d *dialogImpl) Dismiss() error { + _, err := d.channel.Send("dismiss") + return err +} + +func (d *dialogImpl) Page() Page { + return d.page +} + +func newDialog(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *dialogImpl { + bt := &dialogImpl{} + bt.createChannelOwner(bt, parent, objectType, guid, initializer) + page := fromNullableChannel(initializer["page"]) + if page != nil { + bt.page = page.(*pageImpl) + } + return bt +} diff --git a/vendor/github.com/playwright-community/playwright-go/download.go b/vendor/github.com/playwright-community/playwright-go/download.go new file mode 100644 index 0000000..b9d2024 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/download.go @@ -0,0 +1,56 @@ +package playwright + +type downloadImpl struct { + page *pageImpl + url string + suggestedFilename string + artifact *artifactImpl +} + +func (d *downloadImpl) String() string { + return d.SuggestedFilename() +} + +func (d *downloadImpl) Page() Page { + return d.page +} + +func (d *downloadImpl) URL() string { + return d.url +} + +func (d *downloadImpl) SuggestedFilename() string { + return d.suggestedFilename +} + +func (d *downloadImpl) Delete() error { + err := d.artifact.Delete() + return err +} + +func (d *downloadImpl) Failure() error { + return d.artifact.Failure() +} + +func (d *downloadImpl) Path() (string, error) { + path, err := d.artifact.PathAfterFinished() + return path, err +} + +func (d *downloadImpl) SaveAs(path string) error { + err := d.artifact.SaveAs(path) + return err +} + +func (d *downloadImpl) Cancel() error { + return d.artifact.Cancel() +} + +func newDownload(page *pageImpl, url string, suggestedFilename string, artifact *artifactImpl) *downloadImpl { + return &downloadImpl{ + page: page, + url: url, + suggestedFilename: suggestedFilename, + artifact: artifact, + } +} diff --git a/vendor/github.com/playwright-community/playwright-go/element_handle.go b/vendor/github.com/playwright-community/playwright-go/element_handle.go new file mode 100644 index 0000000..62c41ba --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/element_handle.go @@ -0,0 +1,403 @@ +package playwright + +import ( + "encoding/base64" + "errors" + "fmt" + "os" +) + +type elementHandleImpl struct { + jsHandleImpl +} + +func (e *elementHandleImpl) AsElement() ElementHandle { + return e +} + +func (e *elementHandleImpl) OwnerFrame() (Frame, error) { + channel, err := e.channel.Send("ownerFrame") + if err != nil { + return nil, err + } + channelOwner := fromNullableChannel(channel) + if channelOwner == nil { + return nil, nil + } + return channelOwner.(*frameImpl), nil +} + +func (e *elementHandleImpl) ContentFrame() (Frame, error) { + channel, err := e.channel.Send("contentFrame") + if err != nil { + return nil, err + } + channelOwner := fromNullableChannel(channel) + if channelOwner == nil { + return nil, nil + } + return channelOwner.(*frameImpl), nil +} + +func (e *elementHandleImpl) GetAttribute(name string) (string, error) { + attribute, err := e.channel.Send("getAttribute", map[string]interface{}{ + "name": name, + }) + if attribute == nil { + return "", err + } + return attribute.(string), err +} + +func (e *elementHandleImpl) TextContent() (string, error) { + textContent, err := e.channel.Send("textContent") + if textContent == nil { + return "", err + } + return textContent.(string), err +} + +func (e *elementHandleImpl) InnerText() (string, error) { + innerText, err := e.channel.Send("innerText") + if innerText == nil { + return "", err + } + return innerText.(string), err +} + +func (e *elementHandleImpl) InnerHTML() (string, error) { + innerHTML, err := e.channel.Send("innerHTML") + if innerHTML == nil { + return "", err + } + return innerHTML.(string), err +} + +func (e *elementHandleImpl) DispatchEvent(typ string, initObjects ...interface{}) error { + var initObject interface{} + if len(initObjects) == 1 { + initObject = initObjects[0] + } + _, err := e.channel.Send("dispatchEvent", map[string]interface{}{ + "type": typ, + "eventInit": serializeArgument(initObject), + }) + return err +} + +func (e *elementHandleImpl) Hover(options ...ElementHandleHoverOptions) error { + _, err := e.channel.Send("hover", options) + return err +} + +func (e *elementHandleImpl) Click(options ...ElementHandleClickOptions) error { + _, err := e.channel.Send("click", options) + return err +} + +func (e *elementHandleImpl) Dblclick(options ...ElementHandleDblclickOptions) error { + _, err := e.channel.Send("dblclick", options) + return err +} + +func (e *elementHandleImpl) QuerySelector(selector string) (ElementHandle, error) { + channel, err := e.channel.Send("querySelector", map[string]interface{}{ + "selector": selector, + }) + if err != nil { + return nil, err + } + if channel == nil { + return nil, nil + } + return fromChannel(channel).(*elementHandleImpl), nil +} + +func (e *elementHandleImpl) QuerySelectorAll(selector string) ([]ElementHandle, error) { + channels, err := e.channel.Send("querySelectorAll", map[string]interface{}{ + "selector": selector, + }) + if err != nil { + return nil, err + } + elements := make([]ElementHandle, 0) + for _, channel := range channels.([]interface{}) { + elements = append(elements, fromChannel(channel).(*elementHandleImpl)) + } + return elements, nil +} + +func (e *elementHandleImpl) EvalOnSelector(selector string, expression string, options ...interface{}) (interface{}, error) { + var arg interface{} + if len(options) == 1 { + arg = options[0] + } + result, err := e.channel.Send("evalOnSelector", map[string]interface{}{ + "selector": selector, + "expression": expression, + "arg": serializeArgument(arg), + }) + if err != nil { + return nil, err + } + return parseResult(result), nil +} + +func (e *elementHandleImpl) EvalOnSelectorAll(selector string, expression string, options ...interface{}) (interface{}, error) { + var arg interface{} + if len(options) == 1 { + arg = options[0] + } + result, err := e.channel.Send("evalOnSelectorAll", map[string]interface{}{ + "selector": selector, + "expression": expression, + "arg": serializeArgument(arg), + }) + if err != nil { + return nil, err + } + return parseResult(result), nil +} + +func (e *elementHandleImpl) ScrollIntoViewIfNeeded(options ...ElementHandleScrollIntoViewIfNeededOptions) error { + _, err := e.channel.Send("scrollIntoViewIfNeeded", options) + if err != nil { + return err + } + return err +} + +func (e *elementHandleImpl) SetInputFiles(files interface{}, options ...ElementHandleSetInputFilesOptions) error { + frame, err := e.OwnerFrame() + if err != nil { + return err + } + if frame == nil { + return errors.New("Cannot set input files to detached element") + } + + params, err := convertInputFiles(files, frame.(*frameImpl).page.browserContext) + if err != nil { + return err + } + _, err = e.channel.Send("setInputFiles", params, options) + return err +} + +func (e *elementHandleImpl) BoundingBox() (*Rect, error) { + boundingBox, err := e.channel.Send("boundingBox") + if err != nil { + return nil, err + } + + if boundingBox == nil { + return nil, nil + } + + out := &Rect{} + remapMapToStruct(boundingBox, out) + return out, nil +} + +func (e *elementHandleImpl) Check(options ...ElementHandleCheckOptions) error { + _, err := e.channel.Send("check", options) + return err +} + +func (e *elementHandleImpl) Uncheck(options ...ElementHandleUncheckOptions) error { + _, err := e.channel.Send("uncheck", options) + return err +} + +func (e *elementHandleImpl) Press(key string, options ...ElementHandlePressOptions) error { + _, err := e.channel.Send("press", map[string]interface{}{ + "key": key, + }, options) + return err +} + +func (e *elementHandleImpl) Fill(value string, options ...ElementHandleFillOptions) error { + _, err := e.channel.Send("fill", map[string]interface{}{ + "value": value, + }, options) + return err +} + +func (e *elementHandleImpl) Type(value string, options ...ElementHandleTypeOptions) error { + _, err := e.channel.Send("type", map[string]interface{}{ + "text": value, + }, options) + return err +} + +func (e *elementHandleImpl) Focus() error { + _, err := e.channel.Send("focus") + return err +} + +func (e *elementHandleImpl) SelectText(options ...ElementHandleSelectTextOptions) error { + _, err := e.channel.Send("selectText", options) + return err +} + +func (e *elementHandleImpl) Screenshot(options ...ElementHandleScreenshotOptions) ([]byte, error) { + var path *string + overrides := map[string]interface{}{} + if len(options) == 1 { + path = options[0].Path + options[0].Path = nil + if options[0].Mask != nil { + masks := make([]map[string]interface{}, 0) + for _, m := range options[0].Mask { + if m.Err() != nil { // ErrLocatorNotSameFrame + return nil, m.Err() + } + l, ok := m.(*locatorImpl) + if ok { + masks = append(masks, map[string]interface{}{ + "selector": l.selector, + "frame": l.frame.channel, + }) + } + } + overrides["mask"] = masks + options[0].Mask = nil + } + } + data, err := e.channel.Send("screenshot", options, overrides) + if err != nil { + return nil, err + } + image, err := base64.StdEncoding.DecodeString(data.(string)) + if err != nil { + return nil, fmt.Errorf("could not decode base64 :%w", err) + } + if path != nil { + if err := os.WriteFile(*path, image, 0o644); err != nil { + return nil, err + } + } + return image, nil +} + +func (e *elementHandleImpl) Tap(options ...ElementHandleTapOptions) error { + _, err := e.channel.Send("tap", options) + return err +} + +func (e *elementHandleImpl) SelectOption(values SelectOptionValues, options ...ElementHandleSelectOptionOptions) ([]string, error) { + opts := convertSelectOptionSet(values) + selected, err := e.channel.Send("selectOption", opts, options) + if err != nil { + return nil, err + } + + return transformToStringList(selected), nil +} + +func (e *elementHandleImpl) IsChecked() (bool, error) { + checked, err := e.channel.Send("isChecked") + if err != nil { + return false, err + } + return checked.(bool), nil +} + +func (e *elementHandleImpl) IsDisabled() (bool, error) { + disabled, err := e.channel.Send("isDisabled") + if err != nil { + return false, err + } + return disabled.(bool), nil +} + +func (e *elementHandleImpl) IsEditable() (bool, error) { + editable, err := e.channel.Send("isEditable") + if err != nil { + return false, err + } + return editable.(bool), nil +} + +func (e *elementHandleImpl) IsEnabled() (bool, error) { + enabled, err := e.channel.Send("isEnabled") + if err != nil { + return false, err + } + return enabled.(bool), nil +} + +func (e *elementHandleImpl) IsHidden() (bool, error) { + hidden, err := e.channel.Send("isHidden") + if err != nil { + return false, err + } + return hidden.(bool), nil +} + +func (e *elementHandleImpl) IsVisible() (bool, error) { + visible, err := e.channel.Send("isVisible") + if err != nil { + return false, err + } + return visible.(bool), nil +} + +func (e *elementHandleImpl) WaitForElementState(state ElementState, options ...ElementHandleWaitForElementStateOptions) error { + _, err := e.channel.Send("waitForElementState", map[string]interface{}{ + "state": state, + }, options) + if err != nil { + return err + } + return nil +} + +func (e *elementHandleImpl) WaitForSelector(selector string, options ...ElementHandleWaitForSelectorOptions) (ElementHandle, error) { + ch, err := e.channel.Send("waitForSelector", map[string]interface{}{ + "selector": selector, + }, options) + if err != nil { + return nil, err + } + + channelOwner := fromNullableChannel(ch) + if channelOwner == nil { + return nil, nil + } + return channelOwner.(*elementHandleImpl), nil +} + +func (e *elementHandleImpl) InputValue(options ...ElementHandleInputValueOptions) (string, error) { + result, err := e.channel.Send("inputValue", options) + if result == nil { + return "", err + } + return result.(string), err +} + +func (e *elementHandleImpl) SetChecked(checked bool, options ...ElementHandleSetCheckedOptions) error { + if checked { + _, err := e.channel.Send("check", options) + return err + } else { + _, err := e.channel.Send("uncheck", options) + return err + } +} + +func newElementHandle(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *elementHandleImpl { + bt := &elementHandleImpl{} + bt.createChannelOwner(bt, parent, objectType, guid, initializer) + return bt +} + +func transformToStringList(in interface{}) []string { + s := in.([]interface{}) + + var out []string + for _, v := range s { + out = append(out, v.(string)) + } + return out +} diff --git a/vendor/github.com/playwright-community/playwright-go/errors.go b/vendor/github.com/playwright-community/playwright-go/errors.go new file mode 100644 index 0000000..36f7396 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/errors.go @@ -0,0 +1,58 @@ +package playwright + +import ( + "errors" + "fmt" +) + +var ( + // ErrPlaywright wraps all Playwright errors. + // - Use errors.Is to check if the error is a Playwright error. + // - Use errors.As to cast an error to [Error] if you want to access "Stack". + ErrPlaywright = errors.New("playwright") + // ErrTargetClosed usually wraps a reason. + ErrTargetClosed = errors.New("target closed") + // ErrTimeout wraps timeout errors. It can be either Playwright TimeoutError or client timeout. + ErrTimeout = errors.New("timeout") +) + +// Error represents a Playwright error +type Error struct { + Name string `json:"name"` + Message string `json:"message"` + Stack string `json:"stack"` +} + +func (e *Error) Error() string { + return e.Message +} + +func (e *Error) Is(target error) bool { + err, ok := target.(*Error) + if !ok { + return false + } + if err.Name != e.Name { + return false + } + if e.Name != "Error" { + return true // same name and not normal error + } + return e.Message == err.Message +} + +func parseError(err Error) error { + if err.Name == "TimeoutError" { + return fmt.Errorf("%w: %w: %w", ErrPlaywright, ErrTimeout, &err) + } else if err.Name == "TargetClosedError" { + return fmt.Errorf("%w: %w: %w", ErrPlaywright, ErrTargetClosed, &err) + } + return fmt.Errorf("%w: %w", ErrPlaywright, &err) +} + +func targetClosedError(reason *string) error { + if reason == nil { + return ErrTargetClosed + } + return fmt.Errorf("%w: %s", ErrTargetClosed, *reason) +} diff --git a/vendor/github.com/playwright-community/playwright-go/event_emitter.go b/vendor/github.com/playwright-community/playwright-go/event_emitter.go new file mode 100644 index 0000000..d4d62ef --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/event_emitter.go @@ -0,0 +1,163 @@ +package playwright + +import ( + "math" + "reflect" + "slices" + "sync" +) + +type EventEmitter interface { + Emit(name string, payload ...interface{}) bool + ListenerCount(name string) int + On(name string, handler interface{}) + Once(name string, handler interface{}) + RemoveListener(name string, handler interface{}) + RemoveListeners(name string) +} + +type ( + eventEmitter struct { + eventsMutex sync.Mutex + events map[string]*eventRegister + hasInit bool + } + eventRegister struct { + sync.Mutex + listeners []listener + } + listener struct { + handler interface{} + once bool + } +) + +func NewEventEmitter() EventEmitter { + return &eventEmitter{} +} + +func (e *eventEmitter) Emit(name string, payload ...interface{}) (hasListener bool) { + e.eventsMutex.Lock() + e.init() + + evt, ok := e.events[name] + if !ok { + e.eventsMutex.Unlock() + return + } + e.eventsMutex.Unlock() + return evt.callHandlers(payload...) > 0 +} + +func (e *eventEmitter) Once(name string, handler interface{}) { + e.addEvent(name, handler, true) +} + +func (e *eventEmitter) On(name string, handler interface{}) { + e.addEvent(name, handler, false) +} + +func (e *eventEmitter) RemoveListener(name string, handler interface{}) { + e.eventsMutex.Lock() + defer e.eventsMutex.Unlock() + e.init() + + if evt, ok := e.events[name]; ok { + evt.Lock() + defer evt.Unlock() + evt.removeHandler(handler) + } +} + +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() + defer e.eventsMutex.Unlock() + e.init() + + if name != "" { + evt, ok := e.events[name] + if !ok { + return 0 + } + return evt.count() + } + + count := 0 + for key := range e.events { + count += e.events[key].count() + } + + return count +} + +func (e *eventEmitter) addEvent(name string, handler interface{}, once bool) { + e.eventsMutex.Lock() + defer e.eventsMutex.Unlock() + e.init() + + if _, ok := e.events[name]; !ok { + e.events[name] = &eventRegister{ + listeners: make([]listener, 0), + } + } + e.events[name].addHandler(handler, once) +} + +func (e *eventEmitter) init() { + if !e.hasInit { + e.events = make(map[string]*eventRegister, 0) + e.hasInit = true + } +} + +func (er *eventRegister) addHandler(handler interface{}, once bool) { + er.Lock() + defer er.Unlock() + er.listeners = append(er.listeners, listener{handler: handler, once: once}) +} + +func (er *eventRegister) count() int { + er.Lock() + defer er.Unlock() + return len(er.listeners) +} + +func (er *eventRegister) removeHandler(handler interface{}) { + handlerPtr := reflect.ValueOf(handler).Pointer() + + er.listeners = slices.DeleteFunc(er.listeners, func(l listener) bool { + return reflect.ValueOf(l.handler).Pointer() == handlerPtr + }) +} + +func (er *eventRegister) callHandlers(payloads ...interface{}) int { + payloadV := make([]reflect.Value, 0) + + for _, p := range payloads { + payloadV = append(payloadV, reflect.ValueOf(p)) + } + + handle := func(l listener) { + handlerV := reflect.ValueOf(l.handler) + handlerV.Call(payloadV[:int(math.Min(float64(handlerV.Type().NumIn()), float64(len(payloadV))))]) + } + + er.Lock() + defer er.Unlock() + count := len(er.listeners) + for _, l := range er.listeners { + if l.once { + defer er.removeHandler(l.handler) + } + handle(l) + } + return count +} diff --git a/vendor/github.com/playwright-community/playwright-go/fetch.go b/vendor/github.com/playwright-community/playwright-go/fetch.go new file mode 100644 index 0000000..fc7f79f --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/fetch.go @@ -0,0 +1,451 @@ +package playwright + +import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "os" + "strings" +) + +type apiRequestImpl struct { + *Playwright +} + +func (r *apiRequestImpl) NewContext(options ...APIRequestNewContextOptions) (APIRequestContext, error) { + overrides := map[string]interface{}{} + if len(options) == 1 { + if options[0].ClientCertificates != nil { + certs, err := transformClientCertificate(options[0].ClientCertificates) + if err != nil { + return nil, err + } + overrides["clientCertificates"] = certs + options[0].ClientCertificates = nil + } + if options[0].ExtraHttpHeaders != nil { + overrides["extraHTTPHeaders"] = serializeMapToNameAndValue(options[0].ExtraHttpHeaders) + options[0].ExtraHttpHeaders = nil + } + if options[0].StorageStatePath != nil { + var storageState *StorageState + storageString, err := os.ReadFile(*options[0].StorageStatePath) + if err != nil { + return nil, fmt.Errorf("could not read storage state file: %w", err) + } + err = json.Unmarshal(storageString, &storageState) + if err != nil { + return nil, fmt.Errorf("could not parse storage state file: %w", err) + } + options[0].StorageState = storageState + options[0].StorageStatePath = nil + } + } + + channel, err := r.channel.Send("newRequest", options, overrides) + if err != nil { + return nil, err + } + return fromChannel(channel).(*apiRequestContextImpl), nil +} + +func newApiRequestImpl(pw *Playwright) *apiRequestImpl { + return &apiRequestImpl{pw} +} + +type apiRequestContextImpl struct { + channelOwner + tracing *tracingImpl + closeReason *string +} + +func (r *apiRequestContextImpl) Dispose(options ...APIRequestContextDisposeOptions) error { + if len(options) == 1 { + r.closeReason = options[0].Reason + } + _, err := r.channel.Send("dispose", map[string]interface{}{ + "reason": r.closeReason, + }) + if errors.Is(err, ErrTargetClosed) { + return nil + } + return err +} + +func (r *apiRequestContextImpl) Delete(url string, options ...APIRequestContextDeleteOptions) (APIResponse, error) { + opts := APIRequestContextFetchOptions{ + Method: String("DELETE"), + } + if len(options) == 1 { + err := assignStructFields(&opts, options[0], false) + if err != nil { + return nil, err + } + } + + return r.Fetch(url, opts) +} + +func (r *apiRequestContextImpl) Fetch(urlOrRequest interface{}, options ...APIRequestContextFetchOptions) (APIResponse, error) { + switch v := urlOrRequest.(type) { + case string: + return r.innerFetch(v, nil, options...) + case Request: + return r.innerFetch("", v, options...) + default: + return nil, fmt.Errorf("urlOrRequest has unsupported type: %T", urlOrRequest) + } +} + +func (r *apiRequestContextImpl) innerFetch(url string, request Request, options ...APIRequestContextFetchOptions) (APIResponse, error) { + if r.closeReason != nil { + return nil, fmt.Errorf("%w: %s", ErrTargetClosed, *r.closeReason) + } + overrides := map[string]interface{}{} + if url != "" { + overrides["url"] = url + } else if request != nil { + overrides["url"] = request.URL() + } + + if len(options) == 1 { + if options[0].MaxRedirects != nil && *options[0].MaxRedirects < 0 { + return nil, errors.New("maxRedirects must be non-negative") + } + if options[0].MaxRetries != nil && *options[0].MaxRetries < 0 { + return nil, errors.New("maxRetries must be non-negative") + } + // only one of them can be specified + if countNonNil(options[0].Data, options[0].Form, options[0].Multipart) > 1 { + return nil, errors.New("only one of 'data', 'form' or 'multipart' can be specified") + } + if options[0].Method == nil { + if request != nil { + options[0].Method = String(request.Method()) + } else { + options[0].Method = String("GET") + } + } + if options[0].Headers == nil { + if request != nil { + overrides["headers"] = serializeMapToNameAndValue(request.Headers()) + } + } else { + overrides["headers"] = serializeMapToNameAndValue(options[0].Headers) + options[0].Headers = nil + } + if options[0].Data != nil { + switch v := options[0].Data.(type) { + case string: + headersArray, ok := overrides["headers"].([]map[string]string) + if ok && isJsonContentType(headersArray) { + if json.Valid([]byte(v)) { + overrides["jsonData"] = v + } else { + data, err := json.Marshal(v) + if err != nil { + return nil, fmt.Errorf("could not marshal data: %w", err) + } + overrides["jsonData"] = string(data) + } + } else { + overrides["postData"] = base64.StdEncoding.EncodeToString([]byte(v)) + } + case []byte: + overrides["postData"] = base64.StdEncoding.EncodeToString(v) + case interface{}: + data, err := json.Marshal(v) + if err != nil { + return nil, fmt.Errorf("could not marshal data: %w", err) + } + overrides["jsonData"] = string(data) + default: + return nil, errors.New("data must be a string, []byte, or interface{} that can marshal to json") + } + options[0].Data = nil + } else if options[0].Form != nil { + form, ok := options[0].Form.(map[string]interface{}) + if !ok { + return nil, errors.New("form must be a map") + } + overrides["formData"] = serializeMapToNameValue(form) + options[0].Form = nil + } else if options[0].Multipart != nil { + _, ok := options[0].Multipart.(map[string]interface{}) + if !ok { + return nil, errors.New("multipart must be a map") + } + multipartData := []map[string]interface{}{} + for name, value := range options[0].Multipart.(map[string]interface{}) { + switch v := value.(type) { + case InputFile: + multipartData = append(multipartData, map[string]interface{}{ + "name": name, + "file": map[string]string{ + "name": v.Name, + "mimeType": v.MimeType, + "buffer": base64.StdEncoding.EncodeToString(v.Buffer), + }, + }) + default: + multipartData = append(multipartData, map[string]interface{}{ + "name": name, + "value": String(fmt.Sprintf("%v", v)), + }) + } + } + overrides["multipartData"] = multipartData + options[0].Multipart = nil + } else if request != nil { + postDataBuf, err := request.PostDataBuffer() + if err == nil { + overrides["postData"] = base64.StdEncoding.EncodeToString(postDataBuf) + } + } + if options[0].Params != nil { + overrides["params"] = serializeMapToNameValue(options[0].Params) + options[0].Params = nil + } + } + + response, err := r.channel.Send("fetch", options, overrides) + if err != nil { + return nil, err + } + + return newAPIResponse(r, response.(map[string]interface{})), nil +} + +func (r *apiRequestContextImpl) Get(url string, options ...APIRequestContextGetOptions) (APIResponse, error) { + opts := APIRequestContextFetchOptions{ + Method: String("GET"), + } + if len(options) == 1 { + err := assignStructFields(&opts, options[0], false) + if err != nil { + return nil, err + } + } + + return r.Fetch(url, opts) +} + +func (r *apiRequestContextImpl) Head(url string, options ...APIRequestContextHeadOptions) (APIResponse, error) { + opts := APIRequestContextFetchOptions{ + Method: String("HEAD"), + } + if len(options) == 1 { + err := assignStructFields(&opts, options[0], false) + if err != nil { + return nil, err + } + } + + return r.Fetch(url, opts) +} + +func (r *apiRequestContextImpl) Patch(url string, options ...APIRequestContextPatchOptions) (APIResponse, error) { + opts := APIRequestContextFetchOptions{ + Method: String("PATCH"), + } + if len(options) == 1 { + err := assignStructFields(&opts, options[0], false) + if err != nil { + return nil, err + } + } + + return r.Fetch(url, opts) +} + +func (r *apiRequestContextImpl) Put(url string, options ...APIRequestContextPutOptions) (APIResponse, error) { + opts := APIRequestContextFetchOptions{ + Method: String("PUT"), + } + if len(options) == 1 { + err := assignStructFields(&opts, options[0], false) + if err != nil { + return nil, err + } + } + + return r.Fetch(url, opts) +} + +func (r *apiRequestContextImpl) Post(url string, options ...APIRequestContextPostOptions) (APIResponse, error) { + opts := APIRequestContextFetchOptions{ + Method: String("POST"), + } + if len(options) == 1 { + err := assignStructFields(&opts, options[0], false) + if err != nil { + return nil, err + } + } + + return r.Fetch(url, opts) +} + +func (r *apiRequestContextImpl) StorageState(path ...string) (*StorageState, error) { + result, err := r.channel.SendReturnAsDict("storageState") + if err != nil { + return nil, err + } + if len(path) == 1 { + file, err := os.Create(path[0]) + if err != nil { + return nil, err + } + if err := json.NewEncoder(file).Encode(result); err != nil { + return nil, err + } + if err := file.Close(); err != nil { + return nil, err + } + } + var storageState StorageState + remapMapToStruct(result, &storageState) + return &storageState, nil +} + +func newAPIRequestContext(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *apiRequestContextImpl { + rc := &apiRequestContextImpl{} + rc.createChannelOwner(rc, parent, objectType, guid, initializer) + rc.tracing = fromChannel(initializer["tracing"]).(*tracingImpl) + return rc +} + +type apiResponseImpl struct { + request *apiRequestContextImpl + initializer map[string]interface{} + headers *rawHeaders +} + +func (r *apiResponseImpl) Body() ([]byte, error) { + result, err := r.request.channel.SendReturnAsDict("fetchResponseBody", []map[string]interface{}{ + { + "fetchUid": r.fetchUid(), + }, + }) + if err != nil { + if errors.Is(err, ErrTargetClosed) { + return nil, errors.New("response has been disposed") + } + return nil, err + } + body := result["binary"] + if body == nil { + return nil, errors.New("response has been disposed") + } + return base64.StdEncoding.DecodeString(body.(string)) +} + +func (r *apiResponseImpl) Dispose() error { + _, err := r.request.channel.Send("disposeAPIResponse", []map[string]interface{}{ + { + "fetchUid": r.fetchUid(), + }, + }) + return err +} + +func (r *apiResponseImpl) Headers() map[string]string { + return r.headers.Headers() +} + +func (r *apiResponseImpl) HeadersArray() []NameValue { + return r.headers.HeadersArray() +} + +func (r *apiResponseImpl) JSON(v interface{}) error { + body, err := r.Body() + if err != nil { + return err + } + return json.Unmarshal(body, &v) +} + +func (r *apiResponseImpl) Ok() bool { + return r.Status() == 0 || (r.Status() >= 200 && r.Status() <= 299) +} + +func (r *apiResponseImpl) Status() int { + return int(r.initializer["status"].(float64)) +} + +func (r *apiResponseImpl) StatusText() string { + return r.initializer["statusText"].(string) +} + +func (r *apiResponseImpl) Text() (string, error) { + body, err := r.Body() + if err != nil { + return "", err + } + return string(body), nil +} + +func (r *apiResponseImpl) URL() string { + return r.initializer["url"].(string) +} + +func (r *apiResponseImpl) fetchUid() string { + return r.initializer["fetchUid"].(string) +} + +func (r *apiResponseImpl) fetchLog() ([]string, error) { + ret, err := r.request.channel.Send("fetchLog", map[string]interface{}{ + "fetchUid": r.fetchUid(), + }) + if err != nil { + return nil, err + } + result := make([]string, len(ret.([]interface{}))) + for i, v := range ret.([]interface{}) { + result[i] = v.(string) + } + return result, nil +} + +func newAPIResponse(context *apiRequestContextImpl, initializer map[string]interface{}) *apiResponseImpl { + return &apiResponseImpl{ + request: context, + initializer: initializer, + headers: newRawHeaders(initializer["headers"]), + } +} + +func countNonNil(args ...interface{}) int { + count := 0 + for _, v := range args { + if v != nil { + count++ + } + } + return count +} + +func isJsonContentType(headers []map[string]string) bool { + if len(headers) > 0 { + for _, v := range headers { + if strings.ToLower(v["name"]) == "content-type" { + if v["value"] == "application/json" { + return true + } + } + } + } + return false +} + +func serializeMapToNameValue(data map[string]interface{}) []map[string]string { + serialized := make([]map[string]string, 0, len(data)) + for k, v := range data { + serialized = append(serialized, map[string]string{ + "name": k, + "value": fmt.Sprintf("%v", v), + }) + } + return serialized +} diff --git a/vendor/github.com/playwright-community/playwright-go/file_chooser.go b/vendor/github.com/playwright-community/playwright-go/file_chooser.go new file mode 100644 index 0000000..119e885 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/file_chooser.go @@ -0,0 +1,44 @@ +package playwright + +type fileChooserImpl struct { + page Page + elementHandle ElementHandle + isMultiple bool +} + +func (f *fileChooserImpl) Page() Page { + return f.page +} + +func (f *fileChooserImpl) Element() ElementHandle { + return f.elementHandle +} + +func (f *fileChooserImpl) IsMultiple() bool { + return f.isMultiple +} + +// InputFile represents the input file for: +// - FileChooser.SetFiles() +// - ElementHandle.SetInputFiles() +// - Page.SetInputFiles() +type InputFile struct { + Name string `json:"name"` + MimeType string `json:"mimeType,omitempty"` + Buffer []byte `json:"buffer"` +} + +func (f *fileChooserImpl) SetFiles(files interface{}, options ...FileChooserSetFilesOptions) error { + if len(options) == 1 { + return f.elementHandle.SetInputFiles(files, ElementHandleSetInputFilesOptions(options[0])) + } + return f.elementHandle.SetInputFiles(files) +} + +func newFileChooser(page Page, elementHandle ElementHandle, isMultiple bool) *fileChooserImpl { + return &fileChooserImpl{ + page: page, + elementHandle: elementHandle, + isMultiple: isMultiple, + } +} diff --git a/vendor/github.com/playwright-community/playwright-go/frame.go b/vendor/github.com/playwright-community/playwright-go/frame.go new file mode 100644 index 0000000..b571c8e --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/frame.go @@ -0,0 +1,792 @@ +package playwright + +import ( + "errors" + "fmt" + "os" + "time" + + mapset "github.com/deckarep/golang-set/v2" +) + +type frameImpl struct { + channelOwner + detached bool + page *pageImpl + name string + url string + parentFrame Frame + childFrames []Frame + loadStates mapset.Set[string] +} + +func newFrame(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *frameImpl { + var loadStates mapset.Set[string] + + if ls, ok := initializer["loadStates"].([]string); ok { + loadStates = mapset.NewSet[string](ls...) + } else { + loadStates = mapset.NewSet[string]() + } + f := &frameImpl{ + name: initializer["name"].(string), + url: initializer["url"].(string), + loadStates: loadStates, + childFrames: make([]Frame, 0), + } + f.createChannelOwner(f, parent, objectType, guid, initializer) + + channelOwner := fromNullableChannel(initializer["parentFrame"]) + if channelOwner != nil { + f.parentFrame = channelOwner.(*frameImpl) + f.parentFrame.(*frameImpl).childFrames = append(f.parentFrame.(*frameImpl).childFrames, f) + } + + f.channel.On("navigated", f.onFrameNavigated) + f.channel.On("loadstate", f.onLoadState) + return f +} + +func (f *frameImpl) URL() string { + f.RLock() + defer f.RUnlock() + return f.url +} + +func (f *frameImpl) Name() string { + f.RLock() + defer f.RUnlock() + return f.name +} + +func (f *frameImpl) SetContent(content string, options ...FrameSetContentOptions) error { + _, err := f.channel.Send("setContent", map[string]interface{}{ + "html": content, + }, options) + return err +} + +func (f *frameImpl) Content() (string, error) { + content, err := f.channel.Send("content") + if content == nil { + return "", err + } + return content.(string), err +} + +func (f *frameImpl) Goto(url string, options ...FrameGotoOptions) (Response, error) { + channel, err := f.channel.Send("goto", map[string]interface{}{ + "url": url, + }, options) + if err != nil { + return nil, fmt.Errorf("Frame.Goto %s: %w", url, err) + } + channelOwner := fromNullableChannel(channel) + if channelOwner == nil { + // navigation to about:blank or navigation to the same URL with a different hash + return nil, nil + } + return channelOwner.(*responseImpl), nil +} + +func (f *frameImpl) AddScriptTag(options FrameAddScriptTagOptions) (ElementHandle, error) { + if options.Path != nil { + file, err := os.ReadFile(*options.Path) + if err != nil { + return nil, err + } + options.Content = String(string(file)) + options.Path = nil + } + channel, err := f.channel.Send("addScriptTag", options) + if err != nil { + return nil, err + } + return fromChannel(channel).(*elementHandleImpl), nil +} + +func (f *frameImpl) AddStyleTag(options FrameAddStyleTagOptions) (ElementHandle, error) { + if options.Path != nil { + file, err := os.ReadFile(*options.Path) + if err != nil { + return nil, err + } + options.Content = String(string(file)) + options.Path = nil + } + channel, err := f.channel.Send("addStyleTag", options) + if err != nil { + return nil, err + } + return fromChannel(channel).(*elementHandleImpl), nil +} + +func (f *frameImpl) Page() Page { + return f.page +} + +func (f *frameImpl) WaitForLoadState(options ...FrameWaitForLoadStateOptions) error { + option := FrameWaitForLoadStateOptions{} + if len(options) == 1 { + option = options[0] + } + if option.State == nil { + option.State = LoadStateLoad + } + return f.waitForLoadStateImpl(string(*option.State), option.Timeout, nil) +} + +func (f *frameImpl) waitForLoadStateImpl(state string, timeout *float64, cb func() error) error { + if f.loadStates.ContainsOne(state) { + return nil + } + waiter, err := f.setNavigationWaiter(timeout) + if err != nil { + return err + } + waiter.WaitForEvent(f, "loadstate", func(payload interface{}) bool { + gotState := payload.(string) + return gotState == state + }) + if cb == nil { + _, err := waiter.Wait() + return err + } else { + _, err := waiter.RunAndWait(cb) + return err + } +} + +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" + timeout := Float(f.page.timeoutSettings.NavigationTimeout()) + if len(options) == 1 { + if options[0].WaitUntil != nil { + state = string(*options[0].WaitUntil) + } + if options[0].Timeout != nil { + timeout = options[0].Timeout + } + } + return f.waitForLoadStateImpl(state, timeout, nil) + } + navigationOptions := FrameExpectNavigationOptions{URL: url} + if len(options) > 0 { + navigationOptions.Timeout = options[0].Timeout + navigationOptions.WaitUntil = options[0].WaitUntil + } + if _, err := f.ExpectNavigation(nil, navigationOptions); err != nil { + return err + } + return nil +} + +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] + } + if option.WaitUntil == nil { + option.WaitUntil = WaitUntilStateLoad + } + if option.Timeout == nil { + option.Timeout = Float(f.page.timeoutSettings.NavigationTimeout()) + } + deadline := time.Now().Add(time.Duration(*option.Timeout) * time.Millisecond) + var matcher *urlMatcher + if option.URL != nil { + matcher = newURLMatcher(option.URL, f.page.browserContext.options.BaseURL) + } + predicate := func(events ...interface{}) bool { + ev := events[0].(map[string]interface{}) + err, ok := ev["error"] + if ok { + // Any failed navigation results in a rejection. + logger.Error("navigation error", "url", ev["url"].(string), "error", err) + return true + } + return matcher == nil || matcher.Matches(ev["url"].(string)) + } + 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 { + return nil, err + } + + t := time.Until(deadline).Milliseconds() + if t > 0 { + err = f.waitForLoadStateImpl(string(*option.WaitUntil), Float(float64(t)), nil) + if err != nil { + return nil, err + } + } + event := eventData.(map[string]interface{}) + if event["newDocument"] != nil && event["newDocument"].(map[string]interface{})["request"] != nil { + request := fromChannel(event["newDocument"].(map[string]interface{})["request"]).(*requestImpl) + return request.Response() + } + return nil, nil +} + +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) + } else { + waiter.WithTimeout(f.page.timeoutSettings.NavigationTimeout()) + } + waiter.RejectOnEvent(f.page, "close", f.page.closeErrorWithReason()) + waiter.RejectOnEvent(f.page, "crash", fmt.Errorf("Navigation failed because page crashed!")) + waiter.RejectOnEvent(f.page, "framedetached", fmt.Errorf("Navigating frame was detached!"), func(payload interface{}) bool { + frame, ok := payload.(*frameImpl) + if ok && frame == f { + return true + } + return false + }) + return waiter, nil +} + +func (f *frameImpl) onFrameNavigated(ev map[string]interface{}) { + f.Lock() + f.url = ev["url"].(string) + f.name = ev["name"].(string) + f.Unlock() + f.Emit("navigated", ev) + _, ok := ev["error"] + if !ok && f.page != nil { + f.page.Emit("framenavigated", f) + } +} + +func (f *frameImpl) onLoadState(ev map[string]interface{}) { + if ev["add"] != nil { + 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) + } +} + +func (f *frameImpl) QuerySelector(selector string, options ...FrameQuerySelectorOptions) (ElementHandle, error) { + params := map[string]interface{}{ + "selector": selector, + } + if len(options) == 1 { + params["strict"] = options[0].Strict + } + channel, err := f.channel.Send("querySelector", params) + if err != nil { + return nil, err + } + if channel == nil { + return nil, nil + } + return fromChannel(channel).(*elementHandleImpl), nil +} + +func (f *frameImpl) QuerySelectorAll(selector string) ([]ElementHandle, error) { + channels, err := f.channel.Send("querySelectorAll", map[string]interface{}{ + "selector": selector, + }) + if err != nil { + return nil, err + } + elements := make([]ElementHandle, 0) + for _, channel := range channels.([]interface{}) { + elements = append(elements, fromChannel(channel).(*elementHandleImpl)) + } + return elements, nil +} + +func (f *frameImpl) Evaluate(expression string, options ...interface{}) (interface{}, error) { + var arg interface{} + if len(options) == 1 { + arg = options[0] + } + result, err := f.channel.Send("evaluateExpression", map[string]interface{}{ + "expression": expression, + "arg": serializeArgument(arg), + }) + if err != nil { + return nil, err + } + return parseResult(result), nil +} + +func (f *frameImpl) EvalOnSelector(selector string, expression string, arg interface{}, options ...FrameEvalOnSelectorOptions) (interface{}, error) { + params := map[string]interface{}{ + "selector": selector, + "expression": expression, + "arg": serializeArgument(arg), + } + if len(options) == 1 && options[0].Strict != nil { + params["strict"] = *options[0].Strict + } + + result, err := f.channel.Send("evalOnSelector", params) + if err != nil { + return nil, err + } + return parseResult(result), nil +} + +func (f *frameImpl) EvalOnSelectorAll(selector string, expression string, options ...interface{}) (interface{}, error) { + var arg interface{} + if len(options) == 1 { + arg = options[0] + } + result, err := f.channel.Send("evalOnSelectorAll", map[string]interface{}{ + "selector": selector, + "expression": expression, + "arg": serializeArgument(arg), + }) + if err != nil { + return nil, err + } + return parseResult(result), nil +} + +func (f *frameImpl) EvaluateHandle(expression string, options ...interface{}) (JSHandle, error) { + var arg interface{} + if len(options) == 1 { + arg = options[0] + } + result, err := f.channel.Send("evaluateExpressionHandle", map[string]interface{}{ + "expression": expression, + "arg": serializeArgument(arg), + }) + if err != nil { + return nil, err + } + channelOwner := fromChannel(result) + if channelOwner == nil { + return nil, nil + } + return channelOwner.(JSHandle), nil +} + +func (f *frameImpl) Click(selector string, options ...FrameClickOptions) error { + _, err := f.channel.Send("click", map[string]interface{}{ + "selector": selector, + }, options) + return err +} + +func (f *frameImpl) WaitForSelector(selector string, options ...FrameWaitForSelectorOptions) (ElementHandle, error) { + channel, err := f.channel.Send("waitForSelector", map[string]interface{}{ + "selector": selector, + }, options) + if err != nil { + return nil, err + } + channelOwner := fromNullableChannel(channel) + if channelOwner == nil { + return nil, nil + } + return channelOwner.(*elementHandleImpl), nil +} + +func (f *frameImpl) DispatchEvent(selector, typ string, eventInit interface{}, options ...FrameDispatchEventOptions) error { + _, err := f.channel.Send("dispatchEvent", map[string]interface{}{ + "selector": selector, + "type": typ, + "eventInit": serializeArgument(eventInit), + }) + return err +} + +func (f *frameImpl) InnerText(selector string, options ...FrameInnerTextOptions) (string, error) { + innerText, err := f.channel.Send("innerText", map[string]interface{}{ + "selector": selector, + }, options) + if innerText == nil { + return "", err + } + return innerText.(string), err +} + +func (f *frameImpl) InnerHTML(selector string, options ...FrameInnerHTMLOptions) (string, error) { + innerHTML, err := f.channel.Send("innerHTML", map[string]interface{}{ + "selector": selector, + }, options) + if innerHTML == nil { + return "", err + } + return innerHTML.(string), err +} + +func (f *frameImpl) GetAttribute(selector string, name string, options ...FrameGetAttributeOptions) (string, error) { + attribute, err := f.channel.Send("getAttribute", map[string]interface{}{ + "selector": selector, + "name": name, + }, options) + if attribute == nil { + return "", err + } + return attribute.(string), err +} + +func (f *frameImpl) Hover(selector string, options ...FrameHoverOptions) error { + _, err := f.channel.Send("hover", map[string]interface{}{ + "selector": selector, + }, options) + return err +} + +func (f *frameImpl) SetInputFiles(selector string, files interface{}, options ...FrameSetInputFilesOptions) error { + params, err := convertInputFiles(files, f.page.browserContext) + if err != nil { + return err + } + params.Selector = &selector + _, err = f.channel.Send("setInputFiles", params, options) + return err +} + +func (f *frameImpl) Type(selector, text string, options ...FrameTypeOptions) error { + _, err := f.channel.Send("type", map[string]interface{}{ + "selector": selector, + "text": text, + }, options) + return err +} + +func (f *frameImpl) Press(selector, key string, options ...FramePressOptions) error { + _, err := f.channel.Send("press", map[string]interface{}{ + "selector": selector, + "key": key, + }, options) + return err +} + +func (f *frameImpl) Check(selector string, options ...FrameCheckOptions) error { + _, err := f.channel.Send("check", map[string]interface{}{ + "selector": selector, + }, options) + return err +} + +func (f *frameImpl) Uncheck(selector string, options ...FrameUncheckOptions) error { + _, err := f.channel.Send("uncheck", map[string]interface{}{ + "selector": selector, + }, options) + return err +} + +func (f *frameImpl) WaitForTimeout(timeout float64) { + time.Sleep(time.Duration(timeout) * time.Millisecond) +} + +func (f *frameImpl) WaitForFunction(expression string, arg interface{}, options ...FrameWaitForFunctionOptions) (JSHandle, error) { + var option FrameWaitForFunctionOptions + if len(options) == 1 { + option = options[0] + } + result, err := f.channel.Send("waitForFunction", map[string]interface{}{ + "expression": expression, + "arg": serializeArgument(arg), + "timeout": option.Timeout, + "polling": option.Polling, + }) + if err != nil { + return nil, err + } + handle := fromChannel(result) + if handle == nil { + return nil, nil + } + return handle.(*jsHandleImpl), nil +} + +func (f *frameImpl) Title() (string, error) { + title, err := f.channel.Send("title") + if title == nil { + return "", err + } + return title.(string), err +} + +func (f *frameImpl) ChildFrames() []Frame { + return f.childFrames +} + +func (f *frameImpl) Dblclick(selector string, options ...FrameDblclickOptions) error { + _, err := f.channel.Send("dblclick", map[string]interface{}{ + "selector": selector, + }, options) + return err +} + +func (f *frameImpl) Fill(selector string, value string, options ...FrameFillOptions) error { + _, err := f.channel.Send("fill", map[string]interface{}{ + "selector": selector, + "value": value, + }, options) + return err +} + +func (f *frameImpl) Focus(selector string, options ...FrameFocusOptions) error { + _, err := f.channel.Send("focus", map[string]interface{}{ + "selector": selector, + }, options) + return err +} + +func (f *frameImpl) FrameElement() (ElementHandle, error) { + channel, err := f.channel.Send("frameElement") + if err != nil { + return nil, err + } + return fromChannel(channel).(*elementHandleImpl), nil +} + +func (f *frameImpl) IsDetached() bool { + return f.detached +} + +func (f *frameImpl) ParentFrame() Frame { + return f.parentFrame +} + +func (f *frameImpl) TextContent(selector string, options ...FrameTextContentOptions) (string, error) { + textContent, err := f.channel.Send("textContent", map[string]interface{}{ + "selector": selector, + }, options) + if textContent == nil { + return "", err + } + return textContent.(string), err +} + +func (f *frameImpl) Tap(selector string, options ...FrameTapOptions) error { + _, err := f.channel.Send("tap", map[string]interface{}{ + "selector": selector, + }, options) + return err +} + +func (f *frameImpl) SelectOption(selector string, values SelectOptionValues, options ...FrameSelectOptionOptions) ([]string, error) { + opts := convertSelectOptionSet(values) + + m := make(map[string]interface{}) + m["selector"] = selector + for k, v := range opts { + m[k] = v + } + selected, err := f.channel.Send("selectOption", m, options) + if err != nil { + return nil, err + } + + return transformToStringList(selected), nil +} + +func (f *frameImpl) IsChecked(selector string, options ...FrameIsCheckedOptions) (bool, error) { + checked, err := f.channel.Send("isChecked", map[string]interface{}{ + "selector": selector, + }, options) + if err != nil { + return false, err + } + return checked.(bool), nil +} + +func (f *frameImpl) IsDisabled(selector string, options ...FrameIsDisabledOptions) (bool, error) { + disabled, err := f.channel.Send("isDisabled", map[string]interface{}{ + "selector": selector, + }, options) + if err != nil { + return false, err + } + return disabled.(bool), nil +} + +func (f *frameImpl) IsEditable(selector string, options ...FrameIsEditableOptions) (bool, error) { + editable, err := f.channel.Send("isEditable", map[string]interface{}{ + "selector": selector, + }, options) + if err != nil { + return false, err + } + return editable.(bool), nil +} + +func (f *frameImpl) IsEnabled(selector string, options ...FrameIsEnabledOptions) (bool, error) { + enabled, err := f.channel.Send("isEnabled", map[string]interface{}{ + "selector": selector, + }, options) + if err != nil { + return false, err + } + return enabled.(bool), nil +} + +func (f *frameImpl) IsHidden(selector string, options ...FrameIsHiddenOptions) (bool, error) { + hidden, err := f.channel.Send("isHidden", map[string]interface{}{ + "selector": selector, + }, options) + if err != nil { + return false, err + } + return hidden.(bool), nil +} + +func (f *frameImpl) IsVisible(selector string, options ...FrameIsVisibleOptions) (bool, error) { + visible, err := f.channel.Send("isVisible", map[string]interface{}{ + "selector": selector, + }, options) + if err != nil { + return false, err + } + return visible.(bool), nil +} + +func (f *frameImpl) InputValue(selector string, options ...FrameInputValueOptions) (string, error) { + value, err := f.channel.Send("inputValue", map[string]interface{}{ + "selector": selector, + }, options) + if value == nil { + return "", err + } + return value.(string), err +} + +func (f *frameImpl) DragAndDrop(source, target string, options ...FrameDragAndDropOptions) error { + _, err := f.channel.Send("dragAndDrop", map[string]interface{}{ + "source": source, + "target": target, + }, options) + return err +} + +func (f *frameImpl) SetChecked(selector string, checked bool, options ...FrameSetCheckedOptions) error { + if checked { + _, err := f.channel.Send("check", map[string]interface{}{ + "selector": selector, + }, options) + return err + } else { + _, err := f.channel.Send("uncheck", map[string]interface{}{ + "selector": selector, + }, options) + return err + } +} + +func (f *frameImpl) Locator(selector string, options ...FrameLocatorOptions) Locator { + var option LocatorOptions + if len(options) == 1 { + option = LocatorOptions{ + Has: options[0].Has, + HasNot: options[0].HasNot, + HasText: options[0].HasText, + HasNotText: options[0].HasNotText, + } + } + return newLocator(f, selector, option) +} + +func (f *frameImpl) GetByAltText(text interface{}, options ...FrameGetByAltTextOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return f.Locator(getByAltTextSelector(text, exact)) +} + +func (f *frameImpl) GetByLabel(text interface{}, options ...FrameGetByLabelOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return f.Locator(getByLabelSelector(text, exact)) +} + +func (f *frameImpl) GetByPlaceholder(text interface{}, options ...FrameGetByPlaceholderOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return f.Locator(getByPlaceholderSelector(text, exact)) +} + +func (f *frameImpl) GetByRole(role AriaRole, options ...FrameGetByRoleOptions) Locator { + if len(options) == 1 { + return f.Locator(getByRoleSelector(role, LocatorGetByRoleOptions(options[0]))) + } + return f.Locator(getByRoleSelector(role)) +} + +func (f *frameImpl) GetByTestId(testId interface{}) Locator { + return f.Locator(getByTestIdSelector(getTestIdAttributeName(), testId)) +} + +func (f *frameImpl) GetByText(text interface{}, options ...FrameGetByTextOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return f.Locator(getByTextSelector(text, exact)) +} + +func (f *frameImpl) GetByTitle(text interface{}, options ...FrameGetByTitleOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return f.Locator(getByTitleSelector(text, exact)) +} + +func (f *frameImpl) FrameLocator(selector string) FrameLocator { + return newFrameLocator(f, selector) +} + +func (f *frameImpl) highlight(selector string) error { + _, err := f.channel.Send("highlight", map[string]interface{}{ + "selector": selector, + }) + return err +} + +func (f *frameImpl) queryCount(selector string) (int, error) { + response, err := f.channel.Send("queryCount", map[string]interface{}{ + "selector": selector, + }) + if err != nil { + return 0, err + } + return int(response.(float64)), nil +} diff --git a/vendor/github.com/playwright-community/playwright-go/frame_locator.go b/vendor/github.com/playwright-community/playwright-go/frame_locator.go new file mode 100644 index 0000000..d4b8fd0 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/frame_locator.go @@ -0,0 +1,130 @@ +package playwright + +import ( + "errors" + "fmt" + "strconv" +) + +type frameLocatorImpl struct { + frame *frameImpl + frameSelector string +} + +func newFrameLocator(frame *frameImpl, frameSelector string) *frameLocatorImpl { + return &frameLocatorImpl{frame: frame, frameSelector: frameSelector} +} + +func (fl *frameLocatorImpl) First() FrameLocator { + return newFrameLocator(fl.frame, fl.frameSelector+" >> nth=0") +} + +func (fl *frameLocatorImpl) FrameLocator(selector string) FrameLocator { + return newFrameLocator(fl.frame, fl.frameSelector+" >> internal:control=enter-frame >> "+selector) +} + +func (fl *frameLocatorImpl) GetByAltText(text interface{}, options ...FrameLocatorGetByAltTextOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return fl.Locator(getByAltTextSelector(text, exact)) +} + +func (fl *frameLocatorImpl) GetByLabel(text interface{}, options ...FrameLocatorGetByLabelOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return fl.Locator(getByLabelSelector(text, exact)) +} + +func (fl *frameLocatorImpl) GetByPlaceholder(text interface{}, options ...FrameLocatorGetByPlaceholderOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return fl.Locator(getByPlaceholderSelector(text, exact)) +} + +func (fl *frameLocatorImpl) GetByRole(role AriaRole, options ...FrameLocatorGetByRoleOptions) Locator { + if len(options) == 1 { + return fl.Locator(getByRoleSelector(role, LocatorGetByRoleOptions(options[0]))) + } + return fl.Locator(getByRoleSelector(role)) +} + +func (fl *frameLocatorImpl) GetByTestId(testId interface{}) Locator { + return fl.Locator(getByTestIdSelector(getTestIdAttributeName(), testId)) +} + +func (fl *frameLocatorImpl) GetByText(text interface{}, options ...FrameLocatorGetByTextOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return fl.Locator(getByTextSelector(text, exact)) +} + +func (fl *frameLocatorImpl) GetByTitle(text interface{}, options ...FrameLocatorGetByTitleOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return fl.Locator(getByTitleSelector(text, exact)) +} + +func (fl *frameLocatorImpl) Last() FrameLocator { + return newFrameLocator(fl.frame, fl.frameSelector+" >> nth=-1") +} + +func (fl *frameLocatorImpl) Locator(selectorOrLocator interface{}, options ...FrameLocatorLocatorOptions) Locator { + var option LocatorOptions + if len(options) == 1 { + option = LocatorOptions{ + Has: options[0].Has, + HasNot: options[0].HasNot, + HasText: options[0].HasText, + HasNotText: options[0].HasNotText, + } + } + + selector, ok := selectorOrLocator.(string) + if ok { + return newLocator(fl.frame, fl.frameSelector+" >> internal:control=enter-frame >> "+selector, option) + } + locator, ok := selectorOrLocator.(*locatorImpl) + if ok { + if fl.frame != locator.frame { + locator.err = errors.Join(locator.err, ErrLocatorNotSameFrame) + return locator + } + return newLocator(locator.frame, + fmt.Sprintf("%s >> internal:control=enter-frame >> %s", fl.frameSelector, locator.selector), + option, + ) + } + return &locatorImpl{ + frame: fl.frame, + selector: fl.frameSelector, + err: fmt.Errorf("invalid locator parameter: %v", selectorOrLocator), + } +} + +func (fl *frameLocatorImpl) Nth(index int) FrameLocator { + return newFrameLocator(fl.frame, fl.frameSelector+" >> nth="+strconv.Itoa(index)) +} + +func (fl *frameLocatorImpl) Owner() Locator { + return newLocator(fl.frame, fl.frameSelector) +} diff --git a/vendor/github.com/playwright-community/playwright-go/generated-enums.go b/vendor/github.com/playwright-community/playwright-go/generated-enums.go new file mode 100644 index 0000000..92c20c6 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/generated-enums.go @@ -0,0 +1,404 @@ +package playwright + +func getMixedState(in string) *MixedState { + v := MixedState(in) + return &v +} + +type MixedState string + +var ( + MixedStateOn *MixedState = getMixedState("On") + MixedStateOff = getMixedState("Off") + MixedStateMixed = getMixedState("Mixed") +) + +func getElementState(in string) *ElementState { + v := ElementState(in) + return &v +} + +type ElementState string + +var ( + ElementStateVisible *ElementState = getElementState("visible") + ElementStateHidden = getElementState("hidden") + ElementStateStable = getElementState("stable") + ElementStateEnabled = getElementState("enabled") + ElementStateDisabled = getElementState("disabled") + ElementStateEditable = getElementState("editable") +) + +func getAriaRole(in string) *AriaRole { + v := AriaRole(in) + return &v +} + +type AriaRole string + +var ( + AriaRoleAlert *AriaRole = getAriaRole("alert") + AriaRoleAlertdialog = getAriaRole("alertdialog") + AriaRoleApplication = getAriaRole("application") + AriaRoleArticle = getAriaRole("article") + AriaRoleBanner = getAriaRole("banner") + AriaRoleBlockquote = getAriaRole("blockquote") + AriaRoleButton = getAriaRole("button") + AriaRoleCaption = getAriaRole("caption") + AriaRoleCell = getAriaRole("cell") + AriaRoleCheckbox = getAriaRole("checkbox") + AriaRoleCode = getAriaRole("code") + AriaRoleColumnheader = getAriaRole("columnheader") + AriaRoleCombobox = getAriaRole("combobox") + AriaRoleComplementary = getAriaRole("complementary") + AriaRoleContentinfo = getAriaRole("contentinfo") + AriaRoleDefinition = getAriaRole("definition") + AriaRoleDeletion = getAriaRole("deletion") + AriaRoleDialog = getAriaRole("dialog") + AriaRoleDirectory = getAriaRole("directory") + AriaRoleDocument = getAriaRole("document") + AriaRoleEmphasis = getAriaRole("emphasis") + AriaRoleFeed = getAriaRole("feed") + AriaRoleFigure = getAriaRole("figure") + AriaRoleForm = getAriaRole("form") + AriaRoleGeneric = getAriaRole("generic") + AriaRoleGrid = getAriaRole("grid") + AriaRoleGridcell = getAriaRole("gridcell") + AriaRoleGroup = getAriaRole("group") + AriaRoleHeading = getAriaRole("heading") + AriaRoleImg = getAriaRole("img") + AriaRoleInsertion = getAriaRole("insertion") + AriaRoleLink = getAriaRole("link") + AriaRoleList = getAriaRole("list") + AriaRoleListbox = getAriaRole("listbox") + AriaRoleListitem = getAriaRole("listitem") + AriaRoleLog = getAriaRole("log") + AriaRoleMain = getAriaRole("main") + AriaRoleMarquee = getAriaRole("marquee") + AriaRoleMath = getAriaRole("math") + AriaRoleMeter = getAriaRole("meter") + AriaRoleMenu = getAriaRole("menu") + AriaRoleMenubar = getAriaRole("menubar") + AriaRoleMenuitem = getAriaRole("menuitem") + AriaRoleMenuitemcheckbox = getAriaRole("menuitemcheckbox") + AriaRoleMenuitemradio = getAriaRole("menuitemradio") + AriaRoleNavigation = getAriaRole("navigation") + AriaRoleNone = getAriaRole("none") + AriaRoleNote = getAriaRole("note") + AriaRoleOption = getAriaRole("option") + AriaRoleParagraph = getAriaRole("paragraph") + AriaRolePresentation = getAriaRole("presentation") + AriaRoleProgressbar = getAriaRole("progressbar") + AriaRoleRadio = getAriaRole("radio") + AriaRoleRadiogroup = getAriaRole("radiogroup") + AriaRoleRegion = getAriaRole("region") + AriaRoleRow = getAriaRole("row") + AriaRoleRowgroup = getAriaRole("rowgroup") + AriaRoleRowheader = getAriaRole("rowheader") + AriaRoleScrollbar = getAriaRole("scrollbar") + AriaRoleSearch = getAriaRole("search") + AriaRoleSearchbox = getAriaRole("searchbox") + AriaRoleSeparator = getAriaRole("separator") + AriaRoleSlider = getAriaRole("slider") + AriaRoleSpinbutton = getAriaRole("spinbutton") + AriaRoleStatus = getAriaRole("status") + AriaRoleStrong = getAriaRole("strong") + AriaRoleSubscript = getAriaRole("subscript") + AriaRoleSuperscript = getAriaRole("superscript") + AriaRoleSwitch = getAriaRole("switch") + AriaRoleTab = getAriaRole("tab") + AriaRoleTable = getAriaRole("table") + AriaRoleTablist = getAriaRole("tablist") + AriaRoleTabpanel = getAriaRole("tabpanel") + AriaRoleTerm = getAriaRole("term") + AriaRoleTextbox = getAriaRole("textbox") + AriaRoleTime = getAriaRole("time") + AriaRoleTimer = getAriaRole("timer") + AriaRoleToolbar = getAriaRole("toolbar") + AriaRoleTooltip = getAriaRole("tooltip") + AriaRoleTree = getAriaRole("tree") + AriaRoleTreegrid = getAriaRole("treegrid") + AriaRoleTreeitem = getAriaRole("treeitem") +) + +func getColorScheme(in string) *ColorScheme { + v := ColorScheme(in) + return &v +} + +type ColorScheme string + +var ( + ColorSchemeLight *ColorScheme = getColorScheme("light") + ColorSchemeDark = getColorScheme("dark") + ColorSchemeNoPreference = getColorScheme("no-preference") + ColorSchemeNoOverride = getColorScheme("no-override") +) + +func getForcedColors(in string) *ForcedColors { + v := ForcedColors(in) + return &v +} + +type ForcedColors string + +var ( + ForcedColorsActive *ForcedColors = getForcedColors("active") + ForcedColorsNone = getForcedColors("none") + ForcedColorsNoOverride = getForcedColors("no-override") +) + +func getHarContentPolicy(in string) *HarContentPolicy { + v := HarContentPolicy(in) + return &v +} + +type HarContentPolicy string + +var ( + HarContentPolicyOmit *HarContentPolicy = getHarContentPolicy("omit") + HarContentPolicyEmbed = getHarContentPolicy("embed") + HarContentPolicyAttach = getHarContentPolicy("attach") +) + +func getHarMode(in string) *HarMode { + v := HarMode(in) + return &v +} + +type HarMode string + +var ( + HarModeFull *HarMode = getHarMode("full") + HarModeMinimal = getHarMode("minimal") +) + +func getReducedMotion(in string) *ReducedMotion { + v := ReducedMotion(in) + return &v +} + +type ReducedMotion string + +var ( + ReducedMotionReduce *ReducedMotion = getReducedMotion("reduce") + ReducedMotionNoPreference = getReducedMotion("no-preference") + ReducedMotionNoOverride = getReducedMotion("no-override") +) + +func getServiceWorkerPolicy(in string) *ServiceWorkerPolicy { + v := ServiceWorkerPolicy(in) + return &v +} + +type ServiceWorkerPolicy string + +var ( + ServiceWorkerPolicyAllow *ServiceWorkerPolicy = getServiceWorkerPolicy("allow") + ServiceWorkerPolicyBlock = getServiceWorkerPolicy("block") +) + +func getSameSiteAttribute(in string) *SameSiteAttribute { + v := SameSiteAttribute(in) + return &v +} + +type SameSiteAttribute string + +var ( + SameSiteAttributeStrict *SameSiteAttribute = getSameSiteAttribute("Strict") + SameSiteAttributeLax = getSameSiteAttribute("Lax") + SameSiteAttributeNone = getSameSiteAttribute("None") +) + +func getHarNotFound(in string) *HarNotFound { + v := HarNotFound(in) + return &v +} + +type HarNotFound string + +var ( + HarNotFoundAbort *HarNotFound = getHarNotFound("abort") + HarNotFoundFallback = getHarNotFound("fallback") +) + +func getRouteFromHarUpdateContentPolicy(in string) *RouteFromHarUpdateContentPolicy { + v := RouteFromHarUpdateContentPolicy(in) + return &v +} + +type RouteFromHarUpdateContentPolicy string + +var ( + RouteFromHarUpdateContentPolicyEmbed *RouteFromHarUpdateContentPolicy = getRouteFromHarUpdateContentPolicy("embed") + RouteFromHarUpdateContentPolicyAttach = getRouteFromHarUpdateContentPolicy("attach") +) + +func getUnrouteBehavior(in string) *UnrouteBehavior { + v := UnrouteBehavior(in) + return &v +} + +type UnrouteBehavior string + +var ( + UnrouteBehaviorWait *UnrouteBehavior = getUnrouteBehavior("wait") + UnrouteBehaviorIgnoreErrors = getUnrouteBehavior("ignoreErrors") + UnrouteBehaviorDefault = getUnrouteBehavior("default") +) + +func getMouseButton(in string) *MouseButton { + v := MouseButton(in) + return &v +} + +type MouseButton string + +var ( + MouseButtonLeft *MouseButton = getMouseButton("left") + MouseButtonRight = getMouseButton("right") + MouseButtonMiddle = getMouseButton("middle") +) + +func getKeyboardModifier(in string) *KeyboardModifier { + v := KeyboardModifier(in) + return &v +} + +type KeyboardModifier string + +var ( + KeyboardModifierAlt *KeyboardModifier = getKeyboardModifier("Alt") + KeyboardModifierControl = getKeyboardModifier("Control") + KeyboardModifierControlOrMeta = getKeyboardModifier("ControlOrMeta") + KeyboardModifierMeta = getKeyboardModifier("Meta") + KeyboardModifierShift = getKeyboardModifier("Shift") +) + +func getScreenshotAnimations(in string) *ScreenshotAnimations { + v := ScreenshotAnimations(in) + return &v +} + +type ScreenshotAnimations string + +var ( + ScreenshotAnimationsDisabled *ScreenshotAnimations = getScreenshotAnimations("disabled") + ScreenshotAnimationsAllow = getScreenshotAnimations("allow") +) + +func getScreenshotCaret(in string) *ScreenshotCaret { + v := ScreenshotCaret(in) + return &v +} + +type ScreenshotCaret string + +var ( + ScreenshotCaretHide *ScreenshotCaret = getScreenshotCaret("hide") + ScreenshotCaretInitial = getScreenshotCaret("initial") +) + +func getScreenshotScale(in string) *ScreenshotScale { + v := ScreenshotScale(in) + return &v +} + +type ScreenshotScale string + +var ( + ScreenshotScaleCss *ScreenshotScale = getScreenshotScale("css") + ScreenshotScaleDevice = getScreenshotScale("device") +) + +func getScreenshotType(in string) *ScreenshotType { + v := ScreenshotType(in) + return &v +} + +type ScreenshotType string + +var ( + ScreenshotTypePng *ScreenshotType = getScreenshotType("png") + ScreenshotTypeJpeg = getScreenshotType("jpeg") +) + +func getWaitForSelectorState(in string) *WaitForSelectorState { + v := WaitForSelectorState(in) + return &v +} + +type WaitForSelectorState string + +var ( + WaitForSelectorStateAttached *WaitForSelectorState = getWaitForSelectorState("attached") + WaitForSelectorStateDetached = getWaitForSelectorState("detached") + WaitForSelectorStateVisible = getWaitForSelectorState("visible") + WaitForSelectorStateHidden = getWaitForSelectorState("hidden") +) + +func getWaitUntilState(in string) *WaitUntilState { + v := WaitUntilState(in) + return &v +} + +type WaitUntilState string + +var ( + WaitUntilStateLoad *WaitUntilState = getWaitUntilState("load") + WaitUntilStateDomcontentloaded = getWaitUntilState("domcontentloaded") + WaitUntilStateNetworkidle = getWaitUntilState("networkidle") + WaitUntilStateCommit = getWaitUntilState("commit") +) + +func getLoadState(in string) *LoadState { + v := LoadState(in) + return &v +} + +type LoadState string + +var ( + LoadStateLoad *LoadState = getLoadState("load") + LoadStateDomcontentloaded = getLoadState("domcontentloaded") + LoadStateNetworkidle = getLoadState("networkidle") +) + +func getContrast(in string) *Contrast { + v := Contrast(in) + return &v +} + +type Contrast string + +var ( + ContrastNoPreference *Contrast = getContrast("no-preference") + ContrastMore = getContrast("more") + ContrastNoOverride = getContrast("no-override") +) + +func getMedia(in string) *Media { + v := Media(in) + return &v +} + +type Media string + +var ( + MediaScreen *Media = getMedia("screen") + MediaPrint = getMedia("print") + MediaNoOverride = getMedia("no-override") +) + +func getHttpCredentialsSend(in string) *HttpCredentialsSend { + v := HttpCredentialsSend(in) + return &v +} + +type HttpCredentialsSend string + +var ( + HttpCredentialsSendUnauthorized *HttpCredentialsSend = getHttpCredentialsSend("unauthorized") + HttpCredentialsSendAlways = getHttpCredentialsSend("always") +) diff --git a/vendor/github.com/playwright-community/playwright-go/generated-interfaces.go b/vendor/github.com/playwright-community/playwright-go/generated-interfaces.go new file mode 100644 index 0000000..187dc91 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/generated-interfaces.go @@ -0,0 +1,4658 @@ +package playwright + +// Exposes API that can be used for the Web API testing. This class is used for creating [APIRequestContext] instance +// which in turn can be used for sending web requests. An instance of this class can be obtained via +// [Playwright.Request]. For more information see [APIRequestContext]. +type APIRequest interface { + // Creates new instances of [APIRequestContext]. + NewContext(options ...APIRequestNewContextOptions) (APIRequestContext, error) +} + +// This API is used for the Web API testing. You can use it to trigger API endpoints, configure micro-services, +// prepare environment or the service to your e2e test. +// Each Playwright browser context has associated with it [APIRequestContext] instance which shares cookie storage +// with the browser context and can be accessed via [BrowserContext.Request] or [Page.Request]. It is also possible to +// create a new APIRequestContext instance manually by calling [APIRequest.NewContext]. +// **Cookie management** +// [APIRequestContext] returned by [BrowserContext.Request] and [Page.Request] shares cookie storage with the +// corresponding [BrowserContext]. Each API request will have `Cookie` header populated with the values from the +// browser context. If the API response contains `Set-Cookie` header it will automatically update [BrowserContext] +// cookies and requests made from the page will pick them up. This means that if you log in using this API, your e2e +// test will be logged in and vice versa. +// If you want API requests to not interfere with the browser cookies you should create a new [APIRequestContext] by +// calling [APIRequest.NewContext]. Such `APIRequestContext` object will have its own isolated cookie storage. +type APIRequestContext interface { + // Sends HTTP(S) [DELETE] request and returns its + // response. The method will populate request cookies from the context and update context cookies from the response. + // The method will automatically follow redirects. + // + // url: Target URL. + // + // [DELETE]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE + Delete(url string, options ...APIRequestContextDeleteOptions) (APIResponse, error) + + // All responses returned by [APIRequestContext.Get] and similar methods are stored in the memory, so that you can + // later call [APIResponse.Body].This method discards all its resources, calling any method on disposed + // [APIRequestContext] will throw an exception. + Dispose(options ...APIRequestContextDisposeOptions) error + + // Sends HTTP(S) request and returns its response. The method will populate request cookies from the context and + // update context cookies from the response. The method will automatically follow redirects. + // + // urlOrRequest: Target URL or Request to get all parameters from. + Fetch(urlOrRequest interface{}, options ...APIRequestContextFetchOptions) (APIResponse, error) + + // Sends HTTP(S) [GET] request and returns its + // response. The method will populate request cookies from the context and update context cookies from the response. + // The method will automatically follow redirects. + // + // url: Target URL. + // + // [GET]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET + Get(url string, options ...APIRequestContextGetOptions) (APIResponse, error) + + // Sends HTTP(S) [HEAD] request and returns its + // response. The method will populate request cookies from the context and update context cookies from the response. + // The method will automatically follow redirects. + // + // url: Target URL. + // + // [HEAD]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD + Head(url string, options ...APIRequestContextHeadOptions) (APIResponse, error) + + // Sends HTTP(S) [PATCH] request and returns its + // response. The method will populate request cookies from the context and update context cookies from the response. + // The method will automatically follow redirects. + // + // url: Target URL. + // + // [PATCH]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH + Patch(url string, options ...APIRequestContextPatchOptions) (APIResponse, error) + + // Sends HTTP(S) [POST] request and returns its + // response. The method will populate request cookies from the context and update context cookies from the response. + // The method will automatically follow redirects. + // + // url: Target URL. + // + // [POST]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST + Post(url string, options ...APIRequestContextPostOptions) (APIResponse, error) + + // Sends HTTP(S) [PUT] request and returns its + // response. The method will populate request cookies from the context and update context cookies from the response. + // The method will automatically follow redirects. + // + // url: Target URL. + // + // [PUT]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT + Put(url string, options ...APIRequestContextPutOptions) (APIResponse, error) + + // Returns storage state for this request context, contains current cookies and local storage snapshot if it was + // passed to the constructor. + StorageState(path ...string) (*StorageState, error) +} + +// [APIResponse] class represents responses returned by [APIRequestContext.Get] and similar methods. +type APIResponse interface { + // Returns the buffer with response body. + Body() ([]byte, error) + + // Disposes the body of this response. If not called then the body will stay in memory until the context closes. + Dispose() error + + // An object with all the response HTTP headers associated with this response. + Headers() map[string]string + + // An array with all the response HTTP headers associated with this response. Header names are not lower-cased. + // Headers with multiple entries, such as `Set-Cookie`, appear in the array multiple times. + HeadersArray() []NameValue + + // Returns the JSON representation of response body. + // This method will throw if the response body is not parsable via `JSON.parse`. + JSON(v interface{}) error + + // Contains a boolean stating whether the response was successful (status in the range 200-299) or not. + Ok() bool + + // Contains the status code of the response (e.g., 200 for a success). + Status() int + + // Contains the status text of the response (e.g. usually an "OK" for a success). + StatusText() string + + // Returns the text representation of response body. + Text() (string, error) + + // Contains the URL of the response. + URL() string +} + +// The [APIResponseAssertions] class provides assertion methods that can be used to make assertions about the +// [APIResponse] in the tests. +type APIResponseAssertions interface { + // Makes the assertion check for the opposite condition. For example, this code tests that the response status is not + // successful: + Not() APIResponseAssertions + + // Ensures the response status code is within `200..299` range. + ToBeOK() error +} + +// A Browser is created via [BrowserType.Launch]. An example of using a [Browser] to create a [Page]: +type Browser interface { + EventEmitter + // Emitted when Browser gets disconnected from the browser application. This might happen because of one of the + // following: + // - Browser application is closed or crashed. + // - The [Browser.Close] method was called. + OnDisconnected(fn func(Browser)) + + // Get the browser type (chromium, firefox or webkit) that the browser belongs to. + BrowserType() BrowserType + + // In case this browser is obtained using [BrowserType.Launch], closes the browser and all of its pages (if any were + // opened). + // In case this browser is connected to, clears all created contexts belonging to this browser and disconnects from + // the browser server. + // **NOTE** This is similar to force-quitting the browser. To close pages gracefully and ensure you receive page close + // events, call [BrowserContext.Close] on any [BrowserContext] instances you explicitly created earlier using + // [Browser.NewContext] **before** calling [Browser.Close]. + // The [Browser] object itself is considered to be disposed and cannot be used anymore. + Close(options ...BrowserCloseOptions) error + + // Returns an array of all open browser contexts. In a newly created browser, this will return zero browser contexts. + Contexts() []BrowserContext + + // Indicates that the browser is connected. + IsConnected() bool + + // **NOTE** CDP Sessions are only supported on Chromium-based browsers. + // Returns the newly created browser session. + NewBrowserCDPSession() (CDPSession, error) + + // Creates a new browser context. It won't share cookies/cache with other browser contexts. + // **NOTE** If directly using this method to create [BrowserContext]s, it is best practice to explicitly close the + // returned context via [BrowserContext.Close] when your code is done with the [BrowserContext], and before calling + // [Browser.Close]. This will ensure the `context` is closed gracefully and any artifacts—like HARs and videos—are + // fully flushed and saved. + NewContext(options ...BrowserNewContextOptions) (BrowserContext, error) + + // Creates a new page in a new browser context. Closing this page will close the context as well. + // This is a convenience API that should only be used for the single-page scenarios and short snippets. Production + // code and testing frameworks should explicitly create [Browser.NewContext] followed by the [BrowserContext.NewPage] + // to control their exact life times. + NewPage(options ...BrowserNewPageOptions) (Page, error) + + // **NOTE** This API controls + // [Chromium Tracing] which is a low-level + // chromium-specific debugging tool. API to control [Playwright Tracing] could be found + // [here]. + // You can use [Browser.StartTracing] and [Browser.StopTracing] to create a trace file that can be opened in Chrome + // DevTools performance panel. + // + // [Chromium Tracing]: https://www.chromium.org/developers/how-tos/trace-event-profiling-tool + // [Playwright Tracing]: ../trace-viewer + // [here]: ./class-tracing + StartTracing(options ...BrowserStartTracingOptions) error + + // **NOTE** This API controls + // [Chromium Tracing] which is a low-level + // chromium-specific debugging tool. API to control [Playwright Tracing] could be found + // [here]. + // Returns the buffer with trace data. + // + // [Chromium Tracing]: https://www.chromium.org/developers/how-tos/trace-event-profiling-tool + // [Playwright Tracing]: ../trace-viewer + // [here]: ./class-tracing + StopTracing() ([]byte, error) + + // Returns the browser version. + Version() string +} + +// BrowserContexts provide a way to operate multiple independent browser sessions. +// If a page opens another page, e.g. with a `window.open` call, the popup will belong to the parent page's browser +// context. +// Playwright allows creating isolated non-persistent browser contexts with [Browser.NewContext] method. +// Non-persistent browser contexts don't write any browsing data to disk. +type BrowserContext interface { + EventEmitter + // **NOTE** Only works with Chromium browser's persistent context. + // Emitted when new background page is created in the context. + OnBackgroundPage(fn func(Page)) + + // Playwright has ability to mock clock and passage of time. + Clock() Clock + + // Emitted when Browser context gets closed. This might happen because of one of the following: + // - Browser context is closed. + // - Browser application is closed or crashed. + // - The [Browser.Close] method was called. + OnClose(fn func(BrowserContext)) + + // Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. + // The arguments passed into `console.log` and the page are available on the [ConsoleMessage] event handler argument. + OnConsole(fn func(ConsoleMessage)) + + // Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, `confirm` or `beforeunload`. Listener **must** + // either [Dialog.Accept] or [Dialog.Dismiss] the dialog - otherwise the page will + // [freeze] waiting for the dialog, + // and actions like click will never finish. + // + // [freeze]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking + OnDialog(fn func(Dialog)) + + // The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event + // will also fire for popup pages. See also [Page.OnPopup] to receive events about popups relevant to a specific page. + // The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a + // popup with `window.open('http://example.com')`, this event will fire when the network request to + // "http://example.com" is done and its response has started loading in the popup. If you would like to route/listen + // to this network request, use [BrowserContext.Route] and [BrowserContext.OnRequest] respectively instead of similar + // methods on the [Page]. + // **NOTE** Use [Page.WaitForLoadState] to wait until the page gets to a particular state (you should not need it in + // 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]. + OnRequest(fn func(Request)) + + // Emitted when a request fails, for example by timing out. To only listen for failed requests from a particular page, + // use [Page.OnRequestFailed]. + // **NOTE** HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request + // will complete with [BrowserContext.OnRequestFinished] event and not with [BrowserContext.OnRequestFailed]. + OnRequestFailed(fn func(Request)) + + // Emitted when a request finishes successfully after downloading the response body. For a successful response, the + // sequence of events is `request`, `response` and `requestfinished`. To listen for successful requests from a + // particular page, use [Page.OnRequestFinished]. + OnRequestFinished(fn func(Request)) + + // Emitted when [response] status and headers are received for a request. For a successful response, the sequence of + // events is `request`, `response` and `requestfinished`. To listen for response events from a particular page, use + // [Page.OnResponse]. + OnResponse(fn func(Response)) + + // Adds cookies into this browser context. All pages within this context will have these cookies installed. Cookies + // can be obtained via [BrowserContext.Cookies]. + AddCookies(cookies []OptionalCookie) error + + // Adds a script which would be evaluated in one of the following scenarios: + // - Whenever a page is created in the browser context or is navigated. + // - Whenever a child frame is attached or navigated in any page in the browser context. In this case, the script is + // evaluated in the context of the newly attached frame. + // The script is evaluated after the document was created but before any of its scripts were run. This is useful to + // amend the JavaScript environment, e.g. to seed `Math.random`. + // + // script: Script to be evaluated in all pages in the browser context. + AddInitScript(script Script) error + + // **NOTE** Background pages are only supported on Chromium-based browsers. + // All existing background pages in the context. + BackgroundPages() []Page + + // Returns the browser instance of the context. If it was launched as a persistent context null gets returned. + Browser() Browser + + // Removes cookies from context. Accepts optional filter. + ClearCookies(options ...BrowserContextClearCookiesOptions) error + + // Clears all permission overrides for the browser context. + ClearPermissions() error + + // Closes the browser context. All the pages that belong to the browser context will be closed. + // **NOTE** The default browser context cannot be closed. + Close(options ...BrowserContextCloseOptions) error + + // If no URLs are specified, this method returns all cookies. If URLs are specified, only cookies that affect those + // URLs are returned. + Cookies(urls ...string) ([]Cookie, error) + + // The method adds a function called “[object Object]” on the `window` object of every frame in every page in the + // context. When called, the function executes “[object Object]” and returns a [Promise] which resolves to the return + // value of “[object Object]”. If the “[object Object]” returns a [Promise], it will be awaited. + // The first argument of the “[object Object]” function contains information about the caller: `{ browserContext: + // BrowserContext, page: Page, frame: Frame }`. + // See [Page.ExposeBinding] for page-only version. + // + // 1. name: Name of the function on the window object. + // 2. binding: Callback function that will be called in the Playwright's context. + ExposeBinding(name string, binding BindingCallFunction, handle ...bool) error + + // The method adds a function called “[object Object]” on the `window` object of every frame in every page in the + // context. When called, the function executes “[object Object]” and returns a [Promise] which resolves to the return + // value of “[object Object]”. + // If the “[object Object]” returns a [Promise], it will be awaited. + // See [Page.ExposeFunction] for page-only version. + // + // 1. name: Name of the function on the window object. + // 2. binding: Callback function that will be called in the Playwright's context. + ExposeFunction(name string, binding ExposedFunction) error + + // Grants specified permissions to the browser context. Only grants corresponding permissions to the given origin if + // specified. + // + // permissions: A list of permissions to grant. + // + // **NOTE** Supported permissions differ between browsers, and even between different versions of the same browser. + // Any permission may stop working after an update. + // + // Here are some permissions that may be supported by some browsers: + // - `'accelerometer'` + // - `'ambient-light-sensor'` + // - `'background-sync'` + // - `'camera'` + // - `'clipboard-read'` + // - `'clipboard-write'` + // - `'geolocation'` + // - `'gyroscope'` + // - `'magnetometer'` + // - `'microphone'` + // - `'midi-sysex'` (system-exclusive midi) + // - `'midi'` + // - `'notifications'` + // - `'payment-handler'` + // - `'storage-access'` + GrantPermissions(permissions []string, options ...BrowserContextGrantPermissionsOptions) error + + // **NOTE** CDP sessions are only supported on Chromium-based browsers. + // Returns the newly created session. + // + // page: Target to create new session for. For backwards-compatibility, this parameter is named `page`, but it can be a + // `Page` or `Frame` type. + NewCDPSession(page interface{}) (CDPSession, error) + + // Creates a new page in the browser context. + NewPage() (Page, error) + + // Returns all open pages in the context. + Pages() []Page + + // API testing helper associated with this context. Requests made with this API will use context cookies. + Request() APIRequestContext + + // Routing provides the capability to modify network requests that are made by any page in the browser context. Once + // route is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted. + // **NOTE** [BrowserContext.Route] will not intercept requests intercepted by Service Worker. See + // [this] issue. We recommend disabling Service Workers when + // using request interception by setting “[object Object]” to `block`. + // + // 1. url: A glob pattern, regex pattern, or predicate that receives a [URL] to match during routing. If “[object Object]” is + // set in the context options and the provided URL is a string that does not start with `*`, it is resolved using the + // [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor. + // 2. handler: handler function to route the request. + // + // [this]: https://github.com/microsoft/playwright/issues/1090 + Route(url interface{}, handler routeHandler, times ...int) error + + // If specified the network requests that are made in the context will be served from the HAR file. Read more about + // [Replaying from HAR]. + // Playwright will not serve requests intercepted by Service Worker from the HAR file. See + // [this] issue. We recommend disabling Service Workers when + // using request interception by setting “[object Object]” to `block`. + // + // har: Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a + // relative path, then it is resolved relative to the current working directory. + // + // [Replaying from HAR]: https://playwright.dev/docs/mock#replaying-from-har + // [this]: https://github.com/microsoft/playwright/issues/1090 + RouteFromHAR(har string, options ...BrowserContextRouteFromHAROptions) error + + // This method allows to modify websocket connections that are made by any page in the browser context. + // Note that only `WebSocket`s created after this method was called will be routed. It is recommended to call this + // method before creating any pages. + // + // 1. url: Only WebSockets with the url matching this pattern will be routed. A string pattern can be relative to the + // “[object Object]” context option. + // 2. handler: Handler function to route the WebSocket. + RouteWebSocket(url interface{}, handler func(WebSocketRoute)) error + + // **NOTE** Service workers are only supported on Chromium-based browsers. + // All existing service workers in the context. + ServiceWorkers() []Worker + + // This setting will change the default maximum navigation time for the following methods and related shortcuts: + // - [Page.GoBack] + // - [Page.GoForward] + // - [Page.Goto] + // - [Page.Reload] + // - [Page.SetContent] + // - [Page.ExpectNavigation] + // **NOTE** [Page.SetDefaultNavigationTimeout] and [Page.SetDefaultTimeout] take priority over + // [BrowserContext.SetDefaultNavigationTimeout]. + // + // timeout: Maximum navigation time in milliseconds + SetDefaultNavigationTimeout(timeout float64) + + // This setting will change the default maximum time for all the methods accepting “[object Object]” option. + // **NOTE** [Page.SetDefaultNavigationTimeout], [Page.SetDefaultTimeout] and + // [BrowserContext.SetDefaultNavigationTimeout] take priority over [BrowserContext.SetDefaultTimeout]. + // + // timeout: Maximum time in milliseconds. Pass `0` to disable timeout. + SetDefaultTimeout(timeout float64) + + // The extra HTTP headers will be sent with every request initiated by any page in the context. These headers are + // merged with page-specific extra HTTP headers set with [Page.SetExtraHTTPHeaders]. If page overrides a particular + // header, page-specific header value will be used instead of the browser context header value. + // **NOTE** [BrowserContext.SetExtraHTTPHeaders] does not guarantee the order of headers in the outgoing requests. + // + // headers: An object containing additional HTTP headers to be sent with every request. All header values must be strings. + SetExtraHTTPHeaders(headers map[string]string) error + + // Sets the context's geolocation. Passing `null` or `undefined` emulates position unavailable. + SetGeolocation(geolocation *Geolocation) error + + // + // offline: Whether to emulate network being offline for the browser context. + SetOffline(offline bool) error + + // Returns storage state for this browser context, contains current cookies, local storage snapshot and IndexedDB + // snapshot. + StorageState(path ...string) (*StorageState, error) + + Tracing() Tracing + + // Removes all routes created with [BrowserContext.Route] and [BrowserContext.RouteFromHAR]. + UnrouteAll(options ...BrowserContextUnrouteAllOptions) error + + // Removes a route created with [BrowserContext.Route]. When “[object Object]” is not specified, removes all routes + // for the “[object Object]”. + // + // 1. url: A glob pattern, regex pattern or predicate receiving [URL] used to register a routing with [BrowserContext.Route]. + // 2. handler: Optional handler function used to register a routing with [BrowserContext.Route]. + Unroute(url interface{}, handler ...routeHandler) error + + // Performs action and waits for a [ConsoleMessage] to be logged by in the pages in the context. If predicate is + // provided, it passes [ConsoleMessage] value into the `predicate` function and waits for `predicate(message)` to + // return a truthy value. Will throw an error if the page is closed before the [BrowserContext.OnConsole] event is + // fired. + ExpectConsoleMessage(cb func() error, options ...BrowserContextExpectConsoleMessageOptions) (ConsoleMessage, error) + + // Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy + // value. Will throw an error if the context closes before the event is fired. Returns the event data value. + // + // event: Event name, same one would pass into `browserContext.on(event)`. + ExpectEvent(event string, cb func() error, options ...BrowserContextExpectEventOptions) (interface{}, error) + + // Performs action and waits for a new [Page] to be created in the context. If predicate is provided, it passes [Page] + // value into the `predicate` function and waits for `predicate(event)` to return a truthy value. Will throw an error + // if the context closes before new [Page] is created. + ExpectPage(cb func() error, options ...BrowserContextExpectPageOptions) (Page, error) + + // **NOTE** In most cases, you should use [BrowserContext.ExpectEvent]. + // Waits for given `event` to fire. If predicate is provided, it passes event's value into the `predicate` function + // and waits for `predicate(event)` to return a truthy value. Will throw an error if the browser context is closed + // before the `event` is fired. + // + // event: Event name, same one typically passed into `*.on(event)`. + WaitForEvent(event string, options ...BrowserContextWaitForEventOptions) (interface{}, error) +} + +// BrowserType provides methods to launch a specific browser instance or connect to an existing one. The following is +// a typical example of using Playwright to drive automation: +type BrowserType interface { + // This method attaches Playwright to an existing browser instance created via `BrowserType.launchServer` in Node.js. + // **NOTE** The major and minor version of the Playwright instance that connects needs to match the version of + // Playwright that launches the browser (1.2.3 → is compatible with 1.2.x). + // + // wsEndpoint: A Playwright browser websocket endpoint to connect to. You obtain this endpoint via `BrowserServer.wsEndpoint`. + Connect(wsEndpoint string, options ...BrowserTypeConnectOptions) (Browser, error) + + // This method attaches Playwright to an existing browser instance using the Chrome DevTools Protocol. + // The default browser context is accessible via [Browser.Contexts]. + // **NOTE** Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers. + // **NOTE** This connection is significantly lower fidelity than the Playwright protocol connection via + // [BrowserType.Connect]. If you are experiencing issues or attempting to use advanced functionality, you probably + // want to use [BrowserType.Connect]. + // + // endpointURL: A CDP websocket endpoint or http url to connect to. For example `http://localhost:9222/` or + // `ws://127.0.0.1:9222/devtools/browser/387adf4c-243f-4051-a181-46798f4a46f4`. + ConnectOverCDP(endpointURL string, options ...BrowserTypeConnectOverCDPOptions) (Browser, error) + + // A path where Playwright expects to find a bundled browser executable. + ExecutablePath() string + + // Returns the browser instance. + // + // [Chrome Canary]: https://www.google.com/chrome/browser/canary.html + // [Dev Channel]: https://www.chromium.org/getting-involved/dev-channel + // [this article]: https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ + // [This article]: https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md + Launch(options ...BrowserTypeLaunchOptions) (Browser, error) + + // Returns the persistent browser context instance. + // Launches browser that uses persistent storage located at “[object Object]” and returns the only context. Closing + // this context will automatically close the browser. + // + // userDataDir: Path to a User Data Directory, which stores browser session data like cookies and local storage. Pass an empty + // string to create a temporary directory. + // + // More details for + // [Chromium](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md#introduction) and + // [Firefox](https://wiki.mozilla.org/Firefox/CommandLineOptions#User_profile). Chromium's user data directory is the + // **parent** directory of the "Profile Path" seen at `chrome://version`. + // + // Note that browsers do not allow launching multiple instances with the same User Data Directory. + LaunchPersistentContext(userDataDir string, options ...BrowserTypeLaunchPersistentContextOptions) (BrowserContext, error) + + // Returns browser name. For example: `chromium`, `webkit` or `firefox`. + Name() string +} + +// The `CDPSession` instances are used to talk raw Chrome Devtools Protocol: +// - protocol methods can be called with `session.send` method. +// - protocol events can be subscribed to with `session.on` method. +// +// Useful links: +// - Documentation on DevTools Protocol can be found here: +// [DevTools Protocol Viewer]. +// - Getting Started with DevTools Protocol: +// https://github.com/aslushnikov/getting-started-with-cdp/blob/master/README.md +// +// [DevTools Protocol Viewer]: https://chromedevtools.github.io/devtools-protocol/ +type CDPSession interface { + EventEmitter + // Detaches the CDPSession from the target. Once detached, the CDPSession object won't emit any events and can't be + // used to send messages. + Detach() error + + // + // 1. method: Protocol method name. + // 2. params: Optional method parameters. + Send(method string, params map[string]interface{}) (interface{}, error) +} + +// Accurately simulating time-dependent behavior is essential for verifying the correctness of applications. Learn +// more about [clock emulation]. +// Note that clock is installed for the entire [BrowserContext], so the time in all the pages and iframes is +// controlled by the same clock. +// +// [clock emulation]: https://playwright.dev/docs/clock +type Clock interface { + // Advance the clock by jumping forward in time. Only fires due timers at most once. This is equivalent to user + // closing the laptop lid for a while and reopening it later, after given time. + // + // ticks: Time may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are + // "08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds. + FastForward(ticks interface{}) error + + // Install fake implementations for the following time-related functions: + // - `Date` + // - `setTimeout` + // - `clearTimeout` + // - `setInterval` + // - `clearInterval` + // - `requestAnimationFrame` + // - `cancelAnimationFrame` + // - `requestIdleCallback` + // - `cancelIdleCallback` + // - `performance` + // Fake timers are used to manually control the flow of time in tests. They allow you to advance time, fire timers, + // and control the behavior of time-dependent functions. See [Clock.RunFor] and [Clock.FastForward] for more + // information. + Install(options ...ClockInstallOptions) error + + // Advance the clock, firing all the time-related callbacks. + // + // ticks: Time may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are + // "08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds. + RunFor(ticks interface{}) error + + // Advance the clock by jumping forward in time and pause the time. Once this method is called, no timers are fired + // unless [Clock.RunFor], [Clock.FastForward], [Clock.PauseAt] or [Clock.Resume] is called. + // Only fires due timers at most once. This is equivalent to user closing the laptop lid for a while and reopening it + // at the specified time and pausing. + // + // time: Time to pause at. + PauseAt(time interface{}) error + + // Resumes timers. Once this method is called, time resumes flowing, timers are fired as usual. + Resume() error + + // Makes `Date.now` and `new Date()` return fixed fake time at all times, keeps all the timers running. + // Use this method for simple scenarios where you only need to test with a predefined time. For more advanced + // scenarios, use [Clock.Install] instead. Read docs on [clock emulation] to learn more. + // + // time: Time to be set. + // + // [clock emulation]: https://playwright.dev/docs/clock + SetFixedTime(time interface{}) error + + // Sets system time, but does not trigger any timers. Use this to test how the web page reacts to a time shift, for + // example switching from summer to winter time, or changing time zones. + // + // time: Time to be set. + SetSystemTime(time interface{}) error +} + +// [ConsoleMessage] objects are dispatched by page via the [Page.OnConsole] event. For each console message logged in +// the page there will be corresponding event in the Playwright context. +type ConsoleMessage interface { + // List of arguments passed to a `console` function call. See also [Page.OnConsole]. + Args() []JSHandle + + Location() *ConsoleMessageLocation + + // The page that produced this console message, if any. + Page() Page + + // The text of the console message. + Text() string + + // The text of the console message. + String() string + + // One of the following values: `log`, `debug`, `info`, `error`, `warning`, `dir`, `dirxml`, `table`, + // `trace`, `clear`, `startGroup`, `startGroupCollapsed`, `endGroup`, `assert`, `profile`, + // `profileEnd`, `count`, `timeEnd`. + Type() string +} + +// [Dialog] objects are dispatched by page via the [Page.OnDialog] event. +// An example of using `Dialog` class: +// **NOTE** Dialogs are dismissed automatically, unless there is a [Page.OnDialog] listener. When listener is present, +// it **must** either [Dialog.Accept] or [Dialog.Dismiss] the dialog - otherwise the page will +// [freeze] waiting for the dialog, +// and actions like click will never finish. +// +// [freeze]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking +type Dialog interface { + // Returns when the dialog has been accepted. + Accept(promptText ...string) error + + // If dialog is prompt, returns default prompt value. Otherwise, returns empty string. + DefaultValue() string + + // Returns when the dialog has been dismissed. + Dismiss() error + + // A message displayed in the dialog. + Message() string + + // The page that initiated this dialog, if available. + Page() Page + + // Returns dialog's type, can be one of `alert`, `beforeunload`, `confirm` or `prompt`. + Type() string +} + +// [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. +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`. + Cancel() error + + // Deletes the downloaded file. Will wait for the download to finish if necessary. + Delete() error + + // Returns download error if any. Will wait for the download to finish if necessary. + Failure() error + + // Get the page that the download belongs to. + Page() Page + + // Returns path to the downloaded file for a successful download, or throws for a failed/canceled download. The method + // will wait for the download to finish if necessary. The method throws when connected remotely. + // Note that the download's file name is a random GUID, use [Download.SuggestedFilename] to get suggested file name. + Path() (string, error) + + // Copy the download to a user-specified path. It is safe to call this method while the download is still in progress. + // Will wait for the download to finish if necessary. + // + // path: Path where the download should be copied. + SaveAs(path string) error + + // Returns suggested filename for this download. It is typically computed by the browser from the + // [`Content-Disposition`] response + // header or the `download` attribute. See the spec on [whatwg]. + // Different browsers can use different logic for computing it. + // + // [`Content-Disposition`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition + // [whatwg]: https://html.spec.whatwg.org/#downloading-resources + SuggestedFilename() string + + // Returns downloaded url. + URL() string + + String() string +} + +// ElementHandle represents an in-page DOM element. ElementHandles can be created with the [Page.QuerySelector] +// +// method. +// **NOTE** The use of ElementHandle is discouraged, use [Locator] objects and web-first assertions instead. +// ElementHandle prevents DOM element from garbage collection unless the handle is disposed with [JSHandle.Dispose]. +// ElementHandles are auto-disposed when their origin frame gets navigated. +// ElementHandle instances can be used as an argument in [Page.EvalOnSelector] and [Page.Evaluate] methods. +// The difference between the [Locator] and ElementHandle is that the ElementHandle points to a particular element, +// while [Locator] captures the logic of how to retrieve an element. +// In the example below, handle points to a particular DOM element on page. If that element changes text or is used by +// React to render an entirely different component, handle is still pointing to that very DOM element. This can lead +// to unexpected behaviors. +// With the locator, every time the `element` is used, up-to-date DOM element is located in the page using the +// selector. So in the snippet below, underlying DOM element is going to be located twice. +type ElementHandle interface { + JSHandle + // This method returns the bounding box of the element, or `null` if the element is not visible. The bounding box is + // calculated relative to the main frame viewport - which is usually the same as the browser window. + // Scrolling affects the returned bounding box, similarly to + // [Element.GetBoundingClientRect]. + // That means `x` and/or `y` may be negative. + // Elements from child frames return the bounding box relative to the main frame, unlike the + // [Element.GetBoundingClientRect]. + // Assuming the page is static, it is safe to use bounding box coordinates to perform input. For example, the + // following snippet should click the center of the element. + // + // [Element.GetBoundingClientRect]: https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect + // [Element.GetBoundingClientRect]: https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect + BoundingBox() (*Rect, error) + + // This method checks the element by performing the following steps: + // 1. Ensure that element is a checkbox or a radio input. If not, this method throws. If the element is already + // checked, this method returns immediately. + // 2. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Mouse] to click in the center of the element. + // 5. Ensure that the element is now checked. If not, this method throws. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Check] instead. Read more about [locators]. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Check(options ...ElementHandleCheckOptions) error + + // This method clicks the element by performing the following steps: + // 1. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 2. Scroll the element into view if needed. + // 3. Use [Page.Mouse] to click in the center of the element, or the specified “[object Object]”. + // 4. Wait for initiated navigations to either succeed or fail, unless “[object Object]” option is set. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Click] instead. Read more about [locators]. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Click(options ...ElementHandleClickOptions) error + + // Returns the content frame for element handles referencing iframe nodes, or `null` otherwise + ContentFrame() (Frame, error) + + // This method double clicks the element by performing the following steps: + // 1. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 2. Scroll the element into view if needed. + // 3. Use [Page.Mouse] to double click in the center of the element, or the specified “[object Object]”. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // **NOTE** `elementHandle.dblclick()` dispatches two `click` events and a single `dblclick` event. + // + // Deprecated: Use locator-based [Locator.Dblclick] instead. Read more about [locators]. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Dblclick(options ...ElementHandleDblclickOptions) error + + // The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the element, + // `click` is dispatched. This is equivalent to calling + // [element.Click()]. + // + // Deprecated: Use locator-based [Locator.DispatchEvent] instead. Read more about [locators]. + // + // 1. typ: DOM event type: `"click"`, `"dragstart"`, etc. + // 2. eventInit: Optional event-specific initialization properties. + // + // [element.Click()]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click + // [DeviceMotionEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent/DeviceMotionEvent + // [DeviceOrientationEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/DeviceOrientationEvent + // [DragEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/DragEvent + // [Event]: https://developer.mozilla.org/en-US/docs/Web/API/Event/Event + // [FocusEvent]: https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/FocusEvent + // [KeyboardEvent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent + // [MouseEvent]: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent + // [PointerEvent]: https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/PointerEvent + // [TouchEvent]: https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent + // [WheelEvent]: https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/WheelEvent + // [locators]: https://playwright.dev/docs/locators + DispatchEvent(typ string, eventInit ...interface{}) error + + // Returns the return value of “[object Object]”. + // The method finds an element matching the specified selector in the `ElementHandle`s subtree and passes it as a + // first argument to “[object Object]”. If no elements match the selector, the method throws an error. + // If “[object Object]” returns a [Promise], then [ElementHandle.EvalOnSelector] would wait for the promise to resolve + // and return its value. + // + // Deprecated: This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests. Use [Locator.Evaluate], other [Locator] helper methods or web-first assertions instead. + // + // 1. selector: A selector to query for. + // 2. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 3. arg: Optional argument to pass to “[object Object]”. + EvalOnSelector(selector string, expression string, arg ...interface{}) (interface{}, error) + + // Returns the return value of “[object Object]”. + // The method finds all elements matching the specified selector in the `ElementHandle`'s subtree and passes an array + // of matched elements as a first argument to “[object Object]”. + // If “[object Object]” returns a [Promise], then [ElementHandle.EvalOnSelectorAll] would wait for the promise to + // resolve and return its value. + // + // Deprecated: In most cases, [Locator.EvaluateAll], other [Locator] helper methods and web-first assertions do a better job. + // + // 1. selector: A selector to query for. + // 2. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 3. arg: Optional argument to pass to “[object Object]”. + EvalOnSelectorAll(selector string, expression string, arg ...interface{}) (interface{}, error) + + // This method waits for [actionability] checks, focuses the element, fills it and triggers an + // `input` event after filling. Note that you can pass an empty string to clear the input field. + // If the target element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an + // 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.PressSequentially]. + // + // Deprecated: Use locator-based [Locator.Fill] instead. Read more about [locators]. + // + // value: Value to set for the `<input>`, `<textarea>` or `[contenteditable]` element. + // + // [actionability]: https://playwright.dev/docs/actionability + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + Fill(value string, options ...ElementHandleFillOptions) error + + // Calls [focus] on the element. + // + // Deprecated: Use locator-based [Locator.Focus] instead. Read more about [locators]. + // + // [focus]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus + // [locators]: https://playwright.dev/docs/locators + Focus() error + + // Returns element attribute value. + // + // Deprecated: Use locator-based [Locator.GetAttribute] instead. Read more about [locators]. + // + // name: Attribute name to get the value for. + // + // [locators]: https://playwright.dev/docs/locators + GetAttribute(name string) (string, error) + + // This method hovers over the element by performing the following steps: + // 1. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 2. Scroll the element into view if needed. + // 3. Use [Page.Mouse] to hover over the center of the element, or the specified “[object Object]”. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Hover] instead. Read more about [locators]. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Hover(options ...ElementHandleHoverOptions) error + + // Returns the `element.innerHTML`. + // + // Deprecated: Use locator-based [Locator.InnerHTML] instead. Read more about [locators]. + // + // [locators]: https://playwright.dev/docs/locators + InnerHTML() (string, error) + + // Returns the `element.innerText`. + // + // Deprecated: Use locator-based [Locator.InnerText] instead. Read more about [locators]. + // + // [locators]: https://playwright.dev/docs/locators + InnerText() (string, error) + + // Returns `input.value` for the selected `<input>` or `<textarea>` or `<select>` element. + // Throws for non-input elements. However, if the element is inside the `<label>` element that has an associated + // [control], returns the value of the + // control. + // + // Deprecated: Use locator-based [Locator.InputValue] instead. Read more about [locators]. + // + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + InputValue(options ...ElementHandleInputValueOptions) (string, error) + + // Returns whether the element is checked. Throws if the element is not a checkbox or radio input. + // + // Deprecated: Use locator-based [Locator.IsChecked] instead. Read more about [locators]. + // + // [locators]: https://playwright.dev/docs/locators + IsChecked() (bool, error) + + // Returns whether the element is disabled, the opposite of [enabled]. + // + // Deprecated: Use locator-based [Locator.IsDisabled] instead. Read more about [locators]. + // + // [enabled]: https://playwright.dev/docs/actionability#enabled + // [locators]: https://playwright.dev/docs/locators + IsDisabled() (bool, error) + + // Returns whether the element is [editable]. + // + // Deprecated: Use locator-based [Locator.IsEditable] instead. Read more about [locators]. + // + // [editable]: https://playwright.dev/docs/actionability#editable + // [locators]: https://playwright.dev/docs/locators + IsEditable() (bool, error) + + // Returns whether the element is [enabled]. + // + // Deprecated: Use locator-based [Locator.IsEnabled] instead. Read more about [locators]. + // + // [enabled]: https://playwright.dev/docs/actionability#enabled + // [locators]: https://playwright.dev/docs/locators + IsEnabled() (bool, error) + + // Returns whether the element is hidden, the opposite of [visible]. + // + // Deprecated: Use locator-based [Locator.IsHidden] instead. Read more about [locators]. + // + // [visible]: https://playwright.dev/docs/actionability#visible + // [locators]: https://playwright.dev/docs/locators + IsHidden() (bool, error) + + // Returns whether the element is [visible]. + // + // Deprecated: Use locator-based [Locator.IsVisible] instead. Read more about [locators]. + // + // [visible]: https://playwright.dev/docs/actionability#visible + // [locators]: https://playwright.dev/docs/locators + IsVisible() (bool, error) + + // Returns the frame containing the given element. + OwnerFrame() (Frame, error) + + // Focuses the element, and then uses [Keyboard.Down] and [Keyboard.Up]. + // “[object Object]” can specify the intended + // [keyboardEvent.Key] value or a single character + // to generate the text for. A superset of the “[object Object]” values can be found + // [here]. Examples of the keys are: + // `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, + // `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, + // etc. + // Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`, + // `ControlOrMeta`. + // Holding down `Shift` will type the text that corresponds to the “[object Object]” in the upper case. + // If “[object Object]” is a single character, it is case-sensitive, so the values `a` and `A` will generate different + // respective texts. + // Shortcuts such as `key: "Control+o"`, `key: "Control++` or `key: "Control+Shift+T"` are supported as well. When + // specified with the modifier, modifier is pressed and being held while the subsequent key is being pressed. + // + // Deprecated: Use locator-based [Locator.Press] instead. Read more about [locators]. + // + // key: Name of the key to press or a character to generate, such as `ArrowLeft` or `a`. + // + // [keyboardEvent.Key]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key + // [here]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values + // [locators]: https://playwright.dev/docs/locators + Press(key string, options ...ElementHandlePressOptions) error + + // The method finds an element matching the specified selector in the `ElementHandle`'s subtree. If no elements match + // the selector, returns `null`. + // + // Deprecated: Use locator-based [Page.Locator] instead. Read more about [locators]. + // + // selector: A selector to query for. + // + // [locators]: https://playwright.dev/docs/locators + QuerySelector(selector string) (ElementHandle, error) + + // The method finds all elements matching the specified selector in the `ElementHandle`s subtree. If no elements match + // the selector, returns empty array. + // + // Deprecated: Use locator-based [Page.Locator] instead. Read more about [locators]. + // + // selector: A selector to query for. + // + // [locators]: https://playwright.dev/docs/locators + QuerySelectorAll(selector string) ([]ElementHandle, error) + + // This method captures a screenshot of the page, clipped to the size and position of this particular element. If the + // element is covered by other elements, it will not be actually visible on the screenshot. If the element is a + // scrollable container, only the currently scrolled content will be visible on the screenshot. + // This method waits for the [actionability] checks, then scrolls element into view before taking + // a screenshot. If the element is detached from DOM, the method throws an error. + // Returns the buffer with the captured screenshot. + // + // Deprecated: Use locator-based [Locator.Screenshot] instead. Read more about [locators]. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Screenshot(options ...ElementHandleScreenshotOptions) ([]byte, error) + + // This method waits for [actionability] checks, then tries to scroll element into view, unless + // it is completely visible as defined by + // [IntersectionObserver]'s `ratio`. + // Throws when `elementHandle` does not point to an element + // [connected] to a Document or a ShadowRoot. + // See [scrolling] for alternative ways to scroll. + // + // Deprecated: Use locator-based [Locator.ScrollIntoViewIfNeeded] instead. Read more about [locators]. + // + // [actionability]: https://playwright.dev/docs/actionability + // [IntersectionObserver]: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API + // [connected]: https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected + // [scrolling]: https://playwright.dev/docs/input#scrolling + // [locators]: https://playwright.dev/docs/locators + ScrollIntoViewIfNeeded(options ...ElementHandleScrollIntoViewIfNeededOptions) error + + // This method waits for [actionability] checks, waits until all specified options are present in + // the `<select>` element and selects these options. + // If the target element is not a `<select>` element, this method throws an error. However, if the element is inside + // the `<label>` element that has an associated + // [control], the control will be used + // instead. + // Returns the array of option values that have been successfully selected. + // Triggers a `change` and `input` event once all the provided options have been selected. + // + // Deprecated: Use locator-based [Locator.SelectOption] instead. Read more about [locators]. + // + // [actionability]: https://playwright.dev/docs/actionability + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + SelectOption(values SelectOptionValues, options ...ElementHandleSelectOptionOptions) ([]string, error) + + // This method waits for [actionability] checks, then focuses the element and selects all its + // text content. + // If the element is inside the `<label>` element that has an associated + // [control], focuses and selects text in + // the control instead. + // + // Deprecated: Use locator-based [Locator.SelectText] instead. Read more about [locators]. + // + // [actionability]: https://playwright.dev/docs/actionability + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + SelectText(options ...ElementHandleSelectTextOptions) error + + // This method checks or unchecks an element by performing the following steps: + // 1. Ensure that element is a checkbox or a radio input. If not, this method throws. + // 2. If the element already has the right checked state, this method returns immediately. + // 3. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 4. Scroll the element into view if needed. + // 5. Use [Page.Mouse] to click in the center of the element. + // 6. Ensure that the element is now checked or unchecked. If not, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.SetChecked] instead. Read more about [locators]. + // + // checked: Whether to check or uncheck the checkbox. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + SetChecked(checked bool, options ...ElementHandleSetCheckedOptions) error + + // Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then + // they are resolved relative to the current working directory. For empty array, clears the selected files. For inputs + // with a `[webkitdirectory]` attribute, only a single directory path is supported. + // This method expects [ElementHandle] to point to an + // [input element]. However, if the element is inside + // the `<label>` element that has an associated + // [control], targets the control instead. + // + // Deprecated: Use locator-based [Locator.SetInputFiles] instead. Read more about [locators]. + // + // [input element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + SetInputFiles(files interface{}, options ...ElementHandleSetInputFilesOptions) error + + // This method taps the element by performing the following steps: + // 1. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 2. Scroll the element into view if needed. + // 3. Use [Page.Touchscreen] to tap the center of the element, or the specified “[object Object]”. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // **NOTE** `elementHandle.tap()` requires that the `hasTouch` option of the browser context be set to true. + // + // Deprecated: Use locator-based [Locator.Tap] instead. Read more about [locators]. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Tap(options ...ElementHandleTapOptions) error + + // Returns the `node.textContent`. + // + // Deprecated: Use locator-based [Locator.TextContent] instead. Read more about [locators]. + // + // [locators]: https://playwright.dev/docs/locators + TextContent() (string, error) + + // 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 [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 + + // This method checks the element by performing the following steps: + // 1. Ensure that element is a checkbox or a radio input. If not, this method throws. If the element is already + // unchecked, this method returns immediately. + // 2. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Mouse] to click in the center of the element. + // 5. Ensure that the element is now unchecked. If not, this method throws. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Uncheck] instead. Read more about [locators]. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Uncheck(options ...ElementHandleUncheckOptions) error + + // Returns when the element satisfies the “[object Object]”. + // Depending on the “[object Object]” parameter, this method waits for one of the [actionability] + // checks to pass. This method throws when the element is detached while waiting, unless waiting for the `"hidden"` + // state. + // - `"visible"` Wait until the element is [visible]. + // - `"hidden"` Wait until the element is [not visible] or not attached. Note that + // waiting for hidden does not throw when the element detaches. + // - `"stable"` Wait until the element is both [visible] and + // [stable]. + // - `"enabled"` Wait until the element is [enabled]. + // - `"disabled"` Wait until the element is [not enabled]. + // - `"editable"` Wait until the element is [editable]. + // If the element does not satisfy the condition for the “[object Object]” milliseconds, this method will throw. + // + // state: A state to wait for, see below for more details. + // + // [actionability]: https://playwright.dev/docs/actionability + // [visible]: https://playwright.dev/docs/actionability#visible + // [not visible]: https://playwright.dev/docs/actionability#visible + // [visible]: https://playwright.dev/docs/actionability#visible + // [stable]: https://playwright.dev/docs/actionability#stable + // [enabled]: https://playwright.dev/docs/actionability#enabled + // [not enabled]: https://playwright.dev/docs/actionability#enabled + // [editable]: https://playwright.dev/docs/actionability#editable + WaitForElementState(state ElementState, options ...ElementHandleWaitForElementStateOptions) error + + // Returns element specified by selector when it satisfies “[object Object]” option. Returns `null` if waiting for + // `hidden` or `detached`. + // Wait for the “[object Object]” relative to the element handle to satisfy “[object Object]” option (either + // appear/disappear from dom, or become visible/hidden). If at the moment of calling the method “[object Object]” + // already satisfies the condition, the method will return immediately. If the selector doesn't satisfy the condition + // for the “[object Object]” milliseconds, the function will throw. + // + // Deprecated: Use web assertions that assert visibility or a locator-based [Locator.WaitFor] instead. + // + // selector: A selector to query for. + WaitForSelector(selector string, options ...ElementHandleWaitForSelectorOptions) (ElementHandle, error) +} + +// [FileChooser] objects are dispatched by the page in the [Page.OnFileChooser] event. +type FileChooser interface { + // Returns input element associated with this file chooser. + Element() ElementHandle + + // Returns whether this file chooser accepts multiple files. + IsMultiple() bool + + // Returns page this file chooser belongs to. + Page() Page + + // Sets the value of the file input this chooser is associated with. If some of the `filePaths` are relative paths, + // then they are resolved relative to the current working directory. For empty array, clears the selected files. + SetFiles(files interface{}, options ...FileChooserSetFilesOptions) error +} + +// At every point of time, page exposes its current frame tree via the [Page.MainFrame] and [Frame.ChildFrames] +// methods. +// [Frame] object's lifecycle is controlled by three events, dispatched on the page object: +// - [Page.OnFrameAttached] - fired when the frame gets attached to the page. A Frame can be attached to the page +// only once. +// - [Page.OnFrameNavigated] - fired when the frame commits navigation to a different URL. +// - [Page.OnFrameDetached] - fired when the frame gets detached from the page. A Frame can be detached from the +// page only once. +// +// An example of dumping frame tree: +type Frame interface { + // Returns the added tag when the script's onload fires or when the script content was injected into frame. + // Adds a `<script>` tag into the page with the desired url or content. + AddScriptTag(options FrameAddScriptTagOptions) (ElementHandle, error) + + // Returns the added tag when the stylesheet's onload fires or when the CSS content was injected into frame. + // Adds a `<link rel="stylesheet">` tag into the page with the desired url or a `<style type="text/css">` tag with the + // content. + AddStyleTag(options FrameAddStyleTagOptions) (ElementHandle, error) + + // This method checks an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Ensure that matched element is a checkbox or a radio input. If not, this method throws. If the element is + // already checked, this method returns immediately. + // 3. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 4. Scroll the element into view if needed. + // 5. Use [Page.Mouse] to click in the center of the element. + // 6. Ensure that the element is now checked. If not, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Check] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Check(selector string, options ...FrameCheckOptions) error + + ChildFrames() []Frame + + // This method clicks an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Mouse] to click in the center of the element, or the specified “[object Object]”. + // 5. Wait for initiated navigations to either succeed or fail, unless “[object Object]” option is set. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Click] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Click(selector string, options ...FrameClickOptions) error + + // Gets the full HTML contents of the frame, including the doctype. + Content() (string, error) + + // This method double clicks an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Mouse] to double click in the center of the element, or the specified “[object Object]”. if the + // first click of the `dblclick()` triggers a navigation event, this method will throw. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // **NOTE** `frame.dblclick()` dispatches two `click` events and a single `dblclick` event. + // + // Deprecated: Use locator-based [Locator.Dblclick] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Dblclick(selector string, options ...FrameDblclickOptions) error + + // The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the element, + // `click` is dispatched. This is equivalent to calling + // [element.Click()]. + // + // Deprecated: Use locator-based [Locator.DispatchEvent] instead. Read more about [locators]. + // + // 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // 2. typ: DOM event type: `"click"`, `"dragstart"`, etc. + // 3. eventInit: Optional event-specific initialization properties. + // + // [element.Click()]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click + // [DeviceMotionEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent/DeviceMotionEvent + // [DeviceOrientationEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/DeviceOrientationEvent + // [DragEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/DragEvent + // [Event]: https://developer.mozilla.org/en-US/docs/Web/API/Event/Event + // [FocusEvent]: https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/FocusEvent + // [KeyboardEvent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent + // [MouseEvent]: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent + // [PointerEvent]: https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/PointerEvent + // [TouchEvent]: https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent + // [WheelEvent]: https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/WheelEvent + // [locators]: https://playwright.dev/docs/locators + DispatchEvent(selector string, typ string, eventInit interface{}, options ...FrameDispatchEventOptions) error + + // + // 1. source: A selector to search for an element to drag. If there are multiple elements satisfying the selector, the first will + // be used. + // 2. target: A selector to search for an element to drop onto. If there are multiple elements satisfying the selector, the first + // will be used. + DragAndDrop(source string, target string, options ...FrameDragAndDropOptions) error + + // Returns the return value of “[object Object]”. + // The method finds an element matching the specified selector within the frame and passes it as a first argument to + // “[object Object]”. If no elements match the selector, the method throws an error. + // If “[object Object]” returns a [Promise], then [Frame.EvalOnSelector] would wait for the promise to resolve and + // return its value. + // + // Deprecated: This method does not wait for the element to pass the actionability checks and therefore can lead to the flaky tests. Use [Locator.Evaluate], other [Locator] helper methods or web-first assertions instead. + // + // 1. selector: A selector to query for. + // 2. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 3. arg: Optional argument to pass to “[object Object]”. + EvalOnSelector(selector string, expression string, arg interface{}, options ...FrameEvalOnSelectorOptions) (interface{}, error) + + // Returns the return value of “[object Object]”. + // The method finds all elements matching the specified selector within the frame and passes an array of matched + // elements as a first argument to “[object Object]”. + // If “[object Object]” returns a [Promise], then [Frame.EvalOnSelectorAll] would wait for the promise to resolve and + // return its value. + // + // Deprecated: In most cases, [Locator.EvaluateAll], other [Locator] helper methods and web-first assertions do a better job. + // + // 1. selector: A selector to query for. + // 2. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 3. arg: Optional argument to pass to “[object Object]”. + EvalOnSelectorAll(selector string, expression string, arg ...interface{}) (interface{}, error) + + // Returns the return value of “[object Object]”. + // If the function passed to the [Frame.Evaluate] returns a [Promise], then [Frame.Evaluate] would wait for the + // promise to resolve and return its value. + // If the function passed to the [Frame.Evaluate] returns a non-[Serializable] value, then [Frame.Evaluate] returns + // `undefined`. Playwright also supports transferring some additional values that are not serializable by `JSON`: + // `-0`, `NaN`, `Infinity`, `-Infinity`. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + Evaluate(expression string, arg ...interface{}) (interface{}, error) + + // Returns the return value of “[object Object]” as a [JSHandle]. + // The only difference between [Frame.Evaluate] and [Frame.EvaluateHandle] is that [Frame.EvaluateHandle] returns + // [JSHandle]. + // If the function, passed to the [Frame.EvaluateHandle], returns a [Promise], then [Frame.EvaluateHandle] would wait + // for the promise to resolve and return its value. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + EvaluateHandle(expression string, arg ...interface{}) (JSHandle, error) + + // This method waits for an element matching “[object Object]”, waits for [actionability] checks, + // focuses the element, fills it and triggers an `input` event after filling. Note that you can pass an empty string + // to clear the input field. + // If the target element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an + // 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.PressSequentially]. + // + // Deprecated: Use locator-based [Locator.Fill] instead. Read more about [locators]. + // + // 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // 2. value: Value to fill for the `<input>`, `<textarea>` or `[contenteditable]` element. + // + // [actionability]: https://playwright.dev/docs/actionability + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + Fill(selector string, value string, options ...FrameFillOptions) error + + // This method fetches an element with “[object Object]” and focuses it. If there's no element matching + // “[object Object]”, the method waits until a matching element appears in the DOM. + // + // Deprecated: Use locator-based [Locator.Focus] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [locators]: https://playwright.dev/docs/locators + Focus(selector string, options ...FrameFocusOptions) error + + // Returns the `frame` or `iframe` element handle which corresponds to this frame. + // This is an inverse of [ElementHandle.ContentFrame]. Note that returned handle actually belongs to the parent frame. + // This method throws an error if the frame has been detached before `frameElement()` returns. + FrameElement() (ElementHandle, error) + + // When working with iframes, you can create a frame locator that will enter the iframe and allow selecting elements + // in that iframe. + // + // selector: A selector to use when resolving DOM element. + FrameLocator(selector string) FrameLocator + + // Returns element attribute value. + // + // Deprecated: Use locator-based [Locator.GetAttribute] instead. Read more about [locators]. + // + // 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // 2. name: Attribute name to get the value for. + // + // [locators]: https://playwright.dev/docs/locators + GetAttribute(selector string, name string, options ...FrameGetAttributeOptions) (string, error) + + // Allows locating elements by their alt text. + // + // text: Text to locate the element for. + GetByAltText(text interface{}, options ...FrameGetByAltTextOptions) Locator + + // Allows locating input elements by the text of the associated `<label>` or `aria-labelledby` element, or by the + // `aria-label` attribute. + // + // text: Text to locate the element for. + GetByLabel(text interface{}, options ...FrameGetByLabelOptions) Locator + + // Allows locating input elements by the placeholder text. + // + // text: Text to locate the element for. + GetByPlaceholder(text interface{}, options ...FrameGetByPlaceholderOptions) Locator + + // Allows locating elements by their [ARIA role], + // [ARIA attributes] and + // [accessible name]. + // + // # Details + // + // Role selector **does not replace** accessibility audits and conformance tests, but rather gives early feedback + // about the ARIA guidelines. + // Many html elements have an implicitly [defined role] + // that is recognized by the role selector. You can find all the + // [supported roles here]. ARIA guidelines **do not recommend** + // duplicating implicit roles and attributes by setting `role` and/or `aria-*` attributes to default values. + // + // role: Required aria role. + // + // [ARIA role]: https://www.w3.org/TR/wai-aria-1.2/#roles + // [ARIA attributes]: https://www.w3.org/TR/wai-aria-1.2/#aria-attributes + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + // [defined role]: https://w3c.github.io/html-aam/#html-element-role-mappings + // [supported roles here]: https://www.w3.org/TR/wai-aria-1.2/#role_definitions + GetByRole(role AriaRole, options ...FrameGetByRoleOptions) Locator + + // Locate element by the test id. + // + // # Details + // + // By default, the `data-testid` attribute is used as a test id. Use [Selectors.SetTestIdAttribute] to configure a + // different test id attribute if necessary. + // + // testId: Id to locate the element by. + GetByTestId(testId interface{}) Locator + + // Allows locating elements that contain given text. + // See also [Locator.Filter] that allows to match by another criteria, like an accessible role, and then filter by the + // text content. + // + // # Details + // + // Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into + // one, turns line breaks into spaces and ignores leading and trailing whitespace. + // Input elements of the type `button` and `submit` are matched by their `value` instead of the text content. For + // example, locating by text `"Log in"` matches `<input type=button value="Log in">`. + // + // text: Text to locate the element for. + GetByText(text interface{}, options ...FrameGetByTextOptions) Locator + + // Allows locating elements by their title attribute. + // + // text: Text to locate the element for. + GetByTitle(text interface{}, options ...FrameGetByTitleOptions) Locator + + // Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of + // the last redirect. + // The method will throw an error if: + // - there's an SSL error (e.g. in case of self-signed certificates). + // - target URL is invalid. + // - the “[object Object]” is exceeded during navigation. + // - the remote server does not respond or is unreachable. + // - the main resource failed to load. + // The method will not throw an error when any valid HTTP status code is returned by the remote server, including 404 + // "Not Found" and 500 "Internal Server Error". The status code for such responses can be retrieved by calling + // [Response.Status]. + // **NOTE** The method either throws an error or returns a main resource response. The only exceptions are navigation + // to `about:blank` or navigation to the same URL with a different hash, which would succeed and return `null`. + // **NOTE** Headless mode doesn't support navigation to a PDF document. See the + // [upstream issue]. + // + // url: URL to navigate frame to. The url should include scheme, e.g. `https://`. + // + // [upstream issue]: https://bugs.chromium.org/p/chromium/issues/detail?id=761295 + Goto(url string, options ...FrameGotoOptions) (Response, error) + + // This method hovers over an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Mouse] to hover over the center of the element, or the specified “[object Object]”. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Hover] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Hover(selector string, options ...FrameHoverOptions) error + + // Returns `element.innerHTML`. + // + // Deprecated: Use locator-based [Locator.InnerHTML] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [locators]: https://playwright.dev/docs/locators + InnerHTML(selector string, options ...FrameInnerHTMLOptions) (string, error) + + // Returns `element.innerText`. + // + // Deprecated: Use locator-based [Locator.InnerText] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [locators]: https://playwright.dev/docs/locators + InnerText(selector string, options ...FrameInnerTextOptions) (string, error) + + // Returns `input.value` for the selected `<input>` or `<textarea>` or `<select>` element. + // Throws for non-input elements. However, if the element is inside the `<label>` element that has an associated + // [control], returns the value of the + // control. + // + // Deprecated: Use locator-based [Locator.InputValue] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + InputValue(selector string, options ...FrameInputValueOptions) (string, error) + + // Returns whether the element is checked. Throws if the element is not a checkbox or radio input. + // + // Deprecated: Use locator-based [Locator.IsChecked] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [locators]: https://playwright.dev/docs/locators + IsChecked(selector string, options ...FrameIsCheckedOptions) (bool, error) + + // Returns `true` if the frame has been detached, or `false` otherwise. + IsDetached() bool + + // Returns whether the element is disabled, the opposite of [enabled]. + // + // Deprecated: Use locator-based [Locator.IsDisabled] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [enabled]: https://playwright.dev/docs/actionability#enabled + // [locators]: https://playwright.dev/docs/locators + IsDisabled(selector string, options ...FrameIsDisabledOptions) (bool, error) + + // Returns whether the element is [editable]. + // + // Deprecated: Use locator-based [Locator.IsEditable] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [editable]: https://playwright.dev/docs/actionability#editable + // [locators]: https://playwright.dev/docs/locators + IsEditable(selector string, options ...FrameIsEditableOptions) (bool, error) + + // Returns whether the element is [enabled]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [enabled]: https://playwright.dev/docs/actionability#enabled + IsEnabled(selector string, options ...FrameIsEnabledOptions) (bool, error) + + // Returns whether the element is hidden, the opposite of [visible]. “[object Object]” + // that does not match any elements is considered hidden. + // + // Deprecated: Use locator-based [Locator.IsHidden] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [visible]: https://playwright.dev/docs/actionability#visible + // [locators]: https://playwright.dev/docs/locators + IsHidden(selector string, options ...FrameIsHiddenOptions) (bool, error) + + // Returns whether the element is [visible]. “[object Object]” that does not match any + // elements is considered not visible. + // + // Deprecated: Use locator-based [Locator.IsVisible] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [visible]: https://playwright.dev/docs/actionability#visible + // [locators]: https://playwright.dev/docs/locators + IsVisible(selector string, options ...FrameIsVisibleOptions) (bool, error) + + // The method returns an element locator that can be used to perform actions on this page / frame. Locator is resolved + // to the element immediately before performing an action, so a series of actions on the same locator can in fact be + // performed on different DOM elements. That would happen if the DOM structure between those actions has changed. + // [Learn more about locators]. + // [Learn more about locators]. + // + // selector: A selector to use when resolving DOM element. + // + // [Learn more about locators]: https://playwright.dev/docs/locators + // [Learn more about locators]: https://playwright.dev/docs/locators + Locator(selector string, options ...FrameLocatorOptions) Locator + + // Returns frame's name attribute as specified in the tag. + // If the name is empty, returns the id attribute instead. + // **NOTE** This value is calculated once when the frame is created, and will not update if the attribute is changed + // later. + Name() string + + // Returns the page containing this frame. + Page() Page + + // Parent frame, if any. Detached frames and main frames return `null`. + ParentFrame() Frame + + // “[object Object]” can specify the intended + // [keyboardEvent.Key] value or a single character + // to generate the text for. A superset of the “[object Object]” values can be found + // [here]. Examples of the keys are: + // `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, + // `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, + // etc. + // Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`, + // `ControlOrMeta`. `ControlOrMeta` resolves to `Control` on Windows and Linux and to `Meta` on macOS. + // Holding down `Shift` will type the text that corresponds to the “[object Object]” in the upper case. + // If “[object Object]” is a single character, it is case-sensitive, so the values `a` and `A` will generate different + // respective texts. + // Shortcuts such as `key: "Control+o"`, `key: "Control++` or `key: "Control+Shift+T"` are supported as well. When + // specified with the modifier, modifier is pressed and being held while the subsequent key is being pressed. + // + // Deprecated: Use locator-based [Locator.Press] instead. Read more about [locators]. + // + // 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // 2. key: Name of the key to press or a character to generate, such as `ArrowLeft` or `a`. + // + // [keyboardEvent.Key]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key + // [here]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values + // [locators]: https://playwright.dev/docs/locators + Press(selector string, key string, options ...FramePressOptions) error + + // Returns the ElementHandle pointing to the frame element. + // **NOTE** The use of [ElementHandle] is discouraged, use [Locator] objects and web-first assertions instead. + // The method finds an element matching the specified selector within the frame. If no elements match the selector, + // returns `null`. + // + // Deprecated: Use locator-based [Frame.Locator] instead. Read more about [locators]. + // + // selector: A selector to query for. + // + // [locators]: https://playwright.dev/docs/locators + QuerySelector(selector string, options ...FrameQuerySelectorOptions) (ElementHandle, error) + + // Returns the ElementHandles pointing to the frame elements. + // **NOTE** The use of [ElementHandle] is discouraged, use [Locator] objects instead. + // The method finds all elements matching the specified selector within the frame. If no elements match the selector, + // returns empty array. + // + // Deprecated: Use locator-based [Frame.Locator] instead. Read more about [locators]. + // + // selector: A selector to query for. + // + // [locators]: https://playwright.dev/docs/locators + QuerySelectorAll(selector string) ([]ElementHandle, error) + + // This method waits for an element matching “[object Object]”, waits for [actionability] checks, + // waits until all specified options are present in the `<select>` element and selects these options. + // If the target element is not a `<select>` element, this method throws an error. However, if the element is inside + // the `<label>` element that has an associated + // [control], the control will be used + // instead. + // Returns the array of option values that have been successfully selected. + // Triggers a `change` and `input` event once all the provided options have been selected. + // + // Deprecated: Use locator-based [Locator.SelectOption] instead. Read more about [locators]. + // + // selector: A selector to query for. + // + // [actionability]: https://playwright.dev/docs/actionability + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + SelectOption(selector string, values SelectOptionValues, options ...FrameSelectOptionOptions) ([]string, error) + + // This method checks or unchecks an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Ensure that matched element is a checkbox or a radio input. If not, this method throws. + // 3. If the element already has the right checked state, this method returns immediately. + // 4. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 5. Scroll the element into view if needed. + // 6. Use [Page.Mouse] to click in the center of the element. + // 7. Ensure that the element is now checked or unchecked. If not, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.SetChecked] instead. Read more about [locators]. + // + // 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // 2. checked: Whether to check or uncheck the checkbox. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + SetChecked(selector string, checked bool, options ...FrameSetCheckedOptions) error + + // This method internally calls [document.Write()], + // inheriting all its specific characteristics and behaviors. + // + // html: HTML markup to assign to the page. + // + // [document.Write()]: https://developer.mozilla.org/en-US/docs/Web/API/Document/write + SetContent(html string, options ...FrameSetContentOptions) error + + // Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then + // they are resolved relative to the current working directory. For empty array, clears the selected files. + // This method expects “[object Object]” to point to an + // [input element]. However, if the element is inside + // the `<label>` element that has an associated + // [control], targets the control instead. + // + // Deprecated: Use locator-based [Locator.SetInputFiles] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [input element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + SetInputFiles(selector string, files interface{}, options ...FrameSetInputFilesOptions) error + + // This method taps an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Touchscreen] to tap the center of the element, or the specified “[object Object]”. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // **NOTE** `frame.tap()` requires that the `hasTouch` option of the browser context be set to true. + // + // Deprecated: Use locator-based [Locator.Tap] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Tap(selector string, options ...FrameTapOptions) error + + // Returns `element.textContent`. + // + // Deprecated: Use locator-based [Locator.TextContent] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [locators]: https://playwright.dev/docs/locators + TextContent(selector string, options ...FrameTextContentOptions) (string, error) + + // Returns the page title. + Title() (string, error) + + // Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. `frame.type` can be used + // 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: 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. + Type(selector string, text string, options ...FrameTypeOptions) error + + // This method checks an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Ensure that matched element is a checkbox or a radio input. If not, this method throws. If the element is + // already unchecked, this method returns immediately. + // 3. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 4. Scroll the element into view if needed. + // 5. Use [Page.Mouse] to click in the center of the element. + // 6. Ensure that the element is now unchecked. If not, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Uncheck] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Uncheck(selector string, options ...FrameUncheckOptions) error + + // Returns frame's url. + URL() string + + // Returns when the “[object Object]” returns a truthy value, returns that value. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + WaitForFunction(expression string, arg interface{}, options ...FrameWaitForFunctionOptions) (JSHandle, error) + + // Waits for the required load state to be reached. + // This returns when the frame reaches a required load state, `load` by default. The navigation must have been + // committed when this method is called. If current document has already reached the required state, resolves + // immediately. + // **NOTE** Most of the time, this method is not needed because Playwright + // [auto-waits before every action]. + // + // [auto-waits before every action]: https://playwright.dev/docs/actionability + WaitForLoadState(options ...FrameWaitForLoadStateOptions) error + + // Waits for the frame navigation and returns the main resource response. In case of multiple redirects, the + // navigation will resolve with the response of the last redirect. In case of navigation to a different anchor or + // navigation due to History API usage, the navigation will resolve with `null`. + // + // Deprecated: This method is inherently racy, please use [Frame.WaitForURL] instead. + // + // [History API]: https://developer.mozilla.org/en-US/docs/Web/API/History_API + ExpectNavigation(cb func() error, options ...FrameExpectNavigationOptions) (Response, error) + + // Returns when element specified by selector satisfies “[object Object]” option. Returns `null` if waiting for + // `hidden` or `detached`. + // **NOTE** Playwright automatically waits for element to be ready before performing an action. Using [Locator] + // objects and web-first assertions make the code wait-for-selector-free. + // Wait for the “[object Object]” to satisfy “[object Object]” option (either appear/disappear from dom, or become + // visible/hidden). If at the moment of calling the method “[object Object]” already satisfies the condition, the + // method will return immediately. If the selector doesn't satisfy the condition for the “[object Object]” + // milliseconds, the function will throw. + // + // Deprecated: Use web assertions that assert visibility or a locator-based [Locator.WaitFor] instead. Read more about [locators]. + // + // selector: A selector to query for. + // + // [locators]: https://playwright.dev/docs/locators + WaitForSelector(selector string, options ...FrameWaitForSelectorOptions) (ElementHandle, error) + + // Waits for the given “[object Object]” in milliseconds. + // Note that `frame.waitForTimeout()` should only be used for debugging. Tests using the timer in production are going + // to be flaky. Use signals such as network events, selectors becoming visible and others instead. + // + // Deprecated: Never wait for timeout in production. Tests that wait for time are inherently flaky. Use [Locator] actions and web assertions that wait automatically. + // + // timeout: A timeout to wait for + WaitForTimeout(timeout float64) + + // Waits for the frame to navigate to the given URL. + // + // url: A glob pattern, regex pattern or predicate receiving [URL] to match while waiting for the navigation. Note that if + // the parameter is a string without wildcard characters, the method will wait for navigation to URL that is exactly + // equal to the string. + WaitForURL(url interface{}, options ...FrameWaitForURLOptions) error +} + +// FrameLocator represents a view to the `iframe` on the page. It captures the logic sufficient to retrieve the +// `iframe` and locate elements in that iframe. FrameLocator can be created with either [Locator.ContentFrame], +// [Page.FrameLocator] or [Locator.FrameLocator] method. +// **Strictness** +// Frame locators are strict. This means that all operations on frame locators will throw if more than one element +// matches a given selector. +// **Converting Locator to FrameLocator** +// If you have a [Locator] object pointing to an `iframe` it can be converted to [FrameLocator] using +// [Locator.ContentFrame]. +// **Converting FrameLocator to Locator** +// If you have a [FrameLocator] object it can be converted to [Locator] pointing to the same `iframe` using +// [FrameLocator.Owner]. +type FrameLocator interface { + // Returns locator to the first matching frame. + // + // Deprecated: Use [Locator.First] followed by [Locator.ContentFrame] instead. + First() FrameLocator + + // When working with iframes, you can create a frame locator that will enter the iframe and allow selecting elements + // in that iframe. + // + // selector: A selector to use when resolving DOM element. + FrameLocator(selector string) FrameLocator + + // Allows locating elements by their alt text. + // + // text: Text to locate the element for. + GetByAltText(text interface{}, options ...FrameLocatorGetByAltTextOptions) Locator + + // Allows locating input elements by the text of the associated `<label>` or `aria-labelledby` element, or by the + // `aria-label` attribute. + // + // text: Text to locate the element for. + GetByLabel(text interface{}, options ...FrameLocatorGetByLabelOptions) Locator + + // Allows locating input elements by the placeholder text. + // + // text: Text to locate the element for. + GetByPlaceholder(text interface{}, options ...FrameLocatorGetByPlaceholderOptions) Locator + + // Allows locating elements by their [ARIA role], + // [ARIA attributes] and + // [accessible name]. + // + // # Details + // + // Role selector **does not replace** accessibility audits and conformance tests, but rather gives early feedback + // about the ARIA guidelines. + // Many html elements have an implicitly [defined role] + // that is recognized by the role selector. You can find all the + // [supported roles here]. ARIA guidelines **do not recommend** + // duplicating implicit roles and attributes by setting `role` and/or `aria-*` attributes to default values. + // + // role: Required aria role. + // + // [ARIA role]: https://www.w3.org/TR/wai-aria-1.2/#roles + // [ARIA attributes]: https://www.w3.org/TR/wai-aria-1.2/#aria-attributes + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + // [defined role]: https://w3c.github.io/html-aam/#html-element-role-mappings + // [supported roles here]: https://www.w3.org/TR/wai-aria-1.2/#role_definitions + GetByRole(role AriaRole, options ...FrameLocatorGetByRoleOptions) Locator + + // Locate element by the test id. + // + // # Details + // + // By default, the `data-testid` attribute is used as a test id. Use [Selectors.SetTestIdAttribute] to configure a + // different test id attribute if necessary. + // + // testId: Id to locate the element by. + GetByTestId(testId interface{}) Locator + + // Allows locating elements that contain given text. + // See also [Locator.Filter] that allows to match by another criteria, like an accessible role, and then filter by the + // text content. + // + // # Details + // + // Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into + // one, turns line breaks into spaces and ignores leading and trailing whitespace. + // Input elements of the type `button` and `submit` are matched by their `value` instead of the text content. For + // example, locating by text `"Log in"` matches `<input type=button value="Log in">`. + // + // text: Text to locate the element for. + GetByText(text interface{}, options ...FrameLocatorGetByTextOptions) Locator + + // Allows locating elements by their title attribute. + // + // text: Text to locate the element for. + GetByTitle(text interface{}, options ...FrameLocatorGetByTitleOptions) Locator + + // Returns locator to the last matching frame. + // + // Deprecated: Use [Locator.Last] followed by [Locator.ContentFrame] instead. + Last() FrameLocator + + // The method finds an element matching the specified selector in the locator's subtree. It also accepts filter + // options, similar to [Locator.Filter] method. + // [Learn more about locators]. + // + // selectorOrLocator: A selector or locator to use when resolving DOM element. + // + // [Learn more about locators]: https://playwright.dev/docs/locators + Locator(selectorOrLocator interface{}, options ...FrameLocatorLocatorOptions) Locator + + // Returns locator to the n-th matching frame. It's zero based, `nth(0)` selects the first frame. + // + // Deprecated: Use [Locator.Nth] followed by [Locator.ContentFrame] instead. + Nth(index int) FrameLocator + + // Returns a [Locator] object pointing to the same `iframe` as this frame locator. + // Useful when you have a [FrameLocator] object obtained somewhere, and later on would like to interact with the + // `iframe` element. + // For a reverse operation, use [Locator.ContentFrame]. + Owner() Locator +} + +// JSHandle represents an in-page JavaScript object. JSHandles can be created with the [Page.EvaluateHandle] method. +// JSHandle prevents the referenced JavaScript object being garbage collected unless the handle is exposed with +// [JSHandle.Dispose]. JSHandles are auto-disposed when their origin frame gets navigated or the parent context gets +// destroyed. +// JSHandle instances can be used as an argument in [Page.EvalOnSelector], [Page.Evaluate] and [Page.EvaluateHandle] +// methods. +type JSHandle interface { + // Returns either `null` or the object handle itself, if the object handle is an instance of [ElementHandle]. + AsElement() ElementHandle + + // The `jsHandle.dispose` method stops referencing the element handle. + Dispose() error + + // Returns the return value of “[object Object]”. + // This method passes this handle as the first argument to “[object Object]”. + // If “[object Object]” returns a [Promise], then `handle.evaluate` would wait for the promise to resolve and return + // its value. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + Evaluate(expression string, arg ...interface{}) (interface{}, error) + + // Returns the return value of “[object Object]” as a [JSHandle]. + // This method passes this handle as the first argument to “[object Object]”. + // The only difference between `jsHandle.evaluate` and `jsHandle.evaluateHandle` is that `jsHandle.evaluateHandle` + // returns [JSHandle]. + // If the function passed to the `jsHandle.evaluateHandle` returns a [Promise], then `jsHandle.evaluateHandle` would + // wait for the promise to resolve and return its value. + // See [Page.EvaluateHandle] for more details. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + EvaluateHandle(expression string, arg ...interface{}) (JSHandle, error) + + // The method returns a map with **own property names** as keys and JSHandle instances for the property values. + GetProperties() (map[string]JSHandle, error) + + // Fetches a single property from the referenced object. + // + // propertyName: property to get + GetProperty(propertyName string) (JSHandle, error) + + // Returns a JSON representation of the object. If the object has a `toJSON` function, it **will not be called**. + // **NOTE** The method will return an empty JSON object if the referenced object is not stringifiable. It will throw + // an error if the object has circular references. + JSONValue() (interface{}, error) + + String() string +} + +// Keyboard provides an api for managing a virtual keyboard. The high level api is [Keyboard.Type], which takes raw +// characters and generates proper `keydown`, `keypress`/`input`, and `keyup` events on your page. +// For finer control, you can use [Keyboard.Down], [Keyboard.Up], and [Keyboard.InsertText] to manually fire events as +// if they were generated from a real keyboard. +// An example of holding down `Shift` in order to select and delete some text: +// An example of pressing uppercase `A` +// An example to trigger select-all with the keyboard +type Keyboard interface { + // Dispatches a `keydown` event. + // “[object Object]” can specify the intended + // [keyboardEvent.Key] value or a single character + // to generate the text for. A superset of the “[object Object]” values can be found + // [here]. Examples of the keys are: + // `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, + // `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, + // etc. + // Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`, + // `ControlOrMeta`. `ControlOrMeta` resolves to `Control` on Windows and Linux and to `Meta` on macOS. + // Holding down `Shift` will type the text that corresponds to the “[object Object]” in the upper case. + // If “[object Object]” is a single character, it is case-sensitive, so the values `a` and `A` will generate different + // respective texts. + // If “[object Object]” is a modifier key, `Shift`, `Meta`, `Control`, or `Alt`, subsequent key presses will be sent + // with that modifier active. To release the modifier key, use [Keyboard.Up]. + // After the key is pressed once, subsequent calls to [Keyboard.Down] will have + // [repeat] set to true. To release the key, + // use [Keyboard.Up]. + // **NOTE** Modifier keys DO influence `keyboard.down`. Holding down `Shift` will type the text in upper case. + // + // key: Name of the key to press or a character to generate, such as `ArrowLeft` or `a`. + // + // [keyboardEvent.Key]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key + // [here]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values + // [repeat]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat + Down(key string) error + + // Dispatches only `input` event, does not emit the `keydown`, `keyup` or `keypress` events. + // + // text: Sets input to the specified text value. + InsertText(text string) error + + // **NOTE** In most cases, you should use [Locator.Press] instead. + // “[object Object]” can specify the intended + // [keyboardEvent.Key] value or a single character + // to generate the text for. A superset of the “[object Object]” values can be found + // [here]. Examples of the keys are: + // `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, + // `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, + // etc. + // Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`, + // `ControlOrMeta`. `ControlOrMeta` resolves to `Control` on Windows and Linux and to `Meta` on macOS. + // Holding down `Shift` will type the text that corresponds to the “[object Object]” in the upper case. + // If “[object Object]” is a single character, it is case-sensitive, so the values `a` and `A` will generate different + // respective texts. + // Shortcuts such as `key: "Control+o"`, `key: "Control++` or `key: "Control+Shift+T"` are supported as well. When + // specified with the modifier, modifier is pressed and being held while the subsequent key is being pressed. + // + // key: Name of the key to press or a character to generate, such as `ArrowLeft` or `a`. + // + // [keyboardEvent.Key]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key + // [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]. + // + // text: A text to type into a focused element. + Type(text string, options ...KeyboardTypeOptions) error + + // Dispatches a `keyup` event. + // + // key: Name of the key to press or a character to generate, such as `ArrowLeft` or `a`. + Up(key string) error +} + +// Locators are the central piece of Playwright's auto-waiting and retry-ability. In a nutshell, locators represent a +// way to find element(s) on the page at any moment. A locator can be created with the [Page.Locator] method. +// [Learn more about locators]. +// +// [Learn more about locators]: https://playwright.dev/docs/locators +type Locator interface { + // When the locator points to a list of elements, this returns an array of locators, pointing to their respective + // elements. + // **NOTE** [Locator.All] does not wait for elements to match the locator, and instead immediately returns whatever is + // present in the page. + // When the list of elements changes dynamically, [Locator.All] will produce unpredictable and flaky results. + // When the list of elements is stable, but loaded dynamically, wait for the full list to finish loading before + // calling [Locator.All]. + All() ([]Locator, error) + + // Returns an array of `node.innerText` values for all matching nodes. + // **NOTE** If you need to assert text on the page, prefer [LocatorAssertions.ToHaveText] with “[object Object]” + // option to avoid flakiness. See [assertions guide] for more details. + // + // [assertions guide]: https://playwright.dev/docs/test-assertions + AllInnerTexts() ([]string, error) + + // Returns an array of `node.textContent` values for all matching nodes. + // **NOTE** If you need to assert text on the page, prefer [LocatorAssertions.ToHaveText] to avoid flakiness. See + // [assertions guide] for more details. + // + // [assertions guide]: https://playwright.dev/docs/test-assertions + AllTextContents() ([]string, error) + + // Creates a locator that matches both this locator and the argument locator. + // + // locator: Additional locator to match. + And(locator Locator) Locator + + // Captures the aria snapshot of the given element. Read more about [aria snapshots] and + // [LocatorAssertions.ToMatchAriaSnapshot] for the corresponding assertion. + // + // # Details + // + // This method captures the aria snapshot of the given element. The snapshot is a string that represents the state of + // the element and its children. The snapshot can be used to assert the state of the element in the test, or to + // compare it to state in the future. + // The ARIA snapshot is represented using [YAML] markup language: + // - The keys of the objects are the roles and optional accessible names of the elements. + // - The values are either text content or an array of child elements. + // - Generic static text can be represented with the `text` key. + // Below is the HTML markup and the respective ARIA snapshot: + // ```html + // <ul aria-label="Links"> + // <li><a href="/">Home</a></li> + // <li><a href="/about">About</a></li> + // <ul> + // ``` + // ```yml + // - list "Links": + // - listitem: + // - link "Home" + // - listitem: + // - link "About" + // ``` + // + // [aria snapshots]: https://playwright.dev/docs/aria-snapshots + // [YAML]: https://yaml.org/spec/1.2.2/ + AriaSnapshot(options ...LocatorAriaSnapshotOptions) (string, error) + + // Calls [blur] on the element. + // + // [blur]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/blur + Blur(options ...LocatorBlurOptions) error + + // This method returns the bounding box of the element matching the locator, or `null` if the element is not visible. + // The bounding box is calculated relative to the main frame viewport - which is usually the same as the browser + // window. + // + // # Details + // + // Scrolling affects the returned bounding box, similarly to + // [Element.GetBoundingClientRect]. + // That means `x` and/or `y` may be negative. + // Elements from child frames return the bounding box relative to the main frame, unlike the + // [Element.GetBoundingClientRect]. + // Assuming the page is static, it is safe to use bounding box coordinates to perform input. For example, the + // following snippet should click the center of the element. + // + // [Element.GetBoundingClientRect]: https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect + // [Element.GetBoundingClientRect]: https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect + BoundingBox(options ...LocatorBoundingBoxOptions) (*Rect, error) + + // Ensure that checkbox or radio element is checked. + // + // # Details + // + // Performs the following steps: + // 1. Ensure that element is a checkbox or a radio input. If not, this method throws. If the element is already + // checked, this method returns immediately. + // 2. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Mouse] to click in the center of the element. + // 5. Ensure that the element is now checked. If not, this method throws. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // [actionability]: https://playwright.dev/docs/actionability + Check(options ...LocatorCheckOptions) error + + // Clear the input field. + // + // # Details + // + // This method waits for [actionability] checks, focuses the element, clears it and triggers an + // `input` event after clearing. + // If the target element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an + // error. However, if the element is inside the `<label>` element that has an associated + // [control], the control will be cleared + // instead. + // + // [actionability]: https://playwright.dev/docs/actionability + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + Clear(options ...LocatorClearOptions) error + + // Click an element. + // + // # Details + // + // This method clicks the element by performing the following steps: + // 1. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 2. Scroll the element into view if needed. + // 3. Use [Page.Mouse] to click in the center of the element, or the specified “[object Object]”. + // 4. Wait for initiated navigations to either succeed or fail, unless “[object Object]” option is set. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // [actionability]: https://playwright.dev/docs/actionability + Click(options ...LocatorClickOptions) error + + // Returns the number of elements matching the locator. + // **NOTE** If you need to assert the number of elements on the page, prefer [LocatorAssertions.ToHaveCount] to avoid + // flakiness. See [assertions guide] for more details. + // + // [assertions guide]: https://playwright.dev/docs/test-assertions + Count() (int, error) + + // Double-click an element. + // + // # Details + // + // This method double clicks the element by performing the following steps: + // 1. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 2. Scroll the element into view if needed. + // 3. Use [Page.Mouse] to double click in the center of the element, or the specified “[object Object]”. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // **NOTE** `element.dblclick()` dispatches two `click` events and a single `dblclick` event. + // + // [actionability]: https://playwright.dev/docs/actionability + Dblclick(options ...LocatorDblclickOptions) error + + // Programmatically dispatch an event on the matching element. + // + // # Details + // + // The snippet above dispatches the `click` event on the element. Regardless of the visibility state of the element, + // `click` is dispatched. This is equivalent to calling + // [element.Click()]. + // Under the hood, it creates an instance of an event based on the given “[object Object]”, initializes it with + // “[object Object]” properties and dispatches it on the element. Events are `composed`, `cancelable` and bubble by + // default. + // Since “[object Object]” is event-specific, please refer to the events documentation for the lists of initial + // properties: + // - [DeviceMotionEvent] + // - [DeviceOrientationEvent] + // - [DragEvent] + // - [Event] + // - [FocusEvent] + // - [KeyboardEvent] + // - [MouseEvent] + // - [PointerEvent] + // - [TouchEvent] + // - [WheelEvent] + // You can also specify [JSHandle] as the property value if you want live objects to be passed into the event: + // + // 1. typ: DOM event type: `"click"`, `"dragstart"`, etc. + // 2. eventInit: Optional event-specific initialization properties. + // + // [element.Click()]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click + // [DeviceMotionEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent/DeviceMotionEvent + // [DeviceOrientationEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/DeviceOrientationEvent + // [DragEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/DragEvent + // [Event]: https://developer.mozilla.org/en-US/docs/Web/API/Event/Event + // [FocusEvent]: https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/FocusEvent + // [KeyboardEvent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent + // [MouseEvent]: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent + // [PointerEvent]: https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/PointerEvent + // [TouchEvent]: https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent + // [WheelEvent]: https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/WheelEvent + DispatchEvent(typ string, eventInit interface{}, options ...LocatorDispatchEventOptions) error + + // Drag the source element towards the target element and drop it. + // + // # Details + // + // This method drags the locator to another target locator or target position. It will first move to the source + // element, perform a `mousedown`, then move to the target element or position and perform a `mouseup`. + // + // target: Locator of the element to drag to. + DragTo(target Locator, options ...LocatorDragToOptions) error + + // Resolves given locator to the first matching DOM element. If there are no matching elements, waits for one. If + // multiple elements match the locator, throws. + // + // Deprecated: Always prefer using [Locator]s and web assertions over [ElementHandle]s because latter are inherently racy. + ElementHandle(options ...LocatorElementHandleOptions) (ElementHandle, error) + + // Resolves given locator to all matching DOM elements. If there are no matching elements, returns an empty list. + // + // Deprecated: Always prefer using [Locator]s and web assertions over [ElementHandle]s because latter are inherently racy. + ElementHandles() ([]ElementHandle, error) + + // Returns a [FrameLocator] object pointing to the same `iframe` as this locator. + // Useful when you have a [Locator] object obtained somewhere, and later on would like to interact with the content + // inside the frame. + // For a reverse operation, use [FrameLocator.Owner]. + ContentFrame() FrameLocator + + // Execute JavaScript code in the page, taking the matching element as an argument. + // + // # Details + // + // Returns the return value of “[object Object]”, called with the matching element as a first argument, and + // “[object Object]” as a second argument. + // If “[object Object]” returns a [Promise], this method will wait for the promise to resolve and return its value. + // If “[object Object]” throws or rejects, this method throws. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + Evaluate(expression string, arg interface{}, options ...LocatorEvaluateOptions) (interface{}, error) + + // Execute JavaScript code in the page, taking all matching elements as an argument. + // + // # Details + // + // Returns the return value of “[object Object]”, called with an array of all matching elements as a first argument, + // and “[object Object]” as a second argument. + // If “[object Object]” returns a [Promise], this method will wait for the promise to resolve and return its value. + // If “[object Object]” throws or rejects, this method throws. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + EvaluateAll(expression string, arg ...interface{}) (interface{}, error) + + // Execute JavaScript code in the page, taking the matching element as an argument, and return a [JSHandle] with the + // result. + // + // # Details + // + // Returns the return value of “[object Object]” as a[JSHandle], called with the matching element as a first argument, + // and “[object Object]” as a second argument. + // The only difference between [Locator.Evaluate] and [Locator.EvaluateHandle] is that [Locator.EvaluateHandle] + // returns [JSHandle]. + // If “[object Object]” returns a [Promise], this method will wait for the promise to resolve and return its value. + // If “[object Object]” throws or rejects, this method throws. + // See [Page.EvaluateHandle] for more details. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + EvaluateHandle(expression string, arg interface{}, options ...LocatorEvaluateHandleOptions) (JSHandle, error) + + // Set a value to the input field. + // + // # Details + // + // This method waits for [actionability] checks, focuses the element, fills it and triggers an + // `input` event after filling. Note that you can pass an empty string to clear the input field. + // If the target element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an + // 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.PressSequentially]. + // + // value: Value to set for the `<input>`, `<textarea>` or `[contenteditable]` element. + // + // [actionability]: https://playwright.dev/docs/actionability + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + Fill(value string, options ...LocatorFillOptions) error + + // This method narrows existing locator according to the options, for example filters by text. It can be chained to + // filter multiple times. + Filter(options ...LocatorFilterOptions) Locator + + // Returns locator to the first matching element. + First() Locator + + // Calls [focus] on the matching element. + // + // [focus]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus + Focus(options ...LocatorFocusOptions) error + + // When working with iframes, you can create a frame locator that will enter the iframe and allow locating elements in + // that iframe: + // + // selector: A selector to use when resolving DOM element. + FrameLocator(selector string) FrameLocator + + // Returns the matching element's attribute value. + // **NOTE** If you need to assert an element's attribute, prefer [LocatorAssertions.ToHaveAttribute] to avoid + // flakiness. See [assertions guide] for more details. + // + // name: Attribute name to get the value for. + // + // [assertions guide]: https://playwright.dev/docs/test-assertions + GetAttribute(name string, options ...LocatorGetAttributeOptions) (string, error) + + // Allows locating elements by their alt text. + // + // text: Text to locate the element for. + GetByAltText(text interface{}, options ...LocatorGetByAltTextOptions) Locator + + // Allows locating input elements by the text of the associated `<label>` or `aria-labelledby` element, or by the + // `aria-label` attribute. + // + // text: Text to locate the element for. + GetByLabel(text interface{}, options ...LocatorGetByLabelOptions) Locator + + // Allows locating input elements by the placeholder text. + // + // text: Text to locate the element for. + GetByPlaceholder(text interface{}, options ...LocatorGetByPlaceholderOptions) Locator + + // Allows locating elements by their [ARIA role], + // [ARIA attributes] and + // [accessible name]. + // + // # Details + // + // Role selector **does not replace** accessibility audits and conformance tests, but rather gives early feedback + // about the ARIA guidelines. + // Many html elements have an implicitly [defined role] + // that is recognized by the role selector. You can find all the + // [supported roles here]. ARIA guidelines **do not recommend** + // duplicating implicit roles and attributes by setting `role` and/or `aria-*` attributes to default values. + // + // role: Required aria role. + // + // [ARIA role]: https://www.w3.org/TR/wai-aria-1.2/#roles + // [ARIA attributes]: https://www.w3.org/TR/wai-aria-1.2/#aria-attributes + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + // [defined role]: https://w3c.github.io/html-aam/#html-element-role-mappings + // [supported roles here]: https://www.w3.org/TR/wai-aria-1.2/#role_definitions + GetByRole(role AriaRole, options ...LocatorGetByRoleOptions) Locator + + // Locate element by the test id. + // + // # Details + // + // By default, the `data-testid` attribute is used as a test id. Use [Selectors.SetTestIdAttribute] to configure a + // different test id attribute if necessary. + // + // testId: Id to locate the element by. + GetByTestId(testId interface{}) Locator + + // Allows locating elements that contain given text. + // See also [Locator.Filter] that allows to match by another criteria, like an accessible role, and then filter by the + // text content. + // + // # Details + // + // Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into + // one, turns line breaks into spaces and ignores leading and trailing whitespace. + // Input elements of the type `button` and `submit` are matched by their `value` instead of the text content. For + // example, locating by text `"Log in"` matches `<input type=button value="Log in">`. + // + // text: Text to locate the element for. + GetByText(text interface{}, options ...LocatorGetByTextOptions) Locator + + // Allows locating elements by their title attribute. + // + // text: Text to locate the element for. + GetByTitle(text interface{}, options ...LocatorGetByTitleOptions) Locator + + // Highlight the corresponding element(s) on the screen. Useful for debugging, don't commit the code that uses + // [Locator.Highlight]. + Highlight() error + + // Hover over the matching element. + // + // # Details + // + // This method hovers over the element by performing the following steps: + // 1. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 2. Scroll the element into view if needed. + // 3. Use [Page.Mouse] to hover over the center of the element, or the specified “[object Object]”. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // [actionability]: https://playwright.dev/docs/actionability + Hover(options ...LocatorHoverOptions) error + + // Returns the [`element.innerHTML`]. + // + // [`element.innerHTML`]: https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML + InnerHTML(options ...LocatorInnerHTMLOptions) (string, error) + + // Returns the [`element.innerText`]. + // **NOTE** If you need to assert text on the page, prefer [LocatorAssertions.ToHaveText] with “[object Object]” + // option to avoid flakiness. See [assertions guide] for more details. + // + // [`element.innerText`]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText + // [assertions guide]: https://playwright.dev/docs/test-assertions + InnerText(options ...LocatorInnerTextOptions) (string, error) + + // Returns the value for the matching `<input>` or `<textarea>` or `<select>` element. + // **NOTE** If you need to assert input value, prefer [LocatorAssertions.ToHaveValue] to avoid flakiness. See + // [assertions guide] for more details. + // + // # Details + // + // Throws elements that are not an input, textarea or a select. However, if the element is inside the `<label>` + // element that has an associated + // [control], returns the value of the + // control. + // + // [assertions guide]: https://playwright.dev/docs/test-assertions + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + InputValue(options ...LocatorInputValueOptions) (string, error) + + // Returns whether the element is checked. Throws if the element is not a checkbox or radio input. + // **NOTE** If you need to assert that checkbox is checked, prefer [LocatorAssertions.ToBeChecked] to avoid flakiness. + // See [assertions guide] for more details. + // + // [assertions guide]: https://playwright.dev/docs/test-assertions + IsChecked(options ...LocatorIsCheckedOptions) (bool, error) + + // Returns whether the element is disabled, the opposite of [enabled]. + // **NOTE** If you need to assert that an element is disabled, prefer [LocatorAssertions.ToBeDisabled] to avoid + // flakiness. See [assertions guide] for more details. + // + // [enabled]: https://playwright.dev/docs/actionability#enabled + // [assertions guide]: https://playwright.dev/docs/test-assertions + IsDisabled(options ...LocatorIsDisabledOptions) (bool, error) + + // Returns whether the element is [editable]. If the target element is not an `<input>`, + // `<textarea>`, `<select>`, `[contenteditable]` and does not have a role allowing `[aria-readonly]`, this method + // throws an error. + // **NOTE** If you need to assert that an element is editable, prefer [LocatorAssertions.ToBeEditable] to avoid + // flakiness. See [assertions guide] for more details. + // + // [editable]: https://playwright.dev/docs/actionability#editable + // [assertions guide]: https://playwright.dev/docs/test-assertions + IsEditable(options ...LocatorIsEditableOptions) (bool, error) + + // Returns whether the element is [enabled]. + // **NOTE** If you need to assert that an element is enabled, prefer [LocatorAssertions.ToBeEnabled] to avoid + // flakiness. See [assertions guide] for more details. + // + // [enabled]: https://playwright.dev/docs/actionability#enabled + // [assertions guide]: https://playwright.dev/docs/test-assertions + IsEnabled(options ...LocatorIsEnabledOptions) (bool, error) + + // Returns whether the element is hidden, the opposite of [visible]. + // **NOTE** If you need to assert that element is hidden, prefer [LocatorAssertions.ToBeHidden] to avoid flakiness. + // See [assertions guide] for more details. + // + // [visible]: https://playwright.dev/docs/actionability#visible + // [assertions guide]: https://playwright.dev/docs/test-assertions + IsHidden(options ...LocatorIsHiddenOptions) (bool, error) + + // Returns whether the element is [visible]. + // **NOTE** If you need to assert that element is visible, prefer [LocatorAssertions.ToBeVisible] to avoid flakiness. + // See [assertions guide] for more details. + // + // [visible]: https://playwright.dev/docs/actionability#visible + // [assertions guide]: https://playwright.dev/docs/test-assertions + IsVisible(options ...LocatorIsVisibleOptions) (bool, error) + + // Returns locator to the last matching element. + Last() Locator + + // The method finds an element matching the specified selector in the locator's subtree. It also accepts filter + // options, similar to [Locator.Filter] method. + // [Learn more about locators]. + // + // selectorOrLocator: A selector or locator to use when resolving DOM element. + // + // [Learn more about locators]: https://playwright.dev/docs/locators + Locator(selectorOrLocator interface{}, options ...LocatorLocatorOptions) Locator + + // Returns locator to the n-th matching element. It's zero based, `nth(0)` selects the first element. + Nth(index int) Locator + + // Creates a locator matching all elements that match one or both of the two locators. + // Note that when both locators match something, the resulting locator will have multiple matches, potentially causing + // a [locator strictness] violation. + // + // locator: Alternative locator to match. + // + // [locator strictness]: https://playwright.dev/docs/locators#strictness + // ["strict mode violation" error]: https://playwright.dev/docs/locators#strictness + Or(locator Locator) Locator + + // A page this locator belongs to. + Page() (Page, error) + + // Focuses the matching element and presses a combination of the keys. + // + // # Details + // + // Focuses the element, and then uses [Keyboard.Down] and [Keyboard.Up]. + // “[object Object]” can specify the intended + // [keyboardEvent.Key] value or a single character + // to generate the text for. A superset of the “[object Object]” values can be found + // [here]. Examples of the keys are: + // `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, + // `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, + // etc. + // Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`, + // `ControlOrMeta`. `ControlOrMeta` resolves to `Control` on Windows and Linux and to `Meta` on macOS. + // Holding down `Shift` will type the text that corresponds to the “[object Object]” in the upper case. + // If “[object Object]” is a single character, it is case-sensitive, so the values `a` and `A` will generate different + // respective texts. + // Shortcuts such as `key: "Control+o"`, `key: "Control++` or `key: "Control+Shift+T"` are supported as well. When + // specified with the modifier, modifier is pressed and being held while the subsequent key is being pressed. + // + // key: Name of the key to press or a character to generate, such as `ArrowLeft` or `a`. + // + // [keyboardEvent.Key]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key + // [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 + // + // This method captures a screenshot of the page, clipped to the size and position of a particular element matching + // the locator. If the element is covered by other elements, it will not be actually visible on the screenshot. If the + // element is a scrollable container, only the currently scrolled content will be visible on the screenshot. + // This method waits for the [actionability] checks, then scrolls element into view before taking + // a screenshot. If the element is detached from DOM, the method throws an error. + // Returns the buffer with the captured screenshot. + // + // [actionability]: https://playwright.dev/docs/actionability + Screenshot(options ...LocatorScreenshotOptions) ([]byte, error) + + // This method waits for [actionability] checks, then tries to scroll element into view, unless + // it is completely visible as defined by + // [IntersectionObserver]'s `ratio`. + // See [scrolling] for alternative ways to scroll. + // + // [actionability]: https://playwright.dev/docs/actionability + // [IntersectionObserver]: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API + // [scrolling]: https://playwright.dev/docs/input#scrolling + ScrollIntoViewIfNeeded(options ...LocatorScrollIntoViewIfNeededOptions) error + + // Selects option or options in `<select>`. + // + // # Details + // + // This method waits for [actionability] checks, waits until all specified options are present in + // the `<select>` element and selects these options. + // If the target element is not a `<select>` element, this method throws an error. However, if the element is inside + // the `<label>` element that has an associated + // [control], the control will be used + // instead. + // Returns the array of option values that have been successfully selected. + // Triggers a `change` and `input` event once all the provided options have been selected. + // + // [actionability]: https://playwright.dev/docs/actionability + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + SelectOption(values SelectOptionValues, options ...LocatorSelectOptionOptions) ([]string, error) + + // This method waits for [actionability] checks, then focuses the element and selects all its + // text content. + // If the element is inside the `<label>` element that has an associated + // [control], focuses and selects text in + // the control instead. + // + // [actionability]: https://playwright.dev/docs/actionability + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + SelectText(options ...LocatorSelectTextOptions) error + + // Set the state of a checkbox or a radio element. + // + // # Details + // + // This method checks or unchecks an element by performing the following steps: + // 1. Ensure that matched element is a checkbox or a radio input. If not, this method throws. + // 2. If the element already has the right checked state, this method returns immediately. + // 3. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 4. Scroll the element into view if needed. + // 5. Use [Page.Mouse] to click in the center of the element. + // 6. Ensure that the element is now checked or unchecked. If not, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // checked: Whether to check or uncheck the checkbox. + // + // [actionability]: https://playwright.dev/docs/actionability + SetChecked(checked bool, options ...LocatorSetCheckedOptions) error + + // Upload file or multiple files into `<input type=file>`. For inputs with a `[webkitdirectory]` attribute, only a + // single directory path is supported. + // + // # Details + // + // Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then + // they are resolved relative to the current working directory. For empty array, clears the selected files. + // This method expects [Locator] to point to an + // [input element]. However, if the element is inside + // the `<label>` element that has an associated + // [control], targets the control instead. + // + // [input element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + SetInputFiles(files interface{}, options ...LocatorSetInputFilesOptions) error + + // Perform a tap gesture on the element matching the locator. For examples of emulating other gestures by manually + // dispatching touch events, see the [emulating legacy touch events] page. + // + // # Details + // + // This method taps the element by performing the following steps: + // 1. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 2. Scroll the element into view if needed. + // 3. Use [Page.Touchscreen] to tap the center of the element, or the specified “[object Object]”. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // **NOTE** `element.tap()` requires that the `hasTouch` option of the browser context be set to true. + // + // [emulating legacy touch events]: https://playwright.dev/docs/touch-events + // [actionability]: https://playwright.dev/docs/actionability + Tap(options ...LocatorTapOptions) error + + // Returns the [`node.textContent`]. + // **NOTE** If you need to assert text on the page, prefer [LocatorAssertions.ToHaveText] to avoid flakiness. See + // [assertions guide] for more details. + // + // [`node.textContent`]: https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent + // [assertions guide]: https://playwright.dev/docs/test-assertions + TextContent(options ...LocatorTextContentOptions) (string, error) + + // 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 + + // Ensure that checkbox or radio element is unchecked. + // + // # Details + // + // This method unchecks the element by performing the following steps: + // 1. Ensure that element is a checkbox or a radio input. If not, this method throws. If the element is already + // unchecked, this method returns immediately. + // 2. Wait for [actionability] checks on the element, unless “[object Object]” option is set. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Mouse] to click in the center of the element. + // 5. Ensure that the element is now unchecked. If not, this method throws. + // If the element is detached from the DOM at any moment during the action, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // [actionability]: https://playwright.dev/docs/actionability + Uncheck(options ...LocatorUncheckOptions) error + + // Returns when element specified by locator satisfies the “[object Object]” option. + // If target element already satisfies the condition, the method returns immediately. Otherwise, waits for up to + // “[object Object]” milliseconds until the condition is met. + WaitFor(options ...LocatorWaitForOptions) error + + Err() error +} + +// The [LocatorAssertions] class provides assertion methods that can be used to make assertions about the [Locator] +// state in the tests. +type LocatorAssertions interface { + // Makes the assertion check for the opposite condition. For example, this code tests that the Locator doesn't contain + // text `"error"`: + Not() LocatorAssertions + + // Ensures that [Locator] points to an element that is + // [connected] to a Document or a ShadowRoot. + // + // [connected]: https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected + ToBeAttached(options ...LocatorAssertionsToBeAttachedOptions) error + + // Ensures the [Locator] points to a checked input. + ToBeChecked(options ...LocatorAssertionsToBeCheckedOptions) error + + // Ensures the [Locator] points to a disabled element. Element is disabled if it has "disabled" attribute or is + // disabled via + // ['aria-disabled']. Note + // that only native control elements such as HTML `button`, `input`, `select`, `textarea`, `option`, `optgroup` can be + // disabled by setting "disabled" attribute. "disabled" attribute on other elements is ignored by the browser. + // + // ['aria-disabled']: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-disabled + ToBeDisabled(options ...LocatorAssertionsToBeDisabledOptions) error + + // Ensures the [Locator] points to an editable element. + ToBeEditable(options ...LocatorAssertionsToBeEditableOptions) error + + // Ensures the [Locator] points to an empty editable element or to a DOM node that has no text. + ToBeEmpty(options ...LocatorAssertionsToBeEmptyOptions) error + + // Ensures the [Locator] points to an enabled element. + ToBeEnabled(options ...LocatorAssertionsToBeEnabledOptions) error + + // Ensures the [Locator] points to a focused DOM node. + ToBeFocused(options ...LocatorAssertionsToBeFocusedOptions) error + + // Ensures that [Locator] either does not resolve to any DOM node, or resolves to a + // [non-visible] one. + // + // [non-visible]: https://playwright.dev/docs/actionability#visible + ToBeHidden(options ...LocatorAssertionsToBeHiddenOptions) error + + // Ensures the [Locator] points to an element that intersects viewport, according to the + // [intersection observer API]. + // + // [intersection observer API]: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API + ToBeInViewport(options ...LocatorAssertionsToBeInViewportOptions) error + + // Ensures that [Locator] points to an attached and [visible] DOM node. + // To check that at least one element from the list is visible, use [Locator.First]. + // + // [visible]: https://playwright.dev/docs/actionability#visible + ToBeVisible(options ...LocatorAssertionsToBeVisibleOptions) error + + // Ensures the [Locator] points to an element with given CSS classes. All classes from the asserted value, separated + // by spaces, must be present in the + // [Element.ClassList] in any order. + // + // expected: A string containing expected class names, separated by spaces, or a list of such strings to assert multiple + // elements. + // + // [Element.ClassList]: https://developer.mozilla.org/en-US/docs/Web/API/Element/classList + ToContainClass(expected interface{}, options ...LocatorAssertionsToContainClassOptions) error + + // Ensures the [Locator] points to an element that contains the given text. All nested elements will be considered + // when computing the text content of the element. You can use regular expressions for the value as well. + // + // # Details + // + // When `expected` parameter is a string, Playwright will normalize whitespaces and line breaks both in the actual + // text and in the expected string before matching. When regular expression is used, the actual text is matched as is. + // + // expected: Expected substring or RegExp or a list of those. + ToContainText(expected interface{}, options ...LocatorAssertionsToContainTextOptions) error + + // Ensures the [Locator] points to an element with a given + // [accessible description]. + // + // description: Expected accessible description. + // + // [accessible description]: https://w3c.github.io/accname/#dfn-accessible-description + ToHaveAccessibleDescription(description interface{}, options ...LocatorAssertionsToHaveAccessibleDescriptionOptions) error + + // Ensures the [Locator] points to an element with a given + // [aria errormessage]. + // + // errorMessage: Expected accessible error message. + // + // [aria errormessage]: https://w3c.github.io/aria/#aria-errormessage + ToHaveAccessibleErrorMessage(errorMessage interface{}, options ...LocatorAssertionsToHaveAccessibleErrorMessageOptions) error + + // Ensures the [Locator] points to an element with a given + // [accessible name]. + // + // name: Expected accessible name. + // + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + ToHaveAccessibleName(name interface{}, options ...LocatorAssertionsToHaveAccessibleNameOptions) error + + // Ensures the [Locator] points to an element with given attribute. + // + // 1. name: Attribute name. + // 2. value: Expected attribute value. + ToHaveAttribute(name string, value interface{}, options ...LocatorAssertionsToHaveAttributeOptions) error + + // Ensures the [Locator] points to an element with given CSS classes. When a string is provided, it must fully match + // the element's `class` attribute. To match individual classes use [LocatorAssertions.ToContainClass]. + // + // expected: Expected class or RegExp or a list of those. + ToHaveClass(expected interface{}, options ...LocatorAssertionsToHaveClassOptions) error + + // Ensures the [Locator] resolves to an exact number of DOM nodes. + // + // count: Expected count. + ToHaveCount(count int, options ...LocatorAssertionsToHaveCountOptions) error + + // Ensures the [Locator] resolves to an element with the given computed CSS style. + // + // 1. name: CSS property name. + // 2. value: CSS property value. + ToHaveCSS(name string, value interface{}, options ...LocatorAssertionsToHaveCSSOptions) error + + // Ensures the [Locator] points to an element with the given DOM Node ID. + // + // id: Element id. + ToHaveId(id interface{}, options ...LocatorAssertionsToHaveIdOptions) error + + // Ensures the [Locator] points to an element with given JavaScript property. Note that this property can be of a + // primitive type as well as a plain serializable JavaScript object. + // + // 1. name: Property name. + // 2. value: Property value. + ToHaveJSProperty(name string, value interface{}, options ...LocatorAssertionsToHaveJSPropertyOptions) error + + // Ensures the [Locator] points to an element with a given [ARIA role]. + // Note that role is matched as a string, disregarding the ARIA role hierarchy. For example, asserting a superclass + // role `"checkbox"` on an element with a subclass role `"switch"` will fail. + // + // role: Required aria role. + // + // [ARIA role]: https://www.w3.org/TR/wai-aria-1.2/#roles + ToHaveRole(role AriaRole, options ...LocatorAssertionsToHaveRoleOptions) error + + // Ensures the [Locator] points to an element with the given text. All nested elements will be considered when + // computing the text content of the element. You can use regular expressions for the value as well. + // + // # Details + // + // When `expected` parameter is a string, Playwright will normalize whitespaces and line breaks both in the actual + // text and in the expected string before matching. When regular expression is used, the actual text is matched as is. + // + // expected: Expected string or RegExp or a list of those. + ToHaveText(expected interface{}, options ...LocatorAssertionsToHaveTextOptions) error + + // Ensures the [Locator] points to an element with the given input value. You can use regular expressions for the + // value as well. + // + // value: Expected value. + ToHaveValue(value interface{}, options ...LocatorAssertionsToHaveValueOptions) error + + // Ensures the [Locator] points to multi-select/combobox (i.e. a `select` with the `multiple` attribute) and the + // specified values are selected. + // + // values: Expected options currently selected. + ToHaveValues(values []interface{}, options ...LocatorAssertionsToHaveValuesOptions) error + + // Asserts that the target element matches the given [accessibility snapshot]. + // + // [accessibility snapshot]: https://playwright.dev/docs/aria-snapshots + ToMatchAriaSnapshot(expected string, options ...LocatorAssertionsToMatchAriaSnapshotOptions) error +} + +// The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport. +// Every `page` object has its own Mouse, accessible with [Page.Mouse]. +type Mouse interface { + // Shortcut for [Mouse.Move], [Mouse.Down], [Mouse.Up]. + // + // 1. x: X coordinate relative to the main frame's viewport in CSS pixels. + // 2. y: Y coordinate relative to the main frame's viewport in CSS pixels. + Click(x float64, y float64, options ...MouseClickOptions) error + + // Shortcut for [Mouse.Move], [Mouse.Down], [Mouse.Up], [Mouse.Down] and [Mouse.Up]. + // + // 1. x: X coordinate relative to the main frame's viewport in CSS pixels. + // 2. y: Y coordinate relative to the main frame's viewport in CSS pixels. + Dblclick(x float64, y float64, options ...MouseDblclickOptions) error + + // Dispatches a `mousedown` event. + Down(options ...MouseDownOptions) error + + // Dispatches a `mousemove` event. + // + // 1. x: X coordinate relative to the main frame's viewport in CSS pixels. + // 2. y: Y coordinate relative to the main frame's viewport in CSS pixels. + Move(x float64, y float64, options ...MouseMoveOptions) error + + // Dispatches a `mouseup` event. + Up(options ...MouseUpOptions) error + + // Dispatches a `wheel` event. This method is usually used to manually scroll the page. See + // [scrolling] for alternative ways to scroll. + // **NOTE** Wheel events may cause scrolling if they are not handled, and this method does not wait for the scrolling + // to finish before returning. + // + // 1. deltaX: Pixels to scroll horizontally. + // 2. deltaY: Pixels to scroll vertically. + // + // [scrolling]: https://playwright.dev/docs/input#scrolling + Wheel(deltaX float64, deltaY float64) error +} + +// Page provides methods to interact with a single tab in a [Browser], or an +// [extension background page] in Chromium. One [Browser] +// instance might have multiple [Page] instances. +// This example creates a page, navigates it to a URL, and then saves a screenshot: +// The Page class emits various events (described below) which can be handled using any of Node's native +// [`EventEmitter`] methods, such as `on`, `once` or +// `removeListener`. +// This example logs a message for a single page `load` event: +// To unsubscribe from events use the `removeListener` method: +// +// [extension background page]: https://developer.chrome.com/extensions/background_pages +// [`EventEmitter`]: https://nodejs.org/api/events.html#events_class_eventemitter +type Page interface { + EventEmitter + // Playwright has ability to mock clock and passage of time. + Clock() Clock + + // Emitted when the page closes. + OnClose(fn func(Page)) + + // Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. + // The arguments passed into `console.log` are available on the [ConsoleMessage] event handler argument. + OnConsole(fn func(ConsoleMessage)) + + // Emitted when the page crashes. Browser pages might crash if they try to allocate too much memory. When the page + // crashes, ongoing and subsequent operations will throw. + // The most common way to deal with crashes is to catch an exception: + OnCrash(fn func(Page)) + + // Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, `confirm` or `beforeunload`. Listener **must** + // either [Dialog.Accept] or [Dialog.Dismiss] the dialog - otherwise the page will + // [freeze] waiting for the dialog, + // and actions like click will never finish. + // + // [freeze]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking + OnDialog(fn func(Dialog)) + + // Emitted when the JavaScript + // [`DOMContentLoaded`] event is dispatched. + // + // [`DOMContentLoaded`]: https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded + OnDOMContentLoaded(fn func(Page)) + + // Emitted when attachment download started. User can access basic file operations on downloaded content via the + // passed [Download] instance. + OnDownload(fn func(Download)) + + // Emitted when a file chooser is supposed to appear, such as after clicking the `<input type=file>`. Playwright can + // respond to it via setting the input files using [FileChooser.SetFiles] that can be uploaded after that. + OnFileChooser(fn func(FileChooser)) + + // Emitted when a frame is attached. + OnFrameAttached(fn func(Frame)) + + // Emitted when a frame is detached. + OnFrameDetached(fn func(Frame)) + + // Emitted when a frame is navigated to a new url. + OnFrameNavigated(fn func(Frame)) + + // Emitted when the JavaScript [`load`] event is dispatched. + // + // [`load`]: https://developer.mozilla.org/en-US/docs/Web/Events/load + OnLoad(fn func(Page)) + + // Emitted when an uncaught exception happens within the page. + OnPageError(fn func(error)) + + // Emitted when the page opens a new tab or window. This event is emitted in addition to the [BrowserContext.OnPage], + // but only for popups relevant to this page. + // The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a + // popup with `window.open('http://example.com')`, this event will fire when the network request to + // "http://example.com" is done and its response has started loading in the popup. If you would like to route/listen + // to this network request, use [BrowserContext.Route] and [BrowserContext.OnRequest] respectively instead of similar + // methods on the [Page]. + // **NOTE** Use [Page.WaitForLoadState] to wait until the page gets to a particular state (you should not need it in + // most cases). + OnPopup(fn func(Page)) + + // Emitted when a page issues a request. The [request] object is read-only. In order to intercept and mutate requests, + // see [Page.Route] or [BrowserContext.Route]. + OnRequest(fn func(Request)) + + // Emitted when a request fails, for example by timing out. + // **NOTE** HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request + // will complete with [Page.OnRequestFinished] event and not with [Page.OnRequestFailed]. A request will only be + // considered failed when the client cannot get an HTTP response from the server, e.g. due to network error + // net::ERR_FAILED. + OnRequestFailed(fn func(Request)) + + // Emitted when a request finishes successfully after downloading the response body. For a successful response, the + // sequence of events is `request`, `response` and `requestfinished`. + OnRequestFinished(fn func(Request)) + + // Emitted when [response] status and headers are received for a request. For a successful response, the sequence of + // events is `request`, `response` and `requestfinished`. + OnResponse(fn func(Response)) + + // Emitted when [WebSocket] request is sent. + OnWebSocket(fn func(WebSocket)) + + // Emitted when a dedicated [WebWorker] is spawned + // by the page. + // + // [WebWorker]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API + OnWorker(fn func(Worker)) + + // Adds a script which would be evaluated in one of the following scenarios: + // - Whenever the page is navigated. + // - Whenever the child frame is attached or navigated. In this case, the script is evaluated in the context of the + // newly attached frame. + // The script is evaluated after the document was created but before any of its scripts were run. This is useful to + // amend the JavaScript environment, e.g. to seed `Math.random`. + // + // script: Script to be evaluated in the page. + AddInitScript(script Script) error + + // Adds a `<script>` tag into the page with the desired url or content. Returns the added tag when the script's onload + // fires or when the script content was injected into frame. + AddScriptTag(options PageAddScriptTagOptions) (ElementHandle, error) + + // Adds a `<link rel="stylesheet">` tag into the page with the desired url or a `<style type="text/css">` tag with the + // content. Returns the added tag when the stylesheet's onload fires or when the CSS content was injected into frame. + AddStyleTag(options PageAddStyleTagOptions) (ElementHandle, error) + + // Brings page to front (activates tab). + BringToFront() error + + // This method checks an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Ensure that matched element is a checkbox or a radio input. If not, this method throws. If the element is + // already checked, this method returns immediately. + // 3. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 4. Scroll the element into view if needed. + // 5. Use [Page.Mouse] to click in the center of the element. + // 6. Ensure that the element is now checked. If not, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Check] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Check(selector string, options ...PageCheckOptions) error + + // This method clicks an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Mouse] to click in the center of the element, or the specified “[object Object]”. + // 5. Wait for initiated navigations to either succeed or fail, unless “[object Object]” option is set. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Click] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Click(selector string, options ...PageClickOptions) error + + // If “[object Object]” is `false`, does not run any unload handlers and waits for the page to be closed. If + // “[object Object]” is `true` the method will run unload handlers, but will **not** wait for the page to close. + // By default, `page.close()` **does not** run `beforeunload` handlers. + // **NOTE** if “[object Object]” is passed as true, a `beforeunload` dialog might be summoned and should be handled + // manually via [Page.OnDialog] event. + Close(options ...PageCloseOptions) error + + // Gets the full HTML contents of the page, including the doctype. + Content() (string, error) + + // Get the browser context that the page belongs to. + Context() BrowserContext + + // This method double clicks an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Mouse] to double click in the center of the element, or the specified “[object Object]”. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // **NOTE** `page.dblclick()` dispatches two `click` events and a single `dblclick` event. + // + // Deprecated: Use locator-based [Locator.Dblclick] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Dblclick(selector string, options ...PageDblclickOptions) error + + // The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the element, + // `click` is dispatched. This is equivalent to calling + // [element.Click()]. + // + // Deprecated: Use locator-based [Locator.DispatchEvent] instead. Read more about [locators]. + // + // 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // 2. typ: DOM event type: `"click"`, `"dragstart"`, etc. + // 3. eventInit: Optional event-specific initialization properties. + // + // [element.Click()]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click + // [DeviceMotionEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent/DeviceMotionEvent + // [DeviceOrientationEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/DeviceOrientationEvent + // [DragEvent]: https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/DragEvent + // [Event]: https://developer.mozilla.org/en-US/docs/Web/API/Event/Event + // [FocusEvent]: https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/FocusEvent + // [KeyboardEvent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent + // [MouseEvent]: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent + // [PointerEvent]: https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/PointerEvent + // [TouchEvent]: https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent + // [WheelEvent]: https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/WheelEvent + // [locators]: https://playwright.dev/docs/locators + DispatchEvent(selector string, typ string, eventInit interface{}, options ...PageDispatchEventOptions) error + + // This method drags the source element to the target element. It will first move to the source element, perform a + // `mousedown`, then move to the target element and perform a `mouseup`. + // + // 1. source: A selector to search for an element to drag. If there are multiple elements satisfying the selector, the first will + // be used. + // 2. target: A selector to search for an element to drop onto. If there are multiple elements satisfying the selector, the first + // will be used. + DragAndDrop(source string, target string, options ...PageDragAndDropOptions) error + + // This method changes the `CSS media type` through the `media` argument, and/or the `prefers-colors-scheme` media + // feature, using the `colorScheme` argument. + EmulateMedia(options ...PageEmulateMediaOptions) error + + // The method finds an element matching the specified selector within the page and passes it as a first argument to + // “[object Object]”. If no elements match the selector, the method throws an error. Returns the value of + // “[object Object]”. + // If “[object Object]” returns a [Promise], then [Page.EvalOnSelector] would wait for the promise to resolve and + // return its value. + // + // Deprecated: This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests. Use [Locator.Evaluate], other [Locator] helper methods or web-first assertions instead. + // + // 1. selector: A selector to query for. + // 2. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 3. arg: Optional argument to pass to “[object Object]”. + EvalOnSelector(selector string, expression string, arg interface{}, options ...PageEvalOnSelectorOptions) (interface{}, error) + + // The method finds all elements matching the specified selector within the page and passes an array of matched + // elements as a first argument to “[object Object]”. Returns the result of “[object Object]” invocation. + // If “[object Object]” returns a [Promise], then [Page.EvalOnSelectorAll] would wait for the promise to resolve and + // return its value. + // + // Deprecated: In most cases, [Locator.EvaluateAll], other [Locator] helper methods and web-first assertions do a better job. + // + // 1. selector: A selector to query for. + // 2. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 3. arg: Optional argument to pass to “[object Object]”. + EvalOnSelectorAll(selector string, expression string, arg ...interface{}) (interface{}, error) + + // Returns the value of the “[object Object]” invocation. + // If the function passed to the [Page.Evaluate] returns a [Promise], then [Page.Evaluate] would wait for the promise + // to resolve and return its value. + // If the function passed to the [Page.Evaluate] returns a non-[Serializable] value, then [Page.Evaluate] resolves to + // `undefined`. Playwright also supports transferring some additional values that are not serializable by `JSON`: + // `-0`, `NaN`, `Infinity`, `-Infinity`. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + Evaluate(expression string, arg ...interface{}) (interface{}, error) + + // Returns the value of the “[object Object]” invocation as a [JSHandle]. + // The only difference between [Page.Evaluate] and [Page.EvaluateHandle] is that [Page.EvaluateHandle] returns + // [JSHandle]. + // If the function passed to the [Page.EvaluateHandle] returns a [Promise], then [Page.EvaluateHandle] would wait for + // the promise to resolve and return its value. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + EvaluateHandle(expression string, arg ...interface{}) (JSHandle, error) + + // The method adds a function called “[object Object]” on the `window` object of every frame in this page. When + // called, the function executes “[object Object]” and returns a [Promise] which resolves to the return value of + // “[object Object]”. If the “[object Object]” returns a [Promise], it will be awaited. + // The first argument of the “[object Object]” function contains information about the caller: `{ browserContext: + // BrowserContext, page: Page, frame: Frame }`. + // See [BrowserContext.ExposeBinding] for the context-wide version. + // **NOTE** Functions installed via [Page.ExposeBinding] survive navigations. + // + // 1. name: Name of the function on the window object. + // 2. binding: Callback function that will be called in the Playwright's context. + ExposeBinding(name string, binding BindingCallFunction, handle ...bool) error + + // The method adds a function called “[object Object]” on the `window` object of every frame in the page. When called, + // the function executes “[object Object]” and returns a [Promise] which resolves to the return value of + // “[object Object]”. + // If the “[object Object]” returns a [Promise], it will be awaited. + // See [BrowserContext.ExposeFunction] for context-wide exposed function. + // **NOTE** Functions installed via [Page.ExposeFunction] survive navigations. + // + // 1. name: Name of the function on the window object + // 2. binding: Callback function which will be called in Playwright's context. + ExposeFunction(name string, binding ExposedFunction) error + + // This method waits for an element matching “[object Object]”, waits for [actionability] checks, + // focuses the element, fills it and triggers an `input` event after filling. Note that you can pass an empty string + // to clear the input field. + // If the target element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an + // 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.PressSequentially]. + // + // Deprecated: Use locator-based [Locator.Fill] instead. Read more about [locators]. + // + // 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // 2. value: Value to fill for the `<input>`, `<textarea>` or `[contenteditable]` element. + // + // [actionability]: https://playwright.dev/docs/actionability + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + Fill(selector string, value string, options ...PageFillOptions) error + + // This method fetches an element with “[object Object]” and focuses it. If there's no element matching + // “[object Object]”, the method waits until a matching element appears in the DOM. + // + // Deprecated: Use locator-based [Locator.Focus] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [locators]: https://playwright.dev/docs/locators + Focus(selector string, options ...PageFocusOptions) error + + // Returns frame matching the specified criteria. Either `name` or `url` must be specified. + Frame(options ...PageFrameOptions) Frame + + // When working with iframes, you can create a frame locator that will enter the iframe and allow selecting elements + // in that iframe. + // + // selector: A selector to use when resolving DOM element. + FrameLocator(selector string) FrameLocator + + // An array of all frames attached to the page. + Frames() []Frame + + // Returns element attribute value. + // + // Deprecated: Use locator-based [Locator.GetAttribute] instead. Read more about [locators]. + // + // 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // 2. name: Attribute name to get the value for. + // + // [locators]: https://playwright.dev/docs/locators + GetAttribute(selector string, name string, options ...PageGetAttributeOptions) (string, error) + + // Allows locating elements by their alt text. + // + // text: Text to locate the element for. + GetByAltText(text interface{}, options ...PageGetByAltTextOptions) Locator + + // Allows locating input elements by the text of the associated `<label>` or `aria-labelledby` element, or by the + // `aria-label` attribute. + // + // text: Text to locate the element for. + GetByLabel(text interface{}, options ...PageGetByLabelOptions) Locator + + // Allows locating input elements by the placeholder text. + // + // text: Text to locate the element for. + GetByPlaceholder(text interface{}, options ...PageGetByPlaceholderOptions) Locator + + // Allows locating elements by their [ARIA role], + // [ARIA attributes] and + // [accessible name]. + // + // # Details + // + // Role selector **does not replace** accessibility audits and conformance tests, but rather gives early feedback + // about the ARIA guidelines. + // Many html elements have an implicitly [defined role] + // that is recognized by the role selector. You can find all the + // [supported roles here]. ARIA guidelines **do not recommend** + // duplicating implicit roles and attributes by setting `role` and/or `aria-*` attributes to default values. + // + // role: Required aria role. + // + // [ARIA role]: https://www.w3.org/TR/wai-aria-1.2/#roles + // [ARIA attributes]: https://www.w3.org/TR/wai-aria-1.2/#aria-attributes + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + // [defined role]: https://w3c.github.io/html-aam/#html-element-role-mappings + // [supported roles here]: https://www.w3.org/TR/wai-aria-1.2/#role_definitions + GetByRole(role AriaRole, options ...PageGetByRoleOptions) Locator + + // Locate element by the test id. + // + // # Details + // + // By default, the `data-testid` attribute is used as a test id. Use [Selectors.SetTestIdAttribute] to configure a + // different test id attribute if necessary. + // + // testId: Id to locate the element by. + GetByTestId(testId interface{}) Locator + + // Allows locating elements that contain given text. + // See also [Locator.Filter] that allows to match by another criteria, like an accessible role, and then filter by the + // text content. + // + // # Details + // + // Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into + // one, turns line breaks into spaces and ignores leading and trailing whitespace. + // Input elements of the type `button` and `submit` are matched by their `value` instead of the text content. For + // example, locating by text `"Log in"` matches `<input type=button value="Log in">`. + // + // text: Text to locate the element for. + GetByText(text interface{}, options ...PageGetByTextOptions) Locator + + // Allows locating elements by their title attribute. + // + // text: Text to locate the element for. + GetByTitle(text interface{}, options ...PageGetByTitleOptions) Locator + + // Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of + // the last redirect. If cannot go back, returns `null`. + // Navigate to the previous page in history. + GoBack(options ...PageGoBackOptions) (Response, error) + + // Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of + // the last redirect. If cannot go forward, returns `null`. + // Navigate to the next page in history. + GoForward(options ...PageGoForwardOptions) (Response, error) + + // Request the page to perform garbage collection. Note that there is no guarantee that all unreachable objects will + // be collected. + // This is useful to help detect memory leaks. For example, if your page has a large object `suspect` that might be + // leaked, you can check that it does not leak by using a + // [`WeakRef`]. + // + // [`WeakRef`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef + RequestGC() error + + // Returns the main resource response. In case of multiple redirects, the navigation will resolve with the first + // non-redirect response. + // The method will throw an error if: + // - there's an SSL error (e.g. in case of self-signed certificates). + // - target URL is invalid. + // - the “[object Object]” is exceeded during navigation. + // - the remote server does not respond or is unreachable. + // - the main resource failed to load. + // The method will not throw an error when any valid HTTP status code is returned by the remote server, including 404 + // "Not Found" and 500 "Internal Server Error". The status code for such responses can be retrieved by calling + // [Response.Status]. + // **NOTE** The method either throws an error or returns a main resource response. The only exceptions are navigation + // to `about:blank` or navigation to the same URL with a different hash, which would succeed and return `null`. + // **NOTE** Headless mode doesn't support navigation to a PDF document. See the + // [upstream issue]. + // + // url: URL to navigate page to. The url should include scheme, e.g. `https://`. When a “[object Object]” via the context + // options was provided and the passed URL is a path, it gets merged via the + // [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor. + // + // [upstream issue]: https://bugs.chromium.org/p/chromium/issues/detail?id=761295 + Goto(url string, options ...PageGotoOptions) (Response, error) + + // This method hovers over an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Mouse] to hover over the center of the element, or the specified “[object Object]”. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Hover] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Hover(selector string, options ...PageHoverOptions) error + + // Returns `element.innerHTML`. + // + // Deprecated: Use locator-based [Locator.InnerHTML] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [locators]: https://playwright.dev/docs/locators + InnerHTML(selector string, options ...PageInnerHTMLOptions) (string, error) + + // Returns `element.innerText`. + // + // Deprecated: Use locator-based [Locator.InnerText] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [locators]: https://playwright.dev/docs/locators + InnerText(selector string, options ...PageInnerTextOptions) (string, error) + + // Returns `input.value` for the selected `<input>` or `<textarea>` or `<select>` element. + // Throws for non-input elements. However, if the element is inside the `<label>` element that has an associated + // [control], returns the value of the + // control. + // + // Deprecated: Use locator-based [Locator.InputValue] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + InputValue(selector string, options ...PageInputValueOptions) (string, error) + + // Returns whether the element is checked. Throws if the element is not a checkbox or radio input. + // + // Deprecated: Use locator-based [Locator.IsChecked] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [locators]: https://playwright.dev/docs/locators + IsChecked(selector string, options ...PageIsCheckedOptions) (bool, error) + + // Indicates that the page has been closed. + IsClosed() bool + + // Returns whether the element is disabled, the opposite of [enabled]. + // + // Deprecated: Use locator-based [Locator.IsDisabled] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [enabled]: https://playwright.dev/docs/actionability#enabled + // [locators]: https://playwright.dev/docs/locators + IsDisabled(selector string, options ...PageIsDisabledOptions) (bool, error) + + // Returns whether the element is [editable]. + // + // Deprecated: Use locator-based [Locator.IsEditable] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [editable]: https://playwright.dev/docs/actionability#editable + // [locators]: https://playwright.dev/docs/locators + IsEditable(selector string, options ...PageIsEditableOptions) (bool, error) + + // Returns whether the element is [enabled]. + // + // Deprecated: Use locator-based [Locator.IsEnabled] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [enabled]: https://playwright.dev/docs/actionability#enabled + // [locators]: https://playwright.dev/docs/locators + IsEnabled(selector string, options ...PageIsEnabledOptions) (bool, error) + + // Returns whether the element is hidden, the opposite of [visible]. “[object Object]” + // that does not match any elements is considered hidden. + // + // Deprecated: Use locator-based [Locator.IsHidden] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [visible]: https://playwright.dev/docs/actionability#visible + // [locators]: https://playwright.dev/docs/locators + IsHidden(selector string, options ...PageIsHiddenOptions) (bool, error) + + // Returns whether the element is [visible]. “[object Object]” that does not match any + // elements is considered not visible. + // + // Deprecated: Use locator-based [Locator.IsVisible] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [visible]: https://playwright.dev/docs/actionability#visible + // [locators]: https://playwright.dev/docs/locators + IsVisible(selector string, options ...PageIsVisibleOptions) (bool, error) + + Keyboard() Keyboard + + // The method returns an element locator that can be used to perform actions on this page / frame. Locator is resolved + // to the element immediately before performing an action, so a series of actions on the same locator can in fact be + // performed on different DOM elements. That would happen if the DOM structure between those actions has changed. + // [Learn more about locators]. + // + // selector: A selector to use when resolving DOM element. + // + // [Learn more about locators]: https://playwright.dev/docs/locators + Locator(selector string, options ...PageLocatorOptions) Locator + + // The page's main frame. Page is guaranteed to have a main frame which persists during navigations. + MainFrame() Frame + + Mouse() Mouse + + // Returns the opener for popup pages and `null` for others. If the opener has been closed already the returns `null`. + Opener() (Page, error) + + // Pauses script execution. Playwright will stop executing the script and wait for the user to either press 'Resume' + // button in the page overlay or to call `playwright.resume()` in the DevTools console. + // User can inspect selectors or perform manual steps while paused. Resume will continue running the original script + // from the place it was paused. + // **NOTE** This method requires Playwright to be started in a headed mode, with a falsy “[object Object]” option. + Pause() error + + // Returns the PDF buffer. + // `page.pdf()` generates a pdf of the page with `print` css media. To generate a pdf with `screen` media, call + // [Page.EmulateMedia] before calling `page.pdf()`: + // **NOTE** By default, `page.pdf()` generates a pdf with modified colors for printing. Use the + // [`-webkit-print-color-adjust`] + // property to force rendering of exact colors. + // + // [`-webkit-print-color-adjust`]: https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-print-color-adjust + PDF(options ...PagePdfOptions) ([]byte, error) + + // Focuses the element, and then uses [Keyboard.Down] and [Keyboard.Up]. + // “[object Object]” can specify the intended + // [keyboardEvent.Key] value or a single character + // to generate the text for. A superset of the “[object Object]” values can be found + // [here]. Examples of the keys are: + // `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, + // `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, + // etc. + // Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`, + // `ControlOrMeta`. `ControlOrMeta` resolves to `Control` on Windows and Linux and to `Meta` on macOS. + // Holding down `Shift` will type the text that corresponds to the “[object Object]” in the upper case. + // If “[object Object]” is a single character, it is case-sensitive, so the values `a` and `A` will generate different + // respective texts. + // Shortcuts such as `key: "Control+o"`, `key: "Control++` or `key: "Control+Shift+T"` are supported as well. When + // specified with the modifier, modifier is pressed and being held while the subsequent key is being pressed. + // + // Deprecated: Use locator-based [Locator.Press] instead. Read more about [locators]. + // + // 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // 2. key: Name of the key to press or a character to generate, such as `ArrowLeft` or `a`. + // + // [keyboardEvent.Key]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key + // [here]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values + // [locators]: https://playwright.dev/docs/locators + Press(selector string, key string, options ...PagePressOptions) error + + // The method finds an element matching the specified selector within the page. If no elements match the selector, the + // return value resolves to `null`. To wait for an element on the page, use [Locator.WaitFor]. + // + // Deprecated: Use locator-based [Page.Locator] instead. Read more about [locators]. + // + // selector: A selector to query for. + // + // [locators]: https://playwright.dev/docs/locators + QuerySelector(selector string, options ...PageQuerySelectorOptions) (ElementHandle, error) + + // The method finds all elements matching the specified selector within the page. If no elements match the selector, + // the return value resolves to `[]`. + // + // Deprecated: Use locator-based [Page.Locator] instead. Read more about [locators]. + // + // selector: A selector to query for. + // + // [locators]: https://playwright.dev/docs/locators + QuerySelectorAll(selector string) ([]ElementHandle, error) + + // When testing a web page, sometimes unexpected overlays like a "Sign up" dialog appear and block actions you want to + // automate, e.g. clicking a button. These overlays don't always show up in the same way or at the same time, making + // them tricky to handle in automated tests. + // This method lets you set up a special function, called a handler, that activates when it detects that overlay is + // visible. The handler's job is to remove the overlay, allowing your test to continue as if the overlay wasn't there. + // Things to keep in mind: + // - When an overlay is shown predictably, we recommend explicitly waiting for it in your test and dismissing it as + // a part of your normal test flow, instead of using [Page.AddLocatorHandler]. + // - Playwright checks for the overlay every time before executing or retrying an action that requires an + // [actionability check], or before performing an auto-waiting assertion check. When overlay + // is visible, Playwright calls the handler first, and then proceeds with the action/assertion. Note that the + // handler is only called when you perform an action/assertion - if the overlay becomes visible but you don't + // perform any actions, the handler will not be triggered. + // - After executing the handler, Playwright will ensure that overlay that triggered the handler is not visible + // anymore. You can opt-out of this behavior with “[object Object]”. + // - The execution time of the handler counts towards the timeout of the action/assertion that executed the handler. + // If your handler takes too long, it might cause timeouts. + // - You can register multiple handlers. However, only a single handler will be running at a time. Make sure the + // actions within a handler don't depend on another handler. + // **NOTE** Running the handler will alter your page state mid-test. For example it will change the currently focused + // element and move the mouse. Make sure that actions that run after the handler are self-contained and do not rely on + // the focus and mouse state being unchanged. + // For example, consider a test that calls [Locator.Focus] followed by [Keyboard.Press]. If your handler clicks a + // button between these two actions, the focused element most likely will be wrong, and key press will happen on the + // unexpected element. Use [Locator.Press] instead to avoid this problem. + // Another example is a series of mouse actions, where [Mouse.Move] is followed by [Mouse.Down]. Again, when the + // handler runs between these two actions, the mouse position will be wrong during the mouse down. Prefer + // self-contained actions like [Locator.Click] that do not rely on the state being unchanged by a handler. + // + // 1. locator: Locator that triggers the handler. + // 2. handler: Function that should be run once “[object Object]” appears. This function should get rid of the element that blocks + // actions like click. + // + // [actionability check]: https://playwright.dev/docs/actionability + AddLocatorHandler(locator Locator, handler func(Locator), options ...PageAddLocatorHandlerOptions) error + + // Removes all locator handlers added by [Page.AddLocatorHandler] for a specific locator. + // + // locator: Locator passed to [Page.AddLocatorHandler]. + RemoveLocatorHandler(locator Locator) error + + // This method reloads the current page, in the same way as if the user had triggered a browser refresh. Returns the + // main resource response. In case of multiple redirects, the navigation will resolve with the response of the last + // redirect. + Reload(options ...PageReloadOptions) (Response, error) + + // API testing helper associated with this page. This method returns the same instance as [BrowserContext.Request] on + // the page's context. See [BrowserContext.Request] for more details. + Request() APIRequestContext + + // Routing provides the capability to modify network requests that are made by a page. + // Once routing is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or + // aborted. + // **NOTE** The handler will only be called for the first url if the response is a redirect. + // **NOTE** [Page.Route] will not intercept requests intercepted by Service Worker. See + // [this] issue. We recommend disabling Service Workers when + // using request interception by setting “[object Object]” to `block`. + // **NOTE** [Page.Route] will not intercept the first request of a popup page. Use [BrowserContext.Route] instead. + // + // 1. url: A glob pattern, regex pattern, or predicate that receives a [URL] to match during routing. If “[object Object]” is + // set in the context options and the provided URL is a string that does not start with `*`, it is resolved using the + // [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor. + // 2. handler: handler function to route the request. + // + // [this]: https://github.com/microsoft/playwright/issues/1090 + Route(url interface{}, handler routeHandler, times ...int) error + + // If specified the network requests that are made in the page will be served from the HAR file. Read more about + // [Replaying from HAR]. + // Playwright will not serve requests intercepted by Service Worker from the HAR file. See + // [this] issue. We recommend disabling Service Workers when + // using request interception by setting “[object Object]” to `block`. + // + // har: Path to a [HAR](http://www.softwareishard.com/blog/har-12-spec) file with prerecorded network data. If `path` is a + // relative path, then it is resolved relative to the current working directory. + // + // [Replaying from HAR]: https://playwright.dev/docs/mock#replaying-from-har + // [this]: https://github.com/microsoft/playwright/issues/1090 + RouteFromHAR(har string, options ...PageRouteFromHAROptions) error + + // This method allows to modify websocket connections that are made by the page. + // Note that only `WebSocket`s created after this method was called will be routed. It is recommended to call this + // method before navigating the page. + // + // 1. url: Only WebSockets with the url matching this pattern will be routed. A string pattern can be relative to the + // “[object Object]” context option. + // 2. handler: Handler function to route the WebSocket. + RouteWebSocket(url interface{}, handler func(WebSocketRoute)) error + + // Returns the buffer with the captured screenshot. + Screenshot(options ...PageScreenshotOptions) ([]byte, error) + + // This method waits for an element matching “[object Object]”, waits for [actionability] checks, + // waits until all specified options are present in the `<select>` element and selects these options. + // If the target element is not a `<select>` element, this method throws an error. However, if the element is inside + // the `<label>` element that has an associated + // [control], the control will be used + // instead. + // Returns the array of option values that have been successfully selected. + // Triggers a `change` and `input` event once all the provided options have been selected. + // + // Deprecated: Use locator-based [Locator.SelectOption] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + SelectOption(selector string, values SelectOptionValues, options ...PageSelectOptionOptions) ([]string, error) + + // This method checks or unchecks an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Ensure that matched element is a checkbox or a radio input. If not, this method throws. + // 3. If the element already has the right checked state, this method returns immediately. + // 4. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 5. Scroll the element into view if needed. + // 6. Use [Page.Mouse] to click in the center of the element. + // 7. Ensure that the element is now checked or unchecked. If not, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.SetChecked] instead. Read more about [locators]. + // + // 1. selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // 2. checked: Whether to check or uncheck the checkbox. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + SetChecked(selector string, checked bool, options ...PageSetCheckedOptions) error + + // This method internally calls [document.Write()], + // inheriting all its specific characteristics and behaviors. + // + // html: HTML markup to assign to the page. + // + // [document.Write()]: https://developer.mozilla.org/en-US/docs/Web/API/Document/write + SetContent(html string, options ...PageSetContentOptions) error + + // This setting will change the default maximum navigation time for the following methods and related shortcuts: + // - [Page.GoBack] + // - [Page.GoForward] + // - [Page.Goto] + // - [Page.Reload] + // - [Page.SetContent] + // - [Page.ExpectNavigation] + // - [Page.WaitForURL] + // **NOTE** [Page.SetDefaultNavigationTimeout] takes priority over [Page.SetDefaultTimeout], + // [BrowserContext.SetDefaultTimeout] and [BrowserContext.SetDefaultNavigationTimeout]. + // + // timeout: Maximum navigation time in milliseconds + SetDefaultNavigationTimeout(timeout float64) + + // This setting will change the default maximum time for all the methods accepting “[object Object]” option. + // **NOTE** [Page.SetDefaultNavigationTimeout] takes priority over [Page.SetDefaultTimeout]. + // + // timeout: Maximum time in milliseconds. Pass `0` to disable timeout. + SetDefaultTimeout(timeout float64) + + // The extra HTTP headers will be sent with every request the page initiates. + // **NOTE** [Page.SetExtraHTTPHeaders] does not guarantee the order of headers in the outgoing requests. + // + // headers: An object containing additional HTTP headers to be sent with every request. All header values must be strings. + SetExtraHTTPHeaders(headers map[string]string) error + + // Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then + // they are resolved relative to the current working directory. For empty array, clears the selected files. For inputs + // with a `[webkitdirectory]` attribute, only a single directory path is supported. + // This method expects “[object Object]” to point to an + // [input element]. However, if the element is inside + // the `<label>` element that has an associated + // [control], targets the control instead. + // + // Deprecated: Use locator-based [Locator.SetInputFiles] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [input element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input + // [control]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control + // [locators]: https://playwright.dev/docs/locators + SetInputFiles(selector string, files interface{}, options ...PageSetInputFilesOptions) error + + // In the case of multiple pages in a single browser, each page can have its own viewport size. However, + // [Browser.NewContext] allows to set viewport size (and more) for all pages in the context at once. + // [Page.SetViewportSize] will resize the page. A lot of websites don't expect phones to change size, so you should + // set the viewport size before navigating to the page. [Page.SetViewportSize] will also reset `screen` size, use + // [Browser.NewContext] with `screen` and `viewport` parameters if you need better control of these properties. + // + // 1. width: Page width in pixels. + // 2. height: Page height in pixels. + SetViewportSize(width int, height int) error + + // This method taps an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 3. Scroll the element into view if needed. + // 4. Use [Page.Touchscreen] to tap the center of the element, or the specified “[object Object]”. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // **NOTE** [Page.Tap] the method will throw if “[object Object]” option of the browser context is false. + // + // Deprecated: Use locator-based [Locator.Tap] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Tap(selector string, options ...PageTapOptions) error + + // Returns `element.textContent`. + // + // Deprecated: Use locator-based [Locator.TextContent] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [locators]: https://playwright.dev/docs/locators + TextContent(selector string, options ...PageTextContentOptions) (string, error) + + // Returns the page's title. + Title() (string, error) + + Touchscreen() Touchscreen + + // Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. `page.type` can be used to + // 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: 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. + Type(selector string, text string, options ...PageTypeOptions) error + + // This method unchecks an element matching “[object Object]” by performing the following steps: + // 1. Find an element matching “[object Object]”. If there is none, wait until a matching element is attached to + // the DOM. + // 2. Ensure that matched element is a checkbox or a radio input. If not, this method throws. If the element is + // already unchecked, this method returns immediately. + // 3. Wait for [actionability] checks on the matched element, unless “[object Object]” option + // is set. If the element is detached during the checks, the whole action is retried. + // 4. Scroll the element into view if needed. + // 5. Use [Page.Mouse] to click in the center of the element. + // 6. Ensure that the element is now unchecked. If not, this method throws. + // When all steps combined have not finished during the specified “[object Object]”, this method throws a + // [TimeoutError]. Passing zero timeout disables this. + // + // Deprecated: Use locator-based [Locator.Uncheck] instead. Read more about [locators]. + // + // selector: A selector to search for an element. If there are multiple elements satisfying the selector, the first will be + // used. + // + // [actionability]: https://playwright.dev/docs/actionability + // [locators]: https://playwright.dev/docs/locators + Uncheck(selector string, options ...PageUncheckOptions) error + + // Removes all routes created with [Page.Route] and [Page.RouteFromHAR]. + UnrouteAll(options ...PageUnrouteAllOptions) error + + // Removes a route created with [Page.Route]. When “[object Object]” is not specified, removes all routes for the + // “[object Object]”. + // + // 1. url: A glob pattern, regex pattern or predicate receiving [URL] to match while routing. + // 2. handler: Optional handler function to route the request. + Unroute(url interface{}, handler ...routeHandler) error + + URL() string + + // Video object associated with this page. + Video() Video + + ViewportSize() *Size + + // Performs action and waits for a [ConsoleMessage] to be logged by in the page. If predicate is provided, it passes + // [ConsoleMessage] value into the `predicate` function and waits for `predicate(message)` to return a truthy value. + // Will throw an error if the page is closed before the [Page.OnConsole] event is fired. + ExpectConsoleMessage(cb func() error, options ...PageExpectConsoleMessageOptions) (ConsoleMessage, error) + + // Performs action and waits for a new [Download]. If predicate is provided, it passes [Download] value into the + // `predicate` function and waits for `predicate(download)` to return a truthy value. Will throw an error if the page + // is closed before the download event is fired. + ExpectDownload(cb func() error, options ...PageExpectDownloadOptions) (Download, error) + + // Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy + // value. Will throw an error if the page is closed before the event is fired. Returns the event data value. + // + // event: Event name, same one typically passed into `*.on(event)`. + ExpectEvent(event string, cb func() error, options ...PageExpectEventOptions) (interface{}, error) + + // Performs action and waits for a new [FileChooser] to be created. If predicate is provided, it passes [FileChooser] + // value into the `predicate` function and waits for `predicate(fileChooser)` to return a truthy value. Will throw an + // error if the page is closed before the file chooser is opened. + ExpectFileChooser(cb func() error, options ...PageExpectFileChooserOptions) (FileChooser, error) + + // Returns when the “[object Object]” returns a truthy value. It resolves to a JSHandle of the truthy value. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + WaitForFunction(expression string, arg interface{}, options ...PageWaitForFunctionOptions) (JSHandle, error) + + // Returns when the required load state has been reached. + // This resolves when the page reaches a required load state, `load` by default. The navigation must have been + // committed when this method is called. If current document has already reached the required state, resolves + // immediately. + // **NOTE** Most of the time, this method is not needed because Playwright + // [auto-waits before every action]. + // + // [auto-waits before every action]: https://playwright.dev/docs/actionability + WaitForLoadState(options ...PageWaitForLoadStateOptions) error + + // Waits for the main frame navigation and returns the main resource response. In case of multiple redirects, the + // navigation will resolve with the response of the last redirect. In case of navigation to a different anchor or + // navigation due to History API usage, the navigation will resolve with `null`. + // + // Deprecated: This method is inherently racy, please use [Page.WaitForURL] instead. + // + // [History API]: https://developer.mozilla.org/en-US/docs/Web/API/History_API + ExpectNavigation(cb func() error, options ...PageExpectNavigationOptions) (Response, error) + + // Performs action and waits for a popup [Page]. If predicate is provided, it passes [Popup] value into the + // `predicate` function and waits for `predicate(page)` to return a truthy value. Will throw an error if the page is + // closed before the popup event is fired. + ExpectPopup(cb func() error, options ...PageExpectPopupOptions) (Page, error) + + // Waits for the matching request and returns it. See [waiting for event] for more + // details about events. + // + // urlOrPredicate: Request URL string, regex or predicate receiving [Request] object. When a “[object Object]” via the context options + // was provided and the passed URL is a path, it gets merged via the + // [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor. + // + // [waiting for event]: https://playwright.dev/docs/events#waiting-for-event + ExpectRequest(urlOrPredicate interface{}, cb func() error, options ...PageExpectRequestOptions) (Request, error) + + // Performs action and waits for a [Request] to finish loading. If predicate is provided, it passes [Request] value + // into the `predicate` function and waits for `predicate(request)` to return a truthy value. Will throw an error if + // the page is closed before the [Page.OnRequestFinished] event is fired. + ExpectRequestFinished(cb func() error, options ...PageExpectRequestFinishedOptions) (Request, error) + + // Returns the matched response. See [waiting for event] for more details about + // events. + // + // urlOrPredicate: Request URL string, regex or predicate receiving [Response] object. When a “[object Object]” via the context + // options was provided and the passed URL is a path, it gets merged via the + // [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor. + // + // [waiting for event]: https://playwright.dev/docs/events#waiting-for-event + ExpectResponse(urlOrPredicate interface{}, cb func() error, options ...PageExpectResponseOptions) (Response, error) + + // Returns when element specified by selector satisfies “[object Object]” option. Returns `null` if waiting for + // `hidden` or `detached`. + // **NOTE** Playwright automatically waits for element to be ready before performing an action. Using [Locator] + // objects and web-first assertions makes the code wait-for-selector-free. + // Wait for the “[object Object]” to satisfy “[object Object]” option (either appear/disappear from dom, or become + // visible/hidden). If at the moment of calling the method “[object Object]” already satisfies the condition, the + // method will return immediately. If the selector doesn't satisfy the condition for the “[object Object]” + // milliseconds, the function will throw. + // + // Deprecated: Use web assertions that assert visibility or a locator-based [Locator.WaitFor] instead. Read more about [locators]. + // + // selector: A selector to query for. + // + // [locators]: https://playwright.dev/docs/locators + WaitForSelector(selector string, options ...PageWaitForSelectorOptions) (ElementHandle, error) + + // Waits for the given “[object Object]” in milliseconds. + // Note that `page.waitForTimeout()` should only be used for debugging. Tests using the timer in production are going + // to be flaky. Use signals such as network events, selectors becoming visible and others instead. + // + // Deprecated: Never wait for timeout in production. Tests that wait for time are inherently flaky. Use [Locator] actions and web assertions that wait automatically. + // + // timeout: A timeout to wait for + WaitForTimeout(timeout float64) + + // Waits for the main frame to navigate to the given URL. + // + // url: A glob pattern, regex pattern or predicate receiving [URL] to match while waiting for the navigation. Note that if + // the parameter is a string without wildcard characters, the method will wait for navigation to URL that is exactly + // equal to the string. + WaitForURL(url interface{}, options ...PageWaitForURLOptions) error + + // Performs action and waits for a new [WebSocket]. If predicate is provided, it passes [WebSocket] value into the + // `predicate` function and waits for `predicate(webSocket)` to return a truthy value. Will throw an error if the page + // is closed before the WebSocket event is fired. + ExpectWebSocket(cb func() error, options ...PageExpectWebSocketOptions) (WebSocket, error) + + // Performs action and waits for a new [Worker]. If predicate is provided, it passes [Worker] value into the + // `predicate` function and waits for `predicate(worker)` to return a truthy value. Will throw an error if the page is + // closed before the worker event is fired. + ExpectWorker(cb func() error, options ...PageExpectWorkerOptions) (Worker, error) + + // This method returns all of the dedicated + // [WebWorkers] associated with the page. + // **NOTE** This does not contain ServiceWorkers + // + // [WebWorkers]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API + Workers() []Worker + + // **NOTE** In most cases, you should use [Page.ExpectEvent]. + // Waits for given `event` to fire. If predicate is provided, it passes event's value into the `predicate` function + // and waits for `predicate(event)` to return a truthy value. Will throw an error if the page is closed before the + // `event` is fired. + // + // event: Event name, same one typically passed into `*.on(event)`. + WaitForEvent(event string, options ...PageWaitForEventOptions) (interface{}, error) +} + +// The [PageAssertions] class provides assertion methods that can be used to make assertions about the [Page] state in +// the tests. +type PageAssertions interface { + // Makes the assertion check for the opposite condition. For example, this code tests that the page URL doesn't + // contain `"error"`: + Not() PageAssertions + + // Ensures the page has the given title. + // + // titleOrRegExp: Expected title or RegExp. + ToHaveTitle(titleOrRegExp interface{}, options ...PageAssertionsToHaveTitleOptions) error + + // Ensures the page is navigated to the given URL. + // + // urlOrRegExp: Expected URL string or RegExp. + ToHaveURL(urlOrRegExp interface{}, options ...PageAssertionsToHaveURLOptions) error +} + +// Playwright gives you Web-First Assertions with convenience methods for creating assertions that will wait and retry +// until the expected condition is met. +// Consider the following example: +// Playwright will be re-testing the node with the selector `.status` until fetched Node has the `"Submitted"` text. +// It will be re-fetching the node and checking it over and over, until the condition is met or until the timeout is +// reached. You can pass this timeout as an option. +// By default, the timeout for assertions is set to 5 seconds. +type PlaywrightAssertions interface { + // Creates a [APIResponseAssertions] object for the given [APIResponse]. + // + // response: [APIResponse] object to use for assertions. + APIResponse(response APIResponse) APIResponseAssertions + + // Creates a [LocatorAssertions] object for the given [Locator]. + // + // locator: [Locator] object to use for assertions. + Locator(locator Locator) LocatorAssertions + + // Creates a [PageAssertions] object for the given [Page]. + // + // page: [Page] object to use for assertions. + Page(page Page) PageAssertions +} + +// Whenever the page sends a request for a network resource the following sequence of events are emitted by [Page]: +// - [Page.OnRequest] emitted when the request is issued by the page. +// - [Page.OnResponse] emitted when/if the response status and headers are received for the request. +// - [Page.OnRequestFinished] emitted when the response body is downloaded and the request is complete. +// +// If request fails at some point, then instead of `requestfinished` event (and possibly instead of 'response' +// event), the [Page.OnRequestFailed] event is emitted. +// **NOTE** HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request +// will complete with `requestfinished` event. +// If request gets a 'redirect' response, the request is successfully finished with the `requestfinished` event, and a +// new request is issued to a redirected url. +type Request interface { + // An object with all the request HTTP headers associated with this request. The header names are lower-cased. + AllHeaders() (map[string]string, error) + + // The method returns `null` unless this request has failed, as reported by `requestfailed` event. + 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 + // security-related headers, including cookie-related ones. You can use [Request.AllHeaders] for complete list of + // headers that include `cookie` information. + Headers() map[string]string + + // An array with all the request HTTP headers associated with this request. Unlike [Request.AllHeaders], header names + // are NOT lower-cased. Headers with multiple entries, such as `Set-Cookie`, appear in the array multiple times. + HeadersArray() ([]NameValue, error) + + // Returns the value of the header matching the name. The name is case-insensitive. + // + // name: Name of the header. + 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.) + Method() string + + // Request's post body, if any. + PostData() (string, error) + + // Request's post body in a binary form, if any. + PostDataBuffer() ([]byte, error) + + // Returns parsed request's body for `form-urlencoded` and JSON as a fallback if any. + // When the response is `application/x-www-form-urlencoded` then a key/value object of the values will be returned. + // Otherwise it will be parsed as JSON. + PostDataJSON(v interface{}) error + + // Request that was redirected by the server to this one, if any. + // When the server responds with a redirect, Playwright creates a new [Request] object. The two requests are connected + // by `redirectedFrom()` and `redirectedTo()` methods. When multiple server redirects has happened, it is possible to + // construct the whole redirect chain by repeatedly calling `redirectedFrom()`. + RedirectedFrom() Request + + // New request issued by the browser if the server responded with redirect. + RedirectedTo() Request + + // Contains the request's resource type as it was perceived by the rendering engine. ResourceType will be one of the + // following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttrack`, `xhr`, `fetch`, + // `eventsource`, `websocket`, `manifest`, `other`. + ResourceType() string + + // Returns the matching [Response] object, or `null` if the response was not received due to error. + Response() (Response, error) + + // Returns resource size information for given request. + Sizes() (*RequestSizesResult, error) + + // Returns resource timing information for given request. Most of the timing values become available upon the + // response, `responseEnd` becomes available when request finishes. Find more information at + // [Resource Timing API]. + // + // [Resource Timing API]: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming + Timing() *RequestTiming + + // URL of the request. + URL() string +} + +// [Response] class represents responses which are received by page. +type Response interface { + // An object with all the response HTTP headers associated with this response. + AllHeaders() (map[string]string, error) + + // Returns the buffer with response body. + Body() ([]byte, error) + + // Waits for this response to finish, returns always `null`. + Finished() error + + // Returns the [Frame] that initiated this response. + Frame() Frame + + // Indicates whether this Response was fulfilled by a Service Worker's Fetch Handler (i.e. via + // [FetchEvent.RespondWith]. + // + // [FetchEvent.RespondWith]: https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith) + FromServiceWorker() bool + + // An object with the response HTTP headers. The header names are lower-cased. Note that this method does not return + // security-related headers, including cookie-related ones. You can use [Response.AllHeaders] for complete list of + // headers that include `cookie` information. + Headers() map[string]string + + // An array with all the request HTTP headers associated with this response. Unlike [Response.AllHeaders], header + // names are NOT lower-cased. Headers with multiple entries, such as `Set-Cookie`, appear in the array multiple times. + HeadersArray() ([]NameValue, error) + + // Returns the value of the header matching the name. The name is case-insensitive. If multiple headers have the same + // name (except `set-cookie`), they are returned as a list separated by `, `. For `set-cookie`, the `\n` separator is + // used. If no headers are found, `null` is returned. + // + // name: Name of the header. + HeaderValue(name string) (string, error) + + // Returns all values of the headers matching the name, for example `set-cookie`. The name is case-insensitive. + // + // name: Name of the header. + HeaderValues(name string) ([]string, error) + + // Returns the JSON representation of response body. + // This method will throw if the response body is not parsable via `JSON.parse`. + JSON(v interface{}) error + + // Contains a boolean stating whether the response was successful (status in the range 200-299) or not. + Ok() bool + + // Returns the matching [Request] object. + Request() Request + + // Returns SSL and other security information. + SecurityDetails() (*ResponseSecurityDetailsResult, error) + + // Returns the IP address and port of the server. + ServerAddr() (*ResponseServerAddrResult, error) + + // Contains the status code of the response (e.g., 200 for a success). + Status() int + + // Contains the status text of the response (e.g. usually an "OK" for a success). + StatusText() string + + // Returns the text representation of response body. + Text() (string, error) + + // Contains the URL of the response. + URL() string +} + +// Whenever a network route is set up with [Page.Route] or [BrowserContext.Route], the `Route` object allows to handle +// the route. +// Learn more about [networking]. +// +// [networking]: https://playwright.dev/docs/network +type Route interface { + // Aborts the route's request. + Abort(errorCode ...string) error + + // Sends route's request to the network with optional overrides. + // + // # Details + // + // The “[object Object]” option applies to both the routed request and any redirects it initiates. However, + // “[object Object]”, “[object Object]”, and “[object Object]” only apply to the original request and are not carried + // over to redirected requests. + // [Route.Continue] will immediately send the request to the network, other matching handlers won't be invoked. Use + // [Route.Fallback] If you want next matching handler in the chain to be invoked. + // **NOTE** The `Cookie` header cannot be overridden using this method. If a value is provided, it will be ignored, + // and the cookie will be loaded from the browser's cookie store. To set custom cookies, use + // [BrowserContext.AddCookies]. + Continue(options ...RouteContinueOptions) error + + // Continues route's request with optional overrides. The method is similar to [Route.Continue] with the difference + // that other matching handlers will be invoked before sending the request. + Fallback(options ...RouteFallbackOptions) error + + // Performs the request and fetches result without fulfilling it, so that the response could be modified and then + // fulfilled. + // + // # Details + // + // Note that “[object Object]” option will apply to the fetched request as well as any redirects initiated by it. If + // you want to only apply “[object Object]” to the original request, but not to redirects, look into [Route.Continue] + // instead. + Fetch(options ...RouteFetchOptions) (APIResponse, error) + + // Fulfills route's request with given response. + Fulfill(options ...RouteFulfillOptions) error + + // A request to be routed. + Request() Request +} + +// Selectors can be used to install custom selector engines. See [extensibility] for more +// information. +// +// [extensibility]: https://playwright.dev/docs/extensibility +type Selectors interface { + // Selectors must be registered before creating the page. + // + // 1. name: Name that is used in selectors as a prefix, e.g. `{name: 'foo'}` enables `foo=myselectorbody` selectors. May only + // contain `[a-zA-Z0-9_]` characters. + // 2. script: Script that evaluates to a selector engine instance. The script is evaluated in the page context. + Register(name string, script Script, options ...SelectorsRegisterOptions) error + + // Defines custom attribute name to be used in [Page.GetByTestId]. `data-testid` is used by default. + // + // attributeName: Test id attribute name. + SetTestIdAttribute(attributeName string) +} + +// The Touchscreen class operates in main-frame CSS pixels relative to the top-left corner of the viewport. Methods on +// the touchscreen can only be used in browser contexts that have been initialized with `hasTouch` set to true. +// This class is limited to emulating tap gestures. For examples of other gestures simulated by manually dispatching +// touch events, see the [emulating legacy touch events] page. +// +// [emulating legacy touch events]: https://playwright.dev/docs/touch-events +type Touchscreen interface { + // Dispatches a `touchstart` and `touchend` event with a single touch at the position + // (“[object Object]”,“[object Object]”). + // **NOTE** [Page.Tap] the method will throw if “[object Object]” option of the browser context is false. + // + // 1. x: X coordinate relative to the main frame's viewport in CSS pixels. + // 2. y: Y coordinate relative to the main frame's viewport in CSS pixels. + Tap(x int, y int) error +} + +// API for collecting and saving Playwright traces. Playwright traces can be opened in +// [Trace Viewer] after Playwright script runs. +// Start recording a trace before performing actions. At the end, stop tracing and save it to a file. +// +// [Trace Viewer]: https://playwright.dev/docs/trace-viewer +type Tracing interface { + // Start tracing. + Start(options ...TracingStartOptions) error + + // Start a new trace chunk. If you'd like to record multiple traces on the same [BrowserContext], use [Tracing.Start] + // once, and then create multiple trace chunks with [Tracing.StartChunk] and [Tracing.StopChunk]. + StartChunk(options ...TracingStartChunkOptions) error + + // **NOTE** Use `test.step` instead when available. + // Creates a new group within the trace, assigning any subsequent API calls to this group, until [Tracing.GroupEnd] is + // called. Groups can be nested and will be visible in the trace viewer. + // + // name: Group name shown in the trace viewer. + Group(name string, options ...TracingGroupOptions) error + + // Closes the last group created by [Tracing.Group]. + GroupEnd() error + + // Stop tracing. + Stop(path ...string) error + + // Stop the trace chunk. See [Tracing.StartChunk] for more details about multiple trace chunks. + StopChunk(path ...string) error +} + +// When browser context is created with the `recordVideo` option, each page has a video object associated with it. +type Video interface { + // Deletes the video file. Will wait for the video to finish if necessary. + Delete() error + + // Returns the file system path this video will be recorded to. The video is guaranteed to be written to the + // filesystem upon closing the browser context. This method throws when connected remotely. + Path() (string, error) + + // Saves the video to a user-specified path. It is safe to call this method while the video is still in progress, or + // after the page has closed. This method waits until the page is closed and the video is fully saved. + // + // path: Path where the video should be saved. + SaveAs(path string) error +} + +// [WebError] class represents an unhandled exception 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 within a page. It provides the ability to inspect and +// manipulate the data being transmitted and received. +// If you want to intercept or modify WebSocket frames, consider using [WebSocketRoute]. +type WebSocket interface { + // Fired when the websocket closes. + OnClose(fn func(WebSocket)) + + // Fired when the websocket receives a frame. + OnFrameReceived(fn func([]byte)) + + // Fired when the websocket sends a frame. + OnFrameSent(fn func([]byte)) + + // Fired when the websocket has an error. + OnSocketError(fn func(string)) + + // Indicates that the web socket has been closed. + IsClosed() bool + + // Contains the URL of the WebSocket. + URL() string + + // Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy + // value. Will throw an error if the webSocket is closed before the event is fired. Returns the event data value. + // + // event: Event name, same one would pass into `webSocket.on(event)`. + ExpectEvent(event string, cb func() error, options ...WebSocketExpectEventOptions) (interface{}, error) + + // **NOTE** In most cases, you should use [WebSocket.ExpectEvent]. + // Waits for given `event` to fire. If predicate is provided, it passes event's value into the `predicate` function + // and waits for `predicate(event)` to return a truthy value. Will throw an error if the socket is closed before the + // `event` is fired. + // + // event: Event name, same one typically passed into `*.on(event)`. + WaitForEvent(event string, options ...WebSocketWaitForEventOptions) (interface{}, error) +} + +// Whenever a [`WebSocket`] route is set up with +// [Page.RouteWebSocket] or [BrowserContext.RouteWebSocket], the `WebSocketRoute` object allows to handle the +// WebSocket, like an actual server would do. +// **Mocking** +// By default, the routed WebSocket will not connect to the server. This way, you can mock entire communcation over +// the WebSocket. Here is an example that responds to a `"request"` with a `"response"`. +// Since we do not call [WebSocketRoute.ConnectToServer] inside the WebSocket route handler, Playwright assumes that +// WebSocket will be mocked, and opens the WebSocket inside the page automatically. +// Here is another example that handles JSON messages: +// **Intercepting** +// Alternatively, you may want to connect to the actual server, but intercept messages in-between and modify or block +// them. Calling [WebSocketRoute.ConnectToServer] returns a server-side `WebSocketRoute` instance that you can send +// messages to, or handle incoming messages. +// Below is an example that modifies some messages sent by the page to the server. Messages sent from the server to +// the page are left intact, relying on the default forwarding. +// After connecting to the server, all **messages are forwarded** between the page and the server by default. +// However, if you call [WebSocketRoute.OnMessage] on the original route, messages from the page to the server **will +// not be forwarded** anymore, but should instead be handled by the “[object Object]”. +// Similarly, calling [WebSocketRoute.OnMessage] on the server-side WebSocket will **stop forwarding messages** from +// the server to the page, and “[object Object]” should take care of them. +// The following example blocks some messages in both directions. Since it calls [WebSocketRoute.OnMessage] in both +// directions, there is no automatic forwarding at all. +// +// [`WebSocket`]: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket +type WebSocketRoute interface { + // Closes one side of the WebSocket connection. + Close(options ...WebSocketRouteCloseOptions) + + // By default, routed WebSocket does not connect to the server, so you can mock entire WebSocket communication. This + // method connects to the actual WebSocket server, and returns the server-side [WebSocketRoute] instance, giving the + // ability to send and receive messages from the server. + // Once connected to the server: + // - Messages received from the server will be **automatically forwarded** to the WebSocket in the page, unless + // [WebSocketRoute.OnMessage] is called on the server-side `WebSocketRoute`. + // - Messages sent by the [`WebSocket.send()`] call + // in the page will be **automatically forwarded** to the server, unless [WebSocketRoute.OnMessage] is called on + // the original `WebSocketRoute`. + // See examples at the top for more details. + // + // [`WebSocket.send()`]: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send + ConnectToServer() (WebSocketRoute, error) + + // Allows to handle [`WebSocket.close`]. + // By default, closing one side of the connection, either in the page or on the server, will close the other side. + // However, when [WebSocketRoute.OnClose] handler is set up, the default forwarding of closure is disabled, and + // handler should take care of it. + // + // handler: Function that will handle WebSocket closure. Received an optional + // [close code](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#code) and an optional + // [close reason](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#reason). + // + // [`WebSocket.close`]: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close + OnClose(handler func(*int, *string)) + + // This method allows to handle messages that are sent by the WebSocket, either from the page or from the server. + // When called on the original WebSocket route, this method handles messages sent from the page. You can handle this + // messages by responding to them with [WebSocketRoute.Send], forwarding them to the server-side connection returned + // by [WebSocketRoute.ConnectToServer] or do something else. + // Once this method is called, messages are not automatically forwarded to the server or to the page - you should do + // that manually by calling [WebSocketRoute.Send]. See examples at the top for more details. + // Calling this method again will override the handler with a new one. + // + // handler: Function that will handle messages. + OnMessage(handler func(interface{})) + + // Sends a message to the WebSocket. When called on the original WebSocket, sends the message to the page. When called + // on the result of [WebSocketRoute.ConnectToServer], sends the message to the server. See examples at the top for + // more details. + // + // message: Message to send. + Send(message interface{}) + + // URL of the WebSocket created in the page. + URL() string +} + +// The Worker class represents a [WebWorker]. +// `worker` event is emitted on the page object to signal a worker creation. `close` event is emitted on the worker +// object when the worker is gone. +// +// [WebWorker]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API +type Worker interface { + // Emitted when this dedicated [WebWorker] is + // terminated. + // + // [WebWorker]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API + OnClose(fn func(Worker)) + + // Returns the return value of “[object Object]”. + // If the function passed to the [Worker.Evaluate] returns a [Promise], then [Worker.Evaluate] would wait for the + // promise to resolve and return its value. + // If the function passed to the [Worker.Evaluate] returns a non-[Serializable] value, then [Worker.Evaluate] returns + // `undefined`. Playwright also supports transferring some additional values that are not serializable by `JSON`: + // `-0`, `NaN`, `Infinity`, `-Infinity`. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + Evaluate(expression string, arg ...interface{}) (interface{}, error) + + // Returns the return value of “[object Object]” as a [JSHandle]. + // The only difference between [Worker.Evaluate] and [Worker.EvaluateHandle] is that [Worker.EvaluateHandle] returns + // [JSHandle]. + // If the function passed to the [Worker.EvaluateHandle] returns a [Promise], then [Worker.EvaluateHandle] would wait + // for the promise to resolve and return its value. + // + // 1. expression: JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the + // function is automatically invoked. + // 2. arg: Optional argument to pass to “[object Object]”. + EvaluateHandle(expression string, arg ...interface{}) (JSHandle, error) + + URL() string +} diff --git a/vendor/github.com/playwright-community/playwright-go/generated-structs.go b/vendor/github.com/playwright-community/playwright-go/generated-structs.go new file mode 100644 index 0000000..7a90f5a --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/generated-structs.go @@ -0,0 +1,4364 @@ +package playwright + +type APIRequestNewContextOptions struct { + // Methods like [APIRequestContext.Get] take the base URL into consideration by using the + // [`URL()`] constructor for building the corresponding URL. + // Examples: + // - baseURL: `http://localhost:3000` and sending request to `/bar.html` results in `http://localhost:3000/bar.html` + // - baseURL: `http://localhost:3000/foo/` and sending request to `./bar.html` results in + // `http://localhost:3000/foo/bar.html` + // - baseURL: `http://localhost:3000/foo` (without trailing slash) and navigating to `./bar.html` results in + // `http://localhost:3000/bar.html` + // + // [`URL()`]: https://developer.mozilla.org/en-US/docs/Web/API/URL/URL + BaseURL *string `json:"baseURL"` + // TLS Client Authentication allows the server to request a client certificate and verify it. + // + // # Details + // + // An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`, + // a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally, + // `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided + // with an exact match to the request origin that the certificate is valid for. + // **NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it + // work by replacing `localhost` with `local.playwright`. + ClientCertificates []ClientCertificate `json:"clientCertificates"` + // An object containing additional HTTP headers to be sent with every request. Defaults to none. + ExtraHttpHeaders map[string]string `json:"extraHTTPHeaders"` + // Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + // codes. + FailOnStatusCode *bool `json:"failOnStatusCode"` + // Credentials for [HTTP authentication]. If no + // origin is specified, the username and password are sent to any servers upon unauthorized responses. + // + // [HTTP authentication]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication + HttpCredentials *HttpCredentials `json:"httpCredentials"` + // Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"` + // Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + // exceeded. Defaults to `20`. Pass `0` to not follow redirects. This can be overwritten for each request + // individually. + MaxRedirects *int `json:"maxRedirects"` + // Network proxy settings. + Proxy *Proxy `json:"proxy"` + // Populates context with given storage state. This option can be used to initialize context with logged-in + // information obtained via [BrowserContext.StorageState] or [APIRequestContext.StorageState]. Either a path to the + // file with saved storage, or the value returned by one of [BrowserContext.StorageState] or + // [APIRequestContext.StorageState] methods. + StorageState *StorageState `json:"storageState"` + // Populates context with given storage state. This option can be used to initialize context with logged-in + // information obtained via [BrowserContext.StorageState]. Path to the file with saved storage state. + StorageStatePath *string `json:"storageStatePath"` + // Maximum time in milliseconds to wait for the response. Defaults to `30000` (30 seconds). Pass `0` to disable + // timeout. + Timeout *float64 `json:"timeout"` + // Specific user agent to use in this context. + UserAgent *string `json:"userAgent"` +} + +type APIRequestContextDeleteOptions struct { + // Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + // and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + // header will be set to `application/octet-stream` if not explicitly set. + Data interface{} `json:"data"` + // Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + // codes. + FailOnStatusCode *bool `json:"failOnStatusCode"` + // Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + // as this request body. If this parameter is specified `content-type` header will be set to + // `application/x-www-form-urlencoded` unless explicitly provided. + Form interface{} `json:"form"` + // Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + // it. + Headers map[string]string `json:"headers"` + // Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"` + // Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + // exceeded. Defaults to `20`. Pass `0` to not follow redirects. + MaxRedirects *int `json:"maxRedirects"` + // Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + // retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + MaxRetries *int `json:"maxRetries"` + // Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + // request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + // explicitly provided. File values can be passed either as + // [`fs.ReadStream`] or as file-like object containing file + // name, mime-type and its content. + // + // [`fs.ReadStream`]: https://nodejs.org/api/fs.html#fs_class_fs_readstream + Multipart interface{} `json:"multipart"` + // Query parameters to be sent with the URL. + Params map[string]interface{} `json:"params"` + // Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + Timeout *float64 `json:"timeout"` +} + +type APIRequestContextDisposeOptions struct { + // The reason to be reported to the operations interrupted by the context disposal. + Reason *string `json:"reason"` +} + +type APIRequestContextFetchOptions struct { + // Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + // and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + // header will be set to `application/octet-stream` if not explicitly set. + Data interface{} `json:"data"` + // Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + // codes. + FailOnStatusCode *bool `json:"failOnStatusCode"` + // Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + // as this request body. If this parameter is specified `content-type` header will be set to + // `application/x-www-form-urlencoded` unless explicitly provided. + Form interface{} `json:"form"` + // Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + // it. + Headers map[string]string `json:"headers"` + // Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"` + // Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + // exceeded. Defaults to `20`. Pass `0` to not follow redirects. + MaxRedirects *int `json:"maxRedirects"` + // Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + // retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + MaxRetries *int `json:"maxRetries"` + // If set changes the fetch method (e.g. [PUT] or + // [POST]. If not specified, GET method is used. + // + // [PUT]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT + // [POST]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST) + Method *string `json:"method"` + // Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + // request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + // explicitly provided. File values can be passed either as + // [`fs.ReadStream`] or as file-like object containing file + // name, mime-type and its content. + // + // [`fs.ReadStream`]: https://nodejs.org/api/fs.html#fs_class_fs_readstream + Multipart interface{} `json:"multipart"` + // Query parameters to be sent with the URL. + Params map[string]interface{} `json:"params"` + // Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + Timeout *float64 `json:"timeout"` +} + +type APIRequestContextGetOptions struct { + // Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + // and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + // header will be set to `application/octet-stream` if not explicitly set. + Data interface{} `json:"data"` + // Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + // codes. + FailOnStatusCode *bool `json:"failOnStatusCode"` + // Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + // as this request body. If this parameter is specified `content-type` header will be set to + // `application/x-www-form-urlencoded` unless explicitly provided. + Form interface{} `json:"form"` + // Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + // it. + Headers map[string]string `json:"headers"` + // Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"` + // Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + // exceeded. Defaults to `20`. Pass `0` to not follow redirects. + MaxRedirects *int `json:"maxRedirects"` + // Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + // retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + MaxRetries *int `json:"maxRetries"` + // Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + // request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + // explicitly provided. File values can be passed either as + // [`fs.ReadStream`] or as file-like object containing file + // name, mime-type and its content. + // + // [`fs.ReadStream`]: https://nodejs.org/api/fs.html#fs_class_fs_readstream + Multipart interface{} `json:"multipart"` + // Query parameters to be sent with the URL. + Params map[string]interface{} `json:"params"` + // Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + Timeout *float64 `json:"timeout"` +} + +type APIRequestContextHeadOptions struct { + // Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + // and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + // header will be set to `application/octet-stream` if not explicitly set. + Data interface{} `json:"data"` + // Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + // codes. + FailOnStatusCode *bool `json:"failOnStatusCode"` + // Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + // as this request body. If this parameter is specified `content-type` header will be set to + // `application/x-www-form-urlencoded` unless explicitly provided. + Form interface{} `json:"form"` + // Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + // it. + Headers map[string]string `json:"headers"` + // Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"` + // Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + // exceeded. Defaults to `20`. Pass `0` to not follow redirects. + MaxRedirects *int `json:"maxRedirects"` + // Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + // retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + MaxRetries *int `json:"maxRetries"` + // Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + // request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + // explicitly provided. File values can be passed either as + // [`fs.ReadStream`] or as file-like object containing file + // name, mime-type and its content. + // + // [`fs.ReadStream`]: https://nodejs.org/api/fs.html#fs_class_fs_readstream + Multipart interface{} `json:"multipart"` + // Query parameters to be sent with the URL. + Params map[string]interface{} `json:"params"` + // Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + Timeout *float64 `json:"timeout"` +} + +type APIRequestContextPatchOptions struct { + // Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + // and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + // header will be set to `application/octet-stream` if not explicitly set. + Data interface{} `json:"data"` + // Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + // codes. + FailOnStatusCode *bool `json:"failOnStatusCode"` + // Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + // as this request body. If this parameter is specified `content-type` header will be set to + // `application/x-www-form-urlencoded` unless explicitly provided. + Form interface{} `json:"form"` + // Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + // it. + Headers map[string]string `json:"headers"` + // Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"` + // Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + // exceeded. Defaults to `20`. Pass `0` to not follow redirects. + MaxRedirects *int `json:"maxRedirects"` + // Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + // retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + MaxRetries *int `json:"maxRetries"` + // Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + // request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + // explicitly provided. File values can be passed either as + // [`fs.ReadStream`] or as file-like object containing file + // name, mime-type and its content. + // + // [`fs.ReadStream`]: https://nodejs.org/api/fs.html#fs_class_fs_readstream + Multipart interface{} `json:"multipart"` + // Query parameters to be sent with the URL. + Params map[string]interface{} `json:"params"` + // Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + Timeout *float64 `json:"timeout"` +} + +type APIRequestContextPostOptions struct { + // Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + // and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + // header will be set to `application/octet-stream` if not explicitly set. + Data interface{} `json:"data"` + // Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + // codes. + FailOnStatusCode *bool `json:"failOnStatusCode"` + // Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + // as this request body. If this parameter is specified `content-type` header will be set to + // `application/x-www-form-urlencoded` unless explicitly provided. + Form interface{} `json:"form"` + // Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + // it. + Headers map[string]string `json:"headers"` + // Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"` + // Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + // exceeded. Defaults to `20`. Pass `0` to not follow redirects. + MaxRedirects *int `json:"maxRedirects"` + // Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + // retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + MaxRetries *int `json:"maxRetries"` + // Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + // request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + // explicitly provided. File values can be passed either as + // [`fs.ReadStream`] or as file-like object containing file + // name, mime-type and its content. + // + // [`fs.ReadStream`]: https://nodejs.org/api/fs.html#fs_class_fs_readstream + Multipart interface{} `json:"multipart"` + // Query parameters to be sent with the URL. + Params map[string]interface{} `json:"params"` + // Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + Timeout *float64 `json:"timeout"` +} + +type APIRequestContextPutOptions struct { + // Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string + // and `content-type` header will be set to `application/json` if not explicitly set. Otherwise the `content-type` + // header will be set to `application/octet-stream` if not explicitly set. + Data interface{} `json:"data"` + // Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + // codes. + FailOnStatusCode *bool `json:"failOnStatusCode"` + // Provides an object that will be serialized as html form using `application/x-www-form-urlencoded` encoding and sent + // as this request body. If this parameter is specified `content-type` header will be set to + // `application/x-www-form-urlencoded` unless explicitly provided. + Form interface{} `json:"form"` + // Allows to set HTTP headers. These headers will apply to the fetched request as well as any redirects initiated by + // it. + Headers map[string]string `json:"headers"` + // Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"` + // Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + // exceeded. Defaults to `20`. Pass `0` to not follow redirects. + MaxRedirects *int `json:"maxRedirects"` + // Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + // retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + MaxRetries *int `json:"maxRetries"` + // Provides an object that will be serialized as html form using `multipart/form-data` encoding and sent as this + // request body. If this parameter is specified `content-type` header will be set to `multipart/form-data` unless + // explicitly provided. File values can be passed either as + // [`fs.ReadStream`] or as file-like object containing file + // name, mime-type and its content. + // + // [`fs.ReadStream`]: https://nodejs.org/api/fs.html#fs_class_fs_readstream + Multipart interface{} `json:"multipart"` + // Query parameters to be sent with the URL. + Params map[string]interface{} `json:"params"` + // Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + Timeout *float64 `json:"timeout"` +} + +type StorageState struct { + Cookies []Cookie `json:"cookies"` + Origins []Origin `json:"origins"` +} + +type NameValue struct { + // Name of the header. + Name string `json:"name"` + // Value of the header. + Value string `json:"value"` +} + +type BrowserCloseOptions struct { + // The reason to be reported to the operations interrupted by the browser closure. + Reason *string `json:"reason"` +} + +type BrowserNewContextOptions struct { + // Whether to automatically download all the attachments. Defaults to `true` where all the downloads are accepted. + AcceptDownloads *bool `json:"acceptDownloads"` + // When using [Page.Goto], [Page.Route], [Page.WaitForURL], [Page.ExpectRequest], or [Page.ExpectResponse] it takes + // the base URL in consideration by using the [`URL()`] + // constructor for building the corresponding URL. Unset by default. Examples: + // - baseURL: `http://localhost:3000` and navigating to `/bar.html` results in `http://localhost:3000/bar.html` + // - baseURL: `http://localhost:3000/foo/` and navigating to `./bar.html` results in + // `http://localhost:3000/foo/bar.html` + // - baseURL: `http://localhost:3000/foo` (without trailing slash) and navigating to `./bar.html` results in + // `http://localhost:3000/bar.html` + // + // [`URL()`]: https://developer.mozilla.org/en-US/docs/Web/API/URL/URL + BaseURL *string `json:"baseURL"` + // Toggles bypassing page's Content-Security-Policy. Defaults to `false`. + BypassCSP *bool `json:"bypassCSP"` + // TLS Client Authentication allows the server to request a client certificate and verify it. + // + // # Details + // + // An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`, + // a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally, + // `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided + // with an exact match to the request origin that the certificate is valid for. + // **NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it + // work by replacing `localhost` with `local.playwright`. + ClientCertificates []ClientCertificate `json:"clientCertificates"` + // Emulates [prefers-colors-scheme] + // media feature, supported values are `light` and `dark`. See [Page.EmulateMedia] for more details. Passing + // `no-override` resets emulation to system defaults. Defaults to `light`. + // + // [prefers-colors-scheme]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme + ColorScheme *ColorScheme `json:"colorScheme"` + // Specify device scale factor (can be thought of as dpr). Defaults to `1`. Learn more about + // [emulating devices with device scale factor]. + // + // [emulating devices with device scale factor]: https://playwright.dev/docs/emulation#devices + DeviceScaleFactor *float64 `json:"deviceScaleFactor"` + // An object containing additional HTTP headers to be sent with every request. Defaults to none. + ExtraHttpHeaders map[string]string `json:"extraHTTPHeaders"` + // Emulates `forced-colors` media feature, supported values are `active`, `none`. See [Page.EmulateMedia] for + // more details. Passing `no-override` resets emulation to system defaults. Defaults to `none`. + ForcedColors *ForcedColors `json:"forcedColors"` + Geolocation *Geolocation `json:"geolocation"` + // Specifies if viewport supports touch events. Defaults to false. Learn more about + // [mobile emulation]. + // + // [mobile emulation]: https://playwright.dev/docs/emulation#devices + HasTouch *bool `json:"hasTouch"` + // Credentials for [HTTP authentication]. If no + // origin is specified, the username and password are sent to any servers upon unauthorized responses. + // + // [HTTP authentication]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication + HttpCredentials *HttpCredentials `json:"httpCredentials"` + // Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"` + // Whether the `meta viewport` tag is taken into account and touch events are enabled. isMobile is a part of device, + // so you don't actually need to set it manually. Defaults to `false` and is not supported in Firefox. Learn more + // about [mobile emulation]. + // + // [mobile emulation]: https://playwright.dev/docs/emulation#ismobile + IsMobile *bool `json:"isMobile"` + // Whether or not to enable JavaScript in the context. Defaults to `true`. Learn more about + // [disabling JavaScript]. + // + // [disabling JavaScript]: https://playwright.dev/docs/emulation#javascript-enabled + JavaScriptEnabled *bool `json:"javaScriptEnabled"` + // Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, + // `Accept-Language` request header value as well as number and date formatting rules. Defaults to the system default + // locale. Learn more about emulation in our [emulation guide]. + // + // [emulation guide]: https://playwright.dev/docs/emulation#locale--timezone + Locale *string `json:"locale"` + // Does not enforce fixed viewport, allows resizing window in the headed mode. + NoViewport *bool `json:"noViewport"` + // Whether to emulate network being offline. Defaults to `false`. Learn more about + // [network emulation]. + // + // [network emulation]: https://playwright.dev/docs/emulation#offline + Offline *bool `json:"offline"` + // A list of permissions to grant to all pages in this context. See [BrowserContext.GrantPermissions] for more + // details. Defaults to none. + Permissions []string `json:"permissions"` + // Network proxy settings to use with this context. Defaults to none. + Proxy *Proxy `json:"proxy"` + // Optional setting to control resource content management. If `omit` is specified, content is not persisted. If + // `attach` is specified, resources are persisted as separate files and all of these files are archived along with the + // HAR file. Defaults to `embed`, which stores content inline the HAR file as per HAR specification. + RecordHarContent *HarContentPolicy `json:"recordHarContent"` + // When set to `minimal`, only record information necessary for routing from HAR. This omits sizes, timing, page, + // cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to `full`. + RecordHarMode *HarMode `json:"recordHarMode"` + // Optional setting to control whether to omit request content from the HAR. Defaults to `false`. + RecordHarOmitContent *bool `json:"recordHarOmitContent"` + // Enables [HAR] recording for all pages into the specified HAR file + // on the filesystem. If not specified, the HAR is not recorded. Make sure to call [BrowserContext.Close] for the HAR + // to be saved. + // + // [HAR]: http://www.softwareishard.com/blog/har-12-spec + RecordHarPath *string `json:"recordHarPath"` + RecordHarURLFilter interface{} `json:"recordHarUrlFilter"` + // Enables video recording for all pages into `recordVideo.dir` directory. If not specified videos are not recorded. + // Make sure to await [BrowserContext.Close] for videos to be saved. + RecordVideo *RecordVideo `json:"recordVideo"` + // Emulates `prefers-reduced-motion` media feature, supported values are `reduce`, `no-preference`. See + // [Page.EmulateMedia] for more details. Passing `no-override` resets emulation to system defaults. Defaults to + // `no-preference`. + ReducedMotion *ReducedMotion `json:"reducedMotion"` + // Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the + // “[object Object]” is set. + Screen *Size `json:"screen"` + // Whether to allow sites to register Service workers. Defaults to `allow`. + // - `allow`: [Service Workers] can be + // registered. + // - `block`: Playwright will block all registration of Service Workers. + // + // [Service Workers]: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API + ServiceWorkers *ServiceWorkerPolicy `json:"serviceWorkers"` + // Learn more about [storage state and auth]. + // Populates context with given storage state. This option can be used to initialize context with logged-in + // information obtained via [BrowserContext.StorageState]. + // + // [storage state and auth]: https://playwright.dev/docs/auth + StorageState *OptionalStorageState `json:"storageState"` + // Populates context with given storage state. This option can be used to initialize context with logged-in + // information obtained via [BrowserContext.StorageState]. Path to the file with saved storage state. + StorageStatePath *string `json:"storageStatePath"` + // If set to true, enables strict selectors mode for this context. In the strict selectors mode all operations on + // selectors that imply single target DOM element will throw when more than one element matches the selector. This + // option does not affect any Locator APIs (Locators are always strict). Defaults to `false`. See [Locator] to learn + // more about the strict mode. + StrictSelectors *bool `json:"strictSelectors"` + // Changes the timezone of the context. See + // [ICU's metaZones.txt] + // for a list of supported timezone IDs. Defaults to the system timezone. + // + // [ICU's metaZones.txt]: https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1 + TimezoneId *string `json:"timezoneId"` + // Specific user agent to use in this context. + UserAgent *string `json:"userAgent"` + // Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `no_viewport` disables the fixed + // viewport. Learn more about [viewport emulation]. + // + // [viewport emulation]: https://playwright.dev/docs/emulation#viewport + Viewport *Size `json:"viewport"` +} + +type BrowserNewPageOptions struct { + // Whether to automatically download all the attachments. Defaults to `true` where all the downloads are accepted. + AcceptDownloads *bool `json:"acceptDownloads"` + // When using [Page.Goto], [Page.Route], [Page.WaitForURL], [Page.ExpectRequest], or [Page.ExpectResponse] it takes + // the base URL in consideration by using the [`URL()`] + // constructor for building the corresponding URL. Unset by default. Examples: + // - baseURL: `http://localhost:3000` and navigating to `/bar.html` results in `http://localhost:3000/bar.html` + // - baseURL: `http://localhost:3000/foo/` and navigating to `./bar.html` results in + // `http://localhost:3000/foo/bar.html` + // - baseURL: `http://localhost:3000/foo` (without trailing slash) and navigating to `./bar.html` results in + // `http://localhost:3000/bar.html` + // + // [`URL()`]: https://developer.mozilla.org/en-US/docs/Web/API/URL/URL + BaseURL *string `json:"baseURL"` + // Toggles bypassing page's Content-Security-Policy. Defaults to `false`. + BypassCSP *bool `json:"bypassCSP"` + // TLS Client Authentication allows the server to request a client certificate and verify it. + // + // # Details + // + // An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`, + // a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally, + // `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided + // with an exact match to the request origin that the certificate is valid for. + // **NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it + // work by replacing `localhost` with `local.playwright`. + ClientCertificates []ClientCertificate `json:"clientCertificates"` + // Emulates [prefers-colors-scheme] + // media feature, supported values are `light` and `dark`. See [Page.EmulateMedia] for more details. Passing + // `no-override` resets emulation to system defaults. Defaults to `light`. + // + // [prefers-colors-scheme]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme + ColorScheme *ColorScheme `json:"colorScheme"` + // Specify device scale factor (can be thought of as dpr). Defaults to `1`. Learn more about + // [emulating devices with device scale factor]. + // + // [emulating devices with device scale factor]: https://playwright.dev/docs/emulation#devices + DeviceScaleFactor *float64 `json:"deviceScaleFactor"` + // An object containing additional HTTP headers to be sent with every request. Defaults to none. + ExtraHttpHeaders map[string]string `json:"extraHTTPHeaders"` + // Emulates `forced-colors` media feature, supported values are `active`, `none`. See [Page.EmulateMedia] for + // more details. Passing `no-override` resets emulation to system defaults. Defaults to `none`. + ForcedColors *ForcedColors `json:"forcedColors"` + Geolocation *Geolocation `json:"geolocation"` + // Specifies if viewport supports touch events. Defaults to false. Learn more about + // [mobile emulation]. + // + // [mobile emulation]: https://playwright.dev/docs/emulation#devices + HasTouch *bool `json:"hasTouch"` + // Credentials for [HTTP authentication]. If no + // origin is specified, the username and password are sent to any servers upon unauthorized responses. + // + // [HTTP authentication]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication + HttpCredentials *HttpCredentials `json:"httpCredentials"` + // Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"` + // Whether the `meta viewport` tag is taken into account and touch events are enabled. isMobile is a part of device, + // so you don't actually need to set it manually. Defaults to `false` and is not supported in Firefox. Learn more + // about [mobile emulation]. + // + // [mobile emulation]: https://playwright.dev/docs/emulation#ismobile + IsMobile *bool `json:"isMobile"` + // Whether or not to enable JavaScript in the context. Defaults to `true`. Learn more about + // [disabling JavaScript]. + // + // [disabling JavaScript]: https://playwright.dev/docs/emulation#javascript-enabled + JavaScriptEnabled *bool `json:"javaScriptEnabled"` + // Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, + // `Accept-Language` request header value as well as number and date formatting rules. Defaults to the system default + // locale. Learn more about emulation in our [emulation guide]. + // + // [emulation guide]: https://playwright.dev/docs/emulation#locale--timezone + Locale *string `json:"locale"` + // Does not enforce fixed viewport, allows resizing window in the headed mode. + NoViewport *bool `json:"noViewport"` + // Whether to emulate network being offline. Defaults to `false`. Learn more about + // [network emulation]. + // + // [network emulation]: https://playwright.dev/docs/emulation#offline + Offline *bool `json:"offline"` + // A list of permissions to grant to all pages in this context. See [BrowserContext.GrantPermissions] for more + // details. Defaults to none. + Permissions []string `json:"permissions"` + // Network proxy settings to use with this context. Defaults to none. + Proxy *Proxy `json:"proxy"` + // Optional setting to control resource content management. If `omit` is specified, content is not persisted. If + // `attach` is specified, resources are persisted as separate files and all of these files are archived along with the + // HAR file. Defaults to `embed`, which stores content inline the HAR file as per HAR specification. + RecordHarContent *HarContentPolicy `json:"recordHarContent"` + // When set to `minimal`, only record information necessary for routing from HAR. This omits sizes, timing, page, + // cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to `full`. + RecordHarMode *HarMode `json:"recordHarMode"` + // Optional setting to control whether to omit request content from the HAR. Defaults to `false`. + RecordHarOmitContent *bool `json:"recordHarOmitContent"` + // Enables [HAR] recording for all pages into the specified HAR file + // on the filesystem. If not specified, the HAR is not recorded. Make sure to call [BrowserContext.Close] for the HAR + // to be saved. + // + // [HAR]: http://www.softwareishard.com/blog/har-12-spec + RecordHarPath *string `json:"recordHarPath"` + RecordHarURLFilter interface{} `json:"recordHarUrlFilter"` + // Enables video recording for all pages into `recordVideo.dir` directory. If not specified videos are not recorded. + // Make sure to await [BrowserContext.Close] for videos to be saved. + RecordVideo *RecordVideo `json:"recordVideo"` + // Emulates `prefers-reduced-motion` media feature, supported values are `reduce`, `no-preference`. See + // [Page.EmulateMedia] for more details. Passing `no-override` resets emulation to system defaults. Defaults to + // `no-preference`. + ReducedMotion *ReducedMotion `json:"reducedMotion"` + // Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the + // “[object Object]” is set. + Screen *Size `json:"screen"` + // Whether to allow sites to register Service workers. Defaults to `allow`. + // - `allow`: [Service Workers] can be + // registered. + // - `block`: Playwright will block all registration of Service Workers. + // + // [Service Workers]: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API + ServiceWorkers *ServiceWorkerPolicy `json:"serviceWorkers"` + // Learn more about [storage state and auth]. + // Populates context with given storage state. This option can be used to initialize context with logged-in + // information obtained via [BrowserContext.StorageState]. + // + // [storage state and auth]: https://playwright.dev/docs/auth + StorageState *OptionalStorageState `json:"storageState"` + // Populates context with given storage state. This option can be used to initialize context with logged-in + // information obtained via [BrowserContext.StorageState]. Path to the file with saved storage state. + StorageStatePath *string `json:"storageStatePath"` + // If set to true, enables strict selectors mode for this context. In the strict selectors mode all operations on + // selectors that imply single target DOM element will throw when more than one element matches the selector. This + // option does not affect any Locator APIs (Locators are always strict). Defaults to `false`. See [Locator] to learn + // more about the strict mode. + StrictSelectors *bool `json:"strictSelectors"` + // Changes the timezone of the context. See + // [ICU's metaZones.txt] + // for a list of supported timezone IDs. Defaults to the system timezone. + // + // [ICU's metaZones.txt]: https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1 + TimezoneId *string `json:"timezoneId"` + // Specific user agent to use in this context. + UserAgent *string `json:"userAgent"` + // Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `no_viewport` disables the fixed + // viewport. Learn more about [viewport emulation]. + // + // [viewport emulation]: https://playwright.dev/docs/emulation#viewport + Viewport *Size `json:"viewport"` +} + +type BrowserStartTracingOptions struct { + // specify custom categories to use instead of default. + Categories []string `json:"categories"` + // Optional, if specified, tracing includes screenshots of the given page. + Page Page `json:"page"` + // A path to write the trace file to. + Path *string `json:"path"` + // captures screenshots in the trace. + Screenshots *bool `json:"screenshots"` +} + +type OptionalCookie struct { + Name string `json:"name"` + Value string `json:"value"` + // Either url or domain / path are required. Optional. + URL *string `json:"url"` + // For the cookie to apply to all subdomains as well, prefix domain with a dot, like this: ".example.com". Either url + // or domain / path are required. Optional. + Domain *string `json:"domain"` + // Either url or domain / path are required Optional. + Path *string `json:"path"` + // Unix time in seconds. Optional. + Expires *float64 `json:"expires"` + // Optional. + HttpOnly *bool `json:"httpOnly"` + // Optional. + Secure *bool `json:"secure"` + // Optional. + SameSite *SameSiteAttribute `json:"sameSite"` +} + +type Script struct { + // Path to the JavaScript file. If `path` is a relative path, then it is resolved relative to the current working + // directory. Optional. + Path *string `json:"path"` + // Raw script content. Optional. + Content *string `json:"content"` +} + +type BrowserContextClearCookiesOptions struct { + // Only removes cookies with the given domain. + Domain interface{} `json:"domain"` + // Only removes cookies with the given name. + Name interface{} `json:"name"` + // Only removes cookies with the given path. + Path interface{} `json:"path"` +} + +type BrowserContextCloseOptions struct { + // The reason to be reported to the operations interrupted by the context closure. + Reason *string `json:"reason"` +} + +type Cookie struct { + Name string `json:"name"` + Value string `json:"value"` + Domain string `json:"domain"` + Path string `json:"path"` + // Unix time in seconds. + Expires float64 `json:"expires"` + HttpOnly bool `json:"httpOnly"` + Secure bool `json:"secure"` + SameSite *SameSiteAttribute `json:"sameSite"` +} + +type BrowserContextGrantPermissionsOptions struct { + // The [origin] to grant permissions to, e.g. "https://example.com". + Origin *string `json:"origin"` +} + +type BrowserContextRouteFromHAROptions struct { + // - If set to 'abort' any request not found in the HAR file will be aborted. + // - If set to 'fallback' falls through to the next route handler in the handler chain. + // Defaults to abort. + NotFound *HarNotFound `json:"notFound"` + // If specified, updates the given HAR with the actual network information instead of serving from file. The file is + // written to disk when [BrowserContext.Close] is called. + Update *bool `json:"update"` + // Optional setting to control resource content management. If `attach` is specified, resources are persisted as + // separate files or entries in the ZIP archive. If `embed` is specified, content is stored inline the HAR file. + UpdateContent *RouteFromHarUpdateContentPolicy `json:"updateContent"` + // When set to `minimal`, only record information necessary for routing from HAR. This omits sizes, timing, page, + // cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to + // `minimal`. + UpdateMode *HarMode `json:"updateMode"` + // A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the + // pattern will be served from the HAR file. If not specified, all requests are served from the HAR file. + URL interface{} `json:"url"` +} + +type Geolocation struct { + // Latitude between -90 and 90. + Latitude float64 `json:"latitude"` + // Longitude between -180 and 180. + Longitude float64 `json:"longitude"` + // Non-negative accuracy value. Defaults to `0`. + Accuracy *float64 `json:"accuracy"` +} + +type BrowserContextUnrouteAllOptions struct { + // Specifies whether to wait for already running handlers and what to do if they throw errors: + // - `default` - do not wait for current handler calls (if any) to finish, if unrouted handler throws, it may + // result in unhandled error + // - `wait` - wait for current handler calls (if any) to finish + // - `ignoreErrors` - do not wait for current handler calls (if any) to finish, all errors thrown by the handlers + // after unrouting are silently caught + Behavior *UnrouteBehavior `json:"behavior"` +} + +type BrowserContextExpectConsoleMessageOptions struct { + // Receives the [ConsoleMessage] object and resolves to truthy value when the waiting should resolve. + Predicate func(ConsoleMessage) bool `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type BrowserContextExpectEventOptions struct { + // Receives the event data and resolves to truthy value when the waiting should resolve. + Predicate interface{} `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type BrowserContextExpectPageOptions struct { + // Receives the [Page] object and resolves to truthy value when the waiting should resolve. + Predicate func(Page) bool `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type BrowserContextWaitForEventOptions struct { + // Receives the event data and resolves to truthy value when the waiting should resolve. + Predicate interface{} `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type BrowserTypeConnectOptions struct { + // This option exposes network available on the connecting client to the browser being connected to. Consists of a + // list of rules separated by comma. + // Available rules: + // 1. Hostname pattern, for example: `example.com`, `*.org:99`, `x.*.y.com`, `*foo.org`. + // 2. IP literal, for example: `127.0.0.1`, `0.0.0.0:99`, `[::1]`, `[0:0::1]:99`. + // 3. `<loopback>` that matches local loopback interfaces: `localhost`, `*.localhost`, `127.0.0.1`, `[::1]`. + // Some common examples: + // 4. `"*"` to expose all network. + // 5. `"<loopback>"` to expose localhost network. + // 6. `"*.test.internal-domain,*.staging.internal-domain,<loopback>"` to expose test/staging deployments and + // localhost. + ExposeNetwork *string `json:"exposeNetwork"` + // Additional HTTP headers to be sent with web socket connect request. Optional. + Headers map[string]string `json:"headers"` + // Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going + // on. Defaults to 0. + SlowMo *float64 `json:"slowMo"` + // Maximum time in milliseconds to wait for the connection to be established. Defaults to `0` (no timeout). + Timeout *float64 `json:"timeout"` +} + +type BrowserTypeConnectOverCDPOptions struct { + // Additional HTTP headers to be sent with connect request. Optional. + Headers map[string]string `json:"headers"` + // Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going + // on. Defaults to 0. + SlowMo *float64 `json:"slowMo"` + // Maximum time in milliseconds to wait for the connection to be established. Defaults to `30000` (30 seconds). Pass + // `0` to disable timeout. + Timeout *float64 `json:"timeout"` +} + +type BrowserTypeLaunchOptions struct { + // **NOTE** Use custom browser args at your own risk, as some of them may break Playwright functionality. + // Additional arguments to pass to the browser instance. The list of Chromium flags can be found + // [here]. + // + // [here]: https://peter.sh/experiments/chromium-command-line-switches/ + Args []string `json:"args"` + // Browser distribution channel. + // Use "chromium" to [opt in to new headless mode]. + // Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or + // "msedge-canary" to use branded [Google Chrome and Microsoft Edge]. + // + // [opt in to new headless mode]: https://playwright.dev/docs/browsers#chromium-new-headless-mode + // [Google Chrome and Microsoft Edge]: https://playwright.dev/docs/browsers#google-chrome--microsoft-edge + Channel *string `json:"channel"` + // Enable Chromium sandboxing. Defaults to `false`. + ChromiumSandbox *bool `json:"chromiumSandbox"` + // **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the + // “[object Object]” option will be set `false`. + // + // Deprecated: Use [debugging tools] instead. + // + // [debugging tools]: https://playwright.dev/docs/debug + Devtools *bool `json:"devtools"` + // If specified, accepted downloads are downloaded into this directory. Otherwise, temporary directory is created and + // is deleted when browser is closed. In either case, the downloads are deleted when the browser context they were + // created in is closed. + DownloadsPath *string `json:"downloadsPath"` + // Specify environment variables that will be visible to the browser. Defaults to `process.env`. + Env map[string]string `json:"env"` + // Path to a browser executable to run instead of the bundled one. If “[object Object]” is a relative path, then it is + // resolved relative to the current working directory. Note that Playwright only works with the bundled Chromium, + // Firefox or WebKit, use at your own risk. + ExecutablePath *string `json:"executablePath"` + // Firefox user preferences. Learn more about the Firefox user preferences at + // [`about:config`]. + // + // [`about:config`]: https://support.mozilla.org/en-US/kb/about-config-editor-firefox + FirefoxUserPrefs map[string]interface{} `json:"firefoxUserPrefs"` + // Close the browser process on SIGHUP. Defaults to `true`. + HandleSIGHUP *bool `json:"handleSIGHUP"` + // Close the browser process on Ctrl-C. Defaults to `true`. + HandleSIGINT *bool `json:"handleSIGINT"` + // Close the browser process on SIGTERM. Defaults to `true`. + HandleSIGTERM *bool `json:"handleSIGTERM"` + // Whether to run browser in headless mode. More details for + // [Chromium] and + // [Firefox]. Defaults to `true` unless the + // “[object Object]” option is `true`. + // + // [Chromium]: https://developers.google.com/web/updates/2017/04/headless-chrome + // [Firefox]: https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/ + Headless *bool `json:"headless"` + // If `true`, Playwright does not pass its own configurations args and only uses the ones from “[object Object]”. + // Dangerous option; use with care. Defaults to `false`. + IgnoreAllDefaultArgs *bool `json:"ignoreAllDefaultArgs"` + // If `true`, Playwright does not pass its own configurations args and only uses the ones from “[object Object]”. + // Dangerous option; use with care. + IgnoreDefaultArgs []string `json:"ignoreDefaultArgs"` + // Network proxy settings. + Proxy *Proxy `json:"proxy"` + // Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going + // on. + SlowMo *float64 `json:"slowMo"` + // Maximum time in milliseconds to wait for the browser instance to start. Defaults to `30000` (30 seconds). Pass `0` + // to disable timeout. + Timeout *float64 `json:"timeout"` + // If specified, traces are saved into this directory. + TracesDir *string `json:"tracesDir"` +} + +type BrowserTypeLaunchPersistentContextOptions struct { + // Whether to automatically download all the attachments. Defaults to `true` where all the downloads are accepted. + AcceptDownloads *bool `json:"acceptDownloads"` + // **NOTE** Use custom browser args at your own risk, as some of them may break Playwright functionality. + // Additional arguments to pass to the browser instance. The list of Chromium flags can be found + // [here]. + // + // [here]: https://peter.sh/experiments/chromium-command-line-switches/ + Args []string `json:"args"` + // When using [Page.Goto], [Page.Route], [Page.WaitForURL], [Page.ExpectRequest], or [Page.ExpectResponse] it takes + // the base URL in consideration by using the [`URL()`] + // constructor for building the corresponding URL. Unset by default. Examples: + // - baseURL: `http://localhost:3000` and navigating to `/bar.html` results in `http://localhost:3000/bar.html` + // - baseURL: `http://localhost:3000/foo/` and navigating to `./bar.html` results in + // `http://localhost:3000/foo/bar.html` + // - baseURL: `http://localhost:3000/foo` (without trailing slash) and navigating to `./bar.html` results in + // `http://localhost:3000/bar.html` + // + // [`URL()`]: https://developer.mozilla.org/en-US/docs/Web/API/URL/URL + BaseURL *string `json:"baseURL"` + // Toggles bypassing page's Content-Security-Policy. Defaults to `false`. + BypassCSP *bool `json:"bypassCSP"` + // Browser distribution channel. + // Use "chromium" to [opt in to new headless mode]. + // Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or + // "msedge-canary" to use branded [Google Chrome and Microsoft Edge]. + // + // [opt in to new headless mode]: https://playwright.dev/docs/browsers#chromium-new-headless-mode + // [Google Chrome and Microsoft Edge]: https://playwright.dev/docs/browsers#google-chrome--microsoft-edge + Channel *string `json:"channel"` + // Enable Chromium sandboxing. Defaults to `false`. + ChromiumSandbox *bool `json:"chromiumSandbox"` + // TLS Client Authentication allows the server to request a client certificate and verify it. + // + // # Details + // + // An array of client certificates to be used. Each certificate object must have either both `certPath` and `keyPath`, + // a single `pfxPath`, or their corresponding direct value equivalents (`cert` and `key`, or `pfx`). Optionally, + // `passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided + // with an exact match to the request origin that the certificate is valid for. + // **NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it + // work by replacing `localhost` with `local.playwright`. + ClientCertificates []ClientCertificate `json:"clientCertificates"` + // Emulates [prefers-colors-scheme] + // media feature, supported values are `light` and `dark`. See [Page.EmulateMedia] for more details. Passing + // `no-override` resets emulation to system defaults. Defaults to `light`. + // + // [prefers-colors-scheme]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme + ColorScheme *ColorScheme `json:"colorScheme"` + // Specify device scale factor (can be thought of as dpr). Defaults to `1`. Learn more about + // [emulating devices with device scale factor]. + // + // [emulating devices with device scale factor]: https://playwright.dev/docs/emulation#devices + DeviceScaleFactor *float64 `json:"deviceScaleFactor"` + // **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the + // “[object Object]” option will be set `false`. + // + // Deprecated: Use [debugging tools] instead. + // + // [debugging tools]: https://playwright.dev/docs/debug + Devtools *bool `json:"devtools"` + // If specified, accepted downloads are downloaded into this directory. Otherwise, temporary directory is created and + // is deleted when browser is closed. In either case, the downloads are deleted when the browser context they were + // created in is closed. + DownloadsPath *string `json:"downloadsPath"` + // Specify environment variables that will be visible to the browser. Defaults to `process.env`. + Env map[string]string `json:"env"` + // Path to a browser executable to run instead of the bundled one. If “[object Object]” is a relative path, then it is + // resolved relative to the current working directory. Note that Playwright only works with the bundled Chromium, + // Firefox or WebKit, use at your own risk. + ExecutablePath *string `json:"executablePath"` + // An object containing additional HTTP headers to be sent with every request. Defaults to none. + ExtraHttpHeaders map[string]string `json:"extraHTTPHeaders"` + // Firefox user preferences. Learn more about the Firefox user preferences at + // [`about:config`]. + // + // [`about:config`]: https://support.mozilla.org/en-US/kb/about-config-editor-firefox + FirefoxUserPrefs map[string]interface{} `json:"firefoxUserPrefs"` + // Emulates `forced-colors` media feature, supported values are `active`, `none`. See [Page.EmulateMedia] for + // more details. Passing `no-override` resets emulation to system defaults. Defaults to `none`. + ForcedColors *ForcedColors `json:"forcedColors"` + Geolocation *Geolocation `json:"geolocation"` + // Close the browser process on SIGHUP. Defaults to `true`. + HandleSIGHUP *bool `json:"handleSIGHUP"` + // Close the browser process on Ctrl-C. Defaults to `true`. + HandleSIGINT *bool `json:"handleSIGINT"` + // Close the browser process on SIGTERM. Defaults to `true`. + HandleSIGTERM *bool `json:"handleSIGTERM"` + // Specifies if viewport supports touch events. Defaults to false. Learn more about + // [mobile emulation]. + // + // [mobile emulation]: https://playwright.dev/docs/emulation#devices + HasTouch *bool `json:"hasTouch"` + // Whether to run browser in headless mode. More details for + // [Chromium] and + // [Firefox]. Defaults to `true` unless the + // “[object Object]” option is `true`. + // + // [Chromium]: https://developers.google.com/web/updates/2017/04/headless-chrome + // [Firefox]: https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/ + Headless *bool `json:"headless"` + // Credentials for [HTTP authentication]. If no + // origin is specified, the username and password are sent to any servers upon unauthorized responses. + // + // [HTTP authentication]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication + HttpCredentials *HttpCredentials `json:"httpCredentials"` + // If `true`, Playwright does not pass its own configurations args and only uses the ones from “[object Object]”. + // Dangerous option; use with care. Defaults to `false`. + IgnoreAllDefaultArgs *bool `json:"ignoreAllDefaultArgs"` + // If `true`, Playwright does not pass its own configurations args and only uses the ones from “[object Object]”. + // Dangerous option; use with care. + IgnoreDefaultArgs []string `json:"ignoreDefaultArgs"` + // Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + IgnoreHttpsErrors *bool `json:"ignoreHTTPSErrors"` + // Whether the `meta viewport` tag is taken into account and touch events are enabled. isMobile is a part of device, + // so you don't actually need to set it manually. Defaults to `false` and is not supported in Firefox. Learn more + // about [mobile emulation]. + // + // [mobile emulation]: https://playwright.dev/docs/emulation#ismobile + IsMobile *bool `json:"isMobile"` + // Whether or not to enable JavaScript in the context. Defaults to `true`. Learn more about + // [disabling JavaScript]. + // + // [disabling JavaScript]: https://playwright.dev/docs/emulation#javascript-enabled + JavaScriptEnabled *bool `json:"javaScriptEnabled"` + // Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, + // `Accept-Language` request header value as well as number and date formatting rules. Defaults to the system default + // locale. Learn more about emulation in our [emulation guide]. + // + // [emulation guide]: https://playwright.dev/docs/emulation#locale--timezone + Locale *string `json:"locale"` + // Does not enforce fixed viewport, allows resizing window in the headed mode. + NoViewport *bool `json:"noViewport"` + // Whether to emulate network being offline. Defaults to `false`. Learn more about + // [network emulation]. + // + // [network emulation]: https://playwright.dev/docs/emulation#offline + Offline *bool `json:"offline"` + // A list of permissions to grant to all pages in this context. See [BrowserContext.GrantPermissions] for more + // details. Defaults to none. + Permissions []string `json:"permissions"` + // Network proxy settings. + Proxy *Proxy `json:"proxy"` + // Optional setting to control resource content management. If `omit` is specified, content is not persisted. If + // `attach` is specified, resources are persisted as separate files and all of these files are archived along with the + // HAR file. Defaults to `embed`, which stores content inline the HAR file as per HAR specification. + RecordHarContent *HarContentPolicy `json:"recordHarContent"` + // When set to `minimal`, only record information necessary for routing from HAR. This omits sizes, timing, page, + // cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to `full`. + RecordHarMode *HarMode `json:"recordHarMode"` + // Optional setting to control whether to omit request content from the HAR. Defaults to `false`. + RecordHarOmitContent *bool `json:"recordHarOmitContent"` + // Enables [HAR] recording for all pages into the specified HAR file + // on the filesystem. If not specified, the HAR is not recorded. Make sure to call [BrowserContext.Close] for the HAR + // to be saved. + // + // [HAR]: http://www.softwareishard.com/blog/har-12-spec + RecordHarPath *string `json:"recordHarPath"` + RecordHarURLFilter interface{} `json:"recordHarUrlFilter"` + // Enables video recording for all pages into `recordVideo.dir` directory. If not specified videos are not recorded. + // Make sure to await [BrowserContext.Close] for videos to be saved. + RecordVideo *RecordVideo `json:"recordVideo"` + // Emulates `prefers-reduced-motion` media feature, supported values are `reduce`, `no-preference`. See + // [Page.EmulateMedia] for more details. Passing `no-override` resets emulation to system defaults. Defaults to + // `no-preference`. + ReducedMotion *ReducedMotion `json:"reducedMotion"` + // Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the + // “[object Object]” is set. + Screen *Size `json:"screen"` + // Whether to allow sites to register Service workers. Defaults to `allow`. + // - `allow`: [Service Workers] can be + // registered. + // - `block`: Playwright will block all registration of Service Workers. + // + // [Service Workers]: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API + ServiceWorkers *ServiceWorkerPolicy `json:"serviceWorkers"` + // Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going + // on. + SlowMo *float64 `json:"slowMo"` + // If set to true, enables strict selectors mode for this context. In the strict selectors mode all operations on + // selectors that imply single target DOM element will throw when more than one element matches the selector. This + // option does not affect any Locator APIs (Locators are always strict). Defaults to `false`. See [Locator] to learn + // more about the strict mode. + StrictSelectors *bool `json:"strictSelectors"` + // Maximum time in milliseconds to wait for the browser instance to start. Defaults to `30000` (30 seconds). Pass `0` + // to disable timeout. + Timeout *float64 `json:"timeout"` + // Changes the timezone of the context. See + // [ICU's metaZones.txt] + // for a list of supported timezone IDs. Defaults to the system timezone. + // + // [ICU's metaZones.txt]: https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1 + TimezoneId *string `json:"timezoneId"` + // If specified, traces are saved into this directory. + TracesDir *string `json:"tracesDir"` + // Specific user agent to use in this context. + UserAgent *string `json:"userAgent"` + // Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `no_viewport` disables the fixed + // viewport. Learn more about [viewport emulation]. + // + // [viewport emulation]: https://playwright.dev/docs/emulation#viewport + Viewport *Size `json:"viewport"` +} + +type ClockInstallOptions struct { + // Time to initialize with, current system time by default. + Time interface{} `json:"time"` +} + +type ConsoleMessageLocation struct { + // URL of the resource. + URL string `json:"url"` + // 0-based line number in the resource. + LineNumber int `json:"lineNumber"` + // 0-based column number in the resource. + ColumnNumber int `json:"columnNumber"` +} + +type Rect struct { + // the x coordinate of the element in pixels. + X float64 `json:"x"` + // the y coordinate of the element in pixels. + Y float64 `json:"y"` + // the width of the element in pixels. + Width float64 `json:"width"` + // the height of the element in pixels. + Height float64 `json:"height"` +} + +type ElementHandleCheckOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type ElementHandleClickOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // defaults to 1. See [UIEvent.Detail]. + ClickCount *int `json:"clickCount"` + // Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You + // can opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as + // navigating to inaccessible pages. Defaults to `false`. + // + // Deprecated: This option will default to `true` in the future. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type ElementHandleDblclickOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type ElementHandleFillOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type ElementHandleHoverOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type ElementHandleInputValueOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type ElementHandlePressOptions struct { + // Time to wait between `keydown` and `keyup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You + // can opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as + // navigating to inaccessible pages. Defaults to `false`. + // + // Deprecated: This option will default to `true` in the future. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type ElementHandleScreenshotOptions struct { + // When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different + // treatment depending on their duration: + // - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + // - infinite animations are canceled to initial state, and then played over after the screenshot. + // Defaults to `"allow"` that leaves animations untouched. + Animations *ScreenshotAnimations `json:"animations"` + // When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`, text caret behavior will not be + // changed. Defaults to `"hide"`. + Caret *ScreenshotCaret `json:"caret"` + // Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink + // box `#FF00FF` (customized by “[object Object]”) that completely covers its bounding box. The mask is also applied + // to invisible elements, see [Matching only visible elements] to + // disable that. + // + // [Matching only visible elements]: https://playwright.dev/docs/locators#matching-only-visible-elements + Mask []Locator `json:"mask"` + // Specify the color of the overlay box for masked elements, in + // [CSS color format]. Default color is pink `#FF00FF`. + // + // [CSS color format]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value + MaskColor *string `json:"maskColor"` + // Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. + // Defaults to `false`. + OmitBackground *bool `json:"omitBackground"` + // The file path to save the image to. The screenshot type will be inferred from file extension. If “[object Object]” + // is a relative path, then it is resolved relative to the current working directory. If no path is provided, the + // image won't be saved to the disk. + Path *string `json:"path"` + // The quality of the image, between 0-100. Not applicable to `png` images. + Quality *int `json:"quality"` + // When set to `"css"`, screenshot will have a single pixel per each css pixel on the page. For high-dpi devices, this + // will keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so + // screenshots of high-dpi devices will be twice as large or even larger. + // Defaults to `"device"`. + Scale *ScreenshotScale `json:"scale"` + // Text of the stylesheet to apply while making the screenshot. This is where you can hide dynamic elements, make + // elements invisible or change their properties to help you creating repeatable screenshots. This stylesheet pierces + // the Shadow DOM and applies to the inner frames. + Style *string `json:"style"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // Specify screenshot type, defaults to `png`. + Type *ScreenshotType `json:"type"` +} + +type ElementHandleScrollIntoViewIfNeededOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type ElementHandleSelectOptionOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type ElementHandleSelectTextOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type ElementHandleSetCheckedOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type ElementHandleSetInputFilesOptions struct { + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type ElementHandleTapOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type ElementHandleTypeOptions struct { + // Time to wait between key presses in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type ElementHandleUncheckOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type ElementHandleWaitForElementStateOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type ElementHandleWaitForSelectorOptions struct { + // Defaults to `visible`. Can be either: + // - `attached` - wait for element to be present in DOM. + // - `detached` - wait for element to not be present in DOM. + // - `visible` - wait for element to have non-empty bounding box and no `visibility:hidden`. Note that element + // without any content or with `display:none` has an empty bounding box and is not considered visible. + // - `hidden` - wait for element to be either detached from DOM, or have an empty bounding box or + // `visibility:hidden`. This is opposite to the `visible` option. + State *WaitForSelectorState `json:"state"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FileChooserSetFilesOptions struct { + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameAddScriptTagOptions struct { + // Raw JavaScript content to be injected into frame. + Content *string `json:"content"` + // Path to the JavaScript file to be injected into frame. If `path` is a relative path, then it is resolved relative + // to the current working directory. + Path *string `json:"path"` + // Script type. Use 'module' in order to load a JavaScript ES6 module. See + // [script] for more details. + // + // [script]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script + Type *string `json:"type"` + // URL of a script to be added. + URL *string `json:"url"` +} + +type FrameAddStyleTagOptions struct { + // Raw CSS content to be injected into frame. + Content *string `json:"content"` + // Path to the CSS file to be injected into frame. If `path` is a relative path, then it is resolved relative to the + // current working directory. + Path *string `json:"path"` + // URL of the `<link>` tag. + URL *string `json:"url"` +} + +type FrameCheckOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type FrameClickOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // defaults to 1. See [UIEvent.Detail]. + ClickCount *int `json:"clickCount"` + // Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You + // can opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as + // navigating to inaccessible pages. Defaults to `false`. + // + // Deprecated: This option will default to `true` in the future. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type FrameDblclickOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type FrameDispatchEventOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameDragAndDropOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Clicks on the source element at this point relative to the top-left corner of the element's padding box. If not + // specified, some visible point of the element is used. + SourcePosition *Position `json:"sourcePosition"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Drops on the target element at this point relative to the top-left corner of the element's padding box. If not + // specified, some visible point of the element is used. + TargetPosition *Position `json:"targetPosition"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type FrameEvalOnSelectorOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` +} + +type FrameFillOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameFocusOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameGetAttributeOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameGetByAltTextOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type FrameGetByLabelOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type FrameGetByPlaceholderOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type FrameGetByRoleOptions struct { + // An attribute that is usually set by `aria-checked` or native `<input type=checkbox>` controls. + // Learn more about [`aria-checked`]. + // + // [`aria-checked`]: https://www.w3.org/TR/wai-aria-1.2/#aria-checked + Checked *bool `json:"checked"` + // An attribute that is usually set by `aria-disabled` or `disabled`. + // **NOTE** Unlike most other attributes, `disabled` is inherited through the DOM hierarchy. Learn more about + // [`aria-disabled`]. + // + // [`aria-disabled`]: https://www.w3.org/TR/wai-aria-1.2/#aria-disabled + Disabled *bool `json:"disabled"` + // Whether “[object Object]” is matched exactly: case-sensitive and whole-string. Defaults to false. Ignored when + // “[object Object]” is a regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` + // An attribute that is usually set by `aria-expanded`. + // Learn more about [`aria-expanded`]. + // + // [`aria-expanded`]: https://www.w3.org/TR/wai-aria-1.2/#aria-expanded + Expanded *bool `json:"expanded"` + // Option that controls whether hidden elements are matched. By default, only non-hidden elements, as + // [defined by ARIA], are matched by role selector. + // Learn more about [`aria-hidden`]. + // + // [defined by ARIA]: https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion + // [`aria-hidden`]: https://www.w3.org/TR/wai-aria-1.2/#aria-hidden + IncludeHidden *bool `json:"includeHidden"` + // A number attribute that is usually present for roles `heading`, `listitem`, `row`, `treeitem`, with default values + // for `<h1>-<h6>` elements. + // Learn more about [`aria-level`]. + // + // [`aria-level`]: https://www.w3.org/TR/wai-aria-1.2/#aria-level + Level *int `json:"level"` + // Option to match the [accessible name]. By default, matching is + // case-insensitive and searches for a substring, use “[object Object]” to control this behavior. + // Learn more about [accessible name]. + // + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + Name interface{} `json:"name"` + // An attribute that is usually set by `aria-pressed`. + // Learn more about [`aria-pressed`]. + // + // [`aria-pressed`]: https://www.w3.org/TR/wai-aria-1.2/#aria-pressed + Pressed *bool `json:"pressed"` + // An attribute that is usually set by `aria-selected`. + // Learn more about [`aria-selected`]. + // + // [`aria-selected`]: https://www.w3.org/TR/wai-aria-1.2/#aria-selected + Selected *bool `json:"selected"` +} + +type FrameGetByTextOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type FrameGetByTitleOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type FrameGotoOptions struct { + // Referer header value. If provided it will take preference over the referer header value set by + // [Page.SetExtraHTTPHeaders]. + Referer *string `json:"referer"` + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When to consider operation succeeded, defaults to `load`. Events can be either: + // - `domcontentloaded` - consider operation to be finished when the `DOMContentLoaded` event is fired. + // - `load` - consider operation to be finished when the `load` event is fired. + // - `networkidle` - **DISCOURAGED** consider operation to be finished when there are no network connections for + // at least `500` ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + // - `commit` - consider operation to be finished when network response is received and the document started + // loading. + WaitUntil *WaitUntilState `json:"waitUntil"` +} + +type FrameHoverOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type FrameInnerHTMLOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameInnerTextOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameInputValueOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameIsCheckedOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameIsDisabledOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameIsEditableOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameIsEnabledOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameIsHiddenOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // + // Deprecated: This option is ignored. [Frame.IsHidden] does not wait for the element to become hidden and returns immediately. + Timeout *float64 `json:"timeout"` +} + +type FrameIsVisibleOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // + // Deprecated: This option is ignored. [Frame.IsVisible] does not wait for the element to become visible and returns immediately. + Timeout *float64 `json:"timeout"` +} + +type FrameLocatorOptions struct { + // Narrows down the results of the method to those which contain elements matching this relative locator. For example, + // `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`. + // Inner locator **must be relative** to the outer locator and is queried starting with the outer locator match, not + // the document root. For example, you can find `content` that has `div` in + // `<article><content><div>Playwright</div></content></article>`. However, looking for `content` that has `article + // div` will fail, because the inner locator must be relative and should not use any elements outside the `content`. + // Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s. + Has Locator `json:"has"` + // Matches elements that do not contain an element that matches an inner locator. Inner locator is queried against the + // outer one. For example, `article` that does not have `div` matches `<article><span>Playwright</span></article>`. + // Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s. + HasNot Locator `json:"hasNot"` + // Matches elements that do not contain specified text somewhere inside, possibly in a child or a descendant element. + // When passed a [string], matching is case-insensitive and searches for a substring. + HasNotText interface{} `json:"hasNotText"` + // Matches elements containing specified text somewhere inside, possibly in a child or a descendant element. When + // passed a [string], matching is case-insensitive and searches for a substring. For example, `"Playwright"` matches + // `<article><div>Playwright</div></article>`. + HasText interface{} `json:"hasText"` +} + +type FramePressOptions struct { + // Time to wait between `keydown` and `keyup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You + // can opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as + // navigating to inaccessible pages. Defaults to `false`. + // + // Deprecated: This option will default to `true` in the future. + NoWaitAfter *bool `json:"noWaitAfter"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameQuerySelectorOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` +} + +type FrameSelectOptionOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameSetCheckedOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type FrameSetContentOptions struct { + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When to consider operation succeeded, defaults to `load`. Events can be either: + // - `domcontentloaded` - consider operation to be finished when the `DOMContentLoaded` event is fired. + // - `load` - consider operation to be finished when the `load` event is fired. + // - `networkidle` - **DISCOURAGED** consider operation to be finished when there are no network connections for + // at least `500` ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + // - `commit` - consider operation to be finished when network response is received and the document started + // loading. + WaitUntil *WaitUntilState `json:"waitUntil"` +} + +type FrameSetInputFilesOptions struct { + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameTapOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type FrameTextContentOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameTypeOptions struct { + // Time to wait between key presses in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameUncheckOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type FrameWaitForFunctionOptions struct { + // If “[object Object]” is `raf`, then “[object Object]” is constantly executed in `requestAnimationFrame` callback. + // If “[object Object]” is a number, then it is treated as an interval in milliseconds at which the function would be + // executed. Defaults to `raf`. + Polling interface{} `json:"polling"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameWaitForLoadStateOptions struct { + // Optional load state to wait for, defaults to `load`. If the state has been already reached while loading current + // document, the method resolves immediately. Can be one of: + // - `load` - wait for the `load` event to be fired. + // - `domcontentloaded` - wait for the `DOMContentLoaded` event to be fired. + // - `networkidle` - **DISCOURAGED** wait until there are no network connections for at least `500` ms. Don't use + // this method for testing, rely on web assertions to assess readiness instead. + State *LoadState `json:"state"` + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameExpectNavigationOptions struct { + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // A glob pattern, regex pattern or predicate receiving [URL] to match while waiting for the navigation. Note that if + // the parameter is a string without wildcard characters, the method will wait for navigation to URL that is exactly + // equal to the string. + URL interface{} `json:"url"` + // When to consider operation succeeded, defaults to `load`. Events can be either: + // - `domcontentloaded` - consider operation to be finished when the `DOMContentLoaded` event is fired. + // - `load` - consider operation to be finished when the `load` event is fired. + // - `networkidle` - **DISCOURAGED** consider operation to be finished when there are no network connections for + // at least `500` ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + // - `commit` - consider operation to be finished when network response is received and the document started + // loading. + WaitUntil *WaitUntilState `json:"waitUntil"` +} + +type FrameWaitForSelectorOptions struct { + // Defaults to `visible`. Can be either: + // - `attached` - wait for element to be present in DOM. + // - `detached` - wait for element to not be present in DOM. + // - `visible` - wait for element to have non-empty bounding box and no `visibility:hidden`. Note that element + // without any content or with `display:none` has an empty bounding box and is not considered visible. + // - `hidden` - wait for element to be either detached from DOM, or have an empty bounding box or + // `visibility:hidden`. This is opposite to the `visible` option. + State *WaitForSelectorState `json:"state"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type FrameWaitForURLOptions struct { + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When to consider operation succeeded, defaults to `load`. Events can be either: + // - `domcontentloaded` - consider operation to be finished when the `DOMContentLoaded` event is fired. + // - `load` - consider operation to be finished when the `load` event is fired. + // - `networkidle` - **DISCOURAGED** consider operation to be finished when there are no network connections for + // at least `500` ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + // - `commit` - consider operation to be finished when network response is received and the document started + // loading. + WaitUntil *WaitUntilState `json:"waitUntil"` +} + +type FrameLocatorGetByAltTextOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type FrameLocatorGetByLabelOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type FrameLocatorGetByPlaceholderOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type FrameLocatorGetByRoleOptions struct { + // An attribute that is usually set by `aria-checked` or native `<input type=checkbox>` controls. + // Learn more about [`aria-checked`]. + // + // [`aria-checked`]: https://www.w3.org/TR/wai-aria-1.2/#aria-checked + Checked *bool `json:"checked"` + // An attribute that is usually set by `aria-disabled` or `disabled`. + // **NOTE** Unlike most other attributes, `disabled` is inherited through the DOM hierarchy. Learn more about + // [`aria-disabled`]. + // + // [`aria-disabled`]: https://www.w3.org/TR/wai-aria-1.2/#aria-disabled + Disabled *bool `json:"disabled"` + // Whether “[object Object]” is matched exactly: case-sensitive and whole-string. Defaults to false. Ignored when + // “[object Object]” is a regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` + // An attribute that is usually set by `aria-expanded`. + // Learn more about [`aria-expanded`]. + // + // [`aria-expanded`]: https://www.w3.org/TR/wai-aria-1.2/#aria-expanded + Expanded *bool `json:"expanded"` + // Option that controls whether hidden elements are matched. By default, only non-hidden elements, as + // [defined by ARIA], are matched by role selector. + // Learn more about [`aria-hidden`]. + // + // [defined by ARIA]: https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion + // [`aria-hidden`]: https://www.w3.org/TR/wai-aria-1.2/#aria-hidden + IncludeHidden *bool `json:"includeHidden"` + // A number attribute that is usually present for roles `heading`, `listitem`, `row`, `treeitem`, with default values + // for `<h1>-<h6>` elements. + // Learn more about [`aria-level`]. + // + // [`aria-level`]: https://www.w3.org/TR/wai-aria-1.2/#aria-level + Level *int `json:"level"` + // Option to match the [accessible name]. By default, matching is + // case-insensitive and searches for a substring, use “[object Object]” to control this behavior. + // Learn more about [accessible name]. + // + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + Name interface{} `json:"name"` + // An attribute that is usually set by `aria-pressed`. + // Learn more about [`aria-pressed`]. + // + // [`aria-pressed`]: https://www.w3.org/TR/wai-aria-1.2/#aria-pressed + Pressed *bool `json:"pressed"` + // An attribute that is usually set by `aria-selected`. + // Learn more about [`aria-selected`]. + // + // [`aria-selected`]: https://www.w3.org/TR/wai-aria-1.2/#aria-selected + Selected *bool `json:"selected"` +} + +type FrameLocatorGetByTextOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type FrameLocatorGetByTitleOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type FrameLocatorLocatorOptions struct { + // Narrows down the results of the method to those which contain elements matching this relative locator. For example, + // `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`. + // Inner locator **must be relative** to the outer locator and is queried starting with the outer locator match, not + // the document root. For example, you can find `content` that has `div` in + // `<article><content><div>Playwright</div></content></article>`. However, looking for `content` that has `article + // div` will fail, because the inner locator must be relative and should not use any elements outside the `content`. + // Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s. + Has Locator `json:"has"` + // Matches elements that do not contain an element that matches an inner locator. Inner locator is queried against the + // outer one. For example, `article` that does not have `div` matches `<article><span>Playwright</span></article>`. + // Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s. + HasNot Locator `json:"hasNot"` + // Matches elements that do not contain specified text somewhere inside, possibly in a child or a descendant element. + // When passed a [string], matching is case-insensitive and searches for a substring. + HasNotText interface{} `json:"hasNotText"` + // Matches elements containing specified text somewhere inside, possibly in a child or a descendant element. When + // passed a [string], matching is case-insensitive and searches for a substring. For example, `"Playwright"` matches + // `<article><div>Playwright</div></article>`. + HasText interface{} `json:"hasText"` +} + +type KeyboardPressOptions struct { + // Time to wait between `keydown` and `keyup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` +} + +type KeyboardTypeOptions struct { + // Time to wait between key presses in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` +} + +type LocatorAriaSnapshotOptions struct { + // Generate symbolic reference for each element. One can use `aria-ref=<ref>` locator immediately after capturing the + // snapshot to perform actions on the element. + Ref *bool `json:"ref"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorBlurOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorBoundingBoxOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorCheckOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type LocatorClearOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorClickOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // defaults to 1. See [UIEvent.Detail]. + ClickCount *int `json:"clickCount"` + // Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You + // can opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as + // navigating to inaccessible pages. Defaults to `false`. + // + // Deprecated: This option will default to `true` in the future. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type LocatorDblclickOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type LocatorDispatchEventOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorDragToOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Clicks on the source element at this point relative to the top-left corner of the element's padding box. If not + // specified, some visible point of the element is used. + SourcePosition *Position `json:"sourcePosition"` + // Drops on the target element at this point relative to the top-left corner of the element's padding box. If not + // specified, some visible point of the element is used. + TargetPosition *Position `json:"targetPosition"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type LocatorElementHandleOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorEvaluateOptions struct { + // Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved, + // evaluation itself is not limited by the timeout. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + Timeout *float64 `json:"timeout"` +} + +type LocatorEvaluateHandleOptions struct { + // Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved, + // evaluation itself is not limited by the timeout. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + Timeout *float64 `json:"timeout"` +} + +type LocatorFillOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorFilterOptions struct { + // Narrows down the results of the method to those which contain elements matching this relative locator. For example, + // `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`. + // Inner locator **must be relative** to the outer locator and is queried starting with the outer locator match, not + // the document root. For example, you can find `content` that has `div` in + // `<article><content><div>Playwright</div></content></article>`. However, looking for `content` that has `article + // div` will fail, because the inner locator must be relative and should not use any elements outside the `content`. + // Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s. + Has Locator `json:"has"` + // Matches elements that do not contain an element that matches an inner locator. Inner locator is queried against the + // outer one. For example, `article` that does not have `div` matches `<article><span>Playwright</span></article>`. + // Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s. + HasNot Locator `json:"hasNot"` + // Matches elements that do not contain specified text somewhere inside, possibly in a child or a descendant element. + // When passed a [string], matching is case-insensitive and searches for a substring. + HasNotText interface{} `json:"hasNotText"` + // Matches elements containing specified text somewhere inside, possibly in a child or a descendant element. When + // passed a [string], matching is case-insensitive and searches for a substring. For example, `"Playwright"` matches + // `<article><div>Playwright</div></article>`. + HasText interface{} `json:"hasText"` + // Only matches visible or invisible elements. + Visible *bool `json:"visible"` +} + +type LocatorFocusOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorGetAttributeOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorGetByAltTextOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type LocatorGetByLabelOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type LocatorGetByPlaceholderOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type LocatorGetByRoleOptions struct { + // An attribute that is usually set by `aria-checked` or native `<input type=checkbox>` controls. + // Learn more about [`aria-checked`]. + // + // [`aria-checked`]: https://www.w3.org/TR/wai-aria-1.2/#aria-checked + Checked *bool `json:"checked"` + // An attribute that is usually set by `aria-disabled` or `disabled`. + // **NOTE** Unlike most other attributes, `disabled` is inherited through the DOM hierarchy. Learn more about + // [`aria-disabled`]. + // + // [`aria-disabled`]: https://www.w3.org/TR/wai-aria-1.2/#aria-disabled + Disabled *bool `json:"disabled"` + // Whether “[object Object]” is matched exactly: case-sensitive and whole-string. Defaults to false. Ignored when + // “[object Object]” is a regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` + // An attribute that is usually set by `aria-expanded`. + // Learn more about [`aria-expanded`]. + // + // [`aria-expanded`]: https://www.w3.org/TR/wai-aria-1.2/#aria-expanded + Expanded *bool `json:"expanded"` + // Option that controls whether hidden elements are matched. By default, only non-hidden elements, as + // [defined by ARIA], are matched by role selector. + // Learn more about [`aria-hidden`]. + // + // [defined by ARIA]: https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion + // [`aria-hidden`]: https://www.w3.org/TR/wai-aria-1.2/#aria-hidden + IncludeHidden *bool `json:"includeHidden"` + // A number attribute that is usually present for roles `heading`, `listitem`, `row`, `treeitem`, with default values + // for `<h1>-<h6>` elements. + // Learn more about [`aria-level`]. + // + // [`aria-level`]: https://www.w3.org/TR/wai-aria-1.2/#aria-level + Level *int `json:"level"` + // Option to match the [accessible name]. By default, matching is + // case-insensitive and searches for a substring, use “[object Object]” to control this behavior. + // Learn more about [accessible name]. + // + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + Name interface{} `json:"name"` + // An attribute that is usually set by `aria-pressed`. + // Learn more about [`aria-pressed`]. + // + // [`aria-pressed`]: https://www.w3.org/TR/wai-aria-1.2/#aria-pressed + Pressed *bool `json:"pressed"` + // An attribute that is usually set by `aria-selected`. + // Learn more about [`aria-selected`]. + // + // [`aria-selected`]: https://www.w3.org/TR/wai-aria-1.2/#aria-selected + Selected *bool `json:"selected"` +} + +type LocatorGetByTextOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type LocatorGetByTitleOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type LocatorHoverOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type LocatorInnerHTMLOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorInnerTextOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorInputValueOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorIsCheckedOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorIsDisabledOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorIsEditableOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorIsEnabledOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorIsHiddenOptions struct { + // + // Deprecated: This option is ignored. [Locator.IsHidden] does not wait for the element to become hidden and returns immediately. + Timeout *float64 `json:"timeout"` +} + +type LocatorIsVisibleOptions struct { + // + // Deprecated: This option is ignored. [Locator.IsVisible] does not wait for the element to become visible and returns immediately. + Timeout *float64 `json:"timeout"` +} + +type LocatorLocatorOptions struct { + // Narrows down the results of the method to those which contain elements matching this relative locator. For example, + // `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`. + // Inner locator **must be relative** to the outer locator and is queried starting with the outer locator match, not + // the document root. For example, you can find `content` that has `div` in + // `<article><content><div>Playwright</div></content></article>`. However, looking for `content` that has `article + // div` will fail, because the inner locator must be relative and should not use any elements outside the `content`. + // Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s. + Has Locator `json:"has"` + // Matches elements that do not contain an element that matches an inner locator. Inner locator is queried against the + // outer one. For example, `article` that does not have `div` matches `<article><span>Playwright</span></article>`. + // Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s. + HasNot Locator `json:"hasNot"` + // Matches elements that do not contain specified text somewhere inside, possibly in a child or a descendant element. + // When passed a [string], matching is case-insensitive and searches for a substring. + HasNotText interface{} `json:"hasNotText"` + // Matches elements containing specified text somewhere inside, possibly in a child or a descendant element. When + // passed a [string], matching is case-insensitive and searches for a substring. For example, `"Playwright"` matches + // `<article><div>Playwright</div></article>`. + HasText interface{} `json:"hasText"` +} + +type LocatorPressOptions struct { + // Time to wait between `keydown` and `keyup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You + // can opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as + // navigating to inaccessible pages. Defaults to `false`. + // + // Deprecated: This option will default to `true` in the future. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorPressSequentiallyOptions struct { + // Time to wait between key presses in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorScreenshotOptions struct { + // When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different + // treatment depending on their duration: + // - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + // - infinite animations are canceled to initial state, and then played over after the screenshot. + // Defaults to `"allow"` that leaves animations untouched. + Animations *ScreenshotAnimations `json:"animations"` + // When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`, text caret behavior will not be + // changed. Defaults to `"hide"`. + Caret *ScreenshotCaret `json:"caret"` + // Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink + // box `#FF00FF` (customized by “[object Object]”) that completely covers its bounding box. The mask is also applied + // to invisible elements, see [Matching only visible elements] to + // disable that. + // + // [Matching only visible elements]: https://playwright.dev/docs/locators#matching-only-visible-elements + Mask []Locator `json:"mask"` + // Specify the color of the overlay box for masked elements, in + // [CSS color format]. Default color is pink `#FF00FF`. + // + // [CSS color format]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value + MaskColor *string `json:"maskColor"` + // Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. + // Defaults to `false`. + OmitBackground *bool `json:"omitBackground"` + // The file path to save the image to. The screenshot type will be inferred from file extension. If “[object Object]” + // is a relative path, then it is resolved relative to the current working directory. If no path is provided, the + // image won't be saved to the disk. + Path *string `json:"path"` + // The quality of the image, between 0-100. Not applicable to `png` images. + Quality *int `json:"quality"` + // When set to `"css"`, screenshot will have a single pixel per each css pixel on the page. For high-dpi devices, this + // will keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so + // screenshots of high-dpi devices will be twice as large or even larger. + // Defaults to `"device"`. + Scale *ScreenshotScale `json:"scale"` + // Text of the stylesheet to apply while making the screenshot. This is where you can hide dynamic elements, make + // elements invisible or change their properties to help you creating repeatable screenshots. This stylesheet pierces + // the Shadow DOM and applies to the inner frames. + Style *string `json:"style"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // Specify screenshot type, defaults to `png`. + Type *ScreenshotType `json:"type"` +} + +type LocatorScrollIntoViewIfNeededOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorSelectOptionOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorSelectTextOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorSetCheckedOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type LocatorSetInputFilesOptions struct { + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorTapOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type LocatorTextContentOptions struct { + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorTypeOptions struct { + // Time to wait between key presses in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorUncheckOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type LocatorWaitForOptions struct { + // Defaults to `visible`. Can be either: + // - `attached` - wait for element to be present in DOM. + // - `detached` - wait for element to not be present in DOM. + // - `visible` - wait for element to have non-empty bounding box and no `visibility:hidden`. Note that element + // without any content or with `display:none` has an empty bounding box and is not considered visible. + // - `hidden` - wait for element to be either detached from DOM, or have an empty bounding box or + // `visibility:hidden`. This is opposite to the `visible` option. + State *WaitForSelectorState `json:"state"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToBeAttachedOptions struct { + Attached *bool `json:"attached"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToBeCheckedOptions struct { + // Provides state to assert for. Asserts for input to be checked by default. This option can't be used when + // “[object Object]” is set to true. + Checked *bool `json:"checked"` + // Asserts that the element is in the indeterminate (mixed) state. Only supported for checkboxes and radio buttons. + // This option can't be true when “[object Object]” is provided. + Indeterminate *bool `json:"indeterminate"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToBeDisabledOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToBeEditableOptions struct { + Editable *bool `json:"editable"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToBeEmptyOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToBeEnabledOptions struct { + Enabled *bool `json:"enabled"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToBeFocusedOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToBeHiddenOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToBeInViewportOptions struct { + // The minimal ratio of the element to intersect viewport. If equals to `0`, then element should intersect viewport at + // any positive ratio. Defaults to `0`. + Ratio *float64 `json:"ratio"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToBeVisibleOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` + Visible *bool `json:"visible"` +} + +type LocatorAssertionsToContainClassOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToContainTextOptions struct { + // Whether to perform case-insensitive match. “[object Object]” option takes precedence over the corresponding regular + // expression flag if specified. + IgnoreCase *bool `json:"ignoreCase"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` + // Whether to use `element.innerText` instead of `element.textContent` when retrieving DOM node text. + UseInnerText *bool `json:"useInnerText"` +} + +type LocatorAssertionsToHaveAccessibleDescriptionOptions struct { + // Whether to perform case-insensitive match. “[object Object]” option takes precedence over the corresponding regular + // expression flag if specified. + IgnoreCase *bool `json:"ignoreCase"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToHaveAccessibleErrorMessageOptions struct { + // Whether to perform case-insensitive match. “[object Object]” option takes precedence over the corresponding regular + // expression flag if specified. + IgnoreCase *bool `json:"ignoreCase"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToHaveAccessibleNameOptions struct { + // Whether to perform case-insensitive match. “[object Object]” option takes precedence over the corresponding regular + // expression flag if specified. + IgnoreCase *bool `json:"ignoreCase"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToHaveAttributeOptions struct { + // Whether to perform case-insensitive match. “[object Object]” option takes precedence over the corresponding regular + // expression flag if specified. + IgnoreCase *bool `json:"ignoreCase"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToHaveClassOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToHaveCountOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToHaveCSSOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToHaveIdOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToHaveJSPropertyOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToHaveRoleOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToHaveTextOptions struct { + // Whether to perform case-insensitive match. “[object Object]” option takes precedence over the corresponding regular + // expression flag if specified. + IgnoreCase *bool `json:"ignoreCase"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` + // Whether to use `element.innerText` instead of `element.textContent` when retrieving DOM node text. + UseInnerText *bool `json:"useInnerText"` +} + +type LocatorAssertionsToHaveValueOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToHaveValuesOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type LocatorAssertionsToMatchAriaSnapshotOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type MouseClickOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // defaults to 1. See [UIEvent.Detail]. + ClickCount *int `json:"clickCount"` + // Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` +} + +type MouseDblclickOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` +} + +type MouseDownOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // defaults to 1. See [UIEvent.Detail]. + ClickCount *int `json:"clickCount"` +} + +type MouseMoveOptions struct { + // Defaults to 1. Sends intermediate `mousemove` events. + Steps *int `json:"steps"` +} + +type MouseUpOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // defaults to 1. See [UIEvent.Detail]. + ClickCount *int `json:"clickCount"` +} + +type PageAddScriptTagOptions struct { + // Raw JavaScript content to be injected into frame. + Content *string `json:"content"` + // Path to the JavaScript file to be injected into frame. If `path` is a relative path, then it is resolved relative + // to the current working directory. + Path *string `json:"path"` + // Script type. Use 'module' in order to load a JavaScript ES6 module. See + // [script] for more details. + // + // [script]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script + Type *string `json:"type"` + // URL of a script to be added. + URL *string `json:"url"` +} + +type PageAddStyleTagOptions struct { + // Raw CSS content to be injected into frame. + Content *string `json:"content"` + // Path to the CSS file to be injected into frame. If `path` is a relative path, then it is resolved relative to the + // current working directory. + Path *string `json:"path"` + // URL of the `<link>` tag. + URL *string `json:"url"` +} + +type PageCheckOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type PageClickOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // defaults to 1. See [UIEvent.Detail]. + ClickCount *int `json:"clickCount"` + // Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You + // can opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as + // navigating to inaccessible pages. Defaults to `false`. + // + // Deprecated: This option will default to `true` in the future. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type PageCloseOptions struct { + // The reason to be reported to the operations interrupted by the page closure. + Reason *string `json:"reason"` + // Defaults to `false`. Whether to run the + // [before unload] page handlers. + // + // [before unload]: https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload + RunBeforeUnload *bool `json:"runBeforeUnload"` +} + +type PageDblclickOptions struct { + // Defaults to `left`. + Button *MouseButton `json:"button"` + // Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type PageDispatchEventOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageDragAndDropOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // Clicks on the source element at this point relative to the top-left corner of the element's padding box. If not + // specified, some visible point of the element is used. + SourcePosition *Position `json:"sourcePosition"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Drops on the target element at this point relative to the top-left corner of the element's padding box. If not + // specified, some visible point of the element is used. + TargetPosition *Position `json:"targetPosition"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type PageEmulateMediaOptions struct { + // Emulates [prefers-colors-scheme] + // media feature, supported values are `light` and `dark`. Passing `no-override` disables color scheme + // emulation. `no-preference` is deprecated. + // + // [prefers-colors-scheme]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme + ColorScheme *ColorScheme `json:"colorScheme"` + // Emulates `prefers-contrast` media feature, supported values are `no-preference`, `more`. Passing + // `no-override` disables contrast emulation. + Contrast *Contrast `json:"contrast"` + // Emulates `forced-colors` media feature, supported values are `active` and `none`. Passing `no-override` + // disables forced colors emulation. + ForcedColors *ForcedColors `json:"forcedColors"` + // Changes the CSS media type of the page. The only allowed values are `screen`, `print` and `no-override`. + // Passing `no-override` disables CSS media emulation. + Media *Media `json:"media"` + // Emulates `prefers-reduced-motion` media feature, supported values are `reduce`, `no-preference`. Passing + // `no-override` disables reduced motion emulation. + ReducedMotion *ReducedMotion `json:"reducedMotion"` +} + +type PageEvalOnSelectorOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` +} + +type PageFillOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageFocusOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageFrameOptions struct { + // Frame name specified in the `iframe`'s `name` attribute. Optional. + Name *string `json:"name"` + // A glob pattern, regex pattern or predicate receiving frame's `url` as a [URL] object. Optional. + URL interface{} `json:"url"` +} + +type PageGetAttributeOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageGetByAltTextOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type PageGetByLabelOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type PageGetByPlaceholderOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type PageGetByRoleOptions struct { + // An attribute that is usually set by `aria-checked` or native `<input type=checkbox>` controls. + // Learn more about [`aria-checked`]. + // + // [`aria-checked`]: https://www.w3.org/TR/wai-aria-1.2/#aria-checked + Checked *bool `json:"checked"` + // An attribute that is usually set by `aria-disabled` or `disabled`. + // **NOTE** Unlike most other attributes, `disabled` is inherited through the DOM hierarchy. Learn more about + // [`aria-disabled`]. + // + // [`aria-disabled`]: https://www.w3.org/TR/wai-aria-1.2/#aria-disabled + Disabled *bool `json:"disabled"` + // Whether “[object Object]” is matched exactly: case-sensitive and whole-string. Defaults to false. Ignored when + // “[object Object]” is a regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` + // An attribute that is usually set by `aria-expanded`. + // Learn more about [`aria-expanded`]. + // + // [`aria-expanded`]: https://www.w3.org/TR/wai-aria-1.2/#aria-expanded + Expanded *bool `json:"expanded"` + // Option that controls whether hidden elements are matched. By default, only non-hidden elements, as + // [defined by ARIA], are matched by role selector. + // Learn more about [`aria-hidden`]. + // + // [defined by ARIA]: https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion + // [`aria-hidden`]: https://www.w3.org/TR/wai-aria-1.2/#aria-hidden + IncludeHidden *bool `json:"includeHidden"` + // A number attribute that is usually present for roles `heading`, `listitem`, `row`, `treeitem`, with default values + // for `<h1>-<h6>` elements. + // Learn more about [`aria-level`]. + // + // [`aria-level`]: https://www.w3.org/TR/wai-aria-1.2/#aria-level + Level *int `json:"level"` + // Option to match the [accessible name]. By default, matching is + // case-insensitive and searches for a substring, use “[object Object]” to control this behavior. + // Learn more about [accessible name]. + // + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + // [accessible name]: https://w3c.github.io/accname/#dfn-accessible-name + Name interface{} `json:"name"` + // An attribute that is usually set by `aria-pressed`. + // Learn more about [`aria-pressed`]. + // + // [`aria-pressed`]: https://www.w3.org/TR/wai-aria-1.2/#aria-pressed + Pressed *bool `json:"pressed"` + // An attribute that is usually set by `aria-selected`. + // Learn more about [`aria-selected`]. + // + // [`aria-selected`]: https://www.w3.org/TR/wai-aria-1.2/#aria-selected + Selected *bool `json:"selected"` +} + +type PageGetByTextOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type PageGetByTitleOptions struct { + // Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a + // regular expression. Note that exact match still trims whitespace. + Exact *bool `json:"exact"` +} + +type PageGoBackOptions struct { + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When to consider operation succeeded, defaults to `load`. Events can be either: + // - `domcontentloaded` - consider operation to be finished when the `DOMContentLoaded` event is fired. + // - `load` - consider operation to be finished when the `load` event is fired. + // - `networkidle` - **DISCOURAGED** consider operation to be finished when there are no network connections for + // at least `500` ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + // - `commit` - consider operation to be finished when network response is received and the document started + // loading. + WaitUntil *WaitUntilState `json:"waitUntil"` +} + +type PageGoForwardOptions struct { + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When to consider operation succeeded, defaults to `load`. Events can be either: + // - `domcontentloaded` - consider operation to be finished when the `DOMContentLoaded` event is fired. + // - `load` - consider operation to be finished when the `load` event is fired. + // - `networkidle` - **DISCOURAGED** consider operation to be finished when there are no network connections for + // at least `500` ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + // - `commit` - consider operation to be finished when network response is received and the document started + // loading. + WaitUntil *WaitUntilState `json:"waitUntil"` +} + +type PageGotoOptions struct { + // Referer header value. If provided it will take preference over the referer header value set by + // [Page.SetExtraHTTPHeaders]. + Referer *string `json:"referer"` + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When to consider operation succeeded, defaults to `load`. Events can be either: + // - `domcontentloaded` - consider operation to be finished when the `DOMContentLoaded` event is fired. + // - `load` - consider operation to be finished when the `load` event is fired. + // - `networkidle` - **DISCOURAGED** consider operation to be finished when there are no network connections for + // at least `500` ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + // - `commit` - consider operation to be finished when network response is received and the document started + // loading. + WaitUntil *WaitUntilState `json:"waitUntil"` +} + +type PageHoverOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type PageInnerHTMLOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageInnerTextOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageInputValueOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageIsCheckedOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageIsDisabledOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageIsEditableOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageIsEnabledOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageIsHiddenOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // + // Deprecated: This option is ignored. [Page.IsHidden] does not wait for the element to become hidden and returns immediately. + Timeout *float64 `json:"timeout"` +} + +type PageIsVisibleOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // + // Deprecated: This option is ignored. [Page.IsVisible] does not wait for the element to become visible and returns immediately. + Timeout *float64 `json:"timeout"` +} + +type PageLocatorOptions struct { + // Narrows down the results of the method to those which contain elements matching this relative locator. For example, + // `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`. + // Inner locator **must be relative** to the outer locator and is queried starting with the outer locator match, not + // the document root. For example, you can find `content` that has `div` in + // `<article><content><div>Playwright</div></content></article>`. However, looking for `content` that has `article + // div` will fail, because the inner locator must be relative and should not use any elements outside the `content`. + // Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s. + Has Locator `json:"has"` + // Matches elements that do not contain an element that matches an inner locator. Inner locator is queried against the + // outer one. For example, `article` that does not have `div` matches `<article><span>Playwright</span></article>`. + // Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s. + HasNot Locator `json:"hasNot"` + // Matches elements that do not contain specified text somewhere inside, possibly in a child or a descendant element. + // When passed a [string], matching is case-insensitive and searches for a substring. + HasNotText interface{} `json:"hasNotText"` + // Matches elements containing specified text somewhere inside, possibly in a child or a descendant element. When + // passed a [string], matching is case-insensitive and searches for a substring. For example, `"Playwright"` matches + // `<article><div>Playwright</div></article>`. + HasText interface{} `json:"hasText"` +} + +type PagePdfOptions struct { + // Display header and footer. Defaults to `false`. + DisplayHeaderFooter *bool `json:"displayHeaderFooter"` + // HTML template for the print footer. Should use the same format as the “[object Object]”. + FooterTemplate *string `json:"footerTemplate"` + // Paper format. If set, takes priority over “[object Object]” or “[object Object]” options. Defaults to 'Letter'. + Format *string `json:"format"` + // HTML template for the print header. Should be valid HTML markup with following classes used to inject printing + // values into them: + // - `date` formatted print date + // - `title` document title + // - `url` document location + // - `pageNumber` current page number + // - `totalPages` total pages in the document + HeaderTemplate *string `json:"headerTemplate"` + // Paper height, accepts values labeled with units. + Height *string `json:"height"` + // Paper orientation. Defaults to `false`. + Landscape *bool `json:"landscape"` + // Paper margins, defaults to none. + Margin *Margin `json:"margin"` + // Whether or not to embed the document outline into the PDF. Defaults to `false`. + Outline *bool `json:"outline"` + // Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. + PageRanges *string `json:"pageRanges"` + // The file path to save the PDF to. If “[object Object]” is a relative path, then it is resolved relative to the + // current working directory. If no path is provided, the PDF won't be saved to the disk. + Path *string `json:"path"` + // Give any CSS `@page` size declared in the page priority over what is declared in “[object Object]” and + // “[object Object]” or “[object Object]” options. Defaults to `false`, which will scale the content to fit the paper + // size. + PreferCSSPageSize *bool `json:"preferCSSPageSize"` + // Print background graphics. Defaults to `false`. + PrintBackground *bool `json:"printBackground"` + // Scale of the webpage rendering. Defaults to `1`. Scale amount must be between 0.1 and 2. + Scale *float64 `json:"scale"` + // Whether or not to generate tagged (accessible) PDF. Defaults to `false`. + Tagged *bool `json:"tagged"` + // Paper width, accepts values labeled with units. + Width *string `json:"width"` +} + +type PagePressOptions struct { + // Time to wait between `keydown` and `keyup` in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You + // can opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as + // navigating to inaccessible pages. Defaults to `false`. + // + // Deprecated: This option will default to `true` in the future. + NoWaitAfter *bool `json:"noWaitAfter"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageQuerySelectorOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` +} + +type PageAddLocatorHandlerOptions struct { + // By default, after calling the handler Playwright will wait until the overlay becomes hidden, and only then + // Playwright will continue with the action/assertion that triggered the handler. This option allows to opt-out of + // this behavior, so that overlay can stay visible after the handler has run. + NoWaitAfter *bool `json:"noWaitAfter"` + // Specifies the maximum number of times this handler should be called. Unlimited by default. + Times *int `json:"times"` +} + +type PageReloadOptions struct { + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When to consider operation succeeded, defaults to `load`. Events can be either: + // - `domcontentloaded` - consider operation to be finished when the `DOMContentLoaded` event is fired. + // - `load` - consider operation to be finished when the `load` event is fired. + // - `networkidle` - **DISCOURAGED** consider operation to be finished when there are no network connections for + // at least `500` ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + // - `commit` - consider operation to be finished when network response is received and the document started + // loading. + WaitUntil *WaitUntilState `json:"waitUntil"` +} + +type PageRouteFromHAROptions struct { + // - If set to 'abort' any request not found in the HAR file will be aborted. + // - If set to 'fallback' missing requests will be sent to the network. + // Defaults to abort. + NotFound *HarNotFound `json:"notFound"` + // If specified, updates the given HAR with the actual network information instead of serving from file. The file is + // written to disk when [BrowserContext.Close] is called. + Update *bool `json:"update"` + // Optional setting to control resource content management. If `attach` is specified, resources are persisted as + // separate files or entries in the ZIP archive. If `embed` is specified, content is stored inline the HAR file. + UpdateContent *RouteFromHarUpdateContentPolicy `json:"updateContent"` + // When set to `minimal`, only record information necessary for routing from HAR. This omits sizes, timing, page, + // cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to + // `minimal`. + UpdateMode *HarMode `json:"updateMode"` + // A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the + // pattern will be served from the HAR file. If not specified, all requests are served from the HAR file. + URL interface{} `json:"url"` +} + +type PageScreenshotOptions struct { + // When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different + // treatment depending on their duration: + // - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + // - infinite animations are canceled to initial state, and then played over after the screenshot. + // Defaults to `"allow"` that leaves animations untouched. + Animations *ScreenshotAnimations `json:"animations"` + // When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`, text caret behavior will not be + // changed. Defaults to `"hide"`. + Caret *ScreenshotCaret `json:"caret"` + // An object which specifies clipping of the resulting image. + Clip *Rect `json:"clip"` + // When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Defaults to + // `false`. + FullPage *bool `json:"fullPage"` + // Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink + // box `#FF00FF` (customized by “[object Object]”) that completely covers its bounding box. The mask is also applied + // to invisible elements, see [Matching only visible elements] to + // disable that. + // + // [Matching only visible elements]: https://playwright.dev/docs/locators#matching-only-visible-elements + Mask []Locator `json:"mask"` + // Specify the color of the overlay box for masked elements, in + // [CSS color format]. Default color is pink `#FF00FF`. + // + // [CSS color format]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value + MaskColor *string `json:"maskColor"` + // Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. + // Defaults to `false`. + OmitBackground *bool `json:"omitBackground"` + // The file path to save the image to. The screenshot type will be inferred from file extension. If “[object Object]” + // is a relative path, then it is resolved relative to the current working directory. If no path is provided, the + // image won't be saved to the disk. + Path *string `json:"path"` + // The quality of the image, between 0-100. Not applicable to `png` images. + Quality *int `json:"quality"` + // When set to `"css"`, screenshot will have a single pixel per each css pixel on the page. For high-dpi devices, this + // will keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so + // screenshots of high-dpi devices will be twice as large or even larger. + // Defaults to `"device"`. + Scale *ScreenshotScale `json:"scale"` + // Text of the stylesheet to apply while making the screenshot. This is where you can hide dynamic elements, make + // elements invisible or change their properties to help you creating repeatable screenshots. This stylesheet pierces + // the Shadow DOM and applies to the inner frames. + Style *string `json:"style"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // Specify screenshot type, defaults to `png`. + Type *ScreenshotType `json:"type"` +} + +type PageSelectOptionOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageSetCheckedOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type PageSetContentOptions struct { + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When to consider operation succeeded, defaults to `load`. Events can be either: + // - `domcontentloaded` - consider operation to be finished when the `DOMContentLoaded` event is fired. + // - `load` - consider operation to be finished when the `load` event is fired. + // - `networkidle` - **DISCOURAGED** consider operation to be finished when there are no network connections for + // at least `500` ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + // - `commit` - consider operation to be finished when network response is received and the document started + // loading. + WaitUntil *WaitUntilState `json:"waitUntil"` +} + +type PageSetInputFilesOptions struct { + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageTapOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores + // current modifiers back. If not specified, currently pressed modifiers are used. "ControlOrMeta" resolves to + // "Control" on Windows and Linux and to "Meta" on macOS. + Modifiers []KeyboardModifier `json:"modifiers"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. Note that keyboard + // `modifiers` will be pressed regardless of `trial` to allow testing elements which are only visible when those keys + // are pressed. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type PageTextContentOptions struct { + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageTypeOptions struct { + // Time to wait between key presses in milliseconds. Defaults to 0. + Delay *float64 `json:"delay"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageUncheckOptions struct { + // Whether to bypass the [actionability] checks. Defaults to `false`. + // + // [actionability]: https://playwright.dev/docs/actionability + Force *bool `json:"force"` + // This option has no effect. + // + // Deprecated: This option has no effect. + NoWaitAfter *bool `json:"noWaitAfter"` + // A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of + // the element. + Position *Position `json:"position"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When set, this method only performs the [actionability] checks and skips the action. Defaults + // to `false`. Useful to wait until the element is ready for the action without performing it. + // + // [actionability]: https://playwright.dev/docs/actionability + Trial *bool `json:"trial"` +} + +type PageUnrouteAllOptions struct { + // Specifies whether to wait for already running handlers and what to do if they throw errors: + // - `default` - do not wait for current handler calls (if any) to finish, if unrouted handler throws, it may + // result in unhandled error + // - `wait` - wait for current handler calls (if any) to finish + // - `ignoreErrors` - do not wait for current handler calls (if any) to finish, all errors thrown by the handlers + // after unrouting are silently caught + Behavior *UnrouteBehavior `json:"behavior"` +} + +type Size struct { + // page width in pixels. + Width int `json:"width"` + // page height in pixels. + Height int `json:"height"` +} + +type PageExpectConsoleMessageOptions struct { + // Receives the [ConsoleMessage] object and resolves to truthy value when the waiting should resolve. + Predicate func(ConsoleMessage) bool `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type PageExpectDownloadOptions struct { + // Receives the [Download] object and resolves to truthy value when the waiting should resolve. + Predicate func(Download) bool `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type PageExpectEventOptions struct { + // Receives the event data and resolves to truthy value when the waiting should resolve. + Predicate interface{} `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type PageExpectFileChooserOptions struct { + // Receives the [FileChooser] object and resolves to truthy value when the waiting should resolve. + Predicate func(FileChooser) bool `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type PageWaitForFunctionOptions struct { + // If “[object Object]” is `raf`, then “[object Object]” is constantly executed in `requestAnimationFrame` callback. + // If “[object Object]” is a number, then it is treated as an interval in milliseconds at which the function would be + // executed. Defaults to `raf`. + Polling interface{} `json:"polling"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageWaitForLoadStateOptions struct { + // Optional load state to wait for, defaults to `load`. If the state has been already reached while loading current + // document, the method resolves immediately. Can be one of: + // - `load` - wait for the `load` event to be fired. + // - `domcontentloaded` - wait for the `DOMContentLoaded` event to be fired. + // - `networkidle` - **DISCOURAGED** wait until there are no network connections for at least `500` ms. Don't use + // this method for testing, rely on web assertions to assess readiness instead. + State *LoadState `json:"state"` + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageExpectNavigationOptions struct { + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // A glob pattern, regex pattern or predicate receiving [URL] to match while waiting for the navigation. Note that if + // the parameter is a string without wildcard characters, the method will wait for navigation to URL that is exactly + // equal to the string. + URL interface{} `json:"url"` + // When to consider operation succeeded, defaults to `load`. Events can be either: + // - `domcontentloaded` - consider operation to be finished when the `DOMContentLoaded` event is fired. + // - `load` - consider operation to be finished when the `load` event is fired. + // - `networkidle` - **DISCOURAGED** consider operation to be finished when there are no network connections for + // at least `500` ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + // - `commit` - consider operation to be finished when network response is received and the document started + // loading. + WaitUntil *WaitUntilState `json:"waitUntil"` +} + +type PageExpectPopupOptions struct { + // Receives the [Page] object and resolves to truthy value when the waiting should resolve. + Predicate func(Page) bool `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type PageExpectRequestOptions struct { + // Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to disable the timeout. The default value can + // be changed by using the [Page.SetDefaultTimeout] method. + Timeout *float64 `json:"timeout"` +} + +type PageExpectRequestFinishedOptions struct { + // Receives the [Request] object and resolves to truthy value when the waiting should resolve. + Predicate func(Request) bool `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type PageExpectResponseOptions struct { + // Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to disable the timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageWaitForSelectorOptions struct { + // Defaults to `visible`. Can be either: + // - `attached` - wait for element to be present in DOM. + // - `detached` - wait for element to not be present in DOM. + // - `visible` - wait for element to have non-empty bounding box and no `visibility:hidden`. Note that element + // without any content or with `display:none` has an empty bounding box and is not considered visible. + // - `hidden` - wait for element to be either detached from DOM, or have an empty bounding box or + // `visibility:hidden`. This is opposite to the `visible` option. + State *WaitForSelectorState `json:"state"` + // When true, the call requires selector to resolve to a single element. If given selector resolves to more than one + // element, the call throws an exception. + Strict *bool `json:"strict"` + // Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` +} + +type PageWaitForURLOptions struct { + // Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can + // be changed by using the [BrowserContext.SetDefaultNavigationTimeout], [BrowserContext.SetDefaultTimeout], + // [Page.SetDefaultNavigationTimeout] or [Page.SetDefaultTimeout] methods. + Timeout *float64 `json:"timeout"` + // When to consider operation succeeded, defaults to `load`. Events can be either: + // - `domcontentloaded` - consider operation to be finished when the `DOMContentLoaded` event is fired. + // - `load` - consider operation to be finished when the `load` event is fired. + // - `networkidle` - **DISCOURAGED** consider operation to be finished when there are no network connections for + // at least `500` ms. Don't use this method for testing, rely on web assertions to assess readiness instead. + // - `commit` - consider operation to be finished when network response is received and the document started + // loading. + WaitUntil *WaitUntilState `json:"waitUntil"` +} + +type PageExpectWebSocketOptions struct { + // Receives the [WebSocket] object and resolves to truthy value when the waiting should resolve. + Predicate func(WebSocket) bool `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type PageExpectWorkerOptions struct { + // Receives the [Worker] object and resolves to truthy value when the waiting should resolve. + Predicate func(Worker) bool `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type PageWaitForEventOptions struct { + // Receives the event data and resolves to truthy value when the waiting should resolve. + Predicate interface{} `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type PageAssertionsToHaveTitleOptions struct { + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type PageAssertionsToHaveURLOptions struct { + // Whether to perform case-insensitive match. “[object Object]” option takes precedence over the corresponding regular + // expression parameter if specified. A provided predicate ignores this flag. + IgnoreCase *bool `json:"ignoreCase"` + // Time to retry the assertion for in milliseconds. Defaults to `5000`. + Timeout *float64 `json:"timeout"` +} + +type RequestSizesResult struct { + // Size of the request body (POST data payload) in bytes. Set to 0 if there was no body. + RequestBodySize int `json:"requestBodySize"` + // Total number of bytes from the start of the HTTP request message until (and including) the double CRLF before the + // body. + RequestHeadersSize int `json:"requestHeadersSize"` + // Size of the received response body (encoded) in bytes. + ResponseBodySize int `json:"responseBodySize"` + // Total number of bytes from the start of the HTTP response message until (and including) the double CRLF before the + // body. + ResponseHeadersSize int `json:"responseHeadersSize"` +} + +type RequestTiming struct { + // Request start time in milliseconds elapsed since January 1, 1970 00:00:00 UTC + StartTime float64 `json:"startTime"` + // Time immediately before the browser starts the domain name lookup for the resource. The value is given in + // milliseconds relative to `startTime`, -1 if not available. + DomainLookupStart float64 `json:"domainLookupStart"` + // Time immediately after the browser starts the domain name lookup for the resource. The value is given in + // milliseconds relative to `startTime`, -1 if not available. + DomainLookupEnd float64 `json:"domainLookupEnd"` + // Time immediately before the user agent starts establishing the connection to the server to retrieve the resource. + // The value is given in milliseconds relative to `startTime`, -1 if not available. + ConnectStart float64 `json:"connectStart"` + // Time immediately before the browser starts the handshake process to secure the current connection. The value is + // given in milliseconds relative to `startTime`, -1 if not available. + SecureConnectionStart float64 `json:"secureConnectionStart"` + // Time immediately before the user agent starts establishing the connection to the server to retrieve the resource. + // The value is given in milliseconds relative to `startTime`, -1 if not available. + ConnectEnd float64 `json:"connectEnd"` + // Time immediately before the browser starts requesting the resource from the server, cache, or local resource. The + // value is given in milliseconds relative to `startTime`, -1 if not available. + RequestStart float64 `json:"requestStart"` + // Time immediately after the browser receives the first byte of the response from the server, cache, or local + // resource. The value is given in milliseconds relative to `startTime`, -1 if not available. + ResponseStart float64 `json:"responseStart"` + // Time immediately after the browser receives the last byte of the resource or immediately before the transport + // connection is closed, whichever comes first. The value is given in milliseconds relative to `startTime`, -1 if not + // available. + ResponseEnd float64 `json:"responseEnd"` +} + +type ResponseSecurityDetailsResult struct { + // Common Name component of the Issuer field. from the certificate. This should only be used for informational + // purposes. Optional. + Issuer *string `json:"issuer"` + // The specific TLS protocol used. (e.g. `TLS 1.3`). Optional. + Protocol *string `json:"protocol"` + // Common Name component of the Subject field from the certificate. This should only be used for informational + // purposes. Optional. + SubjectName *string `json:"subjectName"` + // Unix timestamp (in seconds) specifying when this cert becomes valid. Optional. + ValidFrom *float64 `json:"validFrom"` + // Unix timestamp (in seconds) specifying when this cert becomes invalid. Optional. + ValidTo *float64 `json:"validTo"` +} + +type ResponseServerAddrResult struct { + // IPv4 or IPV6 address of the server. + IpAddress string `json:"ipAddress"` + Port int `json:"port"` +} + +type RouteContinueOptions struct { + // If set changes the request HTTP headers. Header values will be converted to a string. + Headers map[string]string `json:"headers"` + // If set changes the request method (e.g. GET or POST). + Method *string `json:"method"` + // If set changes the post data of request. + PostData interface{} `json:"postData"` + // If set changes the request URL. New URL must have same protocol as original one. + URL *string `json:"url"` +} + +type RouteFallbackOptions struct { + // If set changes the request HTTP headers. Header values will be converted to a string. + Headers map[string]string `json:"headers"` + // If set changes the request method (e.g. GET or POST). + Method *string `json:"method"` + // If set changes the post data of request. + PostData interface{} `json:"postData"` + // If set changes the request URL. New URL must have same protocol as original one. Changing the URL won't affect the + // route matching, all the routes are matched using the original request URL. + URL *string `json:"url"` +} + +type RouteFetchOptions struct { + // If set changes the request HTTP headers. Header values will be converted to a string. + Headers map[string]string `json:"headers"` + // Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + // exceeded. Defaults to `20`. Pass `0` to not follow redirects. + MaxRedirects *int `json:"maxRedirects"` + // Maximum number of times network errors should be retried. Currently only `ECONNRESET` error is retried. Does not + // retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to `0` - no retries. + MaxRetries *int `json:"maxRetries"` + // If set changes the request method (e.g. GET or POST). + Method *string `json:"method"` + // If set changes the post data of request. + PostData interface{} `json:"postData"` + // Request timeout in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. + Timeout *float64 `json:"timeout"` + // If set changes the request URL. New URL must have same protocol as original one. + URL *string `json:"url"` +} + +type RouteFulfillOptions struct { + // Response body. + Body interface{} `json:"body"` + // If set, equals to setting `Content-Type` response header. + ContentType *string `json:"contentType"` + // Response headers. Header values will be converted to a string. + Headers map[string]string `json:"headers"` + // File path to respond with. The content type will be inferred from file extension. If `path` is a relative path, + // then it is resolved relative to the current working directory. + Path *string `json:"path"` + // [APIResponse] to fulfill route's request with. Individual fields of the response (such as headers) can be + // overridden using fulfill options. + Response APIResponse `json:"response"` + // Response status code, defaults to `200`. + Status *int `json:"status"` +} + +type SelectorsRegisterOptions struct { + // Whether to run this selector engine in isolated JavaScript environment. This environment has access to the same + // DOM, but not any JavaScript objects from the frame's scripts. Defaults to `false`. Note that running as a content + // script is not guaranteed when this engine is used together with other registered engines. + ContentScript *bool `json:"contentScript"` +} + +type TracingStartOptions struct { + // If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the + // “[object Object]” directory specified in [BrowserType.Launch]. To specify the final trace zip file name, you need + // to pass `path` option to [Tracing.Stop] instead. + Name *string `json:"name"` + // Whether to capture screenshots during tracing. Screenshots are used to build a timeline preview. + Screenshots *bool `json:"screenshots"` + // If this option is true tracing will + // - capture DOM snapshot on every action + // - record network activity + Snapshots *bool `json:"snapshots"` + // Whether to include source files for trace actions. + Sources *bool `json:"sources"` + // Trace name to be shown in the Trace Viewer. + Title *string `json:"title"` +} + +type TracingStartChunkOptions struct { + // If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the + // “[object Object]” directory specified in [BrowserType.Launch]. To specify the final trace zip file name, you need + // to pass `path` option to [Tracing.StopChunk] instead. + Name *string `json:"name"` + // Trace name to be shown in the Trace Viewer. + Title *string `json:"title"` +} + +type TracingGroupOptions struct { + // Specifies a custom location for the group to be shown in the trace viewer. Defaults to the location of the + // [Tracing.Group] call. + Location *TracingGroupOptionsLocation `json:"location"` +} + +type WebSocketExpectEventOptions struct { + // Receives the event data and resolves to truthy value when the waiting should resolve. + Predicate interface{} `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type WebSocketWaitForEventOptions struct { + // Receives the event data and resolves to truthy value when the waiting should resolve. + Predicate interface{} `json:"predicate"` + // Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The + // default value can be changed by using the [BrowserContext.SetDefaultTimeout]. + Timeout *float64 `json:"timeout"` +} + +type WebSocketRouteCloseOptions struct { + // Optional [close code]. + // + // [close code]: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#code + Code *int `json:"code"` + // Optional [close reason]. + // + // [close reason]: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#reason + Reason *string `json:"reason"` +} + +type ClientCertificate struct { + // Exact origin that the certificate is valid for. Origin includes `https` protocol, a hostname and optionally a port. + Origin string `json:"origin"` + // Path to the file with the certificate in PEM format. + CertPath *string `json:"certPath"` + // Direct value of the certificate in PEM format. + Cert []byte `json:"cert"` + // Path to the file with the private key in PEM format. + KeyPath *string `json:"keyPath"` + // Direct value of the private key in PEM format. + Key []byte `json:"key"` + // Path to the PFX or PKCS12 encoded private key and certificate chain. + PfxPath *string `json:"pfxPath"` + // Direct value of the PFX or PKCS12 encoded private key and certificate chain. + Pfx []byte `json:"pfx"` + // Passphrase for the private key (PEM or PFX). + Passphrase *string `json:"passphrase"` +} + +type HttpCredentials struct { + Username string `json:"username"` + Password string `json:"password"` + // Restrain sending http credentials on specific origin (scheme://host:port). + Origin *string `json:"origin"` + // This option only applies to the requests sent from corresponding [APIRequestContext] and does not affect requests + // sent from the browser. `always` - `Authorization` header with basic authentication credentials will be sent with + // the each API request. `'unauthorized` - the credentials are only sent when 401 (Unauthorized) response with + // `WWW-Authenticate` header is received. Defaults to `unauthorized`. + Send *HttpCredentialsSend `json:"send"` +} + +type Proxy struct { + // Proxy to be used for all requests. HTTP and SOCKS proxies are supported, for example `http://myproxy.com:3128` or + // `socks5://myproxy.com:3128`. Short form `myproxy.com:3128` is considered an HTTP proxy. + Server string `json:"server"` + // Optional comma-separated domains to bypass proxy, for example `".com, chromium.org, .domain.com"`. + Bypass *string `json:"bypass"` + // Optional username to use if HTTP proxy requires authentication. + Username *string `json:"username"` + // Optional password to use if HTTP proxy requires authentication. + Password *string `json:"password"` +} + +type Origin struct { + Origin string `json:"origin"` + LocalStorage []NameValue `json:"localStorage"` +} + +type RecordVideo struct { + // Path to the directory to put videos into. + Dir string `json:"dir"` + // Optional dimensions of the recorded videos. If not specified the size will be equal to `viewport` scaled down to + // fit into 800x800. If `viewport` is not configured explicitly the video size defaults to 800x450. Actual picture of + // each page will be scaled down if necessary to fit the specified size. + Size *Size `json:"size"` +} + +type OptionalStorageState struct { + // Cookies to set for context + Cookies []OptionalCookie `json:"cookies"` + // localStorage to set for context + Origins []Origin `json:"origins"` +} + +type Position struct { + X float64 `json:"x"` + Y float64 `json:"y"` +} + +type Margin struct { + // Top margin, accepts values labeled with units. Defaults to `0`. + Top *string `json:"top"` + // Right margin, accepts values labeled with units. Defaults to `0`. + Right *string `json:"right"` + // Bottom margin, accepts values labeled with units. Defaults to `0`. + Bottom *string `json:"bottom"` + // Left margin, accepts values labeled with units. Defaults to `0`. + Left *string `json:"left"` +} + +type TracingGroupOptionsLocation struct { + File string `json:"file"` + Line *int `json:"line"` + Column *int `json:"column"` +} diff --git a/vendor/github.com/playwright-community/playwright-go/glob.go b/vendor/github.com/playwright-community/playwright-go/glob.go new file mode 100644 index 0000000..77deba3 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/glob.go @@ -0,0 +1,170 @@ +package playwright + +import ( + "net/url" + "regexp" + "strconv" + "strings" +) + +var escapedChars = map[rune]bool{ + '$': true, + '^': true, + '+': true, + '.': true, + '*': true, + '(': true, + ')': true, + '|': true, + '\\': true, + '?': true, + '{': true, + '}': true, + '[': true, + ']': true, +} + +func globMustToRegex(glob string) *regexp.Regexp { + tokens := []string{"^"} + inGroup := false + + for i := 0; i < len(glob); i++ { + c := rune(glob[i]) + if c == '\\' && i+1 < len(glob) { + char := rune(glob[i+1]) + if _, ok := escapedChars[char]; ok { + tokens = append(tokens, "\\"+string(char)) + } else { + tokens = append(tokens, string(char)) + } + i++ + } else if c == '*' { + beforeDeep := rune(0) + if i > 0 { + beforeDeep = rune(glob[i-1]) + } + starCount := 1 + for i+1 < len(glob) && glob[i+1] == '*' { + starCount++ + i++ + } + afterDeep := rune(0) + if i+1 < len(glob) { + afterDeep = rune(glob[i+1]) + } + isDeep := starCount > 1 && (beforeDeep == '/' || beforeDeep == 0) && (afterDeep == '/' || afterDeep == 0) + if isDeep { + tokens = append(tokens, "((?:[^/]*(?:/|$))*)") + i++ + } else { + tokens = append(tokens, "([^/]*)") + } + } else { + switch c { + case '{': + inGroup = true + tokens = append(tokens, "(") + case '}': + inGroup = false + tokens = append(tokens, ")") + case ',': + if inGroup { + tokens = append(tokens, "|") + } else { + tokens = append(tokens, "\\"+string(c)) + } + default: + if _, ok := escapedChars[c]; ok { + tokens = append(tokens, "\\"+string(c)) + } else { + tokens = append(tokens, string(c)) + } + } + } + } + + tokens = append(tokens, "$") + return regexp.MustCompile(strings.Join(tokens, "")) +} + +func resolveGlobToRegex(baseURL *string, glob string, isWebSocketUrl bool) *regexp.Regexp { + if isWebSocketUrl { + baseURL = toWebSocketBaseURL(baseURL) + } + glob = resolveGlobBase(baseURL, glob) + return globMustToRegex(glob) +} + +func resolveGlobBase(baseURL *string, match string) string { + if strings.HasPrefix(match, "*") { + return match + } + + tokenMap := make(map[string]string) + mapToken := func(original string, replacement string) string { + if len(original) == 0 { + return "" + } + tokenMap[replacement] = original + return replacement + } + // Escaped `\\?` behaves the same as `?` in our glob patterns. + match = strings.ReplaceAll(match, `\\?`, "?") + // Glob symbols may be escaped in the URL and some of them such as ? affect resolution, + // so we replace them with safe components first. + relativePath := strings.Split(match, "/") + for i, token := range relativePath { + if token == "." || token == ".." || token == "" { + continue + } + // Handle special case of http*://, note that the new schema has to be + // a web schema so that slashes are properly inserted after domain. + if i == 0 && strings.HasSuffix(token, ":") { + relativePath[i] = mapToken(token, "http:") + } else { + questionIndex := strings.Index(token, "?") + if questionIndex == -1 { + relativePath[i] = mapToken(token, "$_"+strconv.Itoa(i)+"_$") + } else { + newPrefix := mapToken(token[:questionIndex], "$_"+strconv.Itoa(i)+"_$") + newSuffix := mapToken(token[questionIndex:], "?$"+strconv.Itoa(i)+"_$") + relativePath[i] = newPrefix + newSuffix + } + } + } + resolved := constructURLBasedOnBaseURL(baseURL, strings.Join(relativePath, "/")) + for token, original := range tokenMap { + resolved = strings.ReplaceAll(resolved, token, original) + } + return resolved +} + +func constructURLBasedOnBaseURL(baseURL *string, givenURL string) string { + u, err := url.Parse(givenURL) + if err != nil { + return givenURL + } + if baseURL != nil { + base, err := url.Parse(*baseURL) + if err != nil { + return givenURL + } + u = base.ResolveReference(u) + } + if u.Path == "" { // In Node.js, new URL('http://localhost') returns 'http://localhost/'. + u.Path = "/" + } + return u.String() +} + +func toWebSocketBaseURL(baseURL *string) *string { + if baseURL == nil { + return nil + } + + // Allow http(s) baseURL to match ws(s) urls. + re := regexp.MustCompile(`(?m)^http(s?://)`) + wsBaseURL := re.ReplaceAllString(*baseURL, "ws$1") + + return &wsBaseURL +} diff --git a/vendor/github.com/playwright-community/playwright-go/har_router.go b/vendor/github.com/playwright-community/playwright-go/har_router.go new file mode 100644 index 0000000..0c95d53 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/har_router.go @@ -0,0 +1,110 @@ +package playwright + +import ( + "errors" +) + +type harRouter struct { + localUtils *localUtilsImpl + harId string + notFoundAction HarNotFound + urlOrPredicate interface{} + err error +} + +func (r *harRouter) addContextRoute(context BrowserContext) error { + if r.err != nil { + return r.err + } + err := context.Route(r.urlOrPredicate, func(route Route) { + err := r.handle(route) + if err != nil { + logger.Error("Error handling context route", "error", err) + } + }) + if err != nil { + return err + } + return r.err +} + +func (r *harRouter) addPageRoute(page Page) error { + if r.err != nil { + return r.err + } + err := page.Route(r.urlOrPredicate, func(route Route) { + err := r.handle(route) + if err != nil { + logger.Error("Error handling page route", "error", err) + } + }) + if err != nil { + return err + } + return r.err +} + +func (r *harRouter) dispose() { + go r.localUtils.HarClose(r.harId) +} + +func (r *harRouter) handle(route Route) error { + if r.err != nil { + return r.err + } + request := route.Request() + postData, err := request.PostDataBuffer() + if err != nil { + return err + } + response, err := r.localUtils.HarLookup(harLookupOptions{ + HarId: r.harId, + URL: request.URL(), + Method: request.Method(), + Headers: request.Headers(), + IsNavigationRequest: request.IsNavigationRequest(), + PostData: postData, + }) + if err != nil { + return err + } + switch response.Action { + case "redirect": + if response.RedirectURL == nil { + return errors.New("redirect url is null") + } + return route.(*routeImpl).redirectedNavigationRequest(*response.RedirectURL) + case "fulfill": + if response.Body == nil { + return errors.New("fulfill body is null") + } + return route.Fulfill(RouteFulfillOptions{ + Body: *response.Body, + Status: response.Status, + Headers: deserializeNameAndValueToMap(response.Headers), + }) + case "error": + logger.Error("har action error", "error", *response.Message) + fallthrough + case "noentry": + } + if r.notFoundAction == *HarNotFoundAbort { + return route.Abort() + } + return route.Fallback() +} + +func newHarRouter(localUtils *localUtilsImpl, file string, notFoundAction HarNotFound, urlOrPredicate interface{}) *harRouter { + harId, err := localUtils.HarOpen(file) + var url interface{} = "**/*" + if urlOrPredicate != nil { + url = urlOrPredicate + } + return &harRouter{ + localUtils: localUtils, + harId: harId, + notFoundAction: notFoundAction, + urlOrPredicate: url, + err: err, + } +} diff --git a/vendor/github.com/playwright-community/playwright-go/helpers.go b/vendor/github.com/playwright-community/playwright-go/helpers.go new file mode 100644 index 0000000..b2244f1 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/helpers.go @@ -0,0 +1,628 @@ +package playwright + +import ( + "errors" + "fmt" + "reflect" + "regexp" + "strings" + "sync" + "sync/atomic" + + mapset "github.com/deckarep/golang-set/v2" +) + +type ( + routeHandler = func(Route) +) + +func skipFieldSerialization(val reflect.Value) bool { + typ := val.Type() + return (typ.Kind() == reflect.Ptr || + typ.Kind() == reflect.Interface || + typ.Kind() == reflect.Map || + typ.Kind() == reflect.Slice) && val.IsNil() || (val.Kind() == reflect.Interface && val.Elem().Kind() == reflect.Ptr && val.Elem().IsNil()) +} + +func transformStructValues(in interface{}) interface{} { + v := reflect.ValueOf(in) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + if _, ok := in.(*channel); ok { + return in + } + if v.Kind() == reflect.Map || v.Kind() == reflect.Struct { + return transformStructIntoMapIfNeeded(in) + } + if v.Kind() == reflect.Slice { + outSlice := []interface{}{} + for i := 0; i < v.Len(); i++ { + if !skipFieldSerialization(v.Index(i)) { + outSlice = append(outSlice, transformStructValues(v.Index(i).Interface())) + } + } + return outSlice + } + if v.Interface() == Null() || (v.Kind() == reflect.String && v.String() == Null().(string)) { + return "null" + } + return in +} + +func transformStructIntoMapIfNeeded(inStruct interface{}) map[string]interface{} { + out := make(map[string]interface{}) + v := reflect.ValueOf(inStruct) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + typ := v.Type() + if v.Kind() == reflect.Struct { + // Merge into the base map by the JSON struct tag + for i := 0; i < v.NumField(); i++ { + fi := typ.Field(i) + // Skip the values when the field is a pointer (like *string) and nil. + if fi.IsExported() && !skipFieldSerialization(v.Field(i)) { + // We use the JSON struct fields for getting the original names + // out of the field. + tagv := fi.Tag.Get("json") + key := strings.Split(tagv, ",")[0] + if key == "" { + key = fi.Name + } + out[key] = transformStructValues(v.Field(i).Interface()) + } + } + } else if v.Kind() == reflect.Map { + // Merge into the base map + for _, key := range v.MapKeys() { + if !skipFieldSerialization(v.MapIndex(key)) { + out[key.String()] = transformStructValues(v.MapIndex(key).Interface()) + } + } + } + return out +} + +// transformOptions handles the parameter data transformation +func transformOptions(options ...interface{}) map[string]interface{} { + var base map[string]interface{} + var option interface{} + // Case 1: No options are given + if len(options) == 0 { + return make(map[string]interface{}) + } + if len(options) == 1 { + // Case 2: a single value (either struct or map) is given. + base = make(map[string]interface{}) + option = options[0] + } else if len(options) == 2 { + // Case 3: two values are given. The first one needs to be transformed + // to a map, the sencond one will be then get merged into the first + // base map. + if reflect.ValueOf(options[0]).Kind() != reflect.Map { + base = transformOptions(options[0]) + } else { + base = transformStructIntoMapIfNeeded(options[0]) + } + option = options[1] + } + v := reflect.ValueOf(option) + if v.Kind() == reflect.Slice { + if v.Len() == 0 { + return base + } + option = v.Index(0).Interface() + } + + if option == nil { + return base + } + v = reflect.ValueOf(option) + + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + optionMap := transformStructIntoMapIfNeeded(v.Interface()) + for key, value := range optionMap { + base[key] = value + } + return base +} + +func remapValue(inMapValue reflect.Value, outStructValue reflect.Value) { + switch outStructValue.Type().Kind() { + case reflect.Bool: + outStructValue.SetBool(inMapValue.Bool()) + case reflect.String: + outStructValue.SetString(inMapValue.String()) + case reflect.Float64: + outStructValue.SetFloat(inMapValue.Float()) + case reflect.Int: + outStructValue.SetInt(int64(inMapValue.Float())) + case reflect.Slice: + outStructValue.Set(reflect.MakeSlice(outStructValue.Type(), inMapValue.Len(), inMapValue.Cap())) + for i := 0; i < inMapValue.Len(); i++ { + remapValue(inMapValue.Index(i).Elem(), outStructValue.Index(i)) + } + case reflect.Struct: + structTyp := outStructValue.Type() + for i := 0; i < outStructValue.NumField(); i++ { + fi := structTyp.Field(i) + key := strings.Split(fi.Tag.Get("json"), ",")[0] + structField := outStructValue.Field(i) + structFieldDeref := outStructValue.Field(i) + if structField.Type().Kind() == reflect.Ptr { + structField.Set(reflect.New(structField.Type().Elem())) + structFieldDeref = structField.Elem() + } + for _, e := range inMapValue.MapKeys() { + if key == e.String() { + value := inMapValue.MapIndex(e) + remapValue(value.Elem(), structFieldDeref) + } + } + } + default: + panic(inMapValue.Interface()) + } +} + +func remapMapToStruct(inputMap interface{}, outStruct interface{}) { + remapValue(reflect.ValueOf(inputMap), reflect.ValueOf(outStruct).Elem()) +} + +type urlMatcher struct { + raw interface{} + pattern *regexp.Regexp + matchFn func(url string) bool +} + +func newURLMatcher(urlOrPredicate interface{}, baseURL *string, isWsUrl ...bool) *urlMatcher { + switch v := urlOrPredicate.(type) { + case *regexp.Regexp: + return &urlMatcher{pattern: v, raw: urlOrPredicate} + case string: + return &urlMatcher{ + pattern: resolveGlobToRegex(baseURL, v, len(isWsUrl) > 0 && isWsUrl[0]), + raw: urlOrPredicate, + } + } + fn, ok := urlOrPredicate.(func(string) bool) + if ok { + return &urlMatcher{ + matchFn: fn, + raw: urlOrPredicate, + } + } + panic(fmt.Errorf("invalid urlOrPredicate: %v", urlOrPredicate)) +} + +func (u *urlMatcher) Matches(url string) bool { + if u.matchFn != nil { + return u.matchFn(url) + } + if u.pattern != nil { + return u.pattern.MatchString(url) + } + return false +} + +// SameWith compares String() if urlOrPredicate is *regexp.Regexp +func (u *urlMatcher) SameWith(urlOrPredicate interface{}) bool { + switch v := urlOrPredicate.(type) { + case *regexp.Regexp: + return u.pattern.String() == v.String() + default: + return u.raw == urlOrPredicate + } +} + +type routeHandlerInvocation struct { + route Route + complete chan bool +} + +type routeHandlerEntry struct { + matcher *urlMatcher + handler routeHandler + times int + count int32 + ignoreErrors *atomic.Bool + activeInvocations mapset.Set[*routeHandlerInvocation] +} + +func (r *routeHandlerEntry) Matches(url string) bool { + return r.matcher.Matches(url) +} + +func (r *routeHandlerEntry) Handle(route Route) chan bool { + handlerInvocation := &routeHandlerInvocation{ + route: route, + complete: make(chan bool, 1), + } + r.activeInvocations.Add(handlerInvocation) + + defer func() { + handlerInvocation.complete <- true + r.activeInvocations.Remove(handlerInvocation) + }() + defer func() { + // If the handler was stopped (without waiting for completion), we ignore all exceptions. + if r.ignoreErrors.Load() { + _ = recover() + route.(*routeImpl).reportHandled(false) + } else { + e := recover() + if e != nil { + err, ok := e.(error) + if ok && errors.Is(err, ErrTargetClosed) { + panic(fmt.Errorf("\"%w\" while running route callback.\nConsider awaiting `page.UnrouteAll(playwright.PageUnrouteAllOptions{Behavior: playwright.UnrouteBehaviorIgnoreErrors})`\nbefore the end of the test to ignore remaining routes in flight.", err)) + } + panic(e) + } + } + }() + + return r.handleInternal(route) +} + +func (r *routeHandlerEntry) Stop(behavior string) { + // When a handler is manually unrouted or its page/context is closed we either + // - wait for the current handler invocations to finish + // - or do not wait, if the user opted out of it, but swallow all exceptions + // that happen after the unroute/close. + if behavior == string(*UnrouteBehaviorIgnoreErrors) { + r.ignoreErrors.Store(true) + } else { + wg := &sync.WaitGroup{} + r.activeInvocations.Each(func(activation *routeHandlerInvocation) bool { + if !activation.route.(*routeImpl).didThrow { + wg.Add(1) + go func(complete chan bool) { + <-complete + wg.Done() + }(activation.complete) + } + return false + }) + wg.Wait() + } +} + +func (r *routeHandlerEntry) handleInternal(route Route) chan bool { + handled := route.(*routeImpl).startHandling() + atomic.AddInt32(&r.count, 1) + r.handler(route) + return handled +} + +func (r *routeHandlerEntry) WillExceed() bool { + if r.times == 0 { + return false + } + return int(atomic.LoadInt32(&r.count)+1) >= r.times +} + +func newRouteHandlerEntry(matcher *urlMatcher, handler routeHandler, times ...int) *routeHandlerEntry { + n := 0 + if len(times) > 0 { + n = times[0] + } + return &routeHandlerEntry{ + matcher: matcher, + handler: handler, + times: n, + count: 0, + ignoreErrors: &atomic.Bool{}, + activeInvocations: mapset.NewSet[*routeHandlerInvocation](), + } +} + +func prepareInterceptionPatterns(handlers []*routeHandlerEntry) []map[string]interface{} { + patterns := []map[string]interface{}{} + all := false + for _, h := range handlers { + switch h.matcher.raw.(type) { + case *regexp.Regexp: + pattern, flags := convertRegexp(h.matcher.raw.(*regexp.Regexp)) + patterns = append(patterns, map[string]interface{}{ + "regexSource": pattern, + "regexFlags": flags, + }) + case string: + patterns = append(patterns, map[string]interface{}{ + "glob": h.matcher.raw.(string), + }) + default: + all = true + } + } + if all { + return []map[string]interface{}{ + { + "glob": "**/*", + }, + } + } + return patterns +} + +const defaultTimeout = 30 * 1000 + +type timeoutSettings struct { + sync.RWMutex + parent *timeoutSettings + defaultTimeout *float64 + defaultNavigationTimeout *float64 +} + +func (t *timeoutSettings) SetDefaultTimeout(timeout *float64) { + t.Lock() + defer t.Unlock() + t.defaultTimeout = timeout +} + +func (t *timeoutSettings) DefaultTimeout() *float64 { + t.RLock() + defer t.RUnlock() + return t.defaultTimeout +} + +func (t *timeoutSettings) Timeout(timeout ...float64) float64 { + t.RLock() + defer t.RUnlock() + if len(timeout) == 1 { + return timeout[0] + } + if t.defaultTimeout != nil { + return *t.defaultTimeout + } + if t.parent != nil { + return t.parent.Timeout() + } + return defaultTimeout +} + +func (t *timeoutSettings) DefaultNavigationTimeout() *float64 { + t.RLock() + defer t.RUnlock() + return t.defaultNavigationTimeout +} + +func (t *timeoutSettings) SetDefaultNavigationTimeout(navigationTimeout *float64) { + t.Lock() + defer t.Unlock() + t.defaultNavigationTimeout = navigationTimeout +} + +func (t *timeoutSettings) NavigationTimeout() float64 { + t.RLock() + defer t.RUnlock() + if t.defaultNavigationTimeout != nil { + return *t.defaultNavigationTimeout + } + if t.parent != nil { + return t.parent.NavigationTimeout() + } + return defaultTimeout +} + +func newTimeoutSettings(parent *timeoutSettings) *timeoutSettings { + return &timeoutSettings{ + parent: parent, + defaultTimeout: nil, + defaultNavigationTimeout: nil, + } +} + +// SelectOptionValues is the option struct for ElementHandle.Select() etc. +type SelectOptionValues struct { + ValuesOrLabels *[]string + Values *[]string + Indexes *[]int + Labels *[]string + Elements *[]ElementHandle +} + +func convertSelectOptionSet(values SelectOptionValues) map[string]interface{} { + out := make(map[string]interface{}) + if values == (SelectOptionValues{}) { + return out + } + + var o []map[string]interface{} + if values.ValuesOrLabels != nil { + for _, v := range *values.ValuesOrLabels { + m := map[string]interface{}{"valueOrLabel": v} + o = append(o, m) + } + } + if values.Values != nil { + for _, v := range *values.Values { + m := map[string]interface{}{"value": v} + o = append(o, m) + } + } + if values.Indexes != nil { + for _, i := range *values.Indexes { + m := map[string]interface{}{"index": i} + o = append(o, m) + } + } + if values.Labels != nil { + for _, l := range *values.Labels { + m := map[string]interface{}{"label": l} + o = append(o, m) + } + } + if o != nil { + out["options"] = o + } + + var e []*channel + if values.Elements != nil { + for _, eh := range *values.Elements { + e = append(e, eh.(*elementHandleImpl).channel) + } + } + if e != nil { + out["elements"] = e + } + + return out +} + +func unroute(inRoutes []*routeHandlerEntry, url interface{}, handlers ...routeHandler) ([]*routeHandlerEntry, []*routeHandlerEntry, error) { + var handler routeHandler + if len(handlers) == 1 { + handler = handlers[0] + } + handlerPtr := reflect.ValueOf(handler).Pointer() + + removed := make([]*routeHandlerEntry, 0) + remaining := make([]*routeHandlerEntry, 0) + + for _, route := range inRoutes { + routeHandlerPtr := reflect.ValueOf(route.handler).Pointer() + // note: compare regex expression if url is a regexp, not pointer + if !route.matcher.SameWith(url) || + (handler != nil && routeHandlerPtr != handlerPtr) { + remaining = append(remaining, route) + } else { + removed = append(removed, route) + } + } + + return removed, remaining, nil +} + +func serializeMapToNameAndValue(headers map[string]string) []map[string]string { + serialized := make([]map[string]string, 0) + for name, value := range headers { + serialized = append(serialized, map[string]string{ + "name": name, + "value": value, + }) + } + return serialized +} + +// assignStructFields assigns fields from src to dest, +// +// omitExtra determines whether to omit src's extra fields +func assignStructFields(dest, src interface{}, omitExtra bool) error { + destValue := reflect.ValueOf(dest) + if destValue.Kind() != reflect.Ptr || destValue.IsNil() { + return fmt.Errorf("dest must be a non-nil pointer") + } + destValue = destValue.Elem() + if destValue.Kind() != reflect.Struct { + return fmt.Errorf("dest must be a struct") + } + + srcValue := reflect.ValueOf(src) + if srcValue.Kind() == reflect.Ptr { + srcValue = srcValue.Elem() + } + if srcValue.Kind() != reflect.Struct { + return fmt.Errorf("src must be a struct") + } + + for i := 0; i < destValue.NumField(); i++ { + destField := destValue.Field(i) + destFieldType := destField.Type() + destFieldName := destValue.Type().Field(i).Name + + if srcField := srcValue.FieldByName(destFieldName); srcField.IsValid() && srcField.Type() != destFieldType { + return fmt.Errorf("mismatched field type for field %s", destFieldName) + } else if srcField.IsValid() { + destField.Set(srcField) + } + } + + if !omitExtra { + for i := 0; i < srcValue.NumField(); i++ { + srcFieldName := srcValue.Type().Field(i).Name + + if destField := destValue.FieldByName(srcFieldName); !destField.IsValid() { + return fmt.Errorf("extra field %s in src", srcFieldName) + } + } + } + + return nil +} + +func deserializeNameAndValueToMap(headersArray []map[string]string) map[string]string { + unserialized := make(map[string]string) + for _, item := range headersArray { + unserialized[item["name"]] = item["value"] + } + return unserialized +} + +type recordHarOptions struct { + Path string `json:"path"` + Content *HarContentPolicy `json:"content,omitempty"` + Mode *HarMode `json:"mode,omitempty"` + UrlGlob *string `json:"urlGlob,omitempty"` + UrlRegexSource *string `json:"urlRegexSource,omitempty"` + UrlRegexFlags *string `json:"urlRegexFlags,omitempty"` +} + +type recordHarInputOptions struct { + Path string + URL interface{} + Mode *HarMode + Content *HarContentPolicy + OmitContent *bool +} + +type harRecordingMetadata struct { + Path string + Content *HarContentPolicy +} + +func prepareRecordHarOptions(option recordHarInputOptions) recordHarOptions { + out := recordHarOptions{ + Path: option.Path, + } + if option.URL != nil { + switch option.URL.(type) { + case *regexp.Regexp: + pattern, flags := convertRegexp(option.URL.(*regexp.Regexp)) + out.UrlRegexSource = String(pattern) + out.UrlRegexFlags = String(flags) + case string: + out.UrlGlob = String(option.URL.(string)) + } + } + if option.Mode != nil { + out.Mode = option.Mode + } + if option.Content != nil { + out.Content = option.Content + } else if option.OmitContent != nil && *option.OmitContent { + out.Content = HarContentPolicyOmit + } + return out +} + +type safeValue[T any] struct { + sync.Mutex + v T +} + +func (s *safeValue[T]) Set(v T) { + s.Lock() + defer s.Unlock() + s.v = v +} + +func (s *safeValue[T]) Get() T { + s.Lock() + defer s.Unlock() + return s.v +} diff --git a/vendor/github.com/playwright-community/playwright-go/input.go b/vendor/github.com/playwright-community/playwright-go/input.go new file mode 100644 index 0000000..d6e4ba4 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/input.go @@ -0,0 +1,117 @@ +package playwright + +type mouseImpl struct { + channel *channel +} + +func newMouse(channel *channel) *mouseImpl { + return &mouseImpl{ + channel: channel, + } +} + +func (m *mouseImpl) Move(x float64, y float64, options ...MouseMoveOptions) error { + _, err := m.channel.Send("mouseMove", map[string]interface{}{ + "x": x, + "y": y, + }, options) + return err +} + +func (m *mouseImpl) Down(options ...MouseDownOptions) error { + _, err := m.channel.Send("mouseDown", options) + return err +} + +func (m *mouseImpl) Up(options ...MouseUpOptions) error { + _, err := m.channel.Send("mouseUp", options) + return err +} + +func (m *mouseImpl) Click(x, y float64, options ...MouseClickOptions) error { + _, err := m.channel.Send("mouseClick", map[string]interface{}{ + "x": x, + "y": y, + }, options) + return err +} + +func (m *mouseImpl) Dblclick(x, y float64, options ...MouseDblclickOptions) error { + var option MouseDblclickOptions + if len(options) == 1 { + option = options[0] + } + return m.Click(x, y, MouseClickOptions{ + ClickCount: Int(2), + Button: option.Button, + Delay: option.Delay, + }) +} + +func (m *mouseImpl) Wheel(deltaX, deltaY float64) error { + _, err := m.channel.Send("mouseWheel", map[string]interface{}{ + "deltaX": deltaX, + "deltaY": deltaY, + }) + return err +} + +type keyboardImpl struct { + channel *channel +} + +func newKeyboard(channel *channel) *keyboardImpl { + return &keyboardImpl{ + channel: channel, + } +} + +func (m *keyboardImpl) Down(key string) error { + _, err := m.channel.Send("keyboardDown", map[string]interface{}{ + "key": key, + }) + return err +} + +func (m *keyboardImpl) Up(key string) error { + _, err := m.channel.Send("keyboardUp", map[string]interface{}{ + "key": key, + }) + return err +} + +func (m *keyboardImpl) InsertText(text string) error { + _, err := m.channel.Send("keyboardInsertText", map[string]interface{}{ + "text": text, + }) + return err +} + +func (m *keyboardImpl) Type(text string, options ...KeyboardTypeOptions) error { + _, err := m.channel.Send("keyboardInsertText", map[string]interface{}{ + "text": text, + }, options) + return err +} + +func (m *keyboardImpl) Press(key string, options ...KeyboardPressOptions) error { + _, err := m.channel.Send("keyboardPress", map[string]interface{}{ + "key": key, + }, options) + return err +} + +type touchscreenImpl struct { + channel *channel +} + +func newTouchscreen(channel *channel) *touchscreenImpl { + return &touchscreenImpl{ + channel: channel, + } +} + +func (t *touchscreenImpl) Tap(x int, y int) error { + _, err := t.channel.Send("touchscreenTap", map[string]interface{}{"x": x, "y": y}) + return err +} diff --git a/vendor/github.com/playwright-community/playwright-go/input_files_helper.go b/vendor/github.com/playwright-community/playwright-go/input_files_helper.go new file mode 100644 index 0000000..3318cb5 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/input_files_helper.go @@ -0,0 +1,202 @@ +package playwright + +import ( + "encoding/base64" + "errors" + "fmt" + "os" + "path/filepath" +) + +const fileSizeLimitInBytes = 50 * 1024 * 1024 + +var ErrInputFilesSizeExceeded = errors.New("Cannot set buffer larger than 50Mb, please write it to a file and pass its path instead.") + +type inputFiles struct { + Selector *string `json:"selector,omitempty"` + Streams []*channel `json:"streams,omitempty"` // writableStream + LocalPaths []string `json:"localPaths,omitempty"` + Payloads []map[string]string `json:"payloads,omitempty"` + LocalDirectory *string `json:"localDirectory,omitempty"` + DirectoryStream *channel `json:"directoryStream,omitempty"` +} + +type fileItem struct { + LastModifiedMs *int64 `json:"lastModifiedMs,omitempty"` + Name string `json:"name"` +} + +// convertInputFiles converts files to proper format for Playwright +// +// - files should be one of: string, []string, InputFile, []InputFile, +// string: local file path +func convertInputFiles(files interface{}, context *browserContextImpl) (*inputFiles, error) { + var ( + converted = &inputFiles{} + paths []string + ) + switch items := files.(type) { + case InputFile: + if sizeOfInputFiles([]InputFile{items}) > fileSizeLimitInBytes { + return nil, ErrInputFilesSizeExceeded + } + converted.Payloads = normalizeFilePayloads([]InputFile{items}) + case []InputFile: + if sizeOfInputFiles(items) > fileSizeLimitInBytes { + return nil, ErrInputFilesSizeExceeded + } + converted.Payloads = normalizeFilePayloads(items) + case string: // local file path + paths = []string{items} + case []string: + paths = items + default: + return nil, errors.New("files should be one of: string, []string, InputFile, []InputFile") + } + + localPaths, localDir, err := resolvePathsAndDirectoryForInputFiles(paths) + if err != nil { + return nil, err + } + + if !context.connection.isRemote { + converted.LocalPaths = localPaths + converted.LocalDirectory = localDir + return converted, nil + } + + // remote + params := map[string]interface{}{ + "items": []fileItem{}, + } + allFiles := localPaths + if localDir != nil { + params["rootDirName"] = filepath.Base(*localDir) + allFiles, err = listFiles(*localDir) + if err != nil { + return nil, err + } + } + for _, file := range allFiles { + lastModifiedMs, err := getFileLastModifiedMs(file) + if err != nil { + return nil, fmt.Errorf("failed to get last modified time of %s: %w", file, err) + } + filename := filepath.Base(file) + if localDir != nil { + var err error + filename, err = filepath.Rel(*localDir, file) + if err != nil { + return nil, err + } + } + params["items"] = append(params["items"].([]fileItem), fileItem{ + LastModifiedMs: &lastModifiedMs, + Name: filename, + }) + } + + ret, err := context.connection.WrapAPICall(func() (interface{}, error) { + return context.channel.SendReturnAsDict("createTempFiles", params) + }, true) + if err != nil { + return nil, err + } + result := ret.(map[string]interface{}) + + streams := make([]*channel, 0) + items := result["writableStreams"].([]interface{}) + for i := 0; i < len(allFiles); i++ { + stream := fromChannel(items[i]).(*writableStream) + if err := stream.Copy(allFiles[i]); err != nil { + return nil, err + } + streams = append(streams, stream.channel) + } + + if result["rootDir"] != nil { + converted.DirectoryStream = result["rootDir"].(*channel) + } else { + converted.Streams = streams + } + + return converted, nil +} + +func getFileLastModifiedMs(path string) (int64, error) { + info, err := os.Stat(path) + if err != nil { + return 0, err + } + if info.IsDir() { + return 0, fmt.Errorf("%s is a directory", path) + } + return info.ModTime().UnixMilli(), nil +} + +func sizeOfInputFiles(files []InputFile) int { + size := 0 + for _, file := range files { + size += len(file.Buffer) + } + return size +} + +func normalizeFilePayloads(files []InputFile) []map[string]string { + out := make([]map[string]string, 0) + for _, file := range files { + out = append(out, map[string]string{ + "name": file.Name, + "mimeType": file.MimeType, + "buffer": base64.StdEncoding.EncodeToString(file.Buffer), + }) + } + return out +} + +func resolvePathsAndDirectoryForInputFiles(items []string) (localPaths []string, localDirectory *string, e error) { + for _, item := range items { + abspath, err := filepath.Abs(item) + if err != nil { + e = err + return + } + // if the path is a directory + if info, err := os.Stat(abspath); err == nil { + if info.IsDir() { + if localDirectory != nil { + e = errors.New("Multiple directories are not supported") + return + } + localDirectory = &abspath + } else { + if localPaths == nil { + localPaths = []string{abspath} + } else { + localPaths = append(localPaths, abspath) + } + } + } else { + e = err + return + } + } + if localPaths != nil && localDirectory != nil { + e = errors.New("File paths must be all files or a single directory") + } + return +} + +func listFiles(dir string) ([]string, error) { + var files []string + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + files = append(files, path) + } + return nil + }) + return files, err +} diff --git a/vendor/github.com/playwright-community/playwright-go/internal/safe/map.go b/vendor/github.com/playwright-community/playwright-go/internal/safe/map.go new file mode 100644 index 0000000..93a8800 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/internal/safe/map.go @@ -0,0 +1,90 @@ +package safe + +import ( + "maps" + "sync" +) + +// SyncMap is a thread-safe map +type SyncMap[K comparable, V any] struct { + sync.RWMutex + m map[K]V +} + +// NewSyncMap creates a new thread-safe map +func NewSyncMap[K comparable, V any]() *SyncMap[K, V] { + return &SyncMap[K, V]{ + m: make(map[K]V), + } +} + +func (m *SyncMap[K, V]) Store(k K, v V) { + m.Lock() + defer m.Unlock() + m.m[k] = v +} + +func (m *SyncMap[K, V]) Load(k K) (v V, ok bool) { + m.RLock() + defer m.RUnlock() + v, ok = m.m[k] + return +} + +// LoadOrStore returns the existing value for the key if present. Otherwise, it stores and returns the given value. +func (m *SyncMap[K, V]) LoadOrStore(k K, v V) (actual V, loaded bool) { + m.Lock() + defer m.Unlock() + actual, loaded = m.m[k] + if loaded { + return + } + m.m[k] = v + return v, false +} + +// LoadAndDelete deletes the value for a key, and returns the previous value if any. +func (m *SyncMap[K, V]) LoadAndDelete(k K) (v V, loaded bool) { + m.Lock() + defer m.Unlock() + v, loaded = m.m[k] + if loaded { + delete(m.m, k) + } + return +} + +func (m *SyncMap[K, V]) Delete(k K) { + m.Lock() + defer m.Unlock() + delete(m.m, k) +} + +func (m *SyncMap[K, V]) Clear() { + m.Lock() + defer m.Unlock() + clear(m.m) +} + +func (m *SyncMap[K, V]) Len() int { + m.RLock() + defer m.RUnlock() + return len(m.m) +} + +func (m *SyncMap[K, V]) Clone() map[K]V { + m.RLock() + defer m.RUnlock() + return maps.Clone(m.m) +} + +func (m *SyncMap[K, V]) Range(f func(k K, v V) bool) { + m.RLock() + defer m.RUnlock() + + for k, v := range m.m { + if !f(k, v) { + break + } + } +} diff --git a/vendor/github.com/playwright-community/playwright-go/js_handle.go b/vendor/github.com/playwright-community/playwright-go/js_handle.go new file mode 100644 index 0000000..6aaa68d --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/js_handle.go @@ -0,0 +1,421 @@ +package playwright + +import ( + "bytes" + "encoding/base64" + "encoding/binary" + "errors" + "fmt" + "math" + "math/big" + "net/url" + "reflect" + "time" +) + +type jsHandleImpl struct { + channelOwner + preview string +} + +func (j *jsHandleImpl) Evaluate(expression string, options ...interface{}) (interface{}, error) { + var arg interface{} + if len(options) == 1 { + arg = options[0] + } + result, err := j.channel.Send("evaluateExpression", map[string]interface{}{ + "expression": expression, + "arg": serializeArgument(arg), + }) + if err != nil { + return nil, err + } + return parseResult(result), nil +} + +func (j *jsHandleImpl) EvaluateHandle(expression string, options ...interface{}) (JSHandle, error) { + var arg interface{} + if len(options) == 1 { + arg = options[0] + } + result, err := j.channel.Send("evaluateExpressionHandle", map[string]interface{}{ + "expression": expression, + "arg": serializeArgument(arg), + }) + if err != nil { + return nil, err + } + channelOwner := fromChannel(result) + if channelOwner == nil { + return nil, nil + } + return channelOwner.(*jsHandleImpl), nil +} + +func (j *jsHandleImpl) GetProperty(name string) (JSHandle, error) { + channel, err := j.channel.Send("getProperty", map[string]interface{}{ + "name": name, + }) + if err != nil { + return nil, err + } + return fromChannel(channel).(*jsHandleImpl), nil +} + +func (j *jsHandleImpl) GetProperties() (map[string]JSHandle, error) { + properties, err := j.channel.Send("getPropertyList") + if err != nil { + return nil, err + } + propertiesMap := make(map[string]JSHandle) + for _, property := range properties.([]interface{}) { + item := property.(map[string]interface{}) + propertiesMap[item["name"].(string)] = fromChannel(item["value"]).(*jsHandleImpl) + } + return propertiesMap, nil +} + +func (j *jsHandleImpl) AsElement() ElementHandle { + return nil +} + +func (j *jsHandleImpl) Dispose() error { + _, err := j.channel.Send("dispose") + if errors.Is(err, ErrTargetClosed) { + return nil + } + return err +} + +func (j *jsHandleImpl) String() string { + return j.preview +} + +func (j *jsHandleImpl) JSONValue() (interface{}, error) { + v, err := j.channel.Send("jsonValue") + if err != nil { + return nil, err + } + return parseResult(v), nil +} + +func parseValue(result interface{}, refs map[float64]interface{}) interface{} { + vMap, ok := result.(map[string]interface{}) + if !ok { + return result + } + if v, ok := vMap["n"]; ok { + if math.Ceil(v.(float64))-v.(float64) == 0 { + return int(v.(float64)) + } + return v.(float64) + } + + if v, ok := vMap["u"]; ok { + u, _ := url.Parse(v.(string)) + return u + } + + if v, ok := vMap["bi"]; ok { + n := new(big.Int) + n.SetString(v.(string), 0) + return n + } + + if v, ok := vMap["ref"]; ok { + if vV, ok := refs[v.(float64)]; ok { + return vV + } + return nil + } + + if v, ok := vMap["s"]; ok { + return v.(string) + } + if v, ok := vMap["b"]; ok { + return v.(bool) + } + if v, ok := vMap["v"]; ok { + if v == "undefined" || v == "null" { + return nil + } + if v == "NaN" { + return math.NaN() + } + if v == "Infinity" { + return math.Inf(1) + } + if v == "-Infinity" { + return math.Inf(-1) + } + if v == "-0" { + return math.Copysign(0, -1) + } + return v + } + if v, ok := vMap["d"]; ok { + t, _ := time.Parse(time.RFC3339Nano, v.(string)) + return t + } + if v, ok := vMap["a"]; ok { + aV := v.([]interface{}) + refs[vMap["id"].(float64)] = aV + for i := range aV { + aV[i] = parseValue(aV[i], refs) + } + return aV + } + if v, ok := vMap["o"]; ok { + aV := v.([]interface{}) + out := map[string]interface{}{} + refs[vMap["id"].(float64)] = out + for key := range aV { + entry := aV[key].(map[string]interface{}) + out[entry["k"].(string)] = parseValue(entry["v"], refs) + } + return out + } + + if v, ok := vMap["e"]; ok { + return parseError(Error{ + Name: v.(map[string]interface{})["n"].(string), + Message: v.(map[string]interface{})["m"].(string), + Stack: v.(map[string]interface{})["s"].(string), + }) + } + if v, ok := vMap["ta"]; ok { + b, b_ok := v.(map[string]interface{})["b"].(string) + k, k_ok := v.(map[string]interface{})["k"].(string) + if b_ok && k_ok { + decoded, err := base64.StdEncoding.DecodeString(b) + if err != nil { + panic(fmt.Errorf("Unexpected value: %v", vMap)) + } + r := bytes.NewReader(decoded) + switch k { + case "i8": + result := make([]int8, len(decoded)) + return mustReadArray(r, &result) + case "ui8", "ui8c": + result := make([]uint8, len(decoded)) + return mustReadArray(r, &result) + case "i16": + size := mustBeDivisible(len(decoded), 2) + result := make([]int16, size) + return mustReadArray(r, &result) + case "ui16": + size := mustBeDivisible(len(decoded), 2) + result := make([]uint16, size) + return mustReadArray(r, &result) + case "i32": + size := mustBeDivisible(len(decoded), 4) + result := make([]int32, size) + return mustReadArray(r, &result) + case "ui32": + size := mustBeDivisible(len(decoded), 4) + result := make([]uint32, size) + return mustReadArray(r, &result) + case "f32": + size := mustBeDivisible(len(decoded), 4) + result := make([]float32, size) + return mustReadArray(r, &result) + case "f64": + size := mustBeDivisible(len(decoded), 8) + result := make([]float64, size) + return mustReadArray(r, &result) + case "bi64": + size := mustBeDivisible(len(decoded), 8) + result := make([]int64, size) + return mustReadArray(r, &result) + case "bui64": + size := mustBeDivisible(len(decoded), 8) + result := make([]uint64, size) + return mustReadArray(r, &result) + default: + panic(fmt.Errorf("Unsupported array type: %s", k)) + } + } + } + panic(fmt.Errorf("Unexpected value: %v", vMap)) +} + +func serializeValue(value interface{}, handles *[]*channel, depth int) interface{} { + if handle, ok := value.(*elementHandleImpl); ok { + h := len(*handles) + *handles = append(*handles, handle.channel) + return map[string]interface{}{ + "h": h, + } + } + if handle, ok := value.(*jsHandleImpl); ok { + h := len(*handles) + *handles = append(*handles, handle.channel) + return map[string]interface{}{ + "h": h, + } + } + if u, ok := value.(*url.URL); ok { + return map[string]interface{}{ + "u": u.String(), + } + } + + if err, ok := value.(error); ok { + var e *Error + if errors.As(err, &e) { + return map[string]interface{}{ + "e": map[string]interface{}{ + "n": e.Name, + "m": e.Message, + "s": e.Stack, + }, + } + } + return map[string]interface{}{ + "e": map[string]interface{}{ + "n": "", + "m": err.Error(), + "s": "", + }, + } + } + + if depth > 100 { + panic(errors.New("Maximum argument depth exceeded")) + } + if value == nil { + return map[string]interface{}{ + "v": "undefined", + } + } + if n, ok := value.(*big.Int); ok { + return map[string]interface{}{ + "bi": n.String(), + } + } + + switch v := value.(type) { + case time.Time: + return map[string]interface{}{ + "d": v.Format(time.RFC3339Nano), + } + case int: + return map[string]interface{}{ + "n": v, + } + case string: + return map[string]interface{}{ + "s": v, + } + case bool: + return map[string]interface{}{ + "b": v, + } + } + + refV := reflect.ValueOf(value) + + switch refV.Kind() { + case reflect.Float32, reflect.Float64: + floatV := refV.Float() + if math.IsInf(floatV, 1) { + return map[string]interface{}{ + "v": "Infinity", + } + } + if math.IsInf(floatV, -1) { + return map[string]interface{}{ + "v": "-Infinity", + } + } + // https://github.com/golang/go/issues/2196 + if floatV == math.Copysign(0, -1) { + return map[string]interface{}{ + "v": "-0", + } + } + if math.IsNaN(floatV) { + return map[string]interface{}{ + "v": "NaN", + } + } + return map[string]interface{}{ + "n": floatV, + } + case reflect.Slice: + aV := make([]interface{}, refV.Len()) + for i := 0; i < refV.Len(); i++ { + aV[i] = serializeValue(refV.Index(i).Interface(), handles, depth+1) + } + return map[string]interface{}{ + "a": aV, + } + case reflect.Map: + out := []interface{}{} + vM := value.(map[string]interface{}) + for key := range vM { + v := serializeValue(vM[key], handles, depth+1) + // had key, so convert "undefined" to "null" + if reflect.DeepEqual(v, map[string]interface{}{ + "v": "undefined", + }) { + v = map[string]interface{}{ + "v": "null", + } + } + out = append(out, map[string]interface{}{ + "k": key, + "v": v, + }) + } + return map[string]interface{}{ + "o": out, + } + } + return map[string]interface{}{ + "v": "undefined", + } +} + +func parseResult(result interface{}) interface{} { + return parseValue(result, map[float64]interface{}{}) +} + +func serializeArgument(arg interface{}) interface{} { + handles := []*channel{} + value := serializeValue(arg, &handles, 0) + return map[string]interface{}{ + "value": value, + "handles": handles, + } +} + +func newJSHandle(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *jsHandleImpl { + bt := &jsHandleImpl{ + preview: initializer["preview"].(string), + } + bt.createChannelOwner(bt, parent, objectType, guid, initializer) + bt.channel.On("previewUpdated", func(ev map[string]interface{}) { + bt.preview = ev["preview"].(string) + }) + return bt +} + +func mustBeDivisible(length int, wordSize int) int { + if length%wordSize != 0 { + panic(fmt.Errorf(`Decoded bytes length %d is not a multiple of word size %d`, length, wordSize)) + } + return length / wordSize +} + +func mustReadArray[T int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | float32 | float64](r *bytes.Reader, v *[]T) []float64 { + err := binary.Read(r, binary.LittleEndian, v) + if err != nil { + panic(err) + } + data := make([]float64, len(*v)) + for i, v := range *v { + data[i] = float64(v) + } + return data +} diff --git a/vendor/github.com/playwright-community/playwright-go/jsonPipe.go b/vendor/github.com/playwright-community/playwright-go/jsonPipe.go new file mode 100644 index 0000000..e6c0e79 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/jsonPipe.go @@ -0,0 +1,64 @@ +package playwright + +import ( + "encoding/json" + "errors" + "fmt" +) + +type jsonPipe struct { + channelOwner + msgChan chan *message +} + +func (j *jsonPipe) Send(message map[string]interface{}) error { + _, err := j.channel.Send("send", map[string]interface{}{ + "message": message, + }) + return err +} + +func (j *jsonPipe) Close() error { + _, err := j.channel.Send("close") + return err +} + +func (j *jsonPipe) Poll() (*message, error) { + msg := <-j.msgChan + if msg == nil { + return nil, errors.New("jsonPipe closed") + } + return msg, nil +} + +func newJsonPipe(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *jsonPipe { + j := &jsonPipe{ + msgChan: make(chan *message, 2), + } + j.createChannelOwner(j, parent, objectType, guid, initializer) + j.channel.On("message", func(ev map[string]interface{}) { + var msg message + m, err := json.Marshal(ev["message"]) + if err == nil { + err = json.Unmarshal(m, &msg) + } + if err != nil { + msg = message{ + Error: &struct { + Error Error "json:\"error\"" + }{ + Error: Error{ + Name: "Error", + Message: fmt.Sprintf("jsonPipe: could not decode message: %s", err.Error()), + }, + }, + } + } + j.msgChan <- &msg + }) + j.channel.Once("closed", func() { + j.Emit("closed") + close(j.msgChan) + }) + return j +} diff --git a/vendor/github.com/playwright-community/playwright-go/local_utils.go b/vendor/github.com/playwright-community/playwright-go/local_utils.go new file mode 100644 index 0000000..395c09a --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/local_utils.go @@ -0,0 +1,165 @@ +package playwright + +import ( + "encoding/base64" + "encoding/json" + "fmt" +) + +type localUtilsImpl struct { + channelOwner + Devices map[string]*DeviceDescriptor +} + +type ( + localUtilsZipOptions struct { + ZipFile string `json:"zipFile"` + Entries []interface{} `json:"entries"` + StacksId string `json:"stacksId"` + Mode string `json:"mode"` + IncludeSources bool `json:"includeSources"` + } + + harLookupOptions struct { + HarId string `json:"harId"` + URL string `json:"url"` + Method string `json:"method"` + Headers map[string]string `json:"headers"` + IsNavigationRequest bool `json:"isNavigationRequest"` + PostData interface{} `json:"postData,omitempty"` + } + + harLookupResult struct { + Action string `json:"action"` + Message *string `json:"message,omitempty"` + RedirectURL *string `json:"redirectUrl,omitempty"` + Status *int `json:"status,omitempty"` + Headers []map[string]string `json:"headers,omitempty"` + Body *string `json:"body,omitempty"` + } +) + +func (l *localUtilsImpl) Zip(options localUtilsZipOptions) (interface{}, error) { + return l.channel.Send("zip", options) +} + +func (l *localUtilsImpl) HarOpen(file string) (string, error) { + result, err := l.channel.SendReturnAsDict("harOpen", []map[string]interface{}{ + { + "file": file, + }, + }) + if err == nil { + if harId, ok := result["harId"]; ok { + return harId.(string), nil + } + if err, ok := result["error"]; ok { + return "", fmt.Errorf("%w:%v", ErrPlaywright, err) + } + } + return "", err +} + +func (l *localUtilsImpl) HarLookup(option harLookupOptions) (*harLookupResult, error) { + overrides := make(map[string]interface{}) + overrides["harId"] = option.HarId + overrides["url"] = option.URL + overrides["method"] = option.Method + if option.Headers != nil { + overrides["headers"] = serializeMapToNameAndValue(option.Headers) + } + overrides["isNavigationRequest"] = option.IsNavigationRequest + if option.PostData != nil { + switch v := option.PostData.(type) { + case string: + overrides["postData"] = base64.StdEncoding.EncodeToString([]byte(v)) + case []byte: + overrides["postData"] = base64.StdEncoding.EncodeToString(v) + } + } + ret, err := l.channel.SendReturnAsDict("harLookup", overrides) + if ret == nil { + return nil, err + } + var result harLookupResult + mJson, err := json.Marshal(ret) + if err != nil { + return nil, err + } + err = json.Unmarshal(mJson, &result) + if err != nil { + return nil, err + } + if result.Body != nil { + body, err := base64.StdEncoding.DecodeString(*result.Body) + if err != nil { + return nil, err + } + result.Body = String(string(body)) + } + return &result, err +} + +func (l *localUtilsImpl) HarClose(harId string) error { + _, err := l.channel.Send("harClose", []map[string]interface{}{ + { + "harId": harId, + }, + }) + return err +} + +func (l *localUtilsImpl) HarUnzip(zipFile, harFile string) error { + _, err := l.channel.Send("harUnzip", []map[string]interface{}{ + { + "zipFile": zipFile, + "harFile": harFile, + }, + }) + return err +} + +func (l *localUtilsImpl) TracingStarted(traceName string, tracesDir ...string) (string, error) { + overrides := make(map[string]interface{}) + overrides["traceName"] = traceName + if len(tracesDir) > 0 { + overrides["tracesDir"] = tracesDir[0] + } + stacksId, err := l.channel.Send("tracingStarted", overrides) + if stacksId == nil { + return "", err + } + return stacksId.(string), err +} + +func (l *localUtilsImpl) TraceDiscarded(stacksId string) error { + _, err := l.channel.Send("traceDiscarded", map[string]interface{}{ + "stacksId": stacksId, + }) + return err +} + +func (l *localUtilsImpl) AddStackToTracingNoReply(id uint32, stack []map[string]interface{}) { + l.channel.SendNoReply("addStackToTracingNoReply", map[string]interface{}{ + "callData": map[string]interface{}{ + "id": id, + "stack": stack, + }, + }) +} + +func newLocalUtils(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *localUtilsImpl { + l := &localUtilsImpl{ + Devices: make(map[string]*DeviceDescriptor), + } + l.createChannelOwner(l, parent, objectType, guid, initializer) + for _, dd := range initializer["deviceDescriptors"].([]interface{}) { + entry := dd.(map[string]interface{}) + l.Devices[entry["name"].(string)] = &DeviceDescriptor{ + Viewport: &Size{}, + } + remapMapToStruct(entry["descriptor"], l.Devices[entry["name"].(string)]) + } + l.markAsInternalType() + return l +} diff --git a/vendor/github.com/playwright-community/playwright-go/locator.go b/vendor/github.com/playwright-community/playwright-go/locator.go new file mode 100644 index 0000000..e6a49b7 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/locator.go @@ -0,0 +1,914 @@ +package playwright + +import ( + "errors" + "fmt" + "strconv" +) + +var ( + testIdAttributeName = "data-testid" + ErrLocatorNotSameFrame = errors.New("inner 'has' or 'hasNot' locator must belong to the same frame") +) + +type locatorImpl struct { + frame *frameImpl + selector string + options *LocatorOptions + err error +} + +type LocatorOptions LocatorFilterOptions + +func newLocator(frame *frameImpl, selector string, options ...LocatorOptions) *locatorImpl { + option := &LocatorOptions{} + if len(options) == 1 { + option = &options[0] + } + locator := &locatorImpl{frame: frame, selector: selector, options: option, err: nil} + if option.HasText != nil { + selector += fmt.Sprintf(` >> internal:has-text=%s`, escapeForTextSelector(option.HasText, false)) + } + if option.HasNotText != nil { + selector += fmt.Sprintf(` >> internal:has-not-text=%s`, escapeForTextSelector(option.HasNotText, false)) + } + if option.Has != nil { + has := option.Has.(*locatorImpl) + if frame != has.frame { + locator.err = errors.Join(locator.err, ErrLocatorNotSameFrame) + } else { + selector += fmt.Sprintf(` >> internal:has=%s`, escapeText(has.selector)) + } + } + if option.HasNot != nil { + hasNot := option.HasNot.(*locatorImpl) + if frame != hasNot.frame { + locator.err = errors.Join(locator.err, ErrLocatorNotSameFrame) + } else { + selector += fmt.Sprintf(` >> internal:has-not=%s`, escapeText(hasNot.selector)) + } + } + if option.Visible != nil { + selector += fmt.Sprintf(` >> visible=%s`, strconv.FormatBool(*option.Visible)) + } + + locator.selector = selector + + return locator +} + +func (l *locatorImpl) equals(locator Locator) bool { + return l.frame == locator.(*locatorImpl).frame && l.err == locator.(*locatorImpl).err && l.selector == locator.(*locatorImpl).selector +} + +func (l *locatorImpl) Err() error { + return l.err +} + +func (l *locatorImpl) All() ([]Locator, error) { + result := make([]Locator, 0) + count, err := l.Count() + if err != nil { + return nil, err + } + for i := 0; i < count; i++ { + result = append(result, l.Nth(i)) + } + return result, nil +} + +func (l *locatorImpl) AllInnerTexts() ([]string, error) { + if l.err != nil { + return nil, l.err + } + innerTexts, err := l.frame.EvalOnSelectorAll(l.selector, "ee => ee.map(e => e.innerText)") + if err != nil { + return nil, err + } + texts := innerTexts.([]interface{}) + result := make([]string, len(texts)) + for i := range texts { + result[i] = texts[i].(string) + } + return result, nil +} + +func (l *locatorImpl) AllTextContents() ([]string, error) { + if l.err != nil { + return nil, l.err + } + textContents, err := l.frame.EvalOnSelectorAll(l.selector, "ee => ee.map(e => e.textContent || '')") + if err != nil { + return nil, err + } + texts := textContents.([]interface{}) + result := make([]string, len(texts)) + for i := range texts { + result[i] = texts[i].(string) + } + return result, nil +} + +func (l *locatorImpl) And(locator Locator) Locator { + return newLocator(l.frame, l.selector+` >> internal:and=`+escapeText(locator.(*locatorImpl).selector)) +} + +func (l *locatorImpl) Or(locator Locator) Locator { + return newLocator(l.frame, l.selector+` >> internal:or=`+escapeText(locator.(*locatorImpl).selector)) +} + +func (l *locatorImpl) Blur(options ...LocatorBlurOptions) error { + if l.err != nil { + return l.err + } + params := map[string]interface{}{ + "selector": l.selector, + "strict": true, + } + if len(options) == 1 { + if options[0].Timeout != nil { + params["timeout"] = options[0].Timeout + } + } + _, err := l.frame.channel.Send("blur", params) + return err +} + +func (l *locatorImpl) AriaSnapshot(options ...LocatorAriaSnapshotOptions) (string, error) { + var option LocatorAriaSnapshotOptions + if len(options) == 1 { + option = options[0] + } + ret, err := l.frame.channel.Send("ariaSnapshot", option, + map[string]interface{}{"selector": l.selector}) + if err != nil { + return "", err + } + return ret.(string), nil +} + +func (l *locatorImpl) BoundingBox(options ...LocatorBoundingBoxOptions) (*Rect, error) { + if l.err != nil { + return nil, l.err + } + var option FrameWaitForSelectorOptions + if len(options) == 1 { + option.Timeout = options[0].Timeout + } + + result, err := l.withElement(func(handle ElementHandle) (interface{}, error) { + return handle.BoundingBox() + }, option) + if err != nil { + return nil, err + } + + return result.(*Rect), nil +} + +func (l *locatorImpl) Check(options ...LocatorCheckOptions) error { + if l.err != nil { + return l.err + } + opt := FrameCheckOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.Check(l.selector, opt) +} + +func (l *locatorImpl) Clear(options ...LocatorClearOptions) error { + if l.err != nil { + return l.err + } + if len(options) == 1 { + return l.Fill("", LocatorFillOptions{ + Force: options[0].Force, + Timeout: options[0].Timeout, + }) + } else { + return l.Fill("") + } +} + +func (l *locatorImpl) Click(options ...LocatorClickOptions) error { + if l.err != nil { + return l.err + } + opt := FrameClickOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.Click(l.selector, opt) +} + +func (l *locatorImpl) ContentFrame() FrameLocator { + return newFrameLocator(l.frame, l.selector) +} + +func (l *locatorImpl) Count() (int, error) { + if l.err != nil { + return 0, l.err + } + return l.frame.queryCount(l.selector) +} + +func (l *locatorImpl) Dblclick(options ...LocatorDblclickOptions) error { + if l.err != nil { + return l.err + } + opt := FrameDblclickOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.Dblclick(l.selector, opt) +} + +func (l *locatorImpl) DispatchEvent(typ string, eventInit interface{}, options ...LocatorDispatchEventOptions) error { + if l.err != nil { + return l.err + } + opt := FrameDispatchEventOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.DispatchEvent(l.selector, typ, eventInit, opt) +} + +func (l *locatorImpl) DragTo(target Locator, options ...LocatorDragToOptions) error { + if l.err != nil { + return l.err + } + opt := FrameDragAndDropOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.DragAndDrop(l.selector, target.(*locatorImpl).selector, opt) +} + +func (l *locatorImpl) ElementHandle(options ...LocatorElementHandleOptions) (ElementHandle, error) { + if l.err != nil { + return nil, l.err + } + option := FrameWaitForSelectorOptions{ + State: WaitForSelectorStateAttached, + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&option, options[0], false); err != nil { + return nil, err + } + } + return l.frame.WaitForSelector(l.selector, option) +} + +func (l *locatorImpl) ElementHandles() ([]ElementHandle, error) { + if l.err != nil { + return nil, l.err + } + return l.frame.QuerySelectorAll(l.selector) +} + +func (l *locatorImpl) Evaluate(expression string, arg interface{}, options ...LocatorEvaluateOptions) (interface{}, error) { + if l.err != nil { + return nil, l.err + } + var option FrameWaitForSelectorOptions + if len(options) == 1 { + option.Timeout = options[0].Timeout + } + + return l.withElement(func(handle ElementHandle) (interface{}, error) { + return handle.Evaluate(expression, arg) + }, option) +} + +func (l *locatorImpl) EvaluateAll(expression string, options ...interface{}) (interface{}, error) { + if l.err != nil { + return nil, l.err + } + return l.frame.EvalOnSelectorAll(l.selector, expression, options...) +} + +func (l *locatorImpl) EvaluateHandle(expression string, arg interface{}, options ...LocatorEvaluateHandleOptions) (JSHandle, error) { + if l.err != nil { + return nil, l.err + } + var option FrameWaitForSelectorOptions + if len(options) == 1 { + option.Timeout = options[0].Timeout + } + + h, err := l.withElement(func(handle ElementHandle) (interface{}, error) { + return handle.EvaluateHandle(expression, arg) + }, option) + if err != nil { + return nil, err + } + return h.(JSHandle), nil +} + +func (l *locatorImpl) Fill(value string, options ...LocatorFillOptions) error { + if l.err != nil { + return l.err + } + opt := FrameFillOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.Fill(l.selector, value, opt) +} + +func (l *locatorImpl) Filter(options ...LocatorFilterOptions) Locator { + if len(options) == 1 { + return newLocator(l.frame, l.selector, LocatorOptions(options[0])) + } + return newLocator(l.frame, l.selector) +} + +func (l *locatorImpl) First() Locator { + return newLocator(l.frame, l.selector+" >> nth=0") +} + +func (l *locatorImpl) Focus(options ...LocatorFocusOptions) error { + if l.err != nil { + return l.err + } + opt := FrameFocusOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.Focus(l.selector, opt) +} + +func (l *locatorImpl) FrameLocator(selector string) FrameLocator { + return newFrameLocator(l.frame, l.selector+" >> "+selector) +} + +func (l *locatorImpl) GetAttribute(name string, options ...LocatorGetAttributeOptions) (string, error) { + if l.err != nil { + return "", l.err + } + opt := FrameGetAttributeOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return "", err + } + } + return l.frame.GetAttribute(l.selector, name, opt) +} + +func (l *locatorImpl) GetByAltText(text interface{}, options ...LocatorGetByAltTextOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return l.Locator(getByAltTextSelector(text, exact)) +} + +func (l *locatorImpl) GetByLabel(text interface{}, options ...LocatorGetByLabelOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return l.Locator(getByLabelSelector(text, exact)) +} + +func (l *locatorImpl) GetByPlaceholder(text interface{}, options ...LocatorGetByPlaceholderOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return l.Locator(getByPlaceholderSelector(text, exact)) +} + +func (l *locatorImpl) GetByRole(role AriaRole, options ...LocatorGetByRoleOptions) Locator { + return l.Locator(getByRoleSelector(role, options...)) +} + +func (l *locatorImpl) GetByTestId(testId interface{}) Locator { + return l.Locator(getByTestIdSelector(getTestIdAttributeName(), testId)) +} + +func (l *locatorImpl) GetByText(text interface{}, options ...LocatorGetByTextOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return l.Locator(getByTextSelector(text, exact)) +} + +func (l *locatorImpl) GetByTitle(text interface{}, options ...LocatorGetByTitleOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return l.Locator(getByTitleSelector(text, exact)) +} + +func (l *locatorImpl) Highlight() error { + if l.err != nil { + return l.err + } + return l.frame.highlight(l.selector) +} + +func (l *locatorImpl) Hover(options ...LocatorHoverOptions) error { + if l.err != nil { + return l.err + } + opt := FrameHoverOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.Hover(l.selector, opt) +} + +func (l *locatorImpl) InnerHTML(options ...LocatorInnerHTMLOptions) (string, error) { + if l.err != nil { + return "", l.err + } + opt := FrameInnerHTMLOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return "", err + } + } + return l.frame.InnerHTML(l.selector, opt) +} + +func (l *locatorImpl) InnerText(options ...LocatorInnerTextOptions) (string, error) { + if l.err != nil { + return "", l.err + } + opt := FrameInnerTextOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return "", err + } + } + return l.frame.InnerText(l.selector, opt) +} + +func (l *locatorImpl) InputValue(options ...LocatorInputValueOptions) (string, error) { + if l.err != nil { + return "", l.err + } + opt := FrameInputValueOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return "", err + } + } + return l.frame.InputValue(l.selector, opt) +} + +func (l *locatorImpl) IsChecked(options ...LocatorIsCheckedOptions) (bool, error) { + if l.err != nil { + return false, l.err + } + opt := FrameIsCheckedOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return false, err + } + } + return l.frame.IsChecked(l.selector, opt) +} + +func (l *locatorImpl) IsDisabled(options ...LocatorIsDisabledOptions) (bool, error) { + if l.err != nil { + return false, l.err + } + opt := FrameIsDisabledOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return false, err + } + } + return l.frame.IsDisabled(l.selector, opt) +} + +func (l *locatorImpl) IsEditable(options ...LocatorIsEditableOptions) (bool, error) { + if l.err != nil { + return false, l.err + } + opt := FrameIsEditableOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return false, err + } + } + return l.frame.IsEditable(l.selector, opt) +} + +func (l *locatorImpl) IsEnabled(options ...LocatorIsEnabledOptions) (bool, error) { + if l.err != nil { + return false, l.err + } + opt := FrameIsEnabledOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return false, err + } + } + return l.frame.IsEnabled(l.selector, opt) +} + +func (l *locatorImpl) IsHidden(options ...LocatorIsHiddenOptions) (bool, error) { + if l.err != nil { + return false, l.err + } + opt := FrameIsHiddenOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return false, err + } + } + return l.frame.IsHidden(l.selector, opt) +} + +func (l *locatorImpl) IsVisible(options ...LocatorIsVisibleOptions) (bool, error) { + if l.err != nil { + return false, l.err + } + opt := FrameIsVisibleOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return false, err + } + } + return l.frame.IsVisible(l.selector, opt) +} + +func (l *locatorImpl) Last() Locator { + return newLocator(l.frame, l.selector+" >> nth=-1") +} + +func (l *locatorImpl) Locator(selectorOrLocator interface{}, options ...LocatorLocatorOptions) Locator { + var option LocatorOptions + if len(options) == 1 { + option = LocatorOptions{ + Has: options[0].Has, + HasNot: options[0].HasNot, + HasText: options[0].HasText, + HasNotText: options[0].HasNotText, + } + } + + selector, ok := selectorOrLocator.(string) + if ok { + return newLocator(l.frame, l.selector+" >> "+selector, option) + } + locator, ok := selectorOrLocator.(*locatorImpl) + if ok { + if l.frame != locator.frame { + l.err = errors.Join(l.err, ErrLocatorNotSameFrame) + return l + } + return newLocator(l.frame, + l.selector+" >> internal:chain="+escapeText(locator.selector), + option, + ) + } + l.err = errors.Join(l.err, fmt.Errorf("invalid locator parameter: %v", selectorOrLocator)) + return l +} + +func (l *locatorImpl) Nth(index int) Locator { + return newLocator(l.frame, l.selector+" >> nth="+strconv.Itoa(index)) +} + +func (l *locatorImpl) Page() (Page, error) { + if l.err != nil { + return nil, l.err + } + return l.frame.Page(), nil +} + +func (l *locatorImpl) Press(key string, options ...LocatorPressOptions) error { + if l.err != nil { + return l.err + } + opt := FramePressOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.Press(l.selector, key, opt) +} + +func (l *locatorImpl) PressSequentially(text string, options ...LocatorPressSequentiallyOptions) error { + if l.err != nil { + return l.err + } + var option LocatorTypeOptions + if len(options) == 1 { + option = LocatorTypeOptions(options[0]) + } + return l.Type(text, option) +} + +func (l *locatorImpl) Screenshot(options ...LocatorScreenshotOptions) ([]byte, error) { + if l.err != nil { + return nil, l.err + } + var option FrameWaitForSelectorOptions + if len(options) == 1 { + option.Timeout = options[0].Timeout + } + + result, err := l.withElement(func(handle ElementHandle) (interface{}, error) { + var screenshotOption ElementHandleScreenshotOptions + if len(options) == 1 { + screenshotOption = ElementHandleScreenshotOptions(options[0]) + } + return handle.Screenshot(screenshotOption) + }, option) + if err != nil { + return nil, err + } + + return result.([]byte), nil +} + +func (l *locatorImpl) ScrollIntoViewIfNeeded(options ...LocatorScrollIntoViewIfNeededOptions) error { + if l.err != nil { + return l.err + } + var option FrameWaitForSelectorOptions + if len(options) == 1 { + option.Timeout = options[0].Timeout + } + + _, err := l.withElement(func(handle ElementHandle) (interface{}, error) { + var opt ElementHandleScrollIntoViewIfNeededOptions + if len(options) == 1 { + opt.Timeout = options[0].Timeout + } + return nil, handle.ScrollIntoViewIfNeeded(opt) + }, option) + + return err +} + +func (l *locatorImpl) SelectOption(values SelectOptionValues, options ...LocatorSelectOptionOptions) ([]string, error) { + if l.err != nil { + return nil, l.err + } + opt := FrameSelectOptionOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return nil, err + } + } + return l.frame.SelectOption(l.selector, values, opt) +} + +func (l *locatorImpl) SelectText(options ...LocatorSelectTextOptions) error { + if l.err != nil { + return l.err + } + var option FrameWaitForSelectorOptions + if len(options) == 1 { + option.Timeout = options[0].Timeout + } + + _, err := l.withElement(func(handle ElementHandle) (interface{}, error) { + var opt ElementHandleSelectTextOptions + if len(options) == 1 { + opt = ElementHandleSelectTextOptions(options[0]) + } + return nil, handle.SelectText(opt) + }, option) + + return err +} + +func (l *locatorImpl) SetChecked(checked bool, options ...LocatorSetCheckedOptions) error { + if l.err != nil { + return l.err + } + opt := FrameSetCheckedOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.SetChecked(l.selector, checked, opt) +} + +func (l *locatorImpl) SetInputFiles(files interface{}, options ...LocatorSetInputFilesOptions) error { + if l.err != nil { + return l.err + } + opt := FrameSetInputFilesOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.SetInputFiles(l.selector, files, opt) +} + +func (l *locatorImpl) Tap(options ...LocatorTapOptions) error { + if l.err != nil { + return l.err + } + opt := FrameTapOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.Tap(l.selector, opt) +} + +func (l *locatorImpl) TextContent(options ...LocatorTextContentOptions) (string, error) { + if l.err != nil { + return "", l.err + } + opt := FrameTextContentOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return "", err + } + } + return l.frame.TextContent(l.selector, opt) +} + +func (l *locatorImpl) Type(text string, options ...LocatorTypeOptions) error { + if l.err != nil { + return l.err + } + opt := FrameTypeOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.Type(l.selector, text, opt) +} + +func (l *locatorImpl) Uncheck(options ...LocatorUncheckOptions) error { + if l.err != nil { + return l.err + } + opt := FrameUncheckOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + return l.frame.Uncheck(l.selector, opt) +} + +func (l *locatorImpl) WaitFor(options ...LocatorWaitForOptions) error { + if l.err != nil { + return l.err + } + opt := FrameWaitForSelectorOptions{ + Strict: Bool(true), + } + if len(options) == 1 { + if err := assignStructFields(&opt, options[0], false); err != nil { + return err + } + } + _, err := l.frame.WaitForSelector(l.selector, opt) + return err +} + +func (l *locatorImpl) withElement( + callback func(handle ElementHandle) (interface{}, error), + options ...FrameWaitForSelectorOptions, +) (interface{}, error) { + if l.err != nil { + return nil, l.err + } + handle, err := l.frame.WaitForSelector(l.selector, options...) + if err != nil { + return nil, err + } + + result, err := callback(handle) + if err != nil { + return nil, err + } + return result, nil +} + +func (l *locatorImpl) expect(expression string, options frameExpectOptions) (*frameExpectResult, error) { + if l.err != nil { + return nil, l.err + } + overrides := map[string]interface{}{ + "selector": l.selector, + "expression": expression, + } + if options.ExpectedValue != nil { + overrides["expectedValue"] = serializeArgument(options.ExpectedValue) + options.ExpectedValue = nil + } + result, err := l.frame.channel.SendReturnAsDict("expect", options, overrides) + if err != nil { + return nil, err + } + var ( + received interface{} + matches bool + log []string + ) + + if v, ok := result["received"]; ok { + received = parseResult(v) + } + if v, ok := result["matches"]; ok { + matches = v.(bool) + } + if v, ok := result["log"]; ok { + for _, l := range v.([]interface{}) { + log = append(log, l.(string)) + } + } + return &frameExpectResult{Received: received, Matches: matches, Log: log}, nil +} diff --git a/vendor/github.com/playwright-community/playwright-go/locator_assertions.go b/vendor/github.com/playwright-community/playwright-go/locator_assertions.go new file mode 100644 index 0000000..e2ea2bb --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/locator_assertions.go @@ -0,0 +1,568 @@ +package playwright + +import ( + "fmt" + "regexp" +) + +type locatorAssertionsImpl struct { + assertionsBase +} + +func newLocatorAssertions(locator Locator, isNot bool, defaultTimeout *float64) *locatorAssertionsImpl { + return &locatorAssertionsImpl{ + assertionsBase: assertionsBase{ + actualLocator: locator, + isNot: isNot, + defaultTimeout: defaultTimeout, + }, + } +} + +func (la *locatorAssertionsImpl) ToBeAttached(options ...LocatorAssertionsToBeAttachedOptions) error { + expression := "to.be.attached" + var timeout *float64 + if len(options) == 1 { + if options[0].Attached != nil && !*options[0].Attached { + expression = "to.be.detached" + } + timeout = options[0].Timeout + } + return la.expect( + expression, + frameExpectOptions{Timeout: timeout}, + nil, + "Locator expected to be attached", + ) +} + +func (la *locatorAssertionsImpl) ToBeChecked(options ...LocatorAssertionsToBeCheckedOptions) error { + var timeout *float64 + + expectedValue := map[string]interface{}{} + expected := "checked" + + if len(options) == 1 { + if options[0].Indeterminate != nil { + expectedValue["indeterminate"] = *options[0].Indeterminate + if *options[0].Indeterminate { + expected = "indeterminate" + } + } else { + if options[0].Checked != nil { + expectedValue["checked"] = *options[0].Checked + if !*options[0].Checked { + expected = "unchecked" + } + } + } + timeout = options[0].Timeout + } + return la.expect( + "to.be.checked", + frameExpectOptions{ + ExpectedValue: expectedValue, + Timeout: timeout, + }, + nil, + fmt.Sprintf("Locator expected to be %s", expected), + ) +} + +func (la *locatorAssertionsImpl) ToBeDisabled(options ...LocatorAssertionsToBeDisabledOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + return la.expect( + "to.be.disabled", + frameExpectOptions{Timeout: timeout}, + nil, + "Locator expected to be disabled", + ) +} + +func (la *locatorAssertionsImpl) ToBeEditable(options ...LocatorAssertionsToBeEditableOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + return la.expect( + "to.be.editable", + frameExpectOptions{Timeout: timeout}, + nil, + "Locator expected to be editable", + ) +} + +func (la *locatorAssertionsImpl) ToBeEmpty(options ...LocatorAssertionsToBeEmptyOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + return la.expect( + "to.be.empty", + frameExpectOptions{Timeout: timeout}, + nil, + "Locator expected to be empty", + ) +} + +func (la *locatorAssertionsImpl) ToBeEnabled(options ...LocatorAssertionsToBeEnabledOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + return la.expect( + "to.be.enabled", + frameExpectOptions{Timeout: timeout}, + nil, + "Locator expected to be enabled", + ) +} + +func (la *locatorAssertionsImpl) ToBeFocused(options ...LocatorAssertionsToBeFocusedOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + return la.expect( + "to.be.focused", + frameExpectOptions{Timeout: timeout}, + nil, + "Locator expected to be focused", + ) +} + +func (la *locatorAssertionsImpl) ToBeHidden(options ...LocatorAssertionsToBeHiddenOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + return la.expect( + "to.be.hidden", + frameExpectOptions{Timeout: timeout}, + nil, + "Locator expected to be hidden", + ) +} + +func (la *locatorAssertionsImpl) ToBeInViewport(options ...LocatorAssertionsToBeInViewportOptions) error { + var ( + ratio *float64 + timeout *float64 + ) + if len(options) == 1 { + ratio = options[0].Ratio + timeout = options[0].Timeout + } + return la.expect( + "to.be.in.viewport", + frameExpectOptions{ + ExpectedNumber: ratio, + Timeout: timeout, + }, + nil, + "Locator expected to be in viewport", + ) +} + +func (la *locatorAssertionsImpl) ToBeVisible(options ...LocatorAssertionsToBeVisibleOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + return la.expect( + "to.be.visible", + frameExpectOptions{Timeout: timeout}, + nil, + "Locator expected to be visible", + ) +} + +func (la *locatorAssertionsImpl) ToContainClass(expected interface{}, options ...LocatorAssertionsToContainClassOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + switch expected.(type) { + case []string: + expectedText, err := toExpectedTextValues(convertToInterfaceList(expected), false, false, nil) + if err != nil { + return err + } + return la.expect( + "to.contain.class.array", + frameExpectOptions{ + ExpectedText: expectedText, + Timeout: timeout, + }, + expected, + "Locator expected to contain class", + ) + case string: + expectedText, err := toExpectedTextValues([]interface{}{expected}, false, false, nil) + if err != nil { + return err + } + return la.expect( + "to.contain.class", + frameExpectOptions{ + ExpectedText: expectedText, + Timeout: timeout, + }, + expected, + "Locator expected to contain class", + ) + default: + return fmt.Errorf("expected should be string or []string, but got %T", expected) + } +} + +func (la *locatorAssertionsImpl) ToContainText(expected interface{}, options ...LocatorAssertionsToContainTextOptions) error { + var ( + timeout *float64 + useInnerText *bool + ignoreCase *bool + ) + if len(options) == 1 { + timeout = options[0].Timeout + useInnerText = options[0].UseInnerText + ignoreCase = options[0].IgnoreCase + } + + switch expected.(type) { + case []string, []*regexp.Regexp: + expectedText, err := toExpectedTextValues(convertToInterfaceList(expected), true, true, ignoreCase) + if err != nil { + return err + } + return la.expect( + "to.contain.text.array", + frameExpectOptions{ + ExpectedText: expectedText, + UseInnerText: useInnerText, + Timeout: timeout, + }, + expected, + "Locator expected to contain text", + ) + default: + expectedText, err := toExpectedTextValues([]interface{}{expected}, true, true, ignoreCase) + if err != nil { + return err + } + return la.expect( + "to.have.text", + frameExpectOptions{ + ExpectedText: expectedText, + UseInnerText: useInnerText, + Timeout: timeout, + }, + expected, + "Locator expected to contain text", + ) + } +} + +func (la *locatorAssertionsImpl) ToHaveAccessibleDescription(description interface{}, options ...LocatorAssertionsToHaveAccessibleDescriptionOptions) error { + var timeout *float64 + var ignoreCase *bool + if len(options) == 1 { + timeout = options[0].Timeout + ignoreCase = options[0].IgnoreCase + } + expectedText, err := toExpectedTextValues([]interface{}{description}, false, false, ignoreCase) + if err != nil { + return err + } + return la.expect( + "to.have.accessible.description", + frameExpectOptions{ExpectedText: expectedText, Timeout: timeout}, + description, + "Locator expected to have AccessibleDescription", + ) +} + +func (la *locatorAssertionsImpl) ToHaveAccessibleErrorMessage(errorMessage interface{}, options ...LocatorAssertionsToHaveAccessibleErrorMessageOptions) error { + var timeout *float64 + var ignoreCase *bool + if len(options) == 1 { + timeout = options[0].Timeout + ignoreCase = options[0].IgnoreCase + } + expectedText, err := toExpectedTextValues([]interface{}{errorMessage}, false, false, ignoreCase) + if err != nil { + return err + } + return la.expect( + "to.have.accessible.error.message", + frameExpectOptions{ExpectedText: expectedText, Timeout: timeout}, + errorMessage, + "Locator expected to have AccessibleErrorMessage", + ) +} + +func (la *locatorAssertionsImpl) ToHaveAccessibleName(name interface{}, options ...LocatorAssertionsToHaveAccessibleNameOptions) error { + var timeout *float64 + var ignoreCase *bool + if len(options) == 1 { + timeout = options[0].Timeout + ignoreCase = options[0].IgnoreCase + } + expectedText, err := toExpectedTextValues([]interface{}{name}, false, false, ignoreCase) + if err != nil { + return err + } + return la.expect( + "to.have.accessible.name", + frameExpectOptions{ExpectedText: expectedText, Timeout: timeout}, + name, + "Locator expected to have AccessibleName", + ) +} + +func (la *locatorAssertionsImpl) ToHaveAttribute(name string, value interface{}, options ...LocatorAssertionsToHaveAttributeOptions) error { + var timeout *float64 + var ignoreCase *bool + if len(options) == 1 { + timeout = options[0].Timeout + ignoreCase = options[0].IgnoreCase + } + expectedText, err := toExpectedTextValues([]interface{}{value}, false, false, ignoreCase) + if err != nil { + return err + } + return la.expect( + "to.have.attribute.value", + frameExpectOptions{ + ExpressionArg: name, + ExpectedText: expectedText, + Timeout: timeout, + }, + value, + "Locator expected to have attribute", + ) +} + +func (la *locatorAssertionsImpl) ToHaveClass(expected interface{}, options ...LocatorAssertionsToHaveClassOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + switch expected.(type) { + case []string, []*regexp.Regexp: + expectedText, err := toExpectedTextValues(convertToInterfaceList(expected), false, false, nil) + if err != nil { + return err + } + return la.expect( + "to.have.class.array", + frameExpectOptions{ + ExpectedText: expectedText, + Timeout: timeout, + }, + expected, + "Locator expected to have class", + ) + default: + expectedText, err := toExpectedTextValues([]interface{}{expected}, false, false, nil) + if err != nil { + return err + } + return la.expect( + "to.have.class", + frameExpectOptions{ + ExpectedText: expectedText, + Timeout: timeout, + }, + expected, + "Locator expected to have class", + ) + } +} + +func (la *locatorAssertionsImpl) ToHaveCount(count int, options ...LocatorAssertionsToHaveCountOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + return la.expect( + "to.have.count", + frameExpectOptions{ExpectedNumber: Float(float64(count)), Timeout: timeout}, + count, + "Locator expected to have count", + ) +} + +func (la *locatorAssertionsImpl) ToHaveCSS(name string, value interface{}, options ...LocatorAssertionsToHaveCSSOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + expectedText, err := toExpectedTextValues([]interface{}{value}, false, false, nil) + if err != nil { + return err + } + return la.expect( + "to.have.css", + frameExpectOptions{ + ExpressionArg: name, + ExpectedText: expectedText, + Timeout: timeout, + }, + value, + "Locator expected to have CSS", + ) +} + +func (la *locatorAssertionsImpl) ToHaveId(id interface{}, options ...LocatorAssertionsToHaveIdOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + expectedText, err := toExpectedTextValues([]interface{}{id}, false, false, nil) + if err != nil { + return err + } + return la.expect( + "to.have.id", + frameExpectOptions{ExpectedText: expectedText, Timeout: timeout}, + id, + "Locator expected to have ID", + ) +} + +func (la *locatorAssertionsImpl) ToHaveJSProperty(name string, value interface{}, options ...LocatorAssertionsToHaveJSPropertyOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + return la.expect( + "to.have.property", + frameExpectOptions{ + ExpressionArg: name, + ExpectedValue: value, + Timeout: timeout, + }, + value, + "Locator expected to have JS Property", + ) +} + +func (la *locatorAssertionsImpl) ToHaveRole(role AriaRole, options ...LocatorAssertionsToHaveRoleOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + expectedText, err := toExpectedTextValues([]interface{}{string(role)}, false, false, nil) + if err != nil { + return err + } + return la.expect( + "to.have.role", + frameExpectOptions{ExpectedText: expectedText, Timeout: timeout}, + role, + "Locator expected to have Role", + ) +} + +func (la *locatorAssertionsImpl) ToHaveText(expected interface{}, options ...LocatorAssertionsToHaveTextOptions) error { + var ( + timeout *float64 + useInnerText *bool + ignoreCase *bool + ) + if len(options) == 1 { + timeout = options[0].Timeout + useInnerText = options[0].UseInnerText + ignoreCase = options[0].IgnoreCase + } + + switch expected.(type) { + case []string, []*regexp.Regexp: + expectedText, err := toExpectedTextValues(convertToInterfaceList(expected), false, true, ignoreCase) + if err != nil { + return err + } + return la.expect( + "to.have.text.array", + frameExpectOptions{ + ExpectedText: expectedText, + UseInnerText: useInnerText, + Timeout: timeout, + }, + expected, + "Locator expected to have text", + ) + default: + expectedText, err := toExpectedTextValues([]interface{}{expected}, false, true, ignoreCase) + if err != nil { + return err + } + return la.expect( + "to.have.text", + frameExpectOptions{ + ExpectedText: expectedText, + UseInnerText: useInnerText, + Timeout: timeout, + }, + expected, + "Locator expected to have text", + ) + } +} + +func (la *locatorAssertionsImpl) ToHaveValue(value interface{}, options ...LocatorAssertionsToHaveValueOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + expectedText, err := toExpectedTextValues([]interface{}{value}, false, false, nil) + if err != nil { + return err + } + return la.expect( + "to.have.value", + frameExpectOptions{ExpectedText: expectedText, Timeout: timeout}, + value, + "Locator expected to have Value", + ) +} + +func (la *locatorAssertionsImpl) ToHaveValues(values []interface{}, options ...LocatorAssertionsToHaveValuesOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + expectedText, err := toExpectedTextValues(values, false, false, nil) + if err != nil { + return err + } + return la.expect( + "to.have.values", + frameExpectOptions{ExpectedText: expectedText, Timeout: timeout}, + values, + "Locator expected to have Values", + ) +} + +func (la *locatorAssertionsImpl) ToMatchAriaSnapshot(expected string, options ...LocatorAssertionsToMatchAriaSnapshotOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + return la.expect( + "to.match.aria", + frameExpectOptions{ + ExpectedValue: expected, + Timeout: timeout, + }, + expected, + "Locator expected to match Aria snapshot", + ) +} + +func (la *locatorAssertionsImpl) Not() LocatorAssertions { + return newLocatorAssertions(la.actualLocator, true, la.defaultTimeout) +} diff --git a/vendor/github.com/playwright-community/playwright-go/locator_helpers.go b/vendor/github.com/playwright-community/playwright-go/locator_helpers.go new file mode 100644 index 0000000..2836fca --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/locator_helpers.go @@ -0,0 +1,133 @@ +package playwright + +import ( + "encoding/json" + "fmt" + "regexp" + "strings" +) + +func convertRegexp(reg *regexp.Regexp) (pattern, flags string) { + matches := regexp.MustCompile(`\(\?([imsU]+)\)(.+)`).FindStringSubmatch(reg.String()) + + if len(matches) == 3 { + pattern = matches[2] + flags = matches[1] + } else { + pattern = reg.String() + } + return +} + +func escapeForAttributeSelector(text interface{}, exact bool) string { + switch text := text.(type) { + case *regexp.Regexp: + return escapeRegexForSelector(text) + default: + suffix := "i" + if exact { + suffix = "s" + } + return fmt.Sprintf(`"%s"%s`, strings.Replace(strings.Replace(text.(string), `\`, `\\`, -1), `"`, `\"`, -1), suffix) + } +} + +func escapeForTextSelector(text interface{}, exact bool) string { + switch text := text.(type) { + case *regexp.Regexp: + return escapeRegexForSelector(text) + default: + if exact { + return fmt.Sprintf(`%ss`, escapeText(text.(string))) + } + return fmt.Sprintf(`%si`, escapeText(text.(string))) + } +} + +func escapeRegexForSelector(re *regexp.Regexp) string { + pattern, flag := convertRegexp(re) + return fmt.Sprintf(`/%s/%s`, strings.ReplaceAll(pattern, `>>`, `\>\>`), flag) +} + +func escapeText(s string) string { + builder := &strings.Builder{} + encoder := json.NewEncoder(builder) + encoder.SetEscapeHTML(false) + _ = encoder.Encode(s) + return strings.TrimSpace(builder.String()) +} + +func getByAltTextSelector(text interface{}, exact bool) string { + return getByAttributeTextSelector("alt", text, exact) +} + +func getByAttributeTextSelector(attrName string, text interface{}, exact bool) string { + return fmt.Sprintf(`internal:attr=[%s=%s]`, attrName, escapeForAttributeSelector(text, exact)) +} + +func getByLabelSelector(text interface{}, exact bool) string { + return fmt.Sprintf(`internal:label=%s`, escapeForTextSelector(text, exact)) +} + +func getByPlaceholderSelector(text interface{}, exact bool) string { + return getByAttributeTextSelector("placeholder", text, exact) +} + +func getByRoleSelector(role AriaRole, options ...LocatorGetByRoleOptions) string { + props := make(map[string]string) + if len(options) == 1 { + if options[0].Checked != nil { + props["checked"] = fmt.Sprintf("%t", *options[0].Checked) + } + if options[0].Disabled != nil { + props["disabled"] = fmt.Sprintf("%t", *options[0].Disabled) + } + if options[0].Selected != nil { + props["selected"] = fmt.Sprintf("%t", *options[0].Selected) + } + if options[0].Expanded != nil { + props["expanded"] = fmt.Sprintf("%t", *options[0].Expanded) + } + if options[0].IncludeHidden != nil { + props["include-hidden"] = fmt.Sprintf("%t", *options[0].IncludeHidden) + } + if options[0].Level != nil { + props["level"] = fmt.Sprintf("%d", *options[0].Level) + } + if options[0].Name != nil { + exact := false + if options[0].Exact != nil { + exact = *options[0].Exact + } + props["name"] = escapeForAttributeSelector(options[0].Name, exact) + } + if options[0].Pressed != nil { + props["pressed"] = fmt.Sprintf("%t", *options[0].Pressed) + } + } + propsStr := "" + for k, v := range props { + propsStr += "[" + k + "=" + v + "]" + } + return fmt.Sprintf("internal:role=%s%s", role, propsStr) +} + +func getByTextSelector(text interface{}, exact bool) string { + return fmt.Sprintf(`internal:text=%s`, escapeForTextSelector(text, exact)) +} + +func getByTestIdSelector(testIdAttributeName string, testId interface{}) string { + return fmt.Sprintf(`internal:testid=[%s=%s]`, testIdAttributeName, escapeForAttributeSelector(testId, true)) +} + +func getByTitleSelector(text interface{}, exact bool) string { + return getByAttributeTextSelector("title", text, exact) +} + +func getTestIdAttributeName() string { + return testIdAttributeName +} + +func setTestIdAttributeName(name string) { + testIdAttributeName = name +} diff --git a/vendor/github.com/playwright-community/playwright-go/network.go b/vendor/github.com/playwright-community/playwright-go/network.go new file mode 100644 index 0000000..6f76fa5 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/network.go @@ -0,0 +1,62 @@ +package playwright + +import ( + "strings" +) + +type rawHeaders struct { + headersArray []NameValue + headersMap map[string][]string +} + +func (r *rawHeaders) Get(name string) string { + values := r.GetAll(name) + if len(values) == 0 { + return "" + } + sep := ", " + if strings.ToLower(name) == "set-cookie" { + sep = "\n" + } + return strings.Join(values, sep) +} + +func (r *rawHeaders) GetAll(name string) []string { + name = strings.ToLower(name) + if _, ok := r.headersMap[name]; !ok { + return []string{} + } + return r.headersMap[name] +} + +func (r *rawHeaders) Headers() map[string]string { + out := make(map[string]string) + for key := range r.headersMap { + out[key] = r.Get(key) + } + return out +} + +func (r *rawHeaders) HeadersArray() []NameValue { + return r.headersArray +} + +func newRawHeaders(headers interface{}) *rawHeaders { + r := &rawHeaders{} + r.headersArray = make([]NameValue, 0) + r.headersMap = make(map[string][]string) + for _, header := range headers.([]interface{}) { + entry := header.(map[string]interface{}) + name := entry["name"].(string) + value := entry["value"].(string) + r.headersArray = append(r.headersArray, NameValue{ + Name: name, + Value: value, + }) + if _, ok := r.headersMap[strings.ToLower(name)]; !ok { + r.headersMap[strings.ToLower(name)] = make([]string, 0) + } + r.headersMap[strings.ToLower(name)] = append(r.headersMap[strings.ToLower(name)], value) + } + return r +} diff --git a/vendor/github.com/playwright-community/playwright-go/objectFactory.go b/vendor/github.com/playwright-community/playwright-go/objectFactory.go new file mode 100644 index 0000000..9474c54 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/objectFactory.go @@ -0,0 +1,74 @@ +package playwright + +func createObjectFactory(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) interface{} { + switch objectType { + case "Android": + return nil + case "AndroidSocket": + return nil + case "AndroidDevice": + return nil + case "APIRequestContext": + return newAPIRequestContext(parent, objectType, guid, initializer) + case "Artifact": + return newArtifact(parent, objectType, guid, initializer) + case "BindingCall": + return newBindingCall(parent, objectType, guid, initializer) + case "Browser": + return newBrowser(parent, objectType, guid, initializer) + case "BrowserType": + return newBrowserType(parent, objectType, guid, initializer) + case "BrowserContext": + return newBrowserContext(parent, objectType, guid, initializer) + case "CDPSession": + return newCDPSession(parent, objectType, guid, initializer) + case "Dialog": + return newDialog(parent, objectType, guid, initializer) + case "Electron": + return nil + case "ElectronApplication": + return nil + case "ElementHandle": + return newElementHandle(parent, objectType, guid, initializer) + case "Frame": + return newFrame(parent, objectType, guid, initializer) + case "JSHandle": + return newJSHandle(parent, objectType, guid, initializer) + case "JsonPipe": + return newJsonPipe(parent, objectType, guid, initializer) + case "LocalUtils": + localUtils := newLocalUtils(parent, objectType, guid, initializer) + if localUtils.connection.localUtils == nil { + localUtils.connection.localUtils = localUtils + } + return localUtils + case "Page": + return newPage(parent, objectType, guid, initializer) + case "Playwright": + return newPlaywright(parent, objectType, guid, initializer) + case "Request": + return newRequest(parent, objectType, guid, initializer) + case "Response": + return newResponse(parent, objectType, guid, initializer) + case "Route": + return newRoute(parent, objectType, guid, initializer) + case "Selectors": + return newSelectorsOwner(parent, objectType, guid, initializer) + case "SocksSupport": + return nil + case "Stream": + return newStream(parent, objectType, guid, initializer) + case "Tracing": + return newTracing(parent, objectType, guid, initializer) + case "WebSocket": + return newWebsocket(parent, objectType, guid, initializer) + case "WebSocketRoute": + return newWebSocketRoute(parent, objectType, guid, initializer) + case "Worker": + return newWorker(parent, objectType, guid, initializer) + case "WritableStream": + return newWritableStream(parent, objectType, guid, initializer) + default: + panic(objectType) + } +} diff --git a/vendor/github.com/playwright-community/playwright-go/page.go b/vendor/github.com/playwright-community/playwright-go/page.go new file mode 100644 index 0000000..d4271a0 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/page.go @@ -0,0 +1,1384 @@ +package playwright + +import ( + "encoding/base64" + "errors" + "fmt" + "os" + "slices" + "sync" + + "github.com/playwright-community/playwright-go/internal/safe" +) + +type pageImpl struct { + channelOwner + isClosed bool + closedOrCrashed chan error + video *videoImpl + mouse *mouseImpl + keyboard *keyboardImpl + touchscreen *touchscreenImpl + timeoutSettings *timeoutSettings + browserContext *browserContextImpl + frames []Frame + workers []Worker + mainFrame Frame + routes []*routeHandlerEntry + webSocketRoutes []*webSocketRouteHandler + viewportSize *Size + ownedContext BrowserContext + bindings *safe.SyncMap[string, BindingCallFunction] + closeReason *string + closeWasCalled bool + harRouters []*harRouter + locatorHandlers map[float64]*locatorHandlerEntry +} + +type locatorHandlerEntry struct { + locator *locatorImpl + handler func(Locator) + times *int +} + +func (p *pageImpl) AddLocatorHandler(locator Locator, handler func(Locator), options ...PageAddLocatorHandlerOptions) error { + if locator == nil || handler == nil { + return errors.New("locator or handler must not be nil") + } + if locator.Err() != nil { + return locator.Err() + } + + var option PageAddLocatorHandlerOptions + if len(options) == 1 { + option = options[0] + if option.Times != nil && *option.Times == 0 { + return nil + } + } + + loc := locator.(*locatorImpl) + if loc.frame != p.mainFrame { + return errors.New("locator must belong to the main frame of this page") + } + uid, err := p.channel.Send("registerLocatorHandler", map[string]any{ + "selector": loc.selector, + "noWaitAfter": option.NoWaitAfter, + }) + if err != nil { + return err + } + p.locatorHandlers[uid.(float64)] = &locatorHandlerEntry{locator: loc, handler: handler, times: option.Times} + return nil +} + +func (p *pageImpl) onLocatorHandlerTriggered(uid float64) { + var remove *bool + handler, ok := p.locatorHandlers[uid] + if !ok { + return + } + if handler.times != nil { + *handler.times-- + if *handler.times == 0 { + remove = Bool(true) + } + } + defer func() { + if remove != nil && *remove { + delete(p.locatorHandlers, uid) + } + _, _ = p.connection.WrapAPICall(func() (interface{}, error) { + _, err := p.channel.Send("resolveLocatorHandlerNoReply", map[string]any{ + "uid": uid, + "remove": remove, + }) + return nil, err + }, true) + }() + + handler.handler(handler.locator) +} + +func (p *pageImpl) RemoveLocatorHandler(locator Locator) error { + for uid := range p.locatorHandlers { + if p.locatorHandlers[uid].locator.equals(locator) { + delete(p.locatorHandlers, uid) + p.channel.SendNoReply("unregisterLocatorHandler", map[string]any{ + "uid": uid, + }) + return nil + } + } + return nil +} + +func (p *pageImpl) Context() BrowserContext { + return p.browserContext +} + +func (b *pageImpl) Clock() Clock { + return b.browserContext.clock +} + +func (p *pageImpl) Close(options ...PageCloseOptions) error { + if len(options) == 1 { + p.closeReason = options[0].Reason + } + p.closeWasCalled = true + _, err := p.channel.Send("close", options) + if err == nil && p.ownedContext != nil { + err = p.ownedContext.Close() + } + if errors.Is(err, ErrTargetClosed) || (len(options) == 1 && options[0].RunBeforeUnload != nil && *(options[0].RunBeforeUnload)) { + return nil + } + return err +} + +func (p *pageImpl) InnerText(selector string, options ...PageInnerTextOptions) (string, error) { + if len(options) == 1 { + return p.mainFrame.InnerText(selector, FrameInnerTextOptions(options[0])) + } + return p.mainFrame.InnerText(selector) +} + +func (p *pageImpl) InnerHTML(selector string, options ...PageInnerHTMLOptions) (string, error) { + if len(options) == 1 { + return p.mainFrame.InnerHTML(selector, FrameInnerHTMLOptions(options[0])) + } + return p.mainFrame.InnerHTML(selector) +} + +func (p *pageImpl) Opener() (Page, error) { + channel := p.initializer["opener"] + channelOwner := fromNullableChannel(channel) + if channelOwner == nil { + // not popup page or opener has been closed + return nil, nil + } + return channelOwner.(*pageImpl), nil +} + +func (p *pageImpl) MainFrame() Frame { + return p.mainFrame +} + +func (p *pageImpl) Frame(options ...PageFrameOptions) Frame { + option := PageFrameOptions{} + if len(options) == 1 { + option = options[0] + } + var matcher *urlMatcher + if option.URL != nil { + matcher = newURLMatcher(option.URL, p.browserContext.options.BaseURL) + } + + for _, f := range p.frames { + if option.Name != nil && f.Name() == *option.Name { + return f + } + + if option.URL != nil && matcher != nil && matcher.Matches(f.URL()) { + return f + } + } + + return nil +} + +func (p *pageImpl) Frames() []Frame { + return p.frames +} + +func (p *pageImpl) SetDefaultNavigationTimeout(timeout float64) { + p.timeoutSettings.SetDefaultNavigationTimeout(&timeout) + p.channel.SendNoReplyInternal("setDefaultNavigationTimeoutNoReply", map[string]interface{}{ + "timeout": timeout, + }) +} + +func (p *pageImpl) SetDefaultTimeout(timeout float64) { + p.timeoutSettings.SetDefaultTimeout(&timeout) + p.channel.SendNoReplyInternal("setDefaultTimeoutNoReply", map[string]interface{}{ + "timeout": timeout, + }) +} + +func (p *pageImpl) QuerySelector(selector string, options ...PageQuerySelectorOptions) (ElementHandle, error) { + if len(options) == 1 { + return p.mainFrame.QuerySelector(selector, FrameQuerySelectorOptions(options[0])) + } + return p.mainFrame.QuerySelector(selector) +} + +func (p *pageImpl) QuerySelectorAll(selector string) ([]ElementHandle, error) { + return p.mainFrame.QuerySelectorAll(selector) +} + +func (p *pageImpl) WaitForSelector(selector string, options ...PageWaitForSelectorOptions) (ElementHandle, error) { + if len(options) == 1 { + return p.mainFrame.WaitForSelector(selector, FrameWaitForSelectorOptions(options[0])) + } + return p.mainFrame.WaitForSelector(selector) +} + +func (p *pageImpl) DispatchEvent(selector string, typ string, eventInit interface{}, options ...PageDispatchEventOptions) error { + if len(options) == 1 { + return p.mainFrame.DispatchEvent(selector, typ, eventInit, FrameDispatchEventOptions(options[0])) + } + return p.mainFrame.DispatchEvent(selector, typ, eventInit) +} + +func (p *pageImpl) Evaluate(expression string, arg ...interface{}) (interface{}, error) { + return p.mainFrame.Evaluate(expression, arg...) +} + +func (p *pageImpl) EvaluateHandle(expression string, arg ...interface{}) (JSHandle, error) { + return p.mainFrame.EvaluateHandle(expression, arg...) +} + +func (p *pageImpl) EvalOnSelector(selector string, expression string, arg interface{}, options ...PageEvalOnSelectorOptions) (interface{}, error) { + if len(options) == 1 { + return p.mainFrame.EvalOnSelector(selector, expression, arg, FrameEvalOnSelectorOptions(options[0])) + } + return p.mainFrame.EvalOnSelector(selector, expression, arg) +} + +func (p *pageImpl) EvalOnSelectorAll(selector string, expression string, arg ...interface{}) (interface{}, error) { + return p.mainFrame.EvalOnSelectorAll(selector, expression, arg...) +} + +func (p *pageImpl) AddScriptTag(options PageAddScriptTagOptions) (ElementHandle, error) { + return p.mainFrame.AddScriptTag(FrameAddScriptTagOptions(options)) +} + +func (p *pageImpl) AddStyleTag(options PageAddStyleTagOptions) (ElementHandle, error) { + return p.mainFrame.AddStyleTag(FrameAddStyleTagOptions(options)) +} + +func (p *pageImpl) SetExtraHTTPHeaders(headers map[string]string) error { + _, err := p.channel.Send("setExtraHTTPHeaders", map[string]interface{}{ + "headers": serializeMapToNameAndValue(headers), + }) + return err +} + +func (p *pageImpl) URL() string { + return p.mainFrame.URL() +} + +func (p *pageImpl) Unroute(url interface{}, handlers ...routeHandler) error { + p.Lock() + defer p.Unlock() + + removed, remaining, err := unroute(p.routes, url, handlers...) + if err != nil { + return err + } + return p.unrouteInternal(removed, remaining, UnrouteBehaviorDefault) +} + +func (p *pageImpl) unrouteInternal(removed []*routeHandlerEntry, remaining []*routeHandlerEntry, behavior *UnrouteBehavior) error { + p.routes = remaining + err := p.updateInterceptionPatterns() + if err != nil { + return err + } + if behavior == nil || behavior == UnrouteBehaviorDefault { + return nil + } + wg := &sync.WaitGroup{} + for _, entry := range removed { + wg.Add(1) + go func(entry *routeHandlerEntry) { + defer wg.Done() + entry.Stop(string(*behavior)) + }(entry) + } + wg.Wait() + return nil +} + +func (p *pageImpl) disposeHarRouters() { + for _, router := range p.harRouters { + router.dispose() + } + p.harRouters = make([]*harRouter, 0) +} + +func (p *pageImpl) UnrouteAll(options ...PageUnrouteAllOptions) error { + var behavior *UnrouteBehavior + if len(options) == 1 { + behavior = options[0].Behavior + } + p.Lock() + defer p.Unlock() + defer p.disposeHarRouters() + return p.unrouteInternal(p.routes, []*routeHandlerEntry{}, behavior) +} + +func (p *pageImpl) Content() (string, error) { + return p.mainFrame.Content() +} + +func (p *pageImpl) SetContent(html string, options ...PageSetContentOptions) error { + if len(options) == 1 { + return p.mainFrame.SetContent(html, FrameSetContentOptions(options[0])) + } + return p.mainFrame.SetContent(html) +} + +func (p *pageImpl) Goto(url string, options ...PageGotoOptions) (Response, error) { + if len(options) == 1 { + return p.mainFrame.Goto(url, FrameGotoOptions(options[0])) + } + return p.mainFrame.Goto(url) +} + +func (p *pageImpl) Reload(options ...PageReloadOptions) (Response, error) { + channel, err := p.channel.Send("reload", options) + if err != nil { + return nil, err + } + channelOwner := fromNullableChannel(channel) + if channelOwner == nil { + return nil, nil + } + return channelOwner.(*responseImpl), nil +} + +func (p *pageImpl) WaitForLoadState(options ...PageWaitForLoadStateOptions) error { + if len(options) == 1 { + return p.mainFrame.WaitForLoadState(FrameWaitForLoadStateOptions(options[0])) + } + return p.mainFrame.WaitForLoadState() +} + +func (p *pageImpl) GoBack(options ...PageGoBackOptions) (Response, error) { + channel, err := p.channel.Send("goBack", options) + if err != nil { + return nil, err + } + channelOwner := fromNullableChannel(channel) + if channelOwner == nil { + // can not go back + return nil, nil + } + return channelOwner.(*responseImpl), nil +} + +func (p *pageImpl) GoForward(options ...PageGoForwardOptions) (Response, error) { + channel, err := p.channel.Send("goForward", options) + if err != nil { + return nil, err + } + channelOwner := fromNullableChannel(channel) + if channelOwner == nil { + // can not go forward + return nil, nil + } + return channelOwner.(*responseImpl), nil +} + +func (p *pageImpl) EmulateMedia(options ...PageEmulateMediaOptions) error { + _, err := p.channel.Send("emulateMedia", options) + if err != nil { + return err + } + return err +} + +func (p *pageImpl) SetViewportSize(width, height int) error { + _, err := p.channel.Send("setViewportSize", map[string]interface{}{ + "viewportSize": map[string]interface{}{ + "width": width, + "height": height, + }, + }) + if err != nil { + return err + } + p.viewportSize.Width = width + p.viewportSize.Height = height + return nil +} + +func (p *pageImpl) ViewportSize() *Size { + return p.viewportSize +} + +func (p *pageImpl) BringToFront() error { + _, err := p.channel.Send("bringToFront") + return err +} + +func (p *pageImpl) Type(selector, text string, options ...PageTypeOptions) error { + if len(options) == 1 { + return p.mainFrame.Type(selector, text, FrameTypeOptions(options[0])) + } + return p.mainFrame.Type(selector, text) +} + +func (p *pageImpl) Fill(selector, text string, options ...PageFillOptions) error { + if len(options) == 1 { + return p.mainFrame.Fill(selector, text, FrameFillOptions(options[0])) + } + return p.mainFrame.Fill(selector, text) +} + +func (p *pageImpl) Press(selector, key string, options ...PagePressOptions) error { + if len(options) == 1 { + return p.mainFrame.Press(selector, key, FramePressOptions(options[0])) + } + return p.mainFrame.Press(selector, key) +} + +func (p *pageImpl) Title() (string, error) { + return p.mainFrame.Title() +} + +func (p *pageImpl) Workers() []Worker { + return p.workers +} + +func (p *pageImpl) Request() APIRequestContext { + return p.Context().Request() +} + +func (p *pageImpl) Screenshot(options ...PageScreenshotOptions) ([]byte, error) { + var path *string + overrides := map[string]interface{}{} + if len(options) == 1 { + path = options[0].Path + options[0].Path = nil + if options[0].Mask != nil { + masks := make([]map[string]interface{}, 0) + for _, m := range options[0].Mask { + if m.Err() != nil { // ErrLocatorNotSameFrame + return nil, m.Err() + } + l, ok := m.(*locatorImpl) + if ok { + masks = append(masks, map[string]interface{}{ + "selector": l.selector, + "frame": l.frame.channel, + }) + } + } + overrides["mask"] = masks + } + } + data, err := p.channel.Send("screenshot", options, overrides) + if err != nil { + return nil, err + } + image, err := base64.StdEncoding.DecodeString(data.(string)) + if err != nil { + return nil, fmt.Errorf("could not decode base64 :%w", err) + } + if path != nil { + if err := os.WriteFile(*path, image, 0o644); err != nil { + return nil, err + } + } + return image, nil +} + +func (p *pageImpl) PDF(options ...PagePdfOptions) ([]byte, error) { + var path *string + if len(options) == 1 { + path = options[0].Path + } + data, err := p.channel.Send("pdf", options) + if err != nil { + return nil, err + } + pdf, err := base64.StdEncoding.DecodeString(data.(string)) + if err != nil { + return nil, fmt.Errorf("could not decode base64 :%w", err) + } + if path != nil { + if err := os.WriteFile(*path, pdf, 0o644); err != nil { + return nil, err + } + } + return pdf, nil +} + +func (p *pageImpl) Click(selector string, options ...PageClickOptions) error { + if len(options) == 1 { + return p.mainFrame.Click(selector, FrameClickOptions(options[0])) + } + return p.mainFrame.Click(selector) +} + +func (p *pageImpl) WaitForEvent(event string, options ...PageWaitForEventOptions) (interface{}, error) { + return p.waiterForEvent(event, options...).Wait() +} + +func (p *pageImpl) waiterForEvent(event string, options ...PageWaitForEventOptions) *waiter { + timeout := p.timeoutSettings.Timeout() + var predicate interface{} = nil + if len(options) == 1 { + if options[0].Timeout != nil { + timeout = *options[0].Timeout + } + predicate = options[0].Predicate + } + waiter := newWaiter().WithTimeout(timeout) + waiter.RejectOnEvent(p, "close", p.closeErrorWithReason()) + waiter.RejectOnEvent(p, "crash", errors.New("page crashed")) + return waiter.WaitForEvent(p, event, predicate) +} + +func (p *pageImpl) waiterForRequest(url interface{}, options ...PageExpectRequestOptions) *waiter { + option := PageExpectRequestOptions{} + if len(options) == 1 { + option = options[0] + } + if option.Timeout == nil { + option.Timeout = Float(p.timeoutSettings.Timeout()) + } + var matcher *urlMatcher + if url != nil { + matcher = newURLMatcher(url, p.browserContext.options.BaseURL) + } + predicate := func(req *requestImpl) bool { + if matcher != nil { + return matcher.Matches(req.URL()) + } + return true + } + + waiter := newWaiter().WithTimeout(*option.Timeout) + return waiter.WaitForEvent(p, "request", predicate) +} + +func (p *pageImpl) waiterForResponse(url interface{}, options ...PageExpectResponseOptions) *waiter { + option := PageExpectResponseOptions{} + if len(options) == 1 { + option = options[0] + } + if option.Timeout == nil { + option.Timeout = Float(p.timeoutSettings.Timeout()) + } + var matcher *urlMatcher + if url != nil { + matcher = newURLMatcher(url, p.browserContext.options.BaseURL) + } + predicate := func(req *responseImpl) bool { + if matcher != nil { + return matcher.Matches(req.URL()) + } + return true + } + + waiter := newWaiter().WithTimeout(*option.Timeout) + return waiter.WaitForEvent(p, "response", predicate) +} + +func (p *pageImpl) ExpectEvent(event string, cb func() error, options ...PageExpectEventOptions) (interface{}, error) { + if len(options) == 1 { + return p.waiterForEvent(event, PageWaitForEventOptions(options[0])).RunAndWait(cb) + } + return p.waiterForEvent(event).RunAndWait(cb) +} + +func (p *pageImpl) ExpectNavigation(cb func() error, options ...PageExpectNavigationOptions) (Response, error) { + if len(options) == 1 { + return p.mainFrame.ExpectNavigation(cb, FrameExpectNavigationOptions(options[0])) + } + return p.mainFrame.ExpectNavigation(cb) +} + +func (p *pageImpl) ExpectConsoleMessage(cb func() error, options ...PageExpectConsoleMessageOptions) (ConsoleMessage, error) { + option := PageWaitForEventOptions{} + if len(options) == 1 { + option.Timeout = options[0].Timeout + option.Predicate = options[0].Predicate + } + ret, err := p.waiterForEvent("console", option).RunAndWait(cb) + if ret == nil { + return nil, err + } + return ret.(*consoleMessageImpl), err +} + +func (p *pageImpl) ExpectDownload(cb func() error, options ...PageExpectDownloadOptions) (Download, error) { + option := PageWaitForEventOptions{} + if len(options) == 1 { + option.Timeout = options[0].Timeout + option.Predicate = options[0].Predicate + } + ret, err := p.waiterForEvent("download", option).RunAndWait(cb) + if ret == nil { + return nil, err + } + return ret.(*downloadImpl), err +} + +func (p *pageImpl) ExpectFileChooser(cb func() error, options ...PageExpectFileChooserOptions) (FileChooser, error) { + option := PageWaitForEventOptions{} + if len(options) == 1 { + option.Timeout = options[0].Timeout + option.Predicate = options[0].Predicate + } + ret, err := p.waiterForEvent("filechooser", option).RunAndWait(cb) + if ret == nil { + return nil, err + } + return ret.(*fileChooserImpl), err +} + +func (p *pageImpl) ExpectPopup(cb func() error, options ...PageExpectPopupOptions) (Page, error) { + option := PageWaitForEventOptions{} + if len(options) == 1 { + option.Timeout = options[0].Timeout + option.Predicate = options[0].Predicate + } + ret, err := p.waiterForEvent("popup", option).RunAndWait(cb) + if ret == nil { + return nil, err + } + return ret.(*pageImpl), err +} + +func (p *pageImpl) ExpectResponse(url interface{}, cb func() error, options ...PageExpectResponseOptions) (Response, error) { + ret, err := p.waiterForResponse(url, options...).RunAndWait(cb) + if ret == nil { + return nil, err + } + return ret.(*responseImpl), err +} + +func (p *pageImpl) ExpectRequest(url interface{}, cb func() error, options ...PageExpectRequestOptions) (Request, error) { + ret, err := p.waiterForRequest(url, options...).RunAndWait(cb) + if ret == nil { + return nil, err + } + return ret.(*requestImpl), err +} + +func (p *pageImpl) ExpectRequestFinished(cb func() error, options ...PageExpectRequestFinishedOptions) (Request, error) { + option := PageWaitForEventOptions{} + if len(options) == 1 { + option.Timeout = options[0].Timeout + option.Predicate = options[0].Predicate + } + ret, err := p.waiterForEvent("requestfinished", option).RunAndWait(cb) + if ret == nil { + return nil, err + } + return ret.(*requestImpl), err +} + +func (p *pageImpl) ExpectWebSocket(cb func() error, options ...PageExpectWebSocketOptions) (WebSocket, error) { + option := PageWaitForEventOptions{} + if len(options) == 1 { + option.Timeout = options[0].Timeout + option.Predicate = options[0].Predicate + } + ret, err := p.waiterForEvent("websocket", option).RunAndWait(cb) + if ret == nil { + return nil, err + } + return ret.(*webSocketImpl), err +} + +func (p *pageImpl) ExpectWorker(cb func() error, options ...PageExpectWorkerOptions) (Worker, error) { + option := PageWaitForEventOptions{} + if len(options) == 1 { + option.Timeout = options[0].Timeout + option.Predicate = options[0].Predicate + } + ret, err := p.waiterForEvent("worker", option).RunAndWait(cb) + if ret == nil { + return nil, err + } + return ret.(*workerImpl), err +} + +func (p *pageImpl) Route(url interface{}, handler routeHandler, times ...int) error { + p.Lock() + defer p.Unlock() + p.routes = slices.Insert(p.routes, 0, newRouteHandlerEntry(newURLMatcher(url, p.browserContext.options.BaseURL), handler, times...)) + return p.updateInterceptionPatterns() +} + +func (p *pageImpl) GetAttribute(selector string, name string, options ...PageGetAttributeOptions) (string, error) { + if len(options) == 1 { + return p.mainFrame.GetAttribute(selector, name, FrameGetAttributeOptions(options[0])) + } + return p.mainFrame.GetAttribute(selector, name) +} + +func (p *pageImpl) Hover(selector string, options ...PageHoverOptions) error { + if len(options) == 1 { + return p.mainFrame.Hover(selector, FrameHoverOptions(options[0])) + } + return p.mainFrame.Hover(selector) +} + +func (p *pageImpl) IsClosed() bool { + return p.isClosed +} + +func (p *pageImpl) AddInitScript(script Script) error { + var source string + if script.Content != nil { + source = *script.Content + } + if script.Path != nil { + content, err := os.ReadFile(*script.Path) + if err != nil { + return err + } + source = string(content) + } + _, err := p.channel.Send("addInitScript", map[string]interface{}{ + "source": source, + }) + return err +} + +func (p *pageImpl) Keyboard() Keyboard { + return p.keyboard +} + +func (p *pageImpl) Mouse() Mouse { + return p.mouse +} + +func (p *pageImpl) RouteFromHAR(har string, options ...PageRouteFromHAROptions) error { + opt := PageRouteFromHAROptions{} + if len(options) == 1 { + opt = options[0] + } + if opt.Update != nil && *opt.Update { + return p.browserContext.recordIntoHar(har, browserContextRecordIntoHarOptions{ + Page: p, + URL: opt.URL, + }) + } + notFound := opt.NotFound + if notFound == nil { + notFound = HarNotFoundAbort + } + router := newHarRouter(p.connection.localUtils, har, *notFound, opt.URL) + p.harRouters = append(p.harRouters, router) + return router.addPageRoute(p) +} + +func (p *pageImpl) Touchscreen() Touchscreen { + return p.touchscreen +} + +func newPage(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *pageImpl { + viewportSize := &Size{} + if _, ok := initializer["viewportSize"].(map[string]interface{}); ok { + viewportSize.Height = int(initializer["viewportSize"].(map[string]interface{})["height"].(float64)) + viewportSize.Width = int(initializer["viewportSize"].(map[string]interface{})["width"].(float64)) + } + bt := &pageImpl{ + workers: make([]Worker, 0), + routes: make([]*routeHandlerEntry, 0), + bindings: safe.NewSyncMap[string, BindingCallFunction](), + viewportSize: viewportSize, + harRouters: make([]*harRouter, 0), + locatorHandlers: make(map[float64]*locatorHandlerEntry, 0), + } + bt.createChannelOwner(bt, parent, objectType, guid, initializer) + bt.browserContext = fromChannel(parent.channel).(*browserContextImpl) + bt.timeoutSettings = newTimeoutSettings(bt.browserContext.timeoutSettings) + mainframe := fromChannel(initializer["mainFrame"]).(*frameImpl) + mainframe.page = bt + bt.mainFrame = mainframe + bt.frames = []Frame{mainframe} + bt.mouse = newMouse(bt.channel) + bt.keyboard = newKeyboard(bt.channel) + bt.touchscreen = newTouchscreen(bt.channel) + bt.channel.On("bindingCall", func(params map[string]interface{}) { + bt.onBinding(fromChannel(params["binding"]).(*bindingCallImpl)) + }) + bt.channel.On("close", bt.onClose) + bt.channel.On("crash", func() { + bt.Emit("crash", bt) + }) + bt.channel.On("domcontentloaded", func() { + bt.Emit("domcontentloaded", bt) + }) + bt.channel.On("fileChooser", func(ev map[string]interface{}) { + bt.Emit("filechooser", newFileChooser(bt, fromChannel(ev["element"]).(*elementHandleImpl), ev["isMultiple"].(bool))) + }) + bt.channel.On("frameAttached", func(ev map[string]interface{}) { + bt.onFrameAttached(fromChannel(ev["frame"]).(*frameImpl)) + }) + bt.channel.On("frameDetached", func(ev map[string]interface{}) { + bt.onFrameDetached(fromChannel(ev["frame"]).(*frameImpl)) + }) + bt.channel.On("locatorHandlerTriggered", func(ev map[string]interface{}) { + bt.channel.CreateTask(func() { + bt.onLocatorHandlerTriggered(ev["uid"].(float64)) + }) + }) + bt.channel.On( + "load", func(ev map[string]interface{}) { + bt.Emit("load", bt) + }, + ) + bt.channel.On("popup", func(ev map[string]interface{}) { + bt.Emit("popup", fromChannel(ev["page"]).(*pageImpl)) + }) + bt.channel.On("route", func(ev map[string]interface{}) { + bt.channel.CreateTask(func() { + bt.onRoute(fromChannel(ev["route"]).(*routeImpl)) + }) + }) + bt.channel.On("download", func(ev map[string]interface{}) { + url := ev["url"].(string) + suggestedFilename := ev["suggestedFilename"].(string) + artifact := fromChannel(ev["artifact"]).(*artifactImpl) + bt.Emit("download", newDownload(bt, url, suggestedFilename, artifact)) + }) + bt.channel.On("video", func(params map[string]interface{}) { + artifact := fromChannel(params["artifact"]).(*artifactImpl) + bt.Video().(*videoImpl).artifactReady(artifact) + }) + bt.channel.On("webSocket", func(ev map[string]interface{}) { + bt.Emit("websocket", fromChannel(ev["webSocket"]).(*webSocketImpl)) + }) + bt.channel.On("webSocketRoute", func(ev map[string]interface{}) { + bt.channel.CreateTask(func() { + bt.onWebSocketRoute(fromChannel(ev["webSocketRoute"]).(*webSocketRouteImpl)) + }) + }) + + bt.channel.On("worker", func(ev map[string]interface{}) { + bt.onWorker(fromChannel(ev["worker"]).(*workerImpl)) + }) + bt.closedOrCrashed = make(chan error, 1) + bt.OnClose(func(Page) { + select { + case bt.closedOrCrashed <- bt.closeErrorWithReason(): + default: + } + }) + bt.OnCrash(func(Page) { + select { + case bt.closedOrCrashed <- ErrTargetClosed: + default: + } + }) + bt.setEventSubscriptionMapping(map[string]string{ + "console": "console", + "dialog": "dialog", + "request": "request", + "response": "response", + "requestfinished": "requestFinished", + "responsefailed": "responseFailed", + "filechooser": "fileChooser", + }) + + return bt +} + +func (p *pageImpl) closeErrorWithReason() error { + if p.closeReason != nil { + return targetClosedError(p.closeReason) + } + return targetClosedError(p.browserContext.effectiveCloseReason()) +} + +func (p *pageImpl) onBinding(binding *bindingCallImpl) { + function, ok := p.bindings.Load(binding.initializer["name"].(string)) + if !ok || function == nil { + return + } + go binding.Call(function) +} + +func (p *pageImpl) onFrameAttached(frame *frameImpl) { + frame.page = p + p.frames = append(p.frames, frame) + p.Emit("frameattached", frame) +} + +func (p *pageImpl) onFrameDetached(frame *frameImpl) { + frame.detached = true + frames := make([]Frame, 0) + for i := 0; i < len(p.frames); i++ { + if p.frames[i] != frame { + frames = append(frames, frame) + } + } + if len(frames) != len(p.frames) { + p.frames = frames + } + p.Emit("framedetached", frame) +} + +func (p *pageImpl) onRoute(route *routeImpl) { + p.Lock() + route.context = p.browserContext + routes := make([]*routeHandlerEntry, len(p.routes)) + copy(routes, p.routes) + p.Unlock() + + checkInterceptionIfNeeded := func() { + p.Lock() + defer p.Unlock() + if len(p.routes) == 0 { + _, err := p.connection.WrapAPICall(func() (interface{}, error) { + err := p.updateInterceptionPatterns() + return nil, err + }, true) + if err != nil { + logger.Error("could not update interception patterns", "error", err) + } + } + } + + url := route.Request().URL() + for _, handlerEntry := range routes { + // If the page was closed we stall all requests right away. + if p.closeWasCalled || p.browserContext.closeWasCalled { + return + } + if !handlerEntry.Matches(url) { + continue + } + if !slices.ContainsFunc(p.routes, func(entry *routeHandlerEntry) bool { + return entry == handlerEntry + }) { + continue + } + if handlerEntry.WillExceed() { + p.routes = slices.DeleteFunc(p.routes, func(rhe *routeHandlerEntry) bool { + return rhe == handlerEntry + }) + } + handled := handlerEntry.Handle(route) + checkInterceptionIfNeeded() + + if <-handled { + return + } + } + p.browserContext.onRoute(route) +} + +func (p *pageImpl) updateInterceptionPatterns() error { + patterns := prepareInterceptionPatterns(p.routes) + _, err := p.channel.Send("setNetworkInterceptionPatterns", map[string]interface{}{ + "patterns": patterns, + }) + return err +} + +func (p *pageImpl) onWorker(worker *workerImpl) { + p.workers = append(p.workers, worker) + worker.page = p + p.Emit("worker", worker) +} + +func (p *pageImpl) onClose() { + p.isClosed = true + newPages := []Page{} + newBackgoundPages := []Page{} + if p.browserContext != nil { + p.browserContext.Lock() + for _, page := range p.browserContext.pages { + if page != p { + newPages = append(newPages, page) + } + } + for _, page := range p.browserContext.backgroundPages { + if page != p { + newBackgoundPages = append(newBackgoundPages, page) + } + } + p.browserContext.pages = newPages + p.browserContext.backgroundPages = newBackgoundPages + p.browserContext.Unlock() + } + p.disposeHarRouters() + p.Emit("close", p) +} + +func (p *pageImpl) SetInputFiles(selector string, files interface{}, options ...PageSetInputFilesOptions) error { + if len(options) == 1 { + return p.mainFrame.SetInputFiles(selector, files, FrameSetInputFilesOptions(options[0])) + } + return p.mainFrame.SetInputFiles(selector, files) +} + +func (p *pageImpl) Check(selector string, options ...PageCheckOptions) error { + if len(options) == 1 { + return p.mainFrame.Check(selector, FrameCheckOptions(options[0])) + } + return p.mainFrame.Check(selector) +} + +func (p *pageImpl) Uncheck(selector string, options ...PageUncheckOptions) error { + if len(options) == 1 { + return p.mainFrame.Uncheck(selector, FrameUncheckOptions(options[0])) + } + return p.mainFrame.Uncheck(selector) +} + +func (p *pageImpl) WaitForTimeout(timeout float64) { + p.mainFrame.WaitForTimeout(timeout) +} + +func (p *pageImpl) WaitForFunction(expression string, arg interface{}, options ...PageWaitForFunctionOptions) (JSHandle, error) { + if len(options) == 1 { + return p.mainFrame.WaitForFunction(expression, arg, FrameWaitForFunctionOptions(options[0])) + } + return p.mainFrame.WaitForFunction(expression, arg) +} + +func (p *pageImpl) Dblclick(expression string, options ...PageDblclickOptions) error { + if len(options) == 1 { + return p.mainFrame.Dblclick(expression, FrameDblclickOptions(options[0])) + } + return p.mainFrame.Dblclick(expression) +} + +func (p *pageImpl) Focus(expression string, options ...PageFocusOptions) error { + if len(options) == 1 { + return p.mainFrame.Focus(expression, FrameFocusOptions(options[0])) + } + return p.mainFrame.Focus(expression) +} + +func (p *pageImpl) TextContent(selector string, options ...PageTextContentOptions) (string, error) { + if len(options) == 1 { + return p.mainFrame.TextContent(selector, FrameTextContentOptions(options[0])) + } + return p.mainFrame.TextContent(selector) +} + +func (p *pageImpl) Video() Video { + p.Lock() + defer p.Unlock() + + if p.video == nil { + p.video = newVideo(p) + } + return p.video +} + +func (p *pageImpl) Tap(selector string, options ...PageTapOptions) error { + if len(options) == 1 { + return p.mainFrame.Tap(selector, FrameTapOptions(options[0])) + } + return p.mainFrame.Tap(selector) +} + +func (p *pageImpl) ExposeFunction(name string, binding ExposedFunction) error { + return p.ExposeBinding(name, func(source *BindingSource, args ...interface{}) interface{} { + return binding(args...) + }) +} + +func (p *pageImpl) ExposeBinding(name string, binding BindingCallFunction, handle ...bool) error { + needsHandle := false + if len(handle) == 1 { + needsHandle = handle[0] + } + if _, ok := p.bindings.Load(name); ok { + return fmt.Errorf("Function '%s' has been already registered", name) + } + if _, ok := p.browserContext.bindings.Load(name); ok { + return fmt.Errorf("Function '%s' has been already registered in the browser context", name) + } + _, err := p.channel.Send("exposeBinding", map[string]interface{}{ + "name": name, + "needsHandle": needsHandle, + }) + if err != nil { + return err + } + p.bindings.Store(name, binding) + return nil +} + +func (p *pageImpl) SelectOption(selector string, values SelectOptionValues, options ...PageSelectOptionOptions) ([]string, error) { + if len(options) == 1 { + return p.mainFrame.SelectOption(selector, values, FrameSelectOptionOptions(options[0])) + } + return p.mainFrame.SelectOption(selector, values) +} + +func (p *pageImpl) IsChecked(selector string, options ...PageIsCheckedOptions) (bool, error) { + if len(options) == 1 { + return p.mainFrame.IsChecked(selector, FrameIsCheckedOptions(options[0])) + } + return p.mainFrame.IsChecked(selector) +} + +func (p *pageImpl) IsDisabled(selector string, options ...PageIsDisabledOptions) (bool, error) { + if len(options) == 1 { + return p.mainFrame.IsDisabled(selector, FrameIsDisabledOptions(options[0])) + } + return p.mainFrame.IsDisabled(selector) +} + +func (p *pageImpl) IsEditable(selector string, options ...PageIsEditableOptions) (bool, error) { + if len(options) == 1 { + return p.mainFrame.IsEditable(selector, FrameIsEditableOptions(options[0])) + } + return p.mainFrame.IsEditable(selector) +} + +func (p *pageImpl) IsEnabled(selector string, options ...PageIsEnabledOptions) (bool, error) { + if len(options) == 1 { + return p.mainFrame.IsEnabled(selector, FrameIsEnabledOptions(options[0])) + } + return p.mainFrame.IsEnabled(selector) +} + +func (p *pageImpl) IsHidden(selector string, options ...PageIsHiddenOptions) (bool, error) { + if len(options) == 1 { + return p.mainFrame.IsHidden(selector, FrameIsHiddenOptions(options[0])) + } + return p.mainFrame.IsHidden(selector) +} + +func (p *pageImpl) IsVisible(selector string, options ...PageIsVisibleOptions) (bool, error) { + if len(options) == 1 { + return p.mainFrame.IsVisible(selector, FrameIsVisibleOptions(options[0])) + } + return p.mainFrame.IsVisible(selector) +} + +func (p *pageImpl) DragAndDrop(source, target string, options ...PageDragAndDropOptions) error { + if len(options) == 1 { + return p.mainFrame.DragAndDrop(source, target, FrameDragAndDropOptions(options[0])) + } + return p.mainFrame.DragAndDrop(source, target) +} + +func (p *pageImpl) Pause() (err error) { + defaultNavigationTimout := p.browserContext.timeoutSettings.DefaultNavigationTimeout() + defaultTimeout := p.browserContext.timeoutSettings.DefaultTimeout() + p.browserContext.SetDefaultNavigationTimeout(0) + p.browserContext.SetDefaultTimeout(0) + select { + case err = <-p.closedOrCrashed: + case err = <-p.browserContext.pause(): + } + if err != nil { + return err + } + p.browserContext.setDefaultNavigationTimeoutImpl(defaultNavigationTimout) + p.browserContext.setDefaultTimeoutImpl(defaultTimeout) + return +} + +func (p *pageImpl) InputValue(selector string, options ...PageInputValueOptions) (string, error) { + if len(options) == 1 { + return p.mainFrame.InputValue(selector, FrameInputValueOptions(options[0])) + } + return p.mainFrame.InputValue(selector) +} + +func (p *pageImpl) WaitForURL(url interface{}, options ...PageWaitForURLOptions) error { + if len(options) == 1 { + return p.mainFrame.WaitForURL(url, FrameWaitForURLOptions(options[0])) + } + return p.mainFrame.WaitForURL(url) +} + +func (p *pageImpl) SetChecked(selector string, checked bool, options ...PageSetCheckedOptions) error { + if len(options) == 1 { + return p.mainFrame.SetChecked(selector, checked, FrameSetCheckedOptions(options[0])) + } + return p.mainFrame.SetChecked(selector, checked) +} + +func (p *pageImpl) Locator(selector string, options ...PageLocatorOptions) Locator { + var option FrameLocatorOptions + if len(options) == 1 { + option = FrameLocatorOptions(options[0]) + } + return p.mainFrame.Locator(selector, option) +} + +func (p *pageImpl) GetByAltText(text interface{}, options ...PageGetByAltTextOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return p.Locator(getByAltTextSelector(text, exact)) +} + +func (p *pageImpl) GetByLabel(text interface{}, options ...PageGetByLabelOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return p.Locator(getByLabelSelector(text, exact)) +} + +func (p *pageImpl) GetByPlaceholder(text interface{}, options ...PageGetByPlaceholderOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return p.Locator(getByPlaceholderSelector(text, exact)) +} + +func (p *pageImpl) GetByRole(role AriaRole, options ...PageGetByRoleOptions) Locator { + if len(options) == 1 { + return p.Locator(getByRoleSelector(role, LocatorGetByRoleOptions(options[0]))) + } + return p.Locator(getByRoleSelector(role)) +} + +func (p *pageImpl) GetByTestId(testId interface{}) Locator { + return p.Locator(getByTestIdSelector(getTestIdAttributeName(), testId)) +} + +func (p *pageImpl) GetByText(text interface{}, options ...PageGetByTextOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return p.Locator(getByTextSelector(text, exact)) +} + +func (p *pageImpl) GetByTitle(text interface{}, options ...PageGetByTitleOptions) Locator { + exact := false + if len(options) == 1 { + if *options[0].Exact { + exact = true + } + } + return p.Locator(getByTitleSelector(text, exact)) +} + +func (p *pageImpl) FrameLocator(selector string) FrameLocator { + return p.mainFrame.FrameLocator(selector) +} + +func (p *pageImpl) OnClose(fn func(Page)) { + p.On("close", fn) +} + +func (p *pageImpl) OnConsole(fn func(ConsoleMessage)) { + p.On("console", fn) +} + +func (p *pageImpl) OnCrash(fn func(Page)) { + p.On("crash", fn) +} + +func (p *pageImpl) OnDialog(fn func(Dialog)) { + p.On("dialog", fn) +} + +func (p *pageImpl) OnDOMContentLoaded(fn func(Page)) { + p.On("domcontentloaded", fn) +} + +func (p *pageImpl) OnDownload(fn func(Download)) { + p.On("download", fn) +} + +func (p *pageImpl) OnFileChooser(fn func(FileChooser)) { + p.On("filechooser", fn) +} + +func (p *pageImpl) OnFrameAttached(fn func(Frame)) { + p.On("frameattached", fn) +} + +func (p *pageImpl) OnFrameDetached(fn func(Frame)) { + p.On("framedetached", fn) +} + +func (p *pageImpl) OnFrameNavigated(fn func(Frame)) { + p.On("framenavigated", fn) +} + +func (p *pageImpl) OnLoad(fn func(Page)) { + p.On("load", fn) +} + +func (p *pageImpl) OnPageError(fn func(error)) { + p.On("pageerror", fn) +} + +func (p *pageImpl) OnPopup(fn func(Page)) { + p.On("popup", fn) +} + +func (p *pageImpl) OnRequest(fn func(Request)) { + p.On("request", fn) +} + +func (p *pageImpl) OnRequestFailed(fn func(Request)) { + p.On("requestfailed", fn) +} + +func (p *pageImpl) OnRequestFinished(fn func(Request)) { + p.On("requestfinished", fn) +} + +func (p *pageImpl) OnResponse(fn func(Response)) { + p.On("response", fn) +} + +func (p *pageImpl) OnWebSocket(fn func(WebSocket)) { + p.On("websocket", fn) +} + +func (p *pageImpl) OnWorker(fn func(Worker)) { + p.On("worker", fn) +} + +func (p *pageImpl) RequestGC() error { + _, err := p.channel.Send("requestGC") + return err +} + +func (p *pageImpl) RouteWebSocket(url interface{}, handler func(WebSocketRoute)) error { + p.Lock() + defer p.Unlock() + p.webSocketRoutes = slices.Insert(p.webSocketRoutes, 0, newWebSocketRouteHandler(newURLMatcher(url, p.browserContext.options.BaseURL, true), handler)) + + return p.updateWebSocketInterceptionPatterns() +} + +func (p *pageImpl) onWebSocketRoute(wr WebSocketRoute) { + p.Lock() + index := slices.IndexFunc(p.webSocketRoutes, func(r *webSocketRouteHandler) bool { + return r.Matches(wr.URL()) + }) + if index == -1 { + p.Unlock() + p.browserContext.onWebSocketRoute(wr) + return + } + handler := p.webSocketRoutes[index] + p.Unlock() + handler.Handle(wr) +} + +func (p *pageImpl) updateWebSocketInterceptionPatterns() error { + patterns := prepareWebSocketRouteHandlerInterceptionPatterns(p.webSocketRoutes) + _, err := p.channel.Send("setWebSocketInterceptionPatterns", map[string]interface{}{ + "patterns": patterns, + }) + return err +} diff --git a/vendor/github.com/playwright-community/playwright-go/page_assertions.go b/vendor/github.com/playwright-community/playwright-go/page_assertions.go new file mode 100644 index 0000000..43bd0dc --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/page_assertions.go @@ -0,0 +1,70 @@ +package playwright + +import ( + "net/url" + "path" +) + +type pageAssertionsImpl struct { + assertionsBase + actualPage Page +} + +func newPageAssertions(page Page, isNot bool, defaultTimeout *float64) *pageAssertionsImpl { + return &pageAssertionsImpl{ + assertionsBase: assertionsBase{ + actualLocator: page.Locator(":root"), + isNot: isNot, + defaultTimeout: defaultTimeout, + }, + actualPage: page, + } +} + +func (pa *pageAssertionsImpl) ToHaveTitle(titleOrRegExp interface{}, options ...PageAssertionsToHaveTitleOptions) error { + var timeout *float64 + if len(options) == 1 { + timeout = options[0].Timeout + } + expectedValues, err := toExpectedTextValues([]interface{}{titleOrRegExp}, false, true, nil) + if err != nil { + return err + } + return pa.expect( + "to.have.title", + frameExpectOptions{ExpectedText: expectedValues, Timeout: timeout}, + titleOrRegExp, + "Page title expected to be", + ) +} + +func (pa *pageAssertionsImpl) ToHaveURL(urlOrRegExp interface{}, options ...PageAssertionsToHaveURLOptions) error { + var timeout *float64 + var ignoreCase *bool + if len(options) == 1 { + timeout = options[0].Timeout + ignoreCase = options[0].IgnoreCase + } + + baseURL := pa.actualPage.Context().(*browserContextImpl).options.BaseURL + if urlPath, ok := urlOrRegExp.(string); ok && baseURL != nil { + u, _ := url.Parse(*baseURL) + u.Path = path.Join(u.Path, urlPath) + urlOrRegExp = u.String() + } + + expectedValues, err := toExpectedTextValues([]interface{}{urlOrRegExp}, false, false, ignoreCase) + if err != nil { + return err + } + return pa.expect( + "to.have.url", + frameExpectOptions{ExpectedText: expectedValues, Timeout: timeout}, + urlOrRegExp, + "Page URL expected to be", + ) +} + +func (pa *pageAssertionsImpl) Not() PageAssertions { + return newPageAssertions(pa.actualPage, true, pa.defaultTimeout) +} diff --git a/vendor/github.com/playwright-community/playwright-go/playwright.go b/vendor/github.com/playwright-community/playwright-go/playwright.go new file mode 100644 index 0000000..805ac14 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/playwright.go @@ -0,0 +1,64 @@ +// Package playwright is a library to automate Chromium, Firefox and WebKit with +// a single API. Playwright is built to enable cross-browser web automation that +// is ever-green, capable, reliable and fast. +package playwright + +// DeviceDescriptor represents a single device +type DeviceDescriptor struct { + UserAgent string `json:"userAgent"` + Viewport *Size `json:"viewport"` + Screen *Size `json:"screen"` + DeviceScaleFactor float64 `json:"deviceScaleFactor"` + IsMobile bool `json:"isMobile"` + HasTouch bool `json:"hasTouch"` + DefaultBrowserType string `json:"defaultBrowserType"` +} + +// Playwright represents a Playwright instance +type Playwright struct { + channelOwner + Selectors Selectors + Chromium BrowserType + Firefox BrowserType + WebKit BrowserType + Request APIRequest + Devices map[string]*DeviceDescriptor +} + +// Stop stops the Playwright instance +func (p *Playwright) Stop() error { + return p.connection.Stop() +} + +func (p *Playwright) setSelectors(selectors Selectors) { + selectorsOwner := fromChannel(p.initializer["selectors"]).(*selectorsOwnerImpl) + p.Selectors.(*selectorsImpl).removeChannel(selectorsOwner) + p.Selectors = selectors + p.Selectors.(*selectorsImpl).addChannel(selectorsOwner) +} + +func newPlaywright(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *Playwright { + pw := &Playwright{ + Selectors: newSelectorsImpl(), + Chromium: fromChannel(initializer["chromium"]).(*browserTypeImpl), + Firefox: fromChannel(initializer["firefox"]).(*browserTypeImpl), + WebKit: fromChannel(initializer["webkit"]).(*browserTypeImpl), + Devices: make(map[string]*DeviceDescriptor), + } + pw.createChannelOwner(pw, parent, objectType, guid, initializer) + pw.Request = newApiRequestImpl(pw) + pw.Chromium.(*browserTypeImpl).playwright = pw + pw.Firefox.(*browserTypeImpl).playwright = pw + pw.WebKit.(*browserTypeImpl).playwright = pw + selectorsOwner := fromChannel(initializer["selectors"]).(*selectorsOwnerImpl) + pw.Selectors.(*selectorsImpl).addChannel(selectorsOwner) + pw.connection.afterClose = func() { + pw.Selectors.(*selectorsImpl).removeChannel(selectorsOwner) + } + if pw.connection.localUtils != nil { + pw.Devices = pw.connection.localUtils.Devices + } + return pw +} + +//go:generate bash scripts/generate-api.sh diff --git a/vendor/github.com/playwright-community/playwright-go/request.go b/vendor/github.com/playwright-community/playwright-go/request.go new file mode 100644 index 0000000..43a3161 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/request.go @@ -0,0 +1,274 @@ +package playwright + +import ( + "encoding/base64" + "encoding/json" + "fmt" +) + +type serializedFallbackOverrides struct { + URL *string + Method *string + Headers map[string]string + PostDataBuffer []byte +} + +type requestImpl struct { + channelOwner + timing *RequestTiming + provisionalHeaders *rawHeaders + allHeaders *rawHeaders + redirectedFrom Request + redirectedTo Request + failureText string + fallbackOverrides *serializedFallbackOverrides +} + +func (r *requestImpl) URL() string { + if r.fallbackOverrides.URL != nil { + return *r.fallbackOverrides.URL + } + return r.initializer["url"].(string) +} + +func (r *requestImpl) ResourceType() string { + return r.initializer["resourceType"].(string) +} + +func (r *requestImpl) Method() string { + if r.fallbackOverrides.Method != nil { + return *r.fallbackOverrides.Method + } + return r.initializer["method"].(string) +} + +func (r *requestImpl) PostData() (string, error) { + body, err := r.PostDataBuffer() + if err != nil { + return "", err + } + return string(body), err +} + +func (r *requestImpl) PostDataJSON(v interface{}) error { + body, err := r.PostDataBuffer() + if err != nil { + return err + } + return json.Unmarshal(body, v) +} + +func (r *requestImpl) PostDataBuffer() ([]byte, error) { + if r.fallbackOverrides.PostDataBuffer != nil { + return r.fallbackOverrides.PostDataBuffer, nil + } + if _, ok := r.initializer["postData"]; !ok { + return nil, nil + } + return base64.StdEncoding.DecodeString(r.initializer["postData"].(string)) +} + +func (r *requestImpl) Headers() map[string]string { + if r.fallbackOverrides.Headers != nil { + return newRawHeaders(serializeMapToNameAndValue(r.fallbackOverrides.Headers)).Headers() + } + return r.provisionalHeaders.Headers() +} + +func (r *requestImpl) Response() (Response, error) { + channel, err := r.channel.Send("response") + if err != nil { + return nil, err + } + channelOwner := fromNullableChannel(channel) + if channelOwner == nil { + // no response + return nil, nil + } + return channelOwner.(*responseImpl), nil +} + +func (r *requestImpl) Frame() Frame { + channel, ok := r.initializer["frame"] + if !ok { + // Service Worker requests do not have an associated frame. + return nil + } + frame := fromChannel(channel).(*frameImpl) + if frame.page == nil { + // Frame for this navigation request is not available, because the request + // was issued before the frame is created. You can check whether the request + // is a navigation request by calling IsNavigationRequest() method. + return nil + } + return frame +} + +func (r *requestImpl) IsNavigationRequest() bool { + return r.initializer["isNavigationRequest"].(bool) +} + +func (r *requestImpl) RedirectedFrom() Request { + return r.redirectedFrom +} + +func (r *requestImpl) RedirectedTo() Request { + return r.redirectedTo +} + +func (r *requestImpl) Failure() error { + if r.failureText == "" { + return nil + } + return fmt.Errorf("%v", r.failureText) +} + +func (r *requestImpl) Timing() *RequestTiming { + return r.timing +} + +func (r *requestImpl) AllHeaders() (map[string]string, error) { + headers, err := r.ActualHeaders() + if err != nil { + return nil, err + } + return headers.Headers(), nil +} + +func (r *requestImpl) HeadersArray() ([]NameValue, error) { + headers, err := r.ActualHeaders() + if err != nil { + return nil, err + } + return headers.HeadersArray(), nil +} + +func (r *requestImpl) HeaderValue(name string) (string, error) { + headers, err := r.ActualHeaders() + if err != nil { + return "", err + } + return headers.Get(name), err +} + +func (r *requestImpl) HeaderValues(name string) ([]string, error) { + headers, err := r.ActualHeaders() + if err != nil { + return []string{}, err + } + return headers.GetAll(name), err +} + +func (r *requestImpl) ActualHeaders() (*rawHeaders, error) { + if r.fallbackOverrides.Headers != nil { + return newRawHeaders(serializeMapToNameAndValue(r.fallbackOverrides.Headers)), nil + } + if r.allHeaders == nil { + response, err := r.Response() + if err != nil { + return nil, err + } + if response == nil { + return r.provisionalHeaders, nil + } + headers, err := r.channel.Send("rawRequestHeaders") + if err != nil { + return nil, err + } + r.allHeaders = newRawHeaders(headers) + } + return r.allHeaders, nil +} + +func (r *requestImpl) ServiceWorker() Worker { + channel, ok := r.initializer["serviceWorker"] + if !ok { + return nil + } + return fromChannel(channel).(*workerImpl) +} + +func (r *requestImpl) Sizes() (*RequestSizesResult, error) { + response, err := r.Response() + if err != nil { + return nil, err + } + sizes, err := response.(*responseImpl).channel.Send("sizes") + if err != nil { + return nil, err + } + result := &RequestSizesResult{} + remapMapToStruct(sizes, result) + return result, nil +} + +func (r *requestImpl) applyFallbackOverrides(options RouteFallbackOptions) { + if options.URL != nil { + r.fallbackOverrides.URL = options.URL + } + if options.Method != nil { + r.fallbackOverrides.Method = options.Method + } + r.fallbackOverrides.Headers = options.Headers + if options.PostData != nil { + switch v := options.PostData.(type) { + case string: + r.fallbackOverrides.PostDataBuffer = []byte(v) + case []byte: + r.fallbackOverrides.PostDataBuffer = v + } + } +} + +func (r *requestImpl) targetClosed() <-chan error { + page := r.safePage() + if page == nil { + return make(<-chan error, 1) + } + return page.closedOrCrashed +} + +func (r *requestImpl) setResponseEndTiming(t float64) { + r.timing.ResponseEnd = t + if r.timing.ResponseStart == -1 { + r.timing.ResponseStart = t + } +} + +func (r *requestImpl) safePage() *pageImpl { + channel := fromNullableChannel(r.initializer["frame"]) + if channel == nil { + return nil + } + frame, ok := channel.(*frameImpl) + if !ok { + return nil + } + return frame.page +} + +func newRequest(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *requestImpl { + req := &requestImpl{} + req.createChannelOwner(req, parent, objectType, guid, initializer) + redirectedFrom := fromNullableChannel(initializer["redirectedFrom"]) + if redirectedFrom != nil { + req.redirectedFrom = redirectedFrom.(*requestImpl) + } + if req.redirectedFrom != nil { + req.redirectedFrom.(*requestImpl).redirectedTo = req + } + req.timing = &RequestTiming{ + StartTime: 0, + DomainLookupStart: -1, + DomainLookupEnd: -1, + ConnectStart: -1, + SecureConnectionStart: -1, + ConnectEnd: -1, + RequestStart: -1, + ResponseStart: -1, + ResponseEnd: -1, + } + req.provisionalHeaders = newRawHeaders(req.initializer["headers"]) + req.fallbackOverrides = &serializedFallbackOverrides{} + return req +} diff --git a/vendor/github.com/playwright-community/playwright-go/response.go b/vendor/github.com/playwright-community/playwright-go/response.go new file mode 100644 index 0000000..8f26d6d --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/response.go @@ -0,0 +1,162 @@ +package playwright + +import ( + "encoding/base64" + "encoding/json" +) + +type responseImpl struct { + channelOwner + request *requestImpl + provisionalHeaders *rawHeaders + rawHeaders *rawHeaders + finished chan error +} + +func (r *responseImpl) FromServiceWorker() bool { + return r.initializer["fromServiceWorker"].(bool) +} + +func (r *responseImpl) URL() string { + return r.initializer["url"].(string) +} + +func (r *responseImpl) Ok() bool { + return r.Status() == 0 || (r.Status() >= 200 && r.Status() <= 299) +} + +func (r *responseImpl) Status() int { + return int(r.initializer["status"].(float64)) +} + +func (r *responseImpl) StatusText() string { + return r.initializer["statusText"].(string) +} + +func (r *responseImpl) Headers() map[string]string { + return r.provisionalHeaders.Headers() +} + +func (r *responseImpl) Finished() error { + select { + case err := <-r.request.targetClosed(): + return err + case err := <-r.finished: + return err + } +} + +func (r *responseImpl) Body() ([]byte, error) { + b64Body, err := r.channel.Send("body") + if err != nil { + return nil, err + } + return base64.StdEncoding.DecodeString(b64Body.(string)) +} + +func (r *responseImpl) Text() (string, error) { + body, err := r.Body() + if err != nil { + return "", err + } + return string(body), nil +} + +func (r *responseImpl) JSON(v interface{}) error { + body, err := r.Body() + if err != nil { + return err + } + return json.Unmarshal(body, v) +} + +func (r *responseImpl) Request() Request { + return r.request +} + +func (r *responseImpl) Frame() Frame { + return r.request.Frame() +} + +func (r *responseImpl) AllHeaders() (map[string]string, error) { + headers, err := r.ActualHeaders() + if err != nil { + return nil, err + } + return headers.Headers(), nil +} + +func (r *responseImpl) HeadersArray() ([]NameValue, error) { + headers, err := r.ActualHeaders() + if err != nil { + return nil, err + } + return headers.HeadersArray(), nil +} + +func (r *responseImpl) HeaderValue(name string) (string, error) { + headers, err := r.ActualHeaders() + if err != nil { + return "", err + } + return headers.Get(name), err +} + +func (r *responseImpl) HeaderValues(name string) ([]string, error) { + headers, err := r.ActualHeaders() + if err != nil { + return []string{}, err + } + return headers.GetAll(name), err +} + +func (r *responseImpl) ActualHeaders() (*rawHeaders, error) { + if r.rawHeaders == nil { + headers, err := r.channel.Send("rawResponseHeaders") + if err != nil { + return nil, err + } + r.rawHeaders = newRawHeaders(headers) + } + return r.rawHeaders, nil +} + +func (r *responseImpl) SecurityDetails() (*ResponseSecurityDetailsResult, error) { + details, err := r.channel.Send("securityDetails") + if err != nil { + return nil, err + } + result := &ResponseSecurityDetailsResult{} + remapMapToStruct(details.(map[string]interface{}), result) + return result, nil +} + +func (r *responseImpl) ServerAddr() (*ResponseServerAddrResult, error) { + addr, err := r.channel.Send("serverAddr") + if err != nil { + return nil, err + } + result := &ResponseServerAddrResult{} + remapMapToStruct(addr, result) + return result, nil +} + +func newResponse(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *responseImpl { + resp := &responseImpl{} + resp.createChannelOwner(resp, parent, objectType, guid, initializer) + timing := resp.initializer["timing"].(map[string]interface{}) + resp.request = fromChannel(resp.initializer["request"]).(*requestImpl) + resp.request.timing = &RequestTiming{ + StartTime: timing["startTime"].(float64), + DomainLookupStart: timing["domainLookupStart"].(float64), + DomainLookupEnd: timing["domainLookupEnd"].(float64), + ConnectStart: timing["connectStart"].(float64), + SecureConnectionStart: timing["secureConnectionStart"].(float64), + ConnectEnd: timing["connectEnd"].(float64), + RequestStart: timing["requestStart"].(float64), + ResponseStart: timing["responseStart"].(float64), + } + resp.provisionalHeaders = newRawHeaders(resp.initializer["headers"]) + resp.finished = make(chan error, 1) + return resp +} diff --git a/vendor/github.com/playwright-community/playwright-go/route.go b/vendor/github.com/playwright-community/playwright-go/route.go new file mode 100644 index 0000000..c9e6ee9 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/route.go @@ -0,0 +1,270 @@ +package playwright + +import ( + "encoding/base64" + "errors" + "net/http" + "os" + "reflect" + "strconv" + "strings" +) + +type routeImpl struct { + channelOwner + handling *chan bool + context *browserContextImpl + didThrow bool +} + +func (r *routeImpl) startHandling() chan bool { + r.Lock() + defer r.Unlock() + handling := make(chan bool, 1) + r.handling = &handling + return handling +} + +func (r *routeImpl) reportHandled(done bool) { + r.Lock() + defer r.Unlock() + if r.handling != nil { + handling := *r.handling + r.handling = nil + handling <- done + } +} + +func (r *routeImpl) checkNotHandled() error { + r.RLock() + defer r.RUnlock() + if r.handling == nil { + return errors.New("Route is already handled!") + } + return nil +} + +func (r *routeImpl) Request() Request { + return fromChannel(r.initializer["request"]).(*requestImpl) +} + +func unpackOptionalArgument(input interface{}) interface{} { + inputValue := reflect.ValueOf(input) + if inputValue.Kind() != reflect.Slice { + panic("Needs to be a slice") + } + if inputValue.Len() == 0 { + return nil + } + return inputValue.Index(0).Interface() +} + +func (r *routeImpl) Abort(errorCode ...string) error { + return r.handleRoute(func() error { + return r.raceWithPageClose(func() error { + _, err := r.channel.Send("abort", map[string]interface{}{ + "errorCode": unpackOptionalArgument(errorCode), + }) + return err + }) + }) +} + +func (r *routeImpl) raceWithPageClose(f func() error) error { + errChan := make(chan error, 1) + go func() { + errChan <- f() + }() + + select { + case <-r.Request().(*requestImpl).targetClosed(): + // upstream does not throw the err + return nil + case err := <-errChan: + return err + } +} + +func (r *routeImpl) Fulfill(options ...RouteFulfillOptions) error { + return r.handleRoute(func() error { + return r.innerFulfill(options...) + }) +} + +func (r *routeImpl) handleRoute(cb func() error) error { + err := r.checkNotHandled() + if err != nil { + return err + } + if err := cb(); err != nil { + r.didThrow = true + return err + } + r.reportHandled(true) + return nil +} + +func (r *routeImpl) innerFulfill(options ...RouteFulfillOptions) error { + err := r.checkNotHandled() + if err != nil { + return err + } + option := RouteFulfillOptions{} + if len(options) == 1 { + option = options[0] + } + overrides := map[string]interface{}{ + "status": 200, + } + headers := make(map[string]string) + + if option.Response != nil { + overrides["status"] = option.Response.Status() + headers = option.Response.Headers() + response, ok := option.Response.(*apiResponseImpl) + if option.Body == nil && option.Path == nil && ok && response.request.connection == r.connection { + overrides["fetchResponseUid"] = response.fetchUid() + } else { + option.Body, _ = option.Response.Body() + } + option.Response = nil + } + if option.Status != nil { + overrides["status"] = *option.Status + option.Status = nil + } + + length := 0 + isBase64 := false + var fileContentType string + if _, ok := option.Body.(string); ok { + isBase64 = false + } else if body, ok := option.Body.([]byte); ok { + option.Body = base64.StdEncoding.EncodeToString(body) + length = len(body) + isBase64 = true + } else if option.Path != nil { + content, err := os.ReadFile(*option.Path) + if err != nil { + return err + } + fileContentType = http.DetectContentType(content) + option.Body = base64.StdEncoding.EncodeToString(content) + isBase64 = true + length = len(content) + } + + if option.Headers != nil { + headers = make(map[string]string) + for key, val := range option.Headers { + headers[strings.ToLower(key)] = val + } + option.Headers = nil + } + if option.ContentType != nil { + headers["content-type"] = *option.ContentType + option.ContentType = nil + } else if option.Path != nil { + headers["content-type"] = fileContentType + } + if _, ok := headers["content-length"]; !ok && length > 0 { + headers["content-length"] = strconv.Itoa(length) + } + overrides["headers"] = serializeMapToNameAndValue(headers) + overrides["isBase64"] = isBase64 + + option.Path = nil + err = r.raceWithPageClose(func() error { + _, err := r.channel.Send("fulfill", option, overrides) + return err + }) + return err +} + +func (r *routeImpl) Fallback(options ...RouteFallbackOptions) error { + err := r.checkNotHandled() + if err != nil { + return err + } + opt := RouteFallbackOptions{} + if len(options) == 1 { + opt = options[0] + } + r.Request().(*requestImpl).applyFallbackOverrides(opt) + r.reportHandled(false) + return nil +} + +func (r *routeImpl) Fetch(options ...RouteFetchOptions) (APIResponse, error) { + opt := &APIRequestContextFetchOptions{} + url := "" + if len(options) == 1 { + err := assignStructFields(opt, options[0], true) + if err != nil { + return nil, err + } + opt.Data = options[0].PostData + if options[0].URL != nil { + url = *options[0].URL + } + } + ret, err := r.connection.WrapAPICall(func() (interface{}, error) { + return r.context.request.innerFetch(url, r.Request(), *opt) + }, false) + if ret == nil { + return nil, err + } + return ret.(APIResponse), err +} + +func (r *routeImpl) Continue(options ...RouteContinueOptions) error { + option := &RouteFallbackOptions{} + if len(options) == 1 { + err := assignStructFields(option, options[0], true) + if err != nil { + return err + } + } + + return r.handleRoute(func() error { + r.Request().(*requestImpl).applyFallbackOverrides(*option) + return r.internalContinue(false) + }) +} + +func (r *routeImpl) internalContinue(isFallback bool) error { + overrides := make(map[string]interface{}) + overrides["url"] = r.Request().(*requestImpl).fallbackOverrides.URL + overrides["method"] = r.Request().(*requestImpl).fallbackOverrides.Method + headers := r.Request().(*requestImpl).fallbackOverrides.Headers + if headers != nil { + overrides["headers"] = serializeMapToNameAndValue(headers) + } + postDataBuf := r.Request().(*requestImpl).fallbackOverrides.PostDataBuffer + if postDataBuf != nil { + overrides["postData"] = base64.StdEncoding.EncodeToString(postDataBuf) + } + overrides["isFallback"] = isFallback + return r.raceWithPageClose(func() error { + _, err := r.channel.Send("continue", overrides) + return err + }) +} + +func (r *routeImpl) redirectedNavigationRequest(url string) error { + return r.handleRoute(func() error { + return r.raceWithPageClose(func() error { + _, err := r.channel.Send("redirectNavigationRequest", map[string]interface{}{ + "url": url, + }) + return err + }) + }) +} + +func newRoute(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *routeImpl { + bt := &routeImpl{} + bt.createChannelOwner(bt, parent, objectType, guid, initializer) + bt.markAsInternalType() + return bt +} diff --git a/vendor/github.com/playwright-community/playwright-go/run.go b/vendor/github.com/playwright-community/playwright-go/run.go new file mode 100644 index 0000000..79ad11e --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/run.go @@ -0,0 +1,409 @@ +package playwright + +import ( + "archive/zip" + "bytes" + "errors" + "fmt" + "io" + "log" + "log/slog" + "net/http" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" +) + +const playwrightCliVersion = "1.52.0" + +var ( + logger = slog.Default() + playwrightCDNMirrors = []string{ + "https://playwright.azureedge.net", + "https://playwright-akamai.azureedge.net", + "https://playwright-verizon.azureedge.net", + } +) + +// PlaywrightDriver wraps the Playwright CLI of upstream Playwright. +// +// It's required for playwright-go to work. +type PlaywrightDriver struct { + Version string + options *RunOptions +} + +func NewDriver(options ...*RunOptions) (*PlaywrightDriver, error) { + transformed, err := transformRunOptions(options...) // get default values + if err != nil { + return nil, err + } + return &PlaywrightDriver{ + options: transformed, + Version: playwrightCliVersion, + }, nil +} + +func getDefaultCacheDirectory() (string, error) { + userHomeDir, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("could not get user home directory: %w", err) + } + switch runtime.GOOS { + case "windows": + return filepath.Join(userHomeDir, "AppData", "Local"), nil + case "darwin": + return filepath.Join(userHomeDir, "Library", "Caches"), nil + case "linux": + return filepath.Join(userHomeDir, ".cache"), nil + } + return "", errors.New("could not determine cache directory") +} + +func (d *PlaywrightDriver) isUpToDateDriver() (bool, error) { + if _, err := os.Stat(d.options.DriverDirectory); os.IsNotExist(err) { + if err := os.MkdirAll(d.options.DriverDirectory, 0o777); err != nil { + return false, fmt.Errorf("could not create driver directory: %w", err) + } + } + if _, err := os.Stat(getDriverCliJs(d.options.DriverDirectory)); os.IsNotExist(err) { + return false, nil + } else if err != nil { + return false, fmt.Errorf("could not check if driver is up2date: %w", err) + } + cmd := d.Command("--version") + output, err := cmd.Output() + if err != nil { + return false, fmt.Errorf("could not run driver: %w", err) + } + if bytes.Contains(output, []byte(d.Version)) { + return true, nil + } + // avoid triggering downloads and accidentally overwriting files + return false, fmt.Errorf("driver exists but version not %s in : %s", d.Version, d.options.DriverDirectory) +} + +// Command returns an exec.Cmd for the driver. +func (d *PlaywrightDriver) Command(arg ...string) *exec.Cmd { + cmd := exec.Command(getNodeExecutable(d.options.DriverDirectory), append([]string{getDriverCliJs(d.options.DriverDirectory)}, arg...)...) + cmd.SysProcAttr = defaultSysProcAttr + return cmd +} + +// Install downloads the driver and the browsers depending on [RunOptions]. +func (d *PlaywrightDriver) Install() error { + if err := d.DownloadDriver(); err != nil { + return fmt.Errorf("could not install driver: %w", err) + } + if d.options.SkipInstallBrowsers { + return nil + } + + d.log("Downloading browsers...") + if err := d.installBrowsers(); err != nil { + return fmt.Errorf("could not install browsers: %w", err) + } + d.log("Downloaded browsers successfully") + + return nil +} + +// Uninstall removes the driver and the browsers. +func (d *PlaywrightDriver) Uninstall() error { + d.log("Removing browsers...") + if err := d.uninstallBrowsers(); err != nil { + return fmt.Errorf("could not uninstall browsers: %w", err) + } + + d.log("Removing driver...") + if err := os.RemoveAll(d.options.DriverDirectory); err != nil { + return fmt.Errorf("could not remove driver directory: %w", err) + } + + d.log("Uninstall driver successfully") + return nil +} + +// DownloadDriver downloads the driver only +func (d *PlaywrightDriver) DownloadDriver() error { + up2Date, err := d.isUpToDateDriver() + if err != nil { + return err + } + if up2Date { + return nil + } + + d.log("Downloading driver", "path", d.options.DriverDirectory) + + body, err := downloadDriver(d.getDriverURLs()) + if err != nil { + return err + } + zipReader, err := zip.NewReader(bytes.NewReader(body), int64(len(body))) + if err != nil { + return fmt.Errorf("could not read zip content: %w", err) + } + + for _, zipFile := range zipReader.File { + zipFileDiskPath := filepath.Join(d.options.DriverDirectory, zipFile.Name) + if zipFile.FileInfo().IsDir() { + if err := os.MkdirAll(zipFileDiskPath, os.ModePerm); err != nil { + return fmt.Errorf("could not create directory: %w", err) + } + continue + } + + outFile, err := os.Create(zipFileDiskPath) + if err != nil { + return fmt.Errorf("could not create driver: %w", err) + } + file, err := zipFile.Open() + if err != nil { + return fmt.Errorf("could not open zip file: %w", err) + } + if _, err = io.Copy(outFile, file); err != nil { + return fmt.Errorf("could not copy response body to file: %w", err) + } + if err := outFile.Close(); err != nil { + return fmt.Errorf("could not close file (driver): %w", err) + } + if err := file.Close(); err != nil { + return fmt.Errorf("could not close file (zip file): %w", err) + } + if zipFile.Mode().Perm()&0o100 != 0 && runtime.GOOS != "windows" { + if err := makeFileExecutable(zipFileDiskPath); err != nil { + return fmt.Errorf("could not make executable: %w", err) + } + } + } + + d.log("Downloaded driver successfully") + + return nil +} + +func (d *PlaywrightDriver) log(msg string, args ...any) { + if d.options.Verbose { + logger.Info(msg, args...) + } +} + +func (d *PlaywrightDriver) run() (*connection, error) { + transport, err := newPipeTransport(d, d.options.Stderr) + if err != nil { + return nil, err + } + connection := newConnection(transport) + return connection, nil +} + +func (d *PlaywrightDriver) installBrowsers() error { + additionalArgs := []string{"install"} + if d.options.Browsers != nil { + additionalArgs = append(additionalArgs, d.options.Browsers...) + } + + if d.options.OnlyInstallShell { + additionalArgs = append(additionalArgs, "--only-shell") + } + + if d.options.DryRun { + additionalArgs = append(additionalArgs, "--dry-run") + } + + cmd := d.Command(additionalArgs...) + cmd.Stdout = d.options.Stdout + cmd.Stderr = d.options.Stderr + return cmd.Run() +} + +func (d *PlaywrightDriver) uninstallBrowsers() error { + cmd := d.Command("uninstall") + cmd.Stdout = d.options.Stdout + cmd.Stderr = d.options.Stderr + return cmd.Run() +} + +// RunOptions are custom options to run the driver +type RunOptions struct { + // DriverDirectory points to the playwright driver directory. + // It should have two subdirectories: node and package. + // You can also specify it using the environment variable PLAYWRIGHT_DRIVER_PATH. + // + // Default is user cache directory + "/ms-playwright-go/x.xx.xx": + // - Windows: %USERPROFILE%\AppData\Local + // - macOS: ~/Library/Caches + // - Linux: ~/.cache + DriverDirectory string + // OnlyInstallShell only downloads the headless shell. (For chromium browsers only) + OnlyInstallShell bool + SkipInstallBrowsers bool + // if not set and SkipInstallBrowsers is false, will download all browsers (chromium, firefox, webkit) + Browsers []string + Verbose bool // default true + Stdout io.Writer + Stderr io.Writer + Logger *slog.Logger + // DryRun does not install browser/dependencies. It will only print information. + DryRun bool +} + +// Install does download the driver and the browsers. +// +// Use this before playwright.Run() or use playwright cli to install the driver and browsers +func Install(options ...*RunOptions) error { + driver, err := NewDriver(options...) + if err != nil { + return fmt.Errorf("could not get driver instance: %w", err) + } + if err := driver.Install(); err != nil { + return fmt.Errorf("could not install driver: %w", err) + } + return nil +} + +// Run starts a Playwright instance. +// +// Requires the driver and the browsers to be installed before. +// Either use Install() or use playwright cli. +func Run(options ...*RunOptions) (*Playwright, error) { + driver, err := NewDriver(options...) + if err != nil { + return nil, fmt.Errorf("could not get driver instance: %w", err) + } + up2date, err := driver.isUpToDateDriver() + if err != nil || !up2date { + return nil, fmt.Errorf("please install the driver (v%s) first: %w", playwrightCliVersion, err) + } + connection, err := driver.run() + if err != nil { + return nil, err + } + playwright, err := connection.Start() + return playwright, err +} + +func transformRunOptions(options ...*RunOptions) (*RunOptions, error) { + option := &RunOptions{ + Verbose: true, + } + if len(options) == 1 { + option = options[0] + } + if option.DriverDirectory == "" { // if user did not set it, try to get it from env + option.DriverDirectory = os.Getenv("PLAYWRIGHT_DRIVER_PATH") + } + if option.DriverDirectory == "" { + cacheDirectory, err := getDefaultCacheDirectory() + if err != nil { + return nil, fmt.Errorf("could not get default cache directory: %w", err) + } + option.DriverDirectory = filepath.Join(cacheDirectory, "ms-playwright-go", playwrightCliVersion) + } + if option.Stdout == nil { + option.Stdout = os.Stdout + } + if option.Stderr == nil { + option.Stderr = os.Stderr + } else if option.Logger == nil { + log.SetOutput(option.Stderr) + } + if option.Logger != nil { + logger = option.Logger + } + return option, nil +} + +func getNodeExecutable(driverDirectory string) string { + envPath := os.Getenv("PLAYWRIGHT_NODEJS_PATH") + if envPath != "" { + return envPath + } + + node := "node" + if runtime.GOOS == "windows" { + node = "node.exe" + } + return filepath.Join(driverDirectory, node) +} + +func getDriverCliJs(driverDirectory string) string { + return filepath.Join(driverDirectory, "package", "cli.js") +} + +func (d *PlaywrightDriver) getDriverURLs() []string { + platform := "" + switch runtime.GOOS { + case "windows": + platform = "win32_x64" + case "darwin": + if runtime.GOARCH == "arm64" { + platform = "mac-arm64" + } else { + platform = "mac" + } + case "linux": + if runtime.GOARCH == "arm64" { + platform = "linux-arm64" + } else { + platform = "linux" + } + } + + baseURLs := []string{} + pattern := "%s/builds/driver/playwright-%s-%s.zip" + if !d.isReleaseVersion() { + pattern = "%s/builds/driver/next/playwright-%s-%s.zip" + } + + if hostEnv := os.Getenv("PLAYWRIGHT_DOWNLOAD_HOST"); hostEnv != "" { + baseURLs = append(baseURLs, fmt.Sprintf(pattern, hostEnv, d.Version, platform)) + } else { + for _, mirror := range playwrightCDNMirrors { + baseURLs = append(baseURLs, fmt.Sprintf(pattern, mirror, d.Version, platform)) + } + } + return baseURLs +} + +// isReleaseVersion checks if the version is not a beta or alpha release +// this helps to determine the url from where to download the driver +func (d *PlaywrightDriver) isReleaseVersion() bool { + return !strings.Contains(d.Version, "beta") && !strings.Contains(d.Version, "alpha") && !strings.Contains(d.Version, "next") +} + +func makeFileExecutable(path string) error { + stats, err := os.Stat(path) + if err != nil { + return fmt.Errorf("could not stat driver: %w", err) + } + if err := os.Chmod(path, stats.Mode()|0x40); err != nil { + return fmt.Errorf("could not set permissions: %w", err) + } + return nil +} + +func downloadDriver(driverURLs []string) (body []byte, e error) { + for _, driverURL := range driverURLs { + resp, err := http.Get(driverURL) + if err != nil { + e = errors.Join(e, fmt.Errorf("could not download driver from %s: %w", driverURL, err)) + continue + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + e = errors.Join(e, fmt.Errorf("error: got non 200 status code: %d (%s) from %s", resp.StatusCode, resp.Status, driverURL)) + continue + } + body, err = io.ReadAll(resp.Body) + if err != nil { + e = errors.Join(e, fmt.Errorf("could not read response body: %w", err)) + continue + } + return body, nil + } + return nil, e +} diff --git a/vendor/github.com/playwright-community/playwright-go/run_unix.go b/vendor/github.com/playwright-community/playwright-go/run_unix.go new file mode 100644 index 0000000..8ff102b --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/run_unix.go @@ -0,0 +1,10 @@ +//go:build !windows + +package playwright + +import "syscall" + +var defaultSysProcAttr = &syscall.SysProcAttr{} + +// for WritableStream.Copy +const defaultCopyBufSize = 1024 * 1024 diff --git a/vendor/github.com/playwright-community/playwright-go/run_win.go b/vendor/github.com/playwright-community/playwright-go/run_win.go new file mode 100644 index 0000000..fe7b50d --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/run_win.go @@ -0,0 +1,10 @@ +//go:build windows + +package playwright + +import "syscall" + +var defaultSysProcAttr = &syscall.SysProcAttr{HideWindow: true} + +// for WritableStream.Copy +const defaultCopyBufSize = 64 * 1024 diff --git a/vendor/github.com/playwright-community/playwright-go/selectors.go b/vendor/github.com/playwright-community/playwright-go/selectors.go new file mode 100644 index 0000000..1151647 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/selectors.go @@ -0,0 +1,88 @@ +package playwright + +import ( + "errors" + "os" + "sync" +) + +type selectorsOwnerImpl struct { + channelOwner +} + +func (s *selectorsOwnerImpl) setTestIdAttributeName(name string) { + s.channel.SendNoReply("setTestIdAttributeName", map[string]interface{}{ + "testIdAttributeName": name, + }) +} + +func newSelectorsOwner(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *selectorsOwnerImpl { + obj := &selectorsOwnerImpl{} + obj.createChannelOwner(obj, parent, objectType, guid, initializer) + return obj +} + +type selectorsImpl struct { + channels sync.Map + registrations []map[string]interface{} +} + +func (s *selectorsImpl) Register(name string, script Script, options ...SelectorsRegisterOptions) error { + if script.Path == nil && script.Content == nil { + return errors.New("Either source or path should be specified") + } + source := "" + if script.Path != nil { + content, err := os.ReadFile(*script.Path) + if err != nil { + return err + } + source = string(content) + } else { + source = *script.Content + } + params := map[string]interface{}{ + "name": name, + "source": source, + } + if len(options) == 1 && options[0].ContentScript != nil { + params["contentScript"] = *options[0].ContentScript + } + var err error + s.channels.Range(func(key, value any) bool { + _, err = value.(*selectorsOwnerImpl).channel.Send("register", params) + return err == nil + }) + if err != nil { + return err + } + s.registrations = append(s.registrations, params) + return nil +} + +func (s *selectorsImpl) SetTestIdAttribute(name string) { + setTestIdAttributeName(name) + s.channels.Range(func(key, value any) bool { + value.(*selectorsOwnerImpl).setTestIdAttributeName(name) + return true + }) +} + +func (s *selectorsImpl) addChannel(channel *selectorsOwnerImpl) { + s.channels.Store(channel.guid, channel) + for _, params := range s.registrations { + channel.channel.SendNoReply("register", params) + channel.setTestIdAttributeName(getTestIdAttributeName()) + } +} + +func (s *selectorsImpl) removeChannel(channel *selectorsOwnerImpl) { + s.channels.Delete(channel.guid) +} + +func newSelectorsImpl() *selectorsImpl { + return &selectorsImpl{ + channels: sync.Map{}, + registrations: make([]map[string]interface{}, 0), + } +} diff --git a/vendor/github.com/playwright-community/playwright-go/stream.go b/vendor/github.com/playwright-community/playwright-go/stream.go new file mode 100644 index 0000000..e23942f --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/stream.go @@ -0,0 +1,68 @@ +package playwright + +import ( + "bufio" + "encoding/base64" + "os" + "path/filepath" +) + +type streamImpl struct { + channelOwner +} + +func (s *streamImpl) SaveAs(path string) error { + err := os.MkdirAll(filepath.Dir(path), 0o777) + if err != nil { + return err + } + file, err := os.Create(path) + if err != nil { + return err + } + defer file.Close() + writer := bufio.NewWriter(file) + for { + binary, err := s.channel.Send("read", map[string]interface{}{"size": 1024 * 1024}) + if err != nil { + return err + } + bytes, err := base64.StdEncoding.DecodeString(binary.(string)) + if err != nil { + return err + } + if len(bytes) == 0 { + break + } + _, err = writer.Write(bytes) + if err != nil { + return err + } + } + return writer.Flush() +} + +func (s *streamImpl) ReadAll() ([]byte, error) { + var data []byte + for { + binary, err := s.channel.Send("read", map[string]interface{}{"size": 1024 * 1024}) + if err != nil { + return nil, err + } + bytes, err := base64.StdEncoding.DecodeString(binary.(string)) + if err != nil { + return nil, err + } + if len(bytes) == 0 { + break + } + data = append(data, bytes...) + } + return data, nil +} + +func newStream(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *streamImpl { + stream := &streamImpl{} + stream.createChannelOwner(stream, parent, objectType, guid, initializer) + return stream +} diff --git a/vendor/github.com/playwright-community/playwright-go/tracing.go b/vendor/github.com/playwright-community/playwright-go/tracing.go new file mode 100644 index 0000000..decd872 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/tracing.go @@ -0,0 +1,164 @@ +package playwright + +import "fmt" + +type tracingImpl struct { + channelOwner + includeSources bool + isTracing bool + stacksId string + tracesDir string +} + +func (t *tracingImpl) Start(options ...TracingStartOptions) error { + chunkOption := TracingStartChunkOptions{} + if len(options) == 1 { + if options[0].Sources != nil { + t.includeSources = *options[0].Sources + } + chunkOption.Name = options[0].Name + chunkOption.Title = options[0].Title + } + innerStart := func() (interface{}, error) { + if _, err := t.channel.Send("tracingStart", options); err != nil { + return "", err + } + return t.channel.Send("tracingStartChunk", chunkOption) + } + name, err := innerStart() + if err != nil { + return err + } + return t.startCollectingStacks(name.(string)) +} + +func (t *tracingImpl) StartChunk(options ...TracingStartChunkOptions) error { + name, err := t.channel.Send("tracingStartChunk", options) + if err != nil { + return err + } + return t.startCollectingStacks(name.(string)) +} + +func (t *tracingImpl) StopChunk(path ...string) error { + filePath := "" + if len(path) == 1 { + filePath = path[0] + } + return t.doStopChunk(filePath) +} + +func (t *tracingImpl) Stop(path ...string) error { + filePath := "" + if len(path) == 1 { + filePath = path[0] + } + if err := t.doStopChunk(filePath); err != nil { + return err + } + _, err := t.channel.Send("tracingStop") + return err +} + +func (t *tracingImpl) doStopChunk(filePath string) (err error) { + if t.isTracing { + t.isTracing = false + t.connection.setInTracing(false) + } + if filePath == "" { + // Not interested in artifacts. + _, err = t.channel.Send("tracingStopChunk", map[string]interface{}{ + "mode": "discard", + }) + if t.stacksId != "" { + return t.connection.LocalUtils().TraceDiscarded(t.stacksId) + } + return err + } + + isLocal := !t.connection.isRemote + if isLocal { + result, err := t.channel.SendReturnAsDict("tracingStopChunk", map[string]interface{}{ + "mode": "entries", + }) + if err != nil { + return err + } + entries, ok := result["entries"] + if !ok { + return fmt.Errorf("could not convert result to map: %v", result) + } + _, err = t.connection.LocalUtils().Zip(localUtilsZipOptions{ + ZipFile: filePath, + Entries: entries.([]interface{}), + StacksId: t.stacksId, + Mode: "write", + IncludeSources: t.includeSources, + }) + return err + } + + result, err := t.channel.SendReturnAsDict("tracingStopChunk", map[string]interface{}{ + "mode": "archive", + }) + if err != nil { + return err + } + artifactChannel, ok := result["artifact"] + if !ok { + return fmt.Errorf("could not convert result to map: %v", result) + } + // Save trace to the final local file. + artifact := fromNullableChannel(artifactChannel).(*artifactImpl) + // The artifact may be missing if the browser closed while stopping tracing. + if artifact == nil { + if t.stacksId != "" { + return t.connection.LocalUtils().TraceDiscarded(t.stacksId) + } + return + } + if err := artifact.SaveAs(filePath); err != nil { + return err + } + if err := artifact.Delete(); err != nil { + return err + } + _, err = t.connection.LocalUtils().Zip(localUtilsZipOptions{ + ZipFile: filePath, + Entries: []interface{}{}, + StacksId: t.stacksId, + Mode: "append", + IncludeSources: t.includeSources, + }) + return err +} + +func (t *tracingImpl) startCollectingStacks(name string) (err error) { + if !t.isTracing { + t.isTracing = true + t.connection.setInTracing(true) + } + t.stacksId, err = t.connection.LocalUtils().TracingStarted(name, t.tracesDir) + return +} + +func (t *tracingImpl) Group(name string, options ...TracingGroupOptions) error { + var option TracingGroupOptions + if len(options) == 1 { + option = options[0] + } + _, err := t.channel.Send("tracingGroup", option, map[string]interface{}{"name": name}) + return err +} + +func (t *tracingImpl) GroupEnd() error { + _, err := t.channel.Send("tracingGroupEnd") + return err +} + +func newTracing(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *tracingImpl { + bt := &tracingImpl{} + bt.createChannelOwner(bt, parent, objectType, guid, initializer) + bt.markAsInternalType() + return bt +} diff --git a/vendor/github.com/playwright-community/playwright-go/transport.go b/vendor/github.com/playwright-community/playwright-go/transport.go new file mode 100644 index 0000000..1be3988 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/transport.go @@ -0,0 +1,141 @@ +package playwright + +import ( + "bufio" + "encoding/binary" + "fmt" + "io" + "os" + + "github.com/go-jose/go-jose/v3/json" +) + +type transport interface { + Send(msg map[string]interface{}) error + Poll() (*message, error) + Close() error +} + +type pipeTransport struct { + writer io.WriteCloser + bufReader *bufio.Reader + closed chan struct{} + onClose func() error +} + +func (t *pipeTransport) Poll() (*message, error) { + if t.isClosed() { + return nil, fmt.Errorf("transport closed") + } + + var length uint32 + err := binary.Read(t.bufReader, binary.LittleEndian, &length) + if err != nil { + return nil, fmt.Errorf("could not read protocol padding: %w", err) + } + + data := make([]byte, length) + _, err = io.ReadFull(t.bufReader, data) + if err != nil { + return nil, fmt.Errorf("could not read protocol data: %w", err) + } + + msg := &message{} + if err := json.Unmarshal(data, &msg); err != nil { + return nil, fmt.Errorf("could not decode json: %w", err) + } + if os.Getenv("DEBUGP") != "" { + fmt.Fprintf(os.Stdout, "\x1b[33mRECV>\x1b[0m\n%s\n", data) + } + return msg, nil +} + +type message struct { + ID int `json:"id"` + GUID string `json:"guid"` + Method string `json:"method,omitempty"` + Params map[string]interface{} `json:"params,omitempty"` + Result map[string]interface{} `json:"result,omitempty"` + Error *struct { + Error Error `json:"error"` + } `json:"error,omitempty"` +} + +func (t *pipeTransport) Send(msg map[string]interface{}) error { + if t.isClosed() { + return fmt.Errorf("transport closed") + } + msgBytes, err := json.Marshal(msg) + if err != nil { + return fmt.Errorf("pipeTransport: could not marshal json: %w", err) + } + if os.Getenv("DEBUGP") != "" { + fmt.Fprintf(os.Stdout, "\x1b[32mSEND>\x1b[0m\n%s\n", msgBytes) + } + + lengthPadding := make([]byte, 4) + binary.LittleEndian.PutUint32(lengthPadding, uint32(len(msgBytes))) + if _, err = t.writer.Write(append(lengthPadding, msgBytes...)); err != nil { + return err + } + return nil +} + +func (t *pipeTransport) Close() error { + select { + case <-t.closed: + return nil + default: + return t.onClose() + } +} + +func (t *pipeTransport) isClosed() bool { + select { + case <-t.closed: + return true + default: + return false + } +} + +func newPipeTransport(driver *PlaywrightDriver, stderr io.Writer) (transport, error) { + t := &pipeTransport{ + closed: make(chan struct{}, 1), + } + + cmd := driver.Command("run-driver") + cmd.Stderr = stderr + stdin, err := cmd.StdinPipe() + if err != nil { + return nil, fmt.Errorf("could not create stdin pipe: %w", err) + } + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, fmt.Errorf("could not create stdout pipe: %w", err) + } + t.writer = stdin + t.bufReader = bufio.NewReader(stdout) + + t.onClose = func() error { + select { + case <-t.closed: + default: + close(t.closed) + } + if err := t.writer.Close(); err != nil { + return err + } + // playwright-cli will exit when its stdin is closed + if err := cmd.Wait(); err != nil { + return err + } + return nil + } + + if err := cmd.Start(); err != nil { + return nil, fmt.Errorf("could not start driver: %w", err) + } + + return t, nil +} diff --git a/vendor/github.com/playwright-community/playwright-go/type_helpers.go b/vendor/github.com/playwright-community/playwright-go/type_helpers.go new file mode 100644 index 0000000..d821e7c --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/type_helpers.go @@ -0,0 +1,72 @@ +package playwright + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { + return &v +} + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { + return &v +} + +// Int is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it. +func Int(v int) *int { + return &v +} + +// Float is a helper routine that allocates a new float64 value +// to store v and returns a pointer to it. +func Float(v float64) *float64 { + return &v +} + +// Null will be used in certain scenarios where a strict nil pointer +// check is not possible +func Null() interface{} { + return "PW_NULL" +} + +// StringSlice is a helper routine that allocates a new StringSlice value +// to store v and returns a pointer to it. +func StringSlice(v ...string) *[]string { + var o []string + o = append(o, v...) + return &o +} + +// IntSlice is a helper routine that allocates a new IntSlice value +// to store v and returns a pointer to it. +func IntSlice(v ...int) *[]int { + var o []int + o = append(o, v...) + return &o +} + +// ToOptionalStorageState converts StorageState to OptionalStorageState for use directly in [Browser.NewContext] +func (s StorageState) ToOptionalStorageState() *OptionalStorageState { + cookies := make([]OptionalCookie, len(s.Cookies)) + for i, c := range s.Cookies { + cookies[i] = c.ToOptionalCookie() + } + return &OptionalStorageState{ + Origins: s.Origins, + Cookies: cookies, + } +} + +func (c Cookie) ToOptionalCookie() OptionalCookie { + return OptionalCookie{ + Name: c.Name, + Value: c.Value, + Domain: String(c.Domain), + Path: String(c.Path), + Expires: Float(c.Expires), + HttpOnly: Bool(c.HttpOnly), + Secure: Bool(c.Secure), + SameSite: c.SameSite, + } +} diff --git a/vendor/github.com/playwright-community/playwright-go/video.go b/vendor/github.com/playwright-community/playwright-go/video.go new file mode 100644 index 0000000..a57b61a --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/video.go @@ -0,0 +1,97 @@ +package playwright + +import ( + "errors" + "sync" +) + +type videoImpl struct { + page *pageImpl + artifact *artifactImpl + artifactChan chan *artifactImpl + done chan struct{} + closeOnce sync.Once + isRemote bool +} + +func (v *videoImpl) Path() (string, error) { + if v.isRemote { + return "", errors.New("Path is not available when connecting remotely. Use SaveAs() to save a local copy.") + } + v.getArtifact() + if v.artifact == nil { + return "", errors.New("Page did not produce any video frames") + } + return v.artifact.AbsolutePath(), nil +} + +func (v *videoImpl) Delete() error { + v.getArtifact() + if v.artifact == nil { + return nil + } + return v.artifact.Delete() +} + +func (v *videoImpl) SaveAs(path string) error { + if !v.page.IsClosed() { + return errors.New("Page is not yet closed. Close the page prior to calling SaveAs") + } + v.getArtifact() + if v.artifact == nil { + return errors.New("Page did not produce any video frames") + } + return v.artifact.SaveAs(path) +} + +func (v *videoImpl) artifactReady(artifact *artifactImpl) { + v.artifactChan <- artifact +} + +func (v *videoImpl) pageClosed(p Page) { + v.closeOnce.Do(func() { + close(v.done) + }) +} + +func (v *videoImpl) getArtifact() { + // prevent channel block if no video will be produced + if v.page.browserContext.options == nil { + v.pageClosed(v.page) + } else { + option := v.page.browserContext.options + if option == nil || option.RecordVideo == nil { // no recordVideo option + v.pageClosed(v.page) + } + } + select { + case artifact := <-v.artifactChan: + if artifact != nil { + v.artifact = artifact + } + case <-v.done: // page closed + select { // make sure get artifact if it's ready before page closed + case artifact := <-v.artifactChan: + if artifact != nil { + v.artifact = artifact + } + default: + } + } +} + +func newVideo(page *pageImpl) *videoImpl { + video := &videoImpl{ + page: page, + artifactChan: make(chan *artifactImpl, 1), + done: make(chan struct{}, 1), + isRemote: page.connection.isRemote, + } + + if page.isClosed { + video.pageClosed(page) + } else { + page.OnClose(video.pageClosed) + } + return video +} diff --git a/vendor/github.com/playwright-community/playwright-go/waiter.go b/vendor/github.com/playwright-community/playwright-go/waiter.go new file mode 100644 index 0000000..fbcb39f --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/waiter.go @@ -0,0 +1,181 @@ +package playwright + +import ( + "context" + "fmt" + "reflect" + "sync" + "sync/atomic" + "time" +) + +type ( + waiter struct { + mu sync.Mutex + timeout float64 + fulfilled atomic.Bool + listeners []eventListener + errChan chan error + waitFunc func() (interface{}, error) + } + eventListener struct { + emitter EventEmitter + event string + handler interface{} + } +) + +// RejectOnEvent sets the Waiter to return an error when an event occurs (and the predicate returns true) +func (w *waiter) RejectOnEvent(emitter EventEmitter, event string, err error, predicates ...interface{}) *waiter { + w.mu.Lock() + defer w.mu.Unlock() + if w.waitFunc != nil { + w.reject(fmt.Errorf("waiter: call RejectOnEvent before WaitForEvent")) + return w + } + handler := func(ev ...interface{}) { + if w.fulfilled.Load() { + return + } + if len(predicates) == 0 { + w.reject(err) + } else { + result := reflect.ValueOf(predicates[0]).Call([]reflect.Value{reflect.ValueOf(ev[0])}) + if result[0].Bool() { + w.reject(err) + } + } + } + emitter.On(event, handler) + w.listeners = append(w.listeners, eventListener{ + emitter: emitter, + event: event, + handler: handler, + }) + return w +} + +// WithTimeout sets timeout, in milliseconds, for the waiter. 0 means no timeout. +func (w *waiter) WithTimeout(timeout float64) *waiter { + w.mu.Lock() + defer w.mu.Unlock() + if w.waitFunc != nil { + w.reject(fmt.Errorf("waiter: please set timeout before WaitForEvent")) + return w + } + w.timeout = timeout + return w +} + +// WaitForEvent sets the Waiter to return when an event occurs (and the predicate returns true) +func (w *waiter) WaitForEvent(emitter EventEmitter, event string, predicate interface{}) *waiter { + w.mu.Lock() + defer w.mu.Unlock() + if w.waitFunc != nil { + w.reject(fmt.Errorf("waiter: WaitForEvent can only be called once")) + return w + } + evChan := make(chan interface{}, 1) + handler := w.createHandler(evChan, predicate) + ctx, cancel := context.WithCancel(context.Background()) + if w.timeout != 0 { + timeout := w.timeout + go func() { + select { + case <-time.After(time.Duration(timeout) * time.Millisecond): + err := fmt.Errorf("%w:Timeout %.2fms exceeded.", ErrTimeout, timeout) + w.reject(err) + return + case <-ctx.Done(): + return + } + }() + } + + emitter.On(event, handler) + w.listeners = append(w.listeners, eventListener{ + emitter: emitter, + event: event, + handler: handler, + }) + + w.waitFunc = func() (interface{}, error) { + var ( + err error + val interface{} + ) + select { + case err = <-w.errChan: + break + case val = <-evChan: + break + } + cancel() + w.mu.Lock() + defer w.mu.Unlock() + for _, l := range w.listeners { + l.emitter.RemoveListener(l.event, l.handler) + } + close(evChan) + if err != nil { + return nil, err + } + return val, nil + } + return w +} + +// Wait waits for the waiter to return. It needs to call WaitForEvent once first. +func (w *waiter) Wait() (interface{}, error) { + if w.waitFunc == nil { + return nil, fmt.Errorf("waiter: call WaitForEvent first") + } + return w.waitFunc() +} + +// RunAndWait waits for the waiter to return after calls func. +func (w *waiter) RunAndWait(cb func() error) (interface{}, error) { + if w.waitFunc == nil { + return nil, fmt.Errorf("waiter: call WaitForEvent first") + } + if cb != nil { + if err := cb(); err != nil { + w.errChan <- err + } + } + return w.waitFunc() +} + +func (w *waiter) createHandler(evChan chan<- interface{}, predicate interface{}) func(...interface{}) { + return func(ev ...interface{}) { + if w.fulfilled.Load() { + return + } + if predicate == nil || reflect.ValueOf(predicate).IsNil() { + w.fulfilled.Store(true) + if len(ev) == 1 { + evChan <- ev[0] + } else { + evChan <- nil + } + } else { + result := reflect.ValueOf(predicate).Call([]reflect.Value{reflect.ValueOf(ev[0])}) + if result[0].Bool() { + w.fulfilled.Store(true) + evChan <- ev[0] + } + } + } +} + +func (w *waiter) reject(err error) { + w.fulfilled.Store(true) + w.errChan <- err +} + +func newWaiter() *waiter { + w := &waiter{ + errChan: make(chan error, 1), + } + return w +} diff --git a/vendor/github.com/playwright-community/playwright-go/web_error.go b/vendor/github.com/playwright-community/playwright-go/web_error.go new file mode 100644 index 0000000..b8dab79 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/web_error.go @@ -0,0 +1,21 @@ +package playwright + +type webErrorImpl struct { + err error + page Page +} + +func (e *webErrorImpl) Page() Page { + return e.page +} + +func (e *webErrorImpl) Error() error { + return e.err +} + +func newWebError(page Page, err error) WebError { + return &webErrorImpl{ + err: err, + page: page, + } +} diff --git a/vendor/github.com/playwright-community/playwright-go/websocket.go b/vendor/github.com/playwright-community/playwright-go/websocket.go new file mode 100644 index 0000000..4d63ec3 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/websocket.go @@ -0,0 +1,134 @@ +package playwright + +import ( + "encoding/base64" + "errors" +) + +type webSocketImpl struct { + channelOwner + isClosed bool + page *pageImpl +} + +func (ws *webSocketImpl) URL() string { + return ws.initializer["url"].(string) +} + +func newWebsocket(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *webSocketImpl { + ws := &webSocketImpl{} + ws.createChannelOwner(ws, parent, objectType, guid, initializer) + ws.page = fromChannel(parent.channel).(*pageImpl) + ws.channel.On("close", func() { + ws.Lock() + ws.isClosed = true + ws.Unlock() + ws.Emit("close", ws) + }) + ws.channel.On( + "frameSent", + func(params map[string]interface{}) { + ws.onFrameSent(params["opcode"].(float64), params["data"].(string)) + }, + ) + ws.channel.On( + "frameReceived", + func(params map[string]interface{}) { + ws.onFrameReceived(params["opcode"].(float64), params["data"].(string)) + }, + ) + ws.channel.On( + "socketError", + func(params map[string]interface{}) { + ws.Emit("socketerror", params["error"]) + }, + ) + return ws +} + +func (ws *webSocketImpl) onFrameSent(opcode float64, data string) { + if opcode == 2 { + payload, err := base64.StdEncoding.DecodeString(data) + if err != nil { + logger.Error("could not decode WebSocket.onFrameSent payload", "error", err) + return + } + ws.Emit("framesent", payload) + } else { + ws.Emit("framesent", []byte(data)) + } +} + +func (ws *webSocketImpl) onFrameReceived(opcode float64, data string) { + if opcode == 2 { + payload, err := base64.StdEncoding.DecodeString(data) + if err != nil { + logger.Error("could not decode WebSocket.onFrameReceived payload", "error", err) + return + } + ws.Emit("framereceived", payload) + } else { + ws.Emit("framereceived", []byte(data)) + } +} + +func (ws *webSocketImpl) ExpectEvent(event string, cb func() error, options ...WebSocketExpectEventOptions) (interface{}, error) { + return ws.expectEvent(event, cb, options...) +} + +func (ws *webSocketImpl) WaitForEvent(event string, options ...WebSocketWaitForEventOptions) (interface{}, error) { + if len(options) == 1 { + option := WebSocketExpectEventOptions(options[0]) + return ws.expectEvent(event, nil, option) + } else { + return ws.expectEvent(event, nil) + } +} + +func (ws *webSocketImpl) expectEvent(event string, cb func() error, options ...WebSocketExpectEventOptions) (interface{}, error) { + var predicate interface{} = nil + timeout := ws.page.timeoutSettings.Timeout() + if len(options) == 1 { + if options[0].Timeout != nil { + timeout = *options[0].Timeout + } + if options[0].Predicate != nil { + predicate = options[0].Predicate + } + } + waiter := newWaiter().WithTimeout(timeout) + if event != "close" { + waiter.RejectOnEvent(ws, "close", errors.New("websocket closed")) + } + if event != "socketerror" { + waiter.RejectOnEvent(ws, "socketerror", errors.New("websocket error")) + } + waiter.RejectOnEvent(ws.page, "close", errors.New("page closed")) + if cb == nil { + return waiter.WaitForEvent(ws, event, predicate).Wait() + } else { + return waiter.WaitForEvent(ws, event, predicate).RunAndWait(cb) + } +} + +func (ws *webSocketImpl) IsClosed() bool { + ws.RLock() + defer ws.RUnlock() + return ws.isClosed +} + +func (ws *webSocketImpl) OnClose(fn func(WebSocket)) { + ws.On("close", fn) +} + +func (ws *webSocketImpl) OnFrameReceived(fn func(payload []byte)) { + ws.On("framereceived", fn) +} + +func (ws *webSocketImpl) OnFrameSent(fn func(payload []byte)) { + ws.On("framesent", fn) +} + +func (ws *webSocketImpl) OnSocketError(fn func(string)) { + ws.On("socketerror", fn) +} diff --git a/vendor/github.com/playwright-community/playwright-go/websocket_route.go b/vendor/github.com/playwright-community/playwright-go/websocket_route.go new file mode 100644 index 0000000..bb74ab9 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/websocket_route.go @@ -0,0 +1,220 @@ +package playwright + +import ( + "encoding/base64" + "fmt" + "regexp" + "sync/atomic" +) + +type webSocketRouteImpl struct { + channelOwner + connected *atomic.Bool + server WebSocketRoute + onPageMessage func(interface{}) + onPageClose func(code *int, reason *string) + onServerMessage func(interface{}) + onServerClose func(code *int, reason *string) +} + +func newWebSocketRoute(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *webSocketRouteImpl { + route := &webSocketRouteImpl{ + connected: &atomic.Bool{}, + } + route.createChannelOwner(route, parent, objectType, guid, initializer) + route.markAsInternalType() + + route.server = newServerWebSocketRoute(route) + + route.channel.On("messageFromPage", func(event map[string]interface{}) { + msg, err := untransformWebSocketMessage(event) + if err != nil { + panic(fmt.Errorf("Could not decode WebSocket message: %w", err)) + } + if route.onPageMessage != nil { + route.onPageMessage(msg) + } else if route.connected.Load() { + go route.channel.SendNoReply("sendToServer", event) + } + }) + + route.channel.On("messageFromServer", func(event map[string]interface{}) { + msg, err := untransformWebSocketMessage(event) + if err != nil { + panic(fmt.Errorf("Could not decode WebSocket message: %w", err)) + } + if route.onServerMessage != nil { + route.onServerMessage(msg) + } else { + go route.channel.SendNoReply("sendToPage", event) + } + }) + + route.channel.On("closePage", func(event map[string]interface{}) { + if route.onPageClose != nil { + route.onPageClose(event["code"].(*int), event["reason"].(*string)) + } else { + go route.channel.SendNoReply("closeServer", event) + } + }) + + route.channel.On("closeServer", func(event map[string]interface{}) { + if route.onServerClose != nil { + route.onServerClose(event["code"].(*int), event["reason"].(*string)) + } else { + go route.channel.SendNoReply("closePage", event) + } + }) + + return route +} + +func (r *webSocketRouteImpl) Close(options ...WebSocketRouteCloseOptions) { + r.channel.SendNoReply("closePage", options, map[string]interface{}{"wasClean": true}) +} + +func (r *webSocketRouteImpl) ConnectToServer() (WebSocketRoute, error) { + if r.connected.Load() { + return nil, fmt.Errorf("Already connected to the server") + } + r.channel.SendNoReply("connect") + r.connected.Store(true) + return r.server, nil +} + +func (r *webSocketRouteImpl) OnClose(handler func(code *int, reason *string)) { + r.onPageClose = handler +} + +func (r *webSocketRouteImpl) OnMessage(handler func(interface{})) { + r.onPageMessage = handler +} + +func (r *webSocketRouteImpl) Send(message interface{}) { + data, err := transformWebSocketMessage(message) + if err != nil { + panic(fmt.Errorf("Could not encode WebSocket message: %w", err)) + } + go r.channel.SendNoReply("sendToPage", data) +} + +func (r *webSocketRouteImpl) URL() string { + return r.initializer["url"].(string) +} + +func (r *webSocketRouteImpl) afterHandle() error { + if r.connected.Load() { + return nil + } + // Ensure that websocket is "open" and can send messages without an actual server connection. + _, err := r.channel.Send("ensureOpened") + return err +} + +type serverWebSocketRouteImpl struct { + webSocketRoute *webSocketRouteImpl +} + +func newServerWebSocketRoute(route *webSocketRouteImpl) *serverWebSocketRouteImpl { + return &serverWebSocketRouteImpl{webSocketRoute: route} +} + +func (s *serverWebSocketRouteImpl) OnMessage(handler func(interface{})) { + s.webSocketRoute.onServerMessage = handler +} + +func (s *serverWebSocketRouteImpl) OnClose(handler func(code *int, reason *string)) { + s.webSocketRoute.onServerClose = handler +} + +func (s *serverWebSocketRouteImpl) ConnectToServer() (WebSocketRoute, error) { + return nil, fmt.Errorf("ConnectToServer must be called on the page-side WebSocketRoute") +} + +func (s *serverWebSocketRouteImpl) URL() string { + return s.webSocketRoute.URL() +} + +func (s *serverWebSocketRouteImpl) Close(options ...WebSocketRouteCloseOptions) { + go s.webSocketRoute.channel.SendNoReply("close", options, map[string]interface{}{"wasClean": true}) +} + +func (s *serverWebSocketRouteImpl) Send(message interface{}) { + data, err := transformWebSocketMessage(message) + if err != nil { + panic(fmt.Errorf("Could not encode WebSocket message: %w", err)) + } + go s.webSocketRoute.channel.SendNoReply("sendToServer", data) +} + +func transformWebSocketMessage(message interface{}) (map[string]interface{}, error) { + data := map[string]interface{}{} + switch v := message.(type) { + case []byte: + data["isBase64"] = true + data["message"] = base64.StdEncoding.EncodeToString(v) + case string: + data["isBase64"] = false + data["message"] = v + default: + return nil, fmt.Errorf("Unsupported message type: %T", v) + } + return data, nil +} + +func untransformWebSocketMessage(data map[string]interface{}) (interface{}, error) { + if data["isBase64"].(bool) { + return base64.StdEncoding.DecodeString(data["message"].(string)) + } + return data["message"], nil +} + +type webSocketRouteHandler struct { + matcher *urlMatcher + handler func(WebSocketRoute) +} + +func newWebSocketRouteHandler(matcher *urlMatcher, handler func(WebSocketRoute)) *webSocketRouteHandler { + return &webSocketRouteHandler{matcher: matcher, handler: handler} +} + +func (h *webSocketRouteHandler) Handle(route WebSocketRoute) { + h.handler(route) + err := route.(*webSocketRouteImpl).afterHandle() + if err != nil { + panic(fmt.Errorf("Could not handle WebSocketRoute: %w", err)) + } +} + +func (h *webSocketRouteHandler) Matches(wsURL string) bool { + return h.matcher.Matches(wsURL) +} + +func prepareWebSocketRouteHandlerInterceptionPatterns(handlers []*webSocketRouteHandler) []map[string]interface{} { + patterns := []map[string]interface{}{} + all := false + for _, handler := range handlers { + switch handler.matcher.raw.(type) { + case *regexp.Regexp: + pattern, flags := convertRegexp(handler.matcher.raw.(*regexp.Regexp)) + patterns = append(patterns, map[string]interface{}{ + "regexSource": pattern, + "regexFlags": flags, + }) + case string: + patterns = append(patterns, map[string]interface{}{ + "glob": handler.matcher.raw.(string), + }) + default: + all = true + } + } + if all { + return []map[string]interface{}{ + { + "glob": "**/*", + }, + } + } + return patterns +} diff --git a/vendor/github.com/playwright-community/playwright-go/worker.go b/vendor/github.com/playwright-community/playwright-go/worker.go new file mode 100644 index 0000000..6504385 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/worker.go @@ -0,0 +1,78 @@ +package playwright + +type workerImpl struct { + channelOwner + page *pageImpl + context *browserContextImpl +} + +func (w *workerImpl) URL() string { + return w.initializer["url"].(string) +} + +func (w *workerImpl) Evaluate(expression string, options ...interface{}) (interface{}, error) { + var arg interface{} + if len(options) == 1 { + arg = options[0] + } + result, err := w.channel.Send("evaluateExpression", map[string]interface{}{ + "expression": expression, + "arg": serializeArgument(arg), + }) + if err != nil { + return nil, err + } + return parseResult(result), nil +} + +func (w *workerImpl) EvaluateHandle(expression string, options ...interface{}) (JSHandle, error) { + var arg interface{} + if len(options) == 1 { + arg = options[0] + } + result, err := w.channel.Send("evaluateExpressionHandle", map[string]interface{}{ + "expression": expression, + "arg": serializeArgument(arg), + }) + if err != nil { + return nil, err + } + return fromChannel(result).(*jsHandleImpl), nil +} + +func (w *workerImpl) onClose() { + if w.page != nil { + w.page.Lock() + workers := make([]Worker, 0) + for i := 0; i < len(w.page.workers); i++ { + if w.page.workers[i] != w { + workers = append(workers, w.page.workers[i]) + } + } + w.page.workers = workers + w.page.Unlock() + } + if w.context != nil { + w.context.Lock() + workers := make([]Worker, 0) + for i := 0; i < len(w.context.serviceWorkers); i++ { + if w.context.serviceWorkers[i] != w { + workers = append(workers, w.context.serviceWorkers[i]) + } + } + w.context.serviceWorkers = workers + w.context.Unlock() + } + w.Emit("close", w) +} + +func (w *workerImpl) OnClose(fn func(Worker)) { + w.On("close", fn) +} + +func newWorker(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *workerImpl { + bt := &workerImpl{} + bt.createChannelOwner(bt, parent, objectType, guid, initializer) + bt.channel.On("close", bt.onClose) + return bt +} diff --git a/vendor/github.com/playwright-community/playwright-go/writable_stream.go b/vendor/github.com/playwright-community/playwright-go/writable_stream.go new file mode 100644 index 0000000..7f144b4 --- /dev/null +++ b/vendor/github.com/playwright-community/playwright-go/writable_stream.go @@ -0,0 +1,44 @@ +package playwright + +import ( + "encoding/base64" + "io" + "os" +) + +type writableStream struct { + channelOwner +} + +func (s *writableStream) Copy(file string) error { + f, err := os.OpenFile(file, os.O_RDONLY, 0) + if err != nil { + return err + } + defer f.Close() + + for { + buf := make([]byte, defaultCopyBufSize) + n, err := f.Read(buf) + if err != nil && err != io.EOF { + return err + } + if n == 0 { + break + } + _, err = s.channel.Send("write", map[string]interface{}{ + "binary": base64.StdEncoding.EncodeToString(buf[:n]), + }) + if err != nil { + return err + } + } + _, err = s.channel.Send("close") + return err +} + +func newWritableStream(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *writableStream { + stream := &writableStream{} + stream.createChannelOwner(stream, parent, objectType, guid, initializer) + return stream +} |
