mirror of
https://github.com/playwright-community/playwright-go.git
synced 2026-06-03 21:02:27 +08:00
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 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
735 lines
22 KiB
Go
735 lines
22 KiB
Go
package playwright_test
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/playwright-community/playwright-go"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func pageClockFixture(t *testing.T) *syncSlice[[]interface{}] {
|
|
t.Helper()
|
|
calls := newSyncSlice[[]interface{}]()
|
|
err := page.ExposeFunction("stub", func(args ...interface{}) interface{} {
|
|
calls.Append(args)
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
return calls
|
|
}
|
|
|
|
func beforePageClock(t *testing.T, installTime, pauseAtTime interface{}) {
|
|
require.NoError(t, page.Clock().Install(playwright.ClockInstallOptions{
|
|
Time: installTime,
|
|
}))
|
|
require.NoError(t, page.Clock().PauseAt(pauseAtTime))
|
|
}
|
|
|
|
func TestPageClockRunFor(t *testing.T) {
|
|
t.Run("tiggers immediately without specified delay", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setTimeout(window.stub)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(0))
|
|
require.Eventually(t, func() bool { return calls.Len() == 1 }, 100*time.Millisecond, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("does not trigger without sufficient delay", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setTimeout(window.stub, 100)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(10))
|
|
require.Eventually(t, func() bool { return calls.Len() == 0 }, 100*time.Millisecond, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("triggers after sufficient delay", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setTimeout(window.stub, 100)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(100))
|
|
require.Eventually(t, func() bool { return calls.Len() == 1 }, 100*time.Millisecond, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("triggers simultaneous timers", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setTimeout(window.stub, 100); setTimeout(window.stub, 100)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(100))
|
|
require.Eventually(t, func() bool { return calls.Len() == 2 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("triggers multiple simultaneous timers", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate(
|
|
"setTimeout(window.stub, 100); setTimeout(window.stub, 100); setTimeout(window.stub, 99); setTimeout(window.stub, 100)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(100))
|
|
require.Eventually(t, func() bool { return calls.Len() == 4 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("waits after setTimeout was called", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setTimeout(window.stub, 150)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(50))
|
|
require.Eventually(t, func() bool { return calls.Len() == 0 }, 100*time.Millisecond, 10*time.Millisecond)
|
|
require.NoError(t, page.Clock().RunFor(100))
|
|
require.Eventually(t, func() bool { return calls.Len() == 1 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("triggers event when some throw", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setTimeout(() => { throw new Error(); }, 100); setTimeout(window.stub, 120)")
|
|
require.NoError(t, err)
|
|
require.Error(t, page.Clock().RunFor(120))
|
|
require.Eventually(t, func() bool { return calls.Len() == 1 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("creates updated Date while ticking", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
require.NoError(t, page.Clock().SetSystemTime(0))
|
|
_, err := page.Evaluate("setInterval(() => { window.stub(new Date().getTime()); }, 10)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(100))
|
|
require.Eventually(t, func() bool { return calls.Len() == 10 }, 1*time.Second, 10*time.Millisecond)
|
|
// Goroutines cannot guarantee order and need to be sorted before comparison
|
|
require.ElementsMatch(t, [][]interface{}{
|
|
{10},
|
|
{20},
|
|
{30},
|
|
{40},
|
|
{50},
|
|
{60},
|
|
{70},
|
|
{80},
|
|
{90},
|
|
{100},
|
|
}, calls.Get())
|
|
})
|
|
|
|
t.Run("passes 8 seconds", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setInterval(window.stub, 4000)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor("08"))
|
|
require.Eventually(t, func() bool { return calls.Len() == 2 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("passes 1 minute", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setInterval(window.stub, 6000)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor("01:00"))
|
|
require.Eventually(t, func() bool { return calls.Len() == 10 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("passes 2 hours 34 minutes and 10 seconds", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setInterval(window.stub, 10000)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor("02:34:10"))
|
|
require.Eventually(t, func() bool { return calls.Len() == 925 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("throws for invalid format", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setInterval(window.stub, 10000)")
|
|
require.NoError(t, err)
|
|
require.Error(t, page.Clock().RunFor("12:02:34:10"))
|
|
require.Eventually(t, func() bool { return calls.Len() == 0 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("returns the current now value", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
require.NoError(t, page.Clock().SetSystemTime(0))
|
|
value := 200
|
|
require.NoError(t, page.Clock().RunFor(value))
|
|
ret, err := page.Evaluate("Date.now()")
|
|
require.NoError(t, err)
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
require.Equal(collect, value, ret)
|
|
}, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
}
|
|
|
|
func TestPageClockFastForward(t *testing.T) {
|
|
t.Run("ignores timers which wouldnt be run", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setTimeout(() => { window.stub('should not be logged'); }, 1000)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().FastForward(500))
|
|
require.Eventually(t, func() bool { return calls.Len() == 0 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("pushes back exeution time for skipped timers", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setTimeout(() => { window.stub(Date.now()); }, 1000)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().FastForward(2000))
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
require.Equal(collect, [][]any{
|
|
{1000 + 2000},
|
|
}, calls.Get())
|
|
}, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("supports string time arguments", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate("setTimeout(() => { window.stub(Date.now()); }, 100000)")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().FastForward("01:50"))
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
require.Equal(collect, [][]any{
|
|
{1000 + 110000},
|
|
}, calls.Get())
|
|
}, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
}
|
|
|
|
func TestPageClockStubTimers(t *testing.T) {
|
|
t.Run("sets initial timestamp", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
require.NoError(t, page.Clock().SetSystemTime(1400))
|
|
ret, err := page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1400, ret)
|
|
})
|
|
|
|
t.Run("replaces global setTimeout", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate(`setTimeout(window.stub, 1000)`)
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(1000))
|
|
require.Eventually(t, func() bool { return calls.Len() == 1 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("global fake setTimeout should return id", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
_ = pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
ret, err := page.Evaluate(`setTimeout(window.stub, 1000)`)
|
|
require.NoError(t, err)
|
|
require.IsType(t, int(1), ret)
|
|
})
|
|
|
|
t.Run("replaces global clearTimeout", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate(`const to = setTimeout(window.stub, 1000);
|
|
clearTimeout(to);`)
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(1000))
|
|
require.Eventually(t, func() bool { return calls.Len() == 0 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("replaces global setInterval", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate(`setInterval(window.stub, 500)`)
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(1000))
|
|
require.Eventually(t, func() bool { return calls.Len() == 2 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("replaces global clearInterval", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Evaluate(`const to = setInterval(window.stub, 500);
|
|
clearInterval(to);`)
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(1000))
|
|
require.Eventually(t, func() bool { return calls.Len() == 0 }, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("replaces global performance now", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
// Set up a signal to ensure the async function has started
|
|
_, err := page.Evaluate(`window.timeoutStarted = false`)
|
|
require.NoError(t, err)
|
|
|
|
chanRet := make(chan interface{}, 1)
|
|
go func() {
|
|
ret, err := page.Evaluate(`
|
|
async () => {
|
|
const prev = performance.now();
|
|
window.timeoutStarted = true;
|
|
await new Promise(f => setTimeout(f, 1000));
|
|
const next = performance.now();
|
|
return { prev, next };
|
|
}`)
|
|
if err == nil {
|
|
chanRet <- ret
|
|
} else {
|
|
close(chanRet)
|
|
}
|
|
}()
|
|
|
|
// Wait for the async function to start and set up the setTimeout
|
|
require.Eventually(t, func() bool {
|
|
started, _ := page.Evaluate(`window.timeoutStarted`)
|
|
return started == true
|
|
}, 5*time.Second, 50*time.Millisecond)
|
|
|
|
require.NoError(t, page.Clock().RunFor(1000))
|
|
ret := <-chanRet
|
|
require.Equal(t, map[string]interface{}{
|
|
"prev": 1000,
|
|
"next": 2000,
|
|
}, ret)
|
|
})
|
|
|
|
t.Run("fakes Date constructor", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
ret, err := page.Evaluate(`new Date().getTime()`)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1000, ret)
|
|
})
|
|
}
|
|
|
|
func TestPageClockStubTimersPerformance(t *testing.T) {
|
|
t.Run("replaces global performance time origin", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
beforePageClock(t, 1000, 2000)
|
|
|
|
// Set up a signal to ensure the async function has started
|
|
_, err := page.Evaluate(`window.timeoutStarted = false`)
|
|
require.NoError(t, err)
|
|
|
|
chanRet := make(chan interface{}, 1)
|
|
go func() {
|
|
ret, err := page.Evaluate(`
|
|
async () => {
|
|
const prev = performance.now();
|
|
window.timeoutStarted = true;
|
|
await new Promise(f => setTimeout(f, 1000));
|
|
const next = performance.now();
|
|
return { prev, next };
|
|
}`)
|
|
if err == nil {
|
|
chanRet <- ret
|
|
} else {
|
|
close(chanRet)
|
|
}
|
|
}()
|
|
|
|
// Wait for the async function to start and set up the setTimeout
|
|
require.Eventually(t, func() bool {
|
|
started, _ := page.Evaluate(`window.timeoutStarted`)
|
|
return started == true
|
|
}, 5*time.Second, 50*time.Millisecond)
|
|
|
|
require.NoError(t, page.Clock().RunFor(1000))
|
|
origin, err := page.Evaluate(`performance.timeOrigin`)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1000, origin)
|
|
ret := <-chanRet
|
|
require.Equal(t, map[string]interface{}{
|
|
"prev": 1000,
|
|
"next": 2000,
|
|
}, ret)
|
|
})
|
|
}
|
|
|
|
func TestPageClockPopup(t *testing.T) {
|
|
t.Run("should tick after popup", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
now := time.Date(2015, 9, 25, 0, 0, 0, 0, time.UTC)
|
|
beforePageClock(t, 0, now)
|
|
|
|
popupChan := make(chan playwright.Page, 1)
|
|
page.OnPopup(func(d playwright.Page) {
|
|
popupChan <- d
|
|
})
|
|
_, _ = page.Evaluate(`window.open('about:blank')`)
|
|
popup := <-popupChan
|
|
popupTime, _ := popup.Evaluate(`Date.now()`)
|
|
require.Equal(t, int(now.UnixMilli()), popupTime)
|
|
require.NoError(t, page.Clock().RunFor(1000))
|
|
popupTimeAfter, _ := popup.Evaluate(`Date.now()`)
|
|
require.Equal(t, int(now.UnixMilli())+1000, popupTimeAfter)
|
|
})
|
|
|
|
t.Run("should tick before popup", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
now := time.Date(2015, 9, 25, 0, 0, 0, 0, time.UTC)
|
|
beforePageClock(t, 0, now)
|
|
require.NoError(t, page.Clock().RunFor(1000))
|
|
|
|
popupChan := make(chan playwright.Page, 1)
|
|
page.OnPopup(func(d playwright.Page) {
|
|
popupChan <- d
|
|
})
|
|
_, _ = page.Evaluate(`window.open('about:blank')`)
|
|
popup := <-popupChan
|
|
popupTime, _ := popup.Evaluate(`Date.now()`)
|
|
require.Equal(t, int(now.UnixMilli())+1000, popupTime)
|
|
})
|
|
|
|
t.Run("should run time before popup", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
server.SetRoute("/popup.html", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Add("Content-Type", "text/html")
|
|
_, err := w.Write([]byte(`<script>window.time = Date.now()</script>`))
|
|
if err != nil {
|
|
log.Printf("could not write: %v", err)
|
|
}
|
|
})
|
|
|
|
_, err := page.Goto(server.EMPTY_PAGE)
|
|
require.NoError(t, err)
|
|
|
|
popupChan := make(chan playwright.Page, 1)
|
|
page.OnPopup(func(d playwright.Page) {
|
|
popupChan <- d
|
|
})
|
|
|
|
_, err = page.Evaluate(fmt.Sprintf(`window.open('%s/popup.html')`, server.PREFIX))
|
|
require.NoError(t, err)
|
|
popup := <-popupChan
|
|
popupTime, _ := popup.Evaluate(`window.time`)
|
|
require.GreaterOrEqual(t, popupTime, 2000)
|
|
})
|
|
|
|
t.Run("should not run time before popup on pause", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
server.SetRoute("/popup.html", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Add("Content-Type", "text/html")
|
|
_, err := w.Write([]byte(`<script>window.time = Date.now()</script>`))
|
|
if err != nil {
|
|
log.Printf("could not write: %v", err)
|
|
}
|
|
})
|
|
|
|
beforePageClock(t, 0, 1000)
|
|
|
|
_, err := page.Goto(server.EMPTY_PAGE)
|
|
require.NoError(t, err)
|
|
popupChan := make(chan playwright.Page, 1)
|
|
page.OnPopup(func(d playwright.Page) {
|
|
popupChan <- d
|
|
})
|
|
|
|
_, err = page.Evaluate(fmt.Sprintf(`window.open('%s/popup.html')`, server.PREFIX))
|
|
require.NoError(t, err)
|
|
popup := <-popupChan
|
|
popupTime, _ := popup.Evaluate(`window.time`)
|
|
require.Equal(t, 1000, popupTime)
|
|
})
|
|
}
|
|
|
|
func TestPageClockFixedTime(t *testing.T) {
|
|
t.Run("does not fake methods", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
require.NoError(t, page.Clock().SetFixedTime(0))
|
|
// Should not stall.
|
|
_, err := page.Evaluate(`new Promise(f => setTimeout(f, 1))`)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("allows setting time multiple times", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
require.NoError(t, page.Clock().SetFixedTime(100))
|
|
ret, err := page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 100, ret)
|
|
|
|
require.NoError(t, page.Clock().SetFixedTime(200))
|
|
ret, err = page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 200, ret)
|
|
})
|
|
|
|
t.Run("fixed times is not affected by clock manipulation", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
require.NoError(t, page.Clock().SetFixedTime(100))
|
|
ret, err := page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 100, ret)
|
|
|
|
require.NoError(t, page.Clock().FastForward(20))
|
|
ret, err = page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 100, ret)
|
|
})
|
|
|
|
t.Run("allows installing fake timers after setting time", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
|
|
require.NoError(t, page.Clock().SetFixedTime(100))
|
|
ret, err := page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 100, ret)
|
|
|
|
require.NoError(t, page.Clock().SetFixedTime(200))
|
|
_, err = page.Evaluate(`setTimeout(() => window.stub(Date.now()))`)
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(0))
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
require.Equal(collect, [][]interface{}{
|
|
{200},
|
|
}, calls.Get())
|
|
}, 1*time.Second, 10*time.Millisecond)
|
|
})
|
|
}
|
|
|
|
func TestPageClockWhileRunning(t *testing.T) {
|
|
t.Run("should progress time", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
require.NoError(t, page.Clock().Install(playwright.ClockInstallOptions{Time: 0}))
|
|
_, err := page.Goto("data:text/html,")
|
|
require.NoError(t, err)
|
|
//nolint:staticcheck
|
|
page.WaitForTimeout(1000)
|
|
now, err := page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.LessOrEqual(t, 1000, now)
|
|
require.LessOrEqual(t, now, 2000)
|
|
})
|
|
|
|
t.Run("should run for", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
require.NoError(t, page.Clock().Install(playwright.ClockInstallOptions{Time: 0}))
|
|
_, err := page.Goto("data:text/html,")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(10000))
|
|
now, err := page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.LessOrEqual(t, 10000, now)
|
|
require.LessOrEqual(t, now, 11000)
|
|
})
|
|
|
|
t.Run("should fast forward", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
require.NoError(t, page.Clock().Install(playwright.ClockInstallOptions{Time: 0}))
|
|
_, err := page.Goto("data:text/html,")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().FastForward(10000))
|
|
now, err := page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.LessOrEqual(t, 10000, now)
|
|
require.LessOrEqual(t, now, 11000)
|
|
})
|
|
|
|
t.Run("should pause", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
require.NoError(t, page.Clock().Install(playwright.ClockInstallOptions{Time: 0}))
|
|
_, err := page.Goto("data:text/html,")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().PauseAt(1000))
|
|
//nolint:staticcheck
|
|
page.WaitForTimeout(1000)
|
|
now, err := page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.LessOrEqual(t, 0, now)
|
|
require.LessOrEqual(t, now, 1000)
|
|
})
|
|
|
|
t.Run("should pause and fast forward", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
require.NoError(t, page.Clock().Install(playwright.ClockInstallOptions{Time: 0}))
|
|
_, err := page.Goto("data:text/html,")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().PauseAt(1000))
|
|
require.NoError(t, page.Clock().FastForward(1000))
|
|
now, err := page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2000, now)
|
|
})
|
|
|
|
t.Run("should set system time on pause", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
require.NoError(t, page.Clock().Install(playwright.ClockInstallOptions{Time: 0}))
|
|
_, err := page.Goto("data:text/html,")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().PauseAt(1000))
|
|
now, err := page.Evaluate(`Date.now()`)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1000, now)
|
|
})
|
|
}
|
|
|
|
func TestPageClockWhileOnPause(t *testing.T) {
|
|
t.Run("fast forward should not run nested immediate", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
|
|
require.NoError(t, page.Clock().Install(playwright.ClockInstallOptions{Time: 0}))
|
|
_, err := page.Goto("data:text/html,")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().PauseAt(1000))
|
|
_, err = page.Evaluate(`
|
|
setTimeout(() => {
|
|
window.stub('outer');
|
|
setTimeout(() => window.stub('inner'), 0);
|
|
}, 1000);`)
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().FastForward(1000))
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
require.Equal(collect, [][]any{{"outer"}}, calls.Get())
|
|
}, time.Second, 10*time.Millisecond)
|
|
require.NoError(t, page.Clock().FastForward(1))
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
require.Equal(collect, [][]any{{"outer"}, {"inner"}}, calls.Get())
|
|
}, time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("run for should not run nested immediate", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
|
|
require.NoError(t, page.Clock().Install(playwright.ClockInstallOptions{Time: 0}))
|
|
_, err := page.Goto("data:text/html,")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().PauseAt(1000))
|
|
_, err = page.Evaluate(`
|
|
setTimeout(() => {
|
|
window.stub('outer');
|
|
setTimeout(() => window.stub('inner'), 0);
|
|
}, 1000);`)
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(1000))
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
require.Equal(collect, [][]any{{"outer"}}, calls.Get())
|
|
}, time.Second, 10*time.Millisecond)
|
|
require.NoError(t, page.Clock().RunFor(1))
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
require.Equal(collect, [][]any{{"outer"}, {"inner"}}, calls.Get())
|
|
}, time.Second, 10*time.Millisecond)
|
|
})
|
|
|
|
t.Run("run for should not run nested immediate from microtask", func(t *testing.T) {
|
|
BeforeEach(t)
|
|
|
|
calls := pageClockFixture(t)
|
|
|
|
require.NoError(t, page.Clock().Install(playwright.ClockInstallOptions{Time: 0}))
|
|
_, err := page.Goto("data:text/html,")
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().PauseAt(1000))
|
|
_, err = page.Evaluate(`
|
|
setTimeout(() => {
|
|
window.stub('outer');
|
|
void Promise.resolve().then(() => setTimeout(() => window.stub('inner'), 0));
|
|
}, 1000);`)
|
|
require.NoError(t, err)
|
|
require.NoError(t, page.Clock().RunFor(1000))
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
require.Equal(collect, [][]any{{"outer"}}, calls.Get())
|
|
}, time.Second, 10*time.Millisecond)
|
|
require.NoError(t, page.Clock().RunFor(1))
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
require.Equal(collect, [][]any{{"outer"}, {"inner"}}, calls.Get())
|
|
}, time.Second, 10*time.Millisecond)
|
|
})
|
|
}
|