playwright-go/tests/page_test.go
Remington Arneson fcd06e1fa6
Some checks failed
Go / Lint (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (chromium, oldstable, macos-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (chromium, oldstable, ubuntu-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (chromium, oldstable, windows-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (chromium, stable, macos-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (chromium, stable, ubuntu-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (chromium, stable, windows-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (firefox, oldstable, macos-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (firefox, oldstable, ubuntu-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (firefox, oldstable, windows-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (firefox, stable, macos-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (firefox, stable, ubuntu-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (firefox, stable, windows-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (webkit, oldstable, macos-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (webkit, oldstable, ubuntu-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (webkit, oldstable, windows-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (webkit, stable, macos-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (webkit, stable, ubuntu-latest) (push) Has been cancelled
Go / ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }} (webkit, stable, windows-latest) (push) Has been cancelled
Go / test-examples (push) Has been cancelled
Docs / Deploy docs (push) Has been cancelled
Verify Types / verify (push) Has been cancelled
Go / finish (push) Has been cancelled
chore: roll to Playwright v1.57.0 (#578)
* chore: roll to Playwright v1.57.0

Fix playwright submodule commit

Rerun gofumpt

Change ConsoleMessages to use newConsoleMessage() to properly deserialize event objects

Add test coverage

Update page_test.go

Fix failing end-to-end test

Update README.md

Fix README

Update README.md

* Fix unit tests
2026-01-16 23:06:27 +01:00

1392 lines
39 KiB
Go

package playwright_test
import (
"errors"
"fmt"
"math/big"
"net/http"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"testing"
"time"
"github.com/h2non/filetype"
"github.com/playwright-community/playwright-go"
"github.com/stretchr/testify/require"
)
func TestPageURL(t *testing.T) {
BeforeEach(t)
require.Equal(t, "about:blank", page.URL())
_, err := page.Goto("https://example.com")
require.NoError(t, err)
require.Equal(t, "https://example.com/", page.URL())
require.Equal(t, context, page.Context())
require.Equal(t, 1, len(page.Frames()))
}
func TestPageSetContent(t *testing.T) {
BeforeEach(t)
require.NoError(t, page.SetContent("<h1>foo</h1>",
playwright.PageSetContentOptions{
WaitUntil: playwright.WaitUntilStateNetworkidle,
}))
content, err := page.Content()
require.NoError(t, err)
require.Equal(t, content, "<html><head></head><body><h1>foo</h1></body></html>")
}
func TestPageSetContentShouldRespectDefaultNavigationTimeout(t *testing.T) {
BeforeEach(t)
page.SetDefaultNavigationTimeout(1)
imgPath := "/img.png"
// stall for image
server.SetRoute(imgPath, func(w http.ResponseWriter, r *http.Request) {})
err := page.SetContent(fmt.Sprintf(`<img src="%s"></img>`, server.PREFIX+imgPath))
require.ErrorIs(t, err, playwright.ErrTimeout)
require.ErrorContains(t, err, "Timeout 1ms exceeded.")
}
func TestPageScreenshot(t *testing.T) {
BeforeEach(t)
require.NoError(t, page.SetContent("<h1>foobar</h1>"))
tmpfile, err := os.MkdirTemp("", "screenshot")
require.NoError(t, err)
screenshotPath := filepath.Join(tmpfile, "image.png")
screenshot, err := page.Screenshot()
require.NoError(t, err)
require.True(t, filetype.IsImage(screenshot))
require.Greater(t, len(screenshot), 50)
screenshot, err = page.Screenshot(playwright.PageScreenshotOptions{
Path: playwright.String(screenshotPath),
})
require.NoError(t, err)
require.True(t, filetype.IsImage(screenshot))
require.Greater(t, len(screenshot), 50)
_, err = os.Stat(screenshotPath)
require.NoError(t, err)
}
func TestPageScreenshotWithMask(t *testing.T) {
BeforeEach(t)
require.NoError(t, page.SetContent("<h1>foobar</h1><p>sensitive</p>"))
tmpfile, err := os.MkdirTemp("", "screenshot")
require.NoError(t, err)
screenshotPath := filepath.Join(tmpfile, "image.png")
screenshot1, err := page.Screenshot()
require.NoError(t, err)
require.True(t, filetype.IsImage(screenshot1))
require.Greater(t, len(screenshot1), 50)
sensElem := page.Locator("p")
screenshot2, err := page.Screenshot(playwright.PageScreenshotOptions{
Path: playwright.String(screenshotPath),
Mask: []playwright.Locator{
sensElem,
},
MaskColor: playwright.String("red"),
})
require.NoError(t, err)
require.True(t, filetype.IsImage(screenshot2))
require.Greater(t, len(screenshot2), 50)
require.NotEqual(t, screenshot1, screenshot2)
_, err = os.Stat(screenshotPath)
require.NoError(t, err)
}
func TestPagePDF(t *testing.T) {
BeforeEach(t)
if !isChromium {
t.Skip("Skipping")
}
require.NoError(t, page.SetContent("<h1>foobar</h1>"))
tmpfile, err := os.MkdirTemp("", "pdf")
require.NoError(t, err)
screenshotPath := filepath.Join(tmpfile, "image.png")
screenshot, err := page.PDF()
require.NoError(t, err)
require.Equal(t, "application/pdf", http.DetectContentType(screenshot))
require.Greater(t, len(screenshot), 50)
screenshot, err = page.PDF(playwright.PagePdfOptions{
Path: playwright.String(screenshotPath),
})
require.NoError(t, err)
require.Equal(t, "application/pdf", http.DetectContentType(screenshot))
require.Greater(t, len(screenshot), 50)
_, err = os.Stat(screenshotPath)
require.NoError(t, err)
}
func TestPagePDFWithOutline(t *testing.T) {
BeforeEach(t)
if !isChromium {
t.Skip("Skipping")
}
_, err := page.Goto(fmt.Sprintf("%s/headings.html", server.PREFIX))
require.NoError(t, err)
pdfNoOutline, err := page.PDF()
require.NoError(t, err)
pdfWithOutline, err := page.PDF(playwright.PagePdfOptions{
Tagged: playwright.Bool(true),
Outline: playwright.Bool(true),
})
require.NoError(t, err)
require.Greater(t, len(pdfWithOutline), len(pdfNoOutline))
}
func TestPageQuerySelector(t *testing.T) {
BeforeEach(t)
require.NoError(t, page.SetContent(`<div id="one">
<span id="two">
<div id="three">
<span id="four">
foobar
</span>
</div>
</span>
</div>`))
//nolint:staticcheck
one, err := page.QuerySelector("div#one")
require.NoError(t, err)
//nolint:staticcheck
two, err := one.QuerySelector("span#two")
require.NoError(t, err)
//nolint:staticcheck
three, err := two.QuerySelector("div#three")
require.NoError(t, err)
//nolint:staticcheck
four, err := three.QuerySelector("span#four")
require.NoError(t, err)
//nolint:staticcheck
textContent, err := four.TextContent()
require.NoError(t, err)
require.Equal(t, strings.TrimSpace(textContent), "foobar")
}
func TestPageQuerySelectorAll(t *testing.T) {
BeforeEach(t)
require.NoError(t, page.SetContent(`
<div class="foo">0</div>
<div class="foo">1</div>
<div class="foo">2</div>
`))
//nolint:staticcheck
elements, err := page.QuerySelectorAll("div.foo")
require.NoError(t, err)
require.Equal(t, 3, len(elements))
for i := 0; i < 3; i++ {
//nolint:staticcheck
textContent, err := elements[i].TextContent()
require.NoError(t, err)
require.Equal(t, strconv.Itoa(i), textContent)
}
}
func TestPageEvaluate(t *testing.T) {
BeforeEach(t)
val, err := page.Evaluate(`() => 123`)
require.NoError(t, err)
require.Equal(t, val, 123)
val, err = page.Evaluate(`() => 42n`)
require.NoError(t, err)
require.Equal(t, val, big.NewInt(42))
val, err = page.Evaluate(`a => a`, big.NewInt(17))
require.NoError(t, err)
require.Equal(t, val, big.NewInt(17))
}
func TestPageEvalOnSelectorAll(t *testing.T) {
BeforeEach(t)
err := page.SetContent(`
<div class="foo">1</div>
<div class="foo">2</div>
<div class="foo">3</div>
`)
require.NoError(t, err)
//nolint:staticcheck
val, err := page.EvalOnSelectorAll(".foo", `(elements) => elements.map(el => el.textContent)`)
require.NoError(t, err)
require.Equal(t, val, []interface{}([]interface{}{"1", "2", "3"}))
}
func TestPageEvalOnSelector(t *testing.T) {
BeforeEach(t)
err := page.SetContent(`
<div class="foo">bar</div>
`)
require.NoError(t, err)
//nolint:staticcheck
val, err := page.EvalOnSelector(".foo", `(element) => element.textContent`, nil)
require.NoError(t, err)
require.Equal(t, val, "bar")
}
func TestPageExpectWorker(t *testing.T) {
BeforeEach(t)
worker, err := page.ExpectWorker(func() error {
_, err := page.Goto(server.PREFIX + "/worker/worker.html")
return err
})
require.NoError(t, err)
require.Equal(t, 1, len(page.Workers()))
require.Equal(t, worker, page.Workers()[0])
worker = page.Workers()[0]
require.Contains(t, worker.URL(), "worker.js")
// flaky in the macos-latest of gh action
require.Eventually(t,
func() bool {
v, err := worker.Evaluate(`() => self["workerFunction"] ? true : false`)
require.NoError(t, err)
return v == true
},
500*time.Millisecond, 10*time.Millisecond,
)
res, err := worker.Evaluate(`() => self["workerFunction"]()`)
require.NoError(t, err)
require.Equal(t, "worker function result", res)
_, err = page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.Equal(t, 0, len(page.Workers()))
}
func TestPageExpectRequest(t *testing.T) {
BeforeEach(t)
request, err := page.ExpectRequest("**/*", func() error {
_, err := page.Goto(server.EMPTY_PAGE)
return err
})
require.NoError(t, err)
require.Equal(t, server.EMPTY_PAGE, request.URL())
require.Equal(t, "document", request.ResourceType())
require.Equal(t, "GET", request.Method())
}
func TestPageExpectRequestRegexp(t *testing.T) {
BeforeEach(t)
request, err := page.ExpectRequest(regexp.MustCompile(".*/empty.html"), func() error {
_, err := page.Goto(server.EMPTY_PAGE)
return err
})
require.NoError(t, err)
require.Equal(t, server.EMPTY_PAGE, request.URL())
require.Equal(t, "document", request.ResourceType())
require.Equal(t, "GET", request.Method())
}
func TestPageExpectRequestFunc(t *testing.T) {
BeforeEach(t)
request, err := page.ExpectRequest(func(url string) bool {
return strings.HasSuffix(url, "empty.html")
}, func() error {
_, err := page.Goto(server.EMPTY_PAGE)
return err
})
require.NoError(t, err)
require.Equal(t, server.EMPTY_PAGE, request.URL())
require.Equal(t, "document", request.ResourceType())
require.Equal(t, "GET", request.Method())
}
func TestPageExpectRequestFinished(t *testing.T) {
BeforeEach(t)
request, err := page.ExpectRequestFinished(func() error {
_, err := page.Goto(server.EMPTY_PAGE)
return err
}, playwright.PageExpectRequestFinishedOptions{
Predicate: func(r playwright.Request) bool {
return strings.HasSuffix(r.URL(), "empty.html")
},
})
require.NoError(t, err)
require.Equal(t, server.EMPTY_PAGE, request.URL())
require.Equal(t, "document", request.ResourceType())
require.Equal(t, "GET", request.Method())
}
func TestPageExpectPopup(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
popup, err := page.ExpectPopup(func() error {
_, err := page.Evaluate(`window._popup = window.open(document.location.href)`)
return err
})
require.NoError(t, err)
require.Equal(t, popup.URL(), server.EMPTY_PAGE)
}
func TestPageExpectNavigation(t *testing.T) {
t.Skip()
}
func TestPageExpectLoadState(t *testing.T) {
t.Skip()
}
func TestPageExpectFileChooser(t *testing.T) {
BeforeEach(t)
t.Run("should work for single file pick", func(t *testing.T) {
require.NoError(t, page.SetContent(`<input type=file>`))
fc, err := page.ExpectFileChooser(func() error {
return page.Locator("input").Click()
}, playwright.PageExpectFileChooserOptions{
Timeout: playwright.Float(1000),
})
require.NoError(t, err)
require.False(t, fc.IsMultiple())
})
t.Run("should work for multiple", func(t *testing.T) {
require.NoError(t, page.SetContent(`<input multiple type=file>`))
_, err := page.ExpectFileChooser(func() error {
return page.Locator("input").Click()
}, playwright.PageExpectFileChooserOptions{
Predicate: func(fc playwright.FileChooser) bool {
return fc.IsMultiple()
},
})
require.NoError(t, err)
})
}
func TestPageExpectDialog(t *testing.T) {
t.Skip()
}
func TestPageExpectConsoleMessage(t *testing.T) {
BeforeEach(t)
message, err := page.ExpectConsoleMessage(func() error {
_, err := page.Evaluate(`console.log(123, "abc")`)
return err
})
require.NoError(t, err)
require.Equal(t, message.Text(), "123 abc")
}
func TestPageExpectEvent(t *testing.T) {
t.Skip()
}
func TestPageOpener(t *testing.T) {
BeforeEach(t)
eventPage, err := context.ExpectEvent("page", func() error {
_, err := page.Goto(server.PREFIX + "/popup/window-open.html")
return err
})
require.NoError(t, err)
popup := eventPage.(playwright.Page)
opener, err := popup.Opener()
require.NoError(t, err)
require.Equal(t, opener, page)
opener, err = page.Opener()
require.NoError(t, err)
require.Nil(t, opener)
}
func TestPageTitle(t *testing.T) {
BeforeEach(t)
require.NoError(t, page.SetContent(`<title>abc</title>`))
title, err := page.Title()
require.NoError(t, err)
require.Equal(t, "abc", title)
}
func TestPageWaitForSelector(t *testing.T) {
BeforeEach(t)
require.NoError(t, page.SetContent(`<h1>myElement</h1>`))
//nolint:staticcheck
element, err := page.WaitForSelector("text=myElement")
require.NoError(t, err)
//nolint:staticcheck
textContent, err := element.TextContent()
require.NoError(t, err)
require.Equal(t, "myElement", textContent)
//nolint:staticcheck
_, err = page.WaitForSelector("h1")
require.NoError(t, err)
}
func TestPageDispatchEvent(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.PREFIX + "/input/button.html")
require.NoError(t, err)
//nolint:staticcheck
require.NoError(t, page.DispatchEvent("button", "click", nil))
clicked, err := page.Evaluate("() => result")
require.NoError(t, err)
require.Equal(t, "Clicked", clicked)
}
func TestPageReload(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
_, err = page.Evaluate("window._foo = 10")
require.NoError(t, err)
_, err = page.Reload()
require.NoError(t, err)
v, err := page.Evaluate("window._foo")
require.NoError(t, err)
require.Nil(t, v)
}
func TestPageGoBackGoForward(t *testing.T) {
BeforeEach(t)
resp, err := page.GoBack()
require.NoError(t, err)
require.Nil(t, resp)
_, err = page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
_, err = page.Goto(server.PREFIX + "/grid.html")
require.NoError(t, err)
resp, err = page.GoBack()
require.NoError(t, err)
require.True(t, resp.Ok())
require.Equal(t, resp.URL(), server.EMPTY_PAGE)
resp, err = page.GoForward()
require.NoError(t, err)
require.True(t, resp.Ok())
require.Contains(t, resp.URL(), "/grid.html")
resp, err = page.GoForward()
require.NoError(t, err)
require.Nil(t, resp)
}
func TestPageAddScriptTag(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
scriptHandle, err := page.AddScriptTag(playwright.PageAddScriptTagOptions{
URL: playwright.String("injectedfile.js"),
})
require.NoError(t, err)
require.NotNil(t, scriptHandle.AsElement())
v, err := page.Evaluate("__injected")
require.NoError(t, err)
require.Equal(t, 42, v)
}
func TestPageAddScriptTagFile(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
scriptHandle, err := page.AddScriptTag(playwright.PageAddScriptTagOptions{
Path: playwright.String(Asset("injectedfile.js")),
})
require.NoError(t, err)
require.NotNil(t, scriptHandle.AsElement())
v, err := page.Evaluate("__injected")
require.NoError(t, err)
require.Equal(t, 42, v)
}
func TestPageAddStyleTag(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
_, err = page.AddStyleTag(playwright.PageAddStyleTagOptions{
URL: playwright.String("injectedstyle.css"),
})
require.NoError(t, err)
v, err := page.Evaluate("window.getComputedStyle(document.querySelector('body')).getPropertyValue('background-color')")
require.NoError(t, err)
require.Equal(t, "rgb(255, 0, 0)", v)
}
func TestPageAddStyleTagFile(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
_, err = page.AddStyleTag(playwright.PageAddStyleTagOptions{
Path: playwright.String(Asset("injectedstyle.css")),
})
require.NoError(t, err)
v, err := page.Evaluate("window.getComputedStyle(document.querySelector('body')).getPropertyValue('background-color')")
require.NoError(t, err)
require.Equal(t, "rgb(255, 0, 0)", v)
}
func TestPageWaitForLoadState(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.PREFIX + "/one-style.html")
require.NoError(t, err)
require.NoError(t, page.WaitForLoadState())
require.NoError(t, page.WaitForLoadState(playwright.PageWaitForLoadStateOptions{
State: playwright.LoadStateNetworkidle,
}))
}
func TestPlaywrightDevices(t *testing.T) {
BeforeEach(t)
require.Greater(t, len(pw.Devices), 10)
for name, device := range pw.Devices {
require.NotEmpty(t, name)
require.NotEmpty(t, device.UserAgent)
require.NotEmpty(t, device.Viewport)
require.Greater(t, device.DeviceScaleFactor, float64(0))
require.NotEmpty(t, device.DefaultBrowserType)
}
}
func TestPageAddInitScript(t *testing.T) {
BeforeEach(t)
require.NoError(t, page.AddInitScript(playwright.Script{
Content: playwright.String(`window['injected'] = 123;`),
}))
_, err := page.Goto(server.PREFIX + "/tamperable.html")
require.NoError(t, err)
result, err := page.Evaluate(`() => window['result']`)
require.NoError(t, err)
require.Equal(t, 123, result)
}
func TestPageExpectSelectorTimeout(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
err = page.Locator("foobar").Click(playwright.LocatorClickOptions{
Timeout: playwright.Float(500),
})
require.ErrorIs(t, err, playwright.ErrTimeout)
}
func TestPageType(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.NoError(t, page.SetContent("<input type='text' />"))
//nolint:staticcheck
require.NoError(t, page.Type("input", "hello"))
value, err := page.Locator("input").Evaluate("el => el.value", nil)
require.NoError(t, err)
require.Equal(t, "hello", value)
}
func TestPagePress(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.NoError(t, page.SetContent("<input type='text' />"))
//nolint:staticcheck
require.NoError(t, page.Press("input", "h"))
value, err := page.Locator("input").Evaluate("el => el.value", nil)
require.NoError(t, err)
require.Equal(t, "h", value)
}
func TestPageCheck(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.NoError(t, page.SetContent("<input id='checkbox' type='checkbox'></input>"))
//nolint:staticcheck
require.NoError(t, page.Check("input"))
value, err := page.Locator("input").Evaluate("el => el.checked", nil)
require.NoError(t, err)
require.Equal(t, true, value)
}
func TestPageUncheck(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.NoError(t, page.SetContent("<input id='checkbox' type='checkbox' checked></input>"))
//nolint:staticcheck
require.NoError(t, page.Uncheck("input"))
value, err := page.Locator("input").Evaluate("el => el.checked", nil)
require.NoError(t, err)
require.Equal(t, false, value)
}
func TestPageWaitForTimeout(t *testing.T) {
BeforeEach(t)
before := time.Now()
//nolint:staticcheck
page.WaitForTimeout(1000)
after := time.Now()
duration := after.Sub(before)
require.True(t, duration > time.Second)
require.True(t, duration < 2*time.Second)
}
func TestPageWaitForFunction(t *testing.T) {
BeforeEach(t)
_, err := page.Evaluate(`() => setTimeout(() => window.FOO = true, 500)`)
require.NoError(t, err)
_, err = page.WaitForFunction(`window.FOO === true`, nil)
require.NoError(t, err)
}
func TestPageDblclick(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.NoError(t, page.SetContent(`<button ondblclick="window.clicked=true"/>`))
//nolint:staticcheck
require.NoError(t, page.Dblclick("button"))
result, err := page.Evaluate("window.clicked")
require.NoError(t, err)
require.True(t, result.(bool))
}
func TestPageFocus(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.NoError(t, page.SetContent(`<button onfocus="window.clicked=true"/>`))
//nolint:staticcheck
require.NoError(t, page.Focus("button"))
result, err := page.Evaluate("window.clicked")
require.NoError(t, err)
require.True(t, result.(bool))
}
func TestPageTextContent(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.PREFIX + "/dom.html")
require.NoError(t, err)
//nolint:staticcheck
content, err := page.TextContent("#inner")
require.NoError(t, err)
require.Equal(t, "Text,\nmore text", content)
}
func TestPageAddInitScriptWithPath(t *testing.T) {
BeforeEach(t)
require.NoError(t, page.AddInitScript(playwright.Script{
Path: playwright.String(Asset("injectedfile.js")),
}))
_, err := page.Goto(server.PREFIX + "/tamperable.html")
require.NoError(t, err)
result, err := page.Evaluate(`() => window['result']`)
require.NoError(t, err)
require.Equal(t, 123, result)
}
func TestPageSupportNetworkEvents(t *testing.T) {
BeforeEach(t)
eventsChan := make(chan string, 6)
page.OnRequest(func(request playwright.Request) {
eventsChan <- fmt.Sprintf("%s %s", request.Method(), request.URL())
})
page.OnResponse(func(response playwright.Response) {
eventsChan <- fmt.Sprintf("%d %s", response.Status(), response.URL())
})
page.OnRequestFinished(func(request playwright.Request) {
eventsChan <- fmt.Sprintf("DONE %s", request.URL())
})
page.OnRequestFailed(func(request playwright.Request) {
eventsChan <- fmt.Sprintf("FAIL %s", request.URL())
})
server.SetRedirect("/foo.html", "/empty.html")
FOO_URL := server.PREFIX + "/foo.html"
response, err := page.Goto(FOO_URL)
require.NoError(t, err)
eventsSlice := ChanToSlice(eventsChan, 6)
require.Equal(t, []string{
fmt.Sprintf("GET %s", FOO_URL),
fmt.Sprintf("302 %s", FOO_URL),
fmt.Sprintf("DONE %s", FOO_URL),
fmt.Sprintf("GET %s", server.EMPTY_PAGE),
fmt.Sprintf("200 %s", server.EMPTY_PAGE),
fmt.Sprintf("DONE %s", server.EMPTY_PAGE),
}, eventsSlice)
redirectedFrom := response.Request().RedirectedFrom()
require.Contains(t, redirectedFrom.URL(), "foo.html")
require.Nil(t, redirectedFrom.RedirectedFrom())
require.Equal(t, redirectedFrom.RedirectedTo(), response.Request())
}
func TestPageSetViewport(t *testing.T) {
BeforeEach(t)
utils.VerifyViewport(t, page, 1280, 720)
require.NoError(t, page.SetViewportSize(123, 456))
utils.VerifyViewport(t, page, 123, 456)
}
func TestPageEmulateMedia(t *testing.T) {
BeforeEach(t)
utils.AssertEval(t, page, "matchMedia('screen').matches", true)
utils.AssertEval(t, page, "matchMedia('print').matches", false)
require.NoError(t, page.EmulateMedia(playwright.PageEmulateMediaOptions{
Media: playwright.MediaPrint,
}))
utils.AssertEval(t, page, "matchMedia('screen').matches", false)
utils.AssertEval(t, page, "matchMedia('print').matches", true)
require.NoError(t, page.EmulateMedia())
utils.AssertEval(t, page, "matchMedia('screen').matches", false)
utils.AssertEval(t, page, "matchMedia('print').matches", true)
require.NoError(t, page.EmulateMedia(playwright.PageEmulateMediaOptions{
Media: playwright.MediaNoOverride,
}))
utils.AssertEval(t, page, "matchMedia('screen').matches", true)
utils.AssertEval(t, page, "matchMedia('print').matches", false)
}
func TestPageBringToFront(t *testing.T) {
BeforeEach(t)
page1, err := browser.NewPage()
require.NoError(t, err)
require.NoError(t, page1.SetContent("Page1"))
page2, err := browser.NewPage()
require.NoError(t, err)
require.NoError(t, page2.SetContent("Page2"))
require.NoError(t, page1.BringToFront())
utils.AssertEval(t, page1, "document.visibilityState", "visible")
utils.AssertEval(t, page2, "document.visibilityState", "visible")
require.NoError(t, page2.BringToFront())
utils.AssertEval(t, page1, "document.visibilityState", "visible")
utils.AssertEval(t, page2, "document.visibilityState", "visible")
require.NoError(t, page1.Close())
require.NoError(t, page2.Close())
}
func TestPageFrame(t *testing.T) {
BeforeEach(t)
err := page.SetContent(fmt.Sprintf("<iframe name=target src=%s></iframe>", server.EMPTY_PAGE))
require.NoError(t, err)
name := "target"
frame1 := page.Frame(playwright.PageFrameOptions{Name: &name})
require.Equal(t, name, frame1.Name())
require.Equal(t, server.EMPTY_PAGE, frame1.URL())
frame2 := page.Frame(playwright.PageFrameOptions{URL: server.EMPTY_PAGE})
require.Equal(t, name, frame2.Name())
require.Equal(t, server.EMPTY_PAGE, frame2.URL())
badName := "test"
frame3 := page.Frame(playwright.PageFrameOptions{Name: &badName, URL: server.EMPTY_PAGE})
require.Equal(t, name, frame3.Name())
require.Equal(t, server.EMPTY_PAGE, frame3.URL())
require.Nil(t, page.Frame(playwright.PageFrameOptions{Name: &badName, URL: "https://example.com"}))
require.Nil(t, page.Frame(playwright.PageFrameOptions{Name: &badName}))
}
func TestPageTap(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.NoError(t, page.SetContent("<input id='checkbox' type='checkbox'></input>"))
value, err := page.Locator("input").Evaluate("el => el.checked", nil)
require.NoError(t, err)
require.Equal(t, false, value)
//nolint:staticcheck
require.NoError(t, page.Tap("input"))
value, err = page.Locator("input").Evaluate("el => el.checked", nil)
require.NoError(t, err)
require.Equal(t, true, value)
}
func TestPagePageError(t *testing.T) {
BeforeEach(t)
url := server.PREFIX + "/error.html"
errAny, err := page.ExpectEvent("pageerror", func() error {
_, err := page.Goto(url)
return err
})
require.NoError(t, err)
pageError := &playwright.Error{}
require.True(t, errors.As(errAny.(error), &pageError))
require.Equal(t, "Fancy error!", pageError.Message)
require.Equal(t, "Error", pageError.Name)
if browserName == "chromium" {
require.Equal(t, `Error: Fancy error!
at c (myscript.js:14:11)
at b (myscript.js:10:5)
at a (myscript.js:6:5)
at myscript.js:3:1`, pageError.Stack)
}
if browserName == "firefox" {
require.Equal(t, `Error: Fancy error!
at c (myscript.js:14:11)
at b (myscript.js:10:5)
at a (myscript.js:6:5)
at (myscript.js:3:1)`, pageError.Stack)
}
if browserName == "webkit" {
require.Equal(t, fmt.Sprintf(`Error: Fancy error!
at c (%[1]s:14:36)
at b (%[1]s:10:6)
at a (%[1]s:6:6)
at global code (%[1]s:3:2)`, url), pageError.Stack)
}
}
func TestPageSelectOption(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.NoError(t, page.SetContent("<select id='lang'><option value='go'>go</option><option value='python'>python</option></select>"))
//nolint:staticcheck
selected, err := page.SelectOption("#lang", playwright.SelectOptionValues{
Values: playwright.StringSlice("python"),
})
require.NoError(t, err)
require.Equal(t, 1, len(selected))
require.Equal(t, "python", selected[0])
}
func TestPageUnrouteShouldWork(t *testing.T) {
BeforeEach(t)
intercepted := []int{}
handler1 := func(route playwright.Route) {
intercepted = append(intercepted, 1)
require.NoError(t, route.Continue())
}
require.NoError(t, page.Route("**/*", handler1))
handler2 := func(route playwright.Route) {
intercepted = append(intercepted, 2)
require.NoError(t, route.Continue())
}
require.NoError(t, page.Route("**/empty.html", handler2))
handler3 := func(route playwright.Route) {
intercepted = append(intercepted, 3)
require.NoError(t, route.Continue())
}
require.NoError(t, page.Route("**/empty.html", handler3))
handler4 := func(route playwright.Route) {
intercepted = append(intercepted, 4)
require.NoError(t, route.Continue())
}
require.NoError(t, page.Route(regexp.MustCompile("empty.html"), handler4))
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.Equal(t, []int{4}, intercepted)
intercepted = []int{}
require.NoError(t, page.Unroute(regexp.MustCompile("empty.html"), handler4))
_, err = page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.Equal(t, []int{3}, intercepted)
intercepted = []int{}
require.NoError(t, page.Unroute("**/empty.html"))
_, err = page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.Equal(t, []int{1}, intercepted)
}
func TestPageDragAndDrop(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.PREFIX + "/drag-n-drop.html")
require.NoError(t, err)
require.NoError(t, page.DragAndDrop("#source", "#target"))
value, err := page.Locator("#target").Evaluate("target => target.contains(document.querySelector('#source'))", nil)
require.NoError(t, err)
require.Equal(t, true, value)
}
func TestPageInputValue(t *testing.T) {
BeforeEach(t)
require.NoError(t, page.SetContent(`
<input></input>
`))
require.NoError(t, page.Locator("input").Fill("hello"))
//nolint:staticcheck
value, err := page.InputValue("input")
require.NoError(t, err)
require.Equal(t, "hello", value)
require.NoError(t, page.Locator("input").Fill(""))
//nolint:staticcheck
value, err = page.InputValue("input")
require.NoError(t, err)
require.Equal(t, "", value)
}
func TestPageWaitForFunction2(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
_, err = page.AddScriptTag(
playwright.PageAddScriptTagOptions{
Path: playwright.String(Asset(filepath.Join("es6", "es6pathimport.js"))),
Type: playwright.String("module"),
},
)
require.NoError(t, err)
_, err = page.WaitForFunction("window.__es6injected", nil)
require.NoError(t, err)
value, err := page.Evaluate("window.__es6injected")
require.NoError(t, err)
require.Equal(t, 42, value)
}
func TestPageShouldSetBodysizeAndHeadersize(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
request, err := page.ExpectRequest("**/*", func() error {
_, err = page.Evaluate("() => fetch('./get', { method: 'POST', body: '12345'}).then(r => r.text())")
require.NoError(t, err)
return nil
},
)
require.NoError(t, err)
sizes, err := request.Sizes()
require.NoError(t, err)
require.Equal(t, 5, sizes.RequestBodySize)
require.GreaterOrEqual(t, sizes.RequestHeadersSize, 300)
}
func TestPageTestShouldSetBodysizeTo0(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
request, err := page.ExpectRequest("**/*", func() error {
_, err = page.Evaluate("() => fetch('./get').then(r => r.text())")
require.NoError(t, err)
return nil
},
)
require.NoError(t, err)
sizes, err := request.Sizes()
require.NoError(t, err)
require.Equal(t, 0, sizes.RequestBodySize)
require.GreaterOrEqual(t, sizes.RequestHeadersSize, 200)
}
func TestPageSetChecked(t *testing.T) {
BeforeEach(t)
require.NoError(t, page.SetContent(`<input id='checkbox' type='checkbox'></input>`))
//nolint:staticcheck
require.NoError(t, page.SetChecked("input", true))
isChecked, err := page.Evaluate("checkbox.checked")
require.NoError(t, err)
require.True(t, isChecked.(bool))
//nolint:staticcheck
require.NoError(t, page.SetChecked("input", false))
isChecked, err = page.Evaluate("checkbox.checked")
require.NoError(t, err)
require.False(t, isChecked.(bool))
}
func TestPageExpectRequestTimeout(t *testing.T) {
t.Run("should respect timeout", func(t *testing.T) {
BeforeEach(t)
request, err := page.ExpectRequest("**/one-style.html", func() error {
_, err := page.Goto(server.EMPTY_PAGE)
return err
}, playwright.PageExpectRequestOptions{Timeout: playwright.Float(1000)})
require.Nil(t, request)
require.ErrorContains(t, err, "Timeout 1000.00ms exceeded.")
})
t.Run("should use default timeout", func(t *testing.T) {
BeforeEach(t)
page.SetDefaultTimeout(500)
defer page.SetDefaultTimeout(30 * 1000) // reset
request, err := page.ExpectRequest("**/one-style.html", func() error {
_, err := page.Goto(server.EMPTY_PAGE)
return err
})
require.Nil(t, request)
require.ErrorContains(t, err, "Timeout 500.00ms exceeded.")
})
}
func TestPageExpectResponse(t *testing.T) {
t.Run("should work with predicate", func(t *testing.T) {
BeforeEach(t)
predicate := regexp.MustCompile(`(?i).*/one-style.html`)
response, err := page.ExpectResponse(predicate, func() error {
_, err := page.Goto(server.PREFIX + "/one-style.html")
return err
}, playwright.PageExpectResponseOptions{Timeout: playwright.Float(3 * 1000)})
require.NoError(t, err)
require.Equal(t, fmt.Sprintf("%s/one-style.html", server.PREFIX), response.URL())
})
t.Run("should work", func(t *testing.T) {
BeforeEach(t)
response, err := page.ExpectResponse("**/*", func() error {
_, err := page.Goto(server.EMPTY_PAGE)
return err
})
require.NoError(t, err)
require.Equal(t, server.EMPTY_PAGE, response.URL())
require.True(t, response.Ok())
require.Equal(t, 200, response.Status())
require.Equal(t, "OK", response.StatusText())
})
t.Run("should respect timeout", func(t *testing.T) {
BeforeEach(t)
response, err := page.ExpectResponse("**/one-style.html", func() error {
_, err := page.Goto(server.EMPTY_PAGE)
return err
}, playwright.PageExpectResponseOptions{Timeout: playwright.Float(1000)})
require.Nil(t, response)
require.ErrorContains(t, err, "Timeout 1000.00ms exceeded.")
})
t.Run("should use default timeout", func(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
page.SetDefaultTimeout(500)
defer page.SetDefaultTimeout(30 * 1000) // reset
require.NoError(t, err)
response, err := page.ExpectResponse("**/one-style.html", nil)
require.Nil(t, response)
require.ErrorContains(t, err, "Timeout 500.00ms exceeded.")
})
t.Run("should use context default timeout", func(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
context.SetDefaultTimeout(1000)
defer context.SetDefaultTimeout(30 * 1000) // reset
require.NoError(t, err)
response, err := page.ExpectResponse("**/one-style.html", nil)
require.Nil(t, response)
require.ErrorContains(t, err, "Timeout 1000.00ms exceeded.")
})
}
func TestPageWaitForURL(t *testing.T) {
t.Run("should work", func(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
_, err = page.Evaluate("url => window.location.href = url", fmt.Sprintf("%s/grid.html", server.PREFIX))
require.NoError(t, err)
require.NoError(t, page.WaitForURL("**/grid.html"))
require.Contains(t, page.URL(), "grid.html")
})
t.Run("should respect timeout", func(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
require.ErrorContains(t, page.WaitForURL("**/grid.html", playwright.PageWaitForURLOptions{
Timeout: playwright.Float(1000),
}), "Timeout 1000.00ms exceeded.")
})
t.Run("should work with commit", func(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
_, err = page.Evaluate("url => window.location.href = url", fmt.Sprintf("%s/grid.html", server.PREFIX))
require.NoError(t, err)
require.NoError(t, page.WaitForURL("**/grid.html"), playwright.FrameWaitForURLOptions{
WaitUntil: playwright.WaitUntilStateCommit,
})
require.Contains(t, page.URL(), "grid.html")
})
}
func TestCloseShouldRunBeforunloadIfAskedFor(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(fmt.Sprintf("%s/beforeunload.html", server.PREFIX))
require.NoError(t, err)
dialogInfo, err := page.ExpectEvent("dialog", func() error {
// We have to interact with a page so that 'beforeunload' handlers fire.
require.NoError(t, page.Locator("body").Click())
return page.Close(playwright.PageCloseOptions{
RunBeforeUnload: playwright.Bool(true),
})
})
require.NoError(t, err)
dialog := dialogInfo.(playwright.Dialog)
require.Equal(t, "beforeunload", dialog.Type())
if isChromium {
require.Equal(t, "", dialog.Message())
} else if isWebKit {
require.Equal(t, "Leave?", dialog.Message())
} else {
require.Contains(t, dialog.Message(), "This page is asking you to confirm that you want to leave")
}
_, err = page.ExpectEvent("close", func() error {
require.NoError(t, dialog.Accept())
return nil
})
require.Error(t, err)
}
func TestPageGotoShouldFailWhenExceedingBrowserContextNavigationTimeout(t *testing.T) {
BeforeEach(t)
// Hang for request to the empty.html
server.SetRoute("/empty.html", func(w http.ResponseWriter, r *http.Request) {})
context.SetDefaultNavigationTimeout(2)
_, err := page.Goto(server.EMPTY_PAGE)
require.ErrorIs(t, err, playwright.ErrTimeout)
require.ErrorContains(t, err, "Timeout 2ms exceeded.")
require.ErrorContains(t, err, "/empty.html")
}
func TestShouldEmulateContrast(t *testing.T) {
BeforeEach(t)
ret, err := page.Evaluate(`matchMedia('(prefers-contrast: no-preference)').matches`)
require.NoError(t, err)
require.True(t, ret.(bool))
err = page.EmulateMedia(playwright.PageEmulateMediaOptions{
Contrast: playwright.ContrastNoPreference,
})
require.NoError(t, err)
_, err = page.Evaluate(`matchMedia('(prefers-contrast: no-preference)').matches`)
require.NoError(t, err)
ret, err = page.Evaluate(`matchMedia('(prefers-contrast: more)').matches`)
require.NoError(t, err)
require.False(t, ret.(bool))
err = page.EmulateMedia(playwright.PageEmulateMediaOptions{
Contrast: playwright.ContrastMore,
})
require.NoError(t, err)
ret, err = page.Evaluate(`matchMedia('(prefers-contrast: no-preference)').matches`)
require.NoError(t, err)
require.False(t, ret.(bool))
ret, err = page.Evaluate(`matchMedia('(prefers-contrast: more)').matches`)
require.NoError(t, err)
require.True(t, ret.(bool))
err = page.EmulateMedia(playwright.PageEmulateMediaOptions{
Contrast: playwright.ContrastNoOverride,
})
require.NoError(t, err)
ret, err = page.Evaluate(`matchMedia('(prefers-contrast: no-preference)').matches`)
require.NoError(t, err)
require.True(t, ret.(bool))
}
// TestPageConsoleMessages verifies that Page.ConsoleMessages() returns accumulated console messages
// Based on upstream test: playwright/tests/page/page-event-console.spec.ts
func TestPageConsoleMessages(t *testing.T) {
BeforeEach(t)
// Generate 301 console messages (should keep last 100)
_, err := page.Evaluate(`() => {
for (let i = 0; i < 301; i++) {
console.log('message' + i);
}
}`)
require.NoError(t, err)
messages, err := page.ConsoleMessages()
require.NoError(t, err)
// Should return at least 100 messages (the buffer limit)
require.GreaterOrEqual(t, len(messages), 100, "should be at least 100 messages")
// Verify the last 100 messages are correct (message201 to message300)
expectedStart := 301 - len(messages)
for i, msg := range messages {
expectedText := fmt.Sprintf("message%d", expectedStart+i)
require.Equal(t, expectedText, msg.Text())
require.Equal(t, "log", msg.Type())
// Note: Page() may be nil for console messages retrieved from the buffer
// as they don't include full channel references like live events do
}
}
// TestPageConsoleMessagesEmpty verifies that ConsoleMessages() returns empty array for new page
func TestPageConsoleMessagesEmpty(t *testing.T) {
BeforeEach(t)
messages, err := page.ConsoleMessages()
require.NoError(t, err)
require.Empty(t, messages)
}
// TestPageConsoleMessagesTypes verifies different console message types are captured
func TestPageConsoleMessagesTypes(t *testing.T) {
BeforeEach(t)
_, err := page.Evaluate(`() => {
console.log('log message');
console.warn('warn message');
console.error('error message');
console.info('info message');
}`)
require.NoError(t, err)
messages, err := page.ConsoleMessages()
require.NoError(t, err)
require.Len(t, messages, 4)
expectedTypes := []string{"log", "warning", "error", "info"}
for i, msg := range messages {
require.Equal(t, expectedTypes[i], msg.Type())
}
}
// TestPageRequests verifies that Page.Requests() returns accumulated requests
// Based on upstream test: playwright/tests/page/page-event-request.spec.ts
func TestPageRequests(t *testing.T) {
BeforeEach(t)
// Navigate to a page (creates initial request)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
// Create multiple fetch requests
for i := 0; i < 99; i++ {
path := fmt.Sprintf("/fetch%d", i)
server.SetRoute(path, func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte("response"))
require.NoError(t, err)
})
}
// Make 99 fetch requests
for i := 0; i < 99; i++ {
url := fmt.Sprintf("%s/fetch%d", server.PREFIX, i)
_, err := page.Evaluate(`url => fetch(url)`, url)
require.NoError(t, err)
}
requests, err := page.Requests()
require.NoError(t, err)
// Should have at least 100 requests (navigation + 99 fetches, buffer limit is 100)
require.GreaterOrEqual(t, len(requests), 99, "should capture fetch requests")
// Verify requests are functional
for _, req := range requests {
require.NotEmpty(t, req.URL())
require.NotEmpty(t, req.Method())
}
}
// TestPageRequestsEmpty verifies that Requests() returns empty array for new page
func TestPageRequestsEmpty(t *testing.T) {
BeforeEach(t)
requests, err := page.Requests()
require.NoError(t, err)
require.Empty(t, requests)
}
// TestPageRequestsWithNavigation verifies navigation requests are included
func TestPageRequestsWithNavigation(t *testing.T) {
BeforeEach(t)
_, err := page.Goto(server.EMPTY_PAGE)
require.NoError(t, err)
requests, err := page.Requests()
require.NoError(t, err)
require.Len(t, requests, 1, "should capture navigation request")
req := requests[0]
require.Equal(t, server.EMPTY_PAGE, req.URL())
require.Equal(t, "GET", req.Method())
require.Equal(t, "document", req.ResourceType())
}