From 43186a8a52cd76a4049a8fe510c6ccff3db8ff24 Mon Sep 17 00:00:00 2001 From: canstand Date: Wed, 10 Jul 2024 03:42:12 +0000 Subject: [PATCH] deploy: 17169dc3a5ac0950f9c43759e0bbd4c77b4cbda5 --- assets/css/style.css.map | 8 +-- binding_call.go | 23 +++++++ js_handle.go | 13 ---- tests/binding_test.go | 23 ++++++- tests/browser_test.go | 2 +- tests/page_clock_test.go | 125 ++++++++++++++++++--------------------- tests/video_test.go | 10 +++- tests/websocket_test.go | 8 +-- 8 files changed, 118 insertions(+), 94 deletions(-) diff --git a/assets/css/style.css.map b/assets/css/style.css.map index e8e642a9..c295bbee 100644 --- a/assets/css/style.css.map +++ b/assets/css/style.css.map @@ -3,10 +3,10 @@ "file": "style.css", "sources": [ "style.scss", - "../../../../../tmp/jekyll-remote-theme-20240705-2874-2uoud4/_sass/jekyll-theme-cayman.scss", - "../../../../../tmp/jekyll-remote-theme-20240705-2874-2uoud4/_sass/normalize.scss", - "../../../../../tmp/jekyll-remote-theme-20240705-2874-2uoud4/_sass/rouge-github.scss", - "../../../../../tmp/jekyll-remote-theme-20240705-2874-2uoud4/_sass/variables.scss" + "../../../../../tmp/jekyll-remote-theme-20240710-2843-ldl7x5/_sass/jekyll-theme-cayman.scss", + "../../../../../tmp/jekyll-remote-theme-20240710-2843-ldl7x5/_sass/normalize.scss", + "../../../../../tmp/jekyll-remote-theme-20240710-2843-ldl7x5/_sass/rouge-github.scss", + "../../../../../tmp/jekyll-remote-theme-20240710-2843-ldl7x5/_sass/variables.scss" ], "sourcesContent": [ "@import 'jekyll-theme-cayman';\n", diff --git a/binding_call.go b/binding_call.go index 394eb2d1..a018557b 100644 --- a/binding_call.go +++ b/binding_call.go @@ -1,5 +1,12 @@ package playwright +import ( + "fmt" + "strings" + + "github.com/go-stack/stack" +) + type BindingCall interface { Call(f BindingCallFunction) } @@ -57,6 +64,22 @@ func (b *bindingCallImpl) Call(f BindingCallFunction) { } } +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) diff --git a/js_handle.go b/js_handle.go index 0ef668a2..7b667a5f 100644 --- a/js_handle.go +++ b/js_handle.go @@ -7,8 +7,6 @@ import ( "math/big" "net/url" "reflect" - "runtime/debug" - "strings" "time" ) @@ -308,17 +306,6 @@ func serializeArgument(arg interface{}) interface{} { } } -func serializeError(err error) map[string]interface{} { - stack := strings.Split(string(debug.Stack()), "\n") - return map[string]interface{}{ - "error": &Error{ - Name: "Playwright for Go Error", - Message: err.Error(), - Stack: strings.Join(stack[:len(stack)-5], "\n"), - }, - } -} - func newJSHandle(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *jsHandleImpl { bt := &jsHandleImpl{ preview: initializer["preview"].(string), diff --git a/tests/binding_test.go b/tests/binding_test.go index 89919fd4..eebfeb0e 100644 --- a/tests/binding_test.go +++ b/tests/binding_test.go @@ -78,7 +78,7 @@ func TestBrowserContextExposeBindingPanic(t *testing.T) { innerError := result.(map[string]interface{}) require.Equal(t, innerError["message"], "WOOF WOOF") stack := strings.Split(innerError["stack"].(string), "\n") - require.Contains(t, stack[len(stack)-1], "binding_test.go") + require.Contains(t, stack[3], "binding_test.go") } func TestBrowserContextExposeBindingHandleShouldWork(t *testing.T) { @@ -102,3 +102,24 @@ func TestBrowserContextExposeBindingHandleShouldWork(t *testing.T) { require.NoError(t, err) require.Equal(t, 42, res) } + +func TestPageExposeBindingPanic(t *testing.T) { + BeforeEach(t) + + err := page.ExposeBinding("woof", func(source *playwright.BindingSource, args ...interface{}) interface{} { + panic(errors.New("WOOF WOOF")) + }) + require.NoError(t, err) + result, err := page.Evaluate(`async () => { + try { + await window['woof'](); + } catch (e) { + return {message: e.message, stack: e.stack}; + } + }`) + require.NoError(t, err) + innerError := result.(map[string]interface{}) + require.Equal(t, innerError["message"], "WOOF WOOF") + stack := strings.Split(innerError["stack"].(string), "\n") + require.Contains(t, stack[3], "binding_test.go") +} diff --git a/tests/browser_test.go b/tests/browser_test.go index 100ac499..557d7f36 100644 --- a/tests/browser_test.go +++ b/tests/browser_test.go @@ -37,7 +37,7 @@ func TestBrowserNewContext(t *testing.T) { } func TestBrowserNewContextWithExtraHTTPHeaders(t *testing.T) { - context, page = newBrowserContextAndPage(t, playwright.BrowserNewContextOptions{ + BeforeEach(t, playwright.BrowserNewContextOptions{ ExtraHttpHeaders: map[string]string{"extra-http": "42"}, }) diff --git a/tests/page_clock_test.go b/tests/page_clock_test.go index 0c9d1ba4..417ce26c 100644 --- a/tests/page_clock_test.go +++ b/tests/page_clock_test.go @@ -8,8 +8,8 @@ import ( "time" "github.com/playwright-community/playwright-go" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "golang.org/x/exp/slices" ) func pageClockFixture(t *testing.T) *syncSlice[[]interface{}] { @@ -40,8 +40,7 @@ func TestPageClockRunFor(t *testing.T) { _, err := page.Evaluate("setTimeout(window.stub)") require.NoError(t, err) require.NoError(t, page.Clock().RunFor(0)) - time.Sleep(100 * time.Millisecond) // wait for binding call to resolve - require.Equal(t, 1, calls.Len()) + 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) { @@ -53,8 +52,7 @@ func TestPageClockRunFor(t *testing.T) { _, err := page.Evaluate("setTimeout(window.stub, 100)") require.NoError(t, err) require.NoError(t, page.Clock().RunFor(10)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 0, calls.Len()) + 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) { @@ -66,8 +64,7 @@ func TestPageClockRunFor(t *testing.T) { _, err := page.Evaluate("setTimeout(window.stub, 100)") require.NoError(t, err) require.NoError(t, page.Clock().RunFor(100)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 1, calls.Len()) + require.Eventually(t, func() bool { return calls.Len() == 1 }, 100*time.Millisecond, 10*time.Millisecond) }) t.Run("triggers simultaneous timers", func(t *testing.T) { @@ -79,8 +76,7 @@ func TestPageClockRunFor(t *testing.T) { _, err := page.Evaluate("setTimeout(window.stub, 100); setTimeout(window.stub, 100)") require.NoError(t, err) require.NoError(t, page.Clock().RunFor(100)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 2, calls.Len()) + 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) { @@ -93,8 +89,7 @@ func TestPageClockRunFor(t *testing.T) { "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)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 4, calls.Len()) + 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) { @@ -106,11 +101,9 @@ func TestPageClockRunFor(t *testing.T) { _, err := page.Evaluate("setTimeout(window.stub, 150)") require.NoError(t, err) require.NoError(t, page.Clock().RunFor(50)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 0, calls.Len()) + require.Eventually(t, func() bool { return calls.Len() == 0 }, 100*time.Millisecond, 10*time.Millisecond) require.NoError(t, page.Clock().RunFor(100)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 1, calls.Len()) + 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) { @@ -122,8 +115,7 @@ func TestPageClockRunFor(t *testing.T) { _, err := page.Evaluate("setTimeout(() => { throw new Error(); }, 100); setTimeout(window.stub, 120)") require.NoError(t, err) require.Error(t, page.Clock().RunFor(120)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 1, calls.Len()) + 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) { @@ -136,13 +128,9 @@ func TestPageClockRunFor(t *testing.T) { _, err := page.Evaluate("setInterval(() => { window.stub(new Date().getTime()); }, 10)") require.NoError(t, err) require.NoError(t, page.Clock().RunFor(100)) - time.Sleep(100 * time.Millisecond) + 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 - data := calls.Get() - slices.SortFunc(data, func(a, b []interface{}) int { - return a[0].(int) - b[0].(int) - }) - require.Equal(t, [][]interface{}{ + require.ElementsMatch(t, [][]interface{}{ {10}, {20}, {30}, @@ -153,7 +141,7 @@ func TestPageClockRunFor(t *testing.T) { {80}, {90}, {100}, - }, data) + }, calls.Get()) }) t.Run("passes 8 seconds", func(t *testing.T) { @@ -165,8 +153,7 @@ func TestPageClockRunFor(t *testing.T) { _, err := page.Evaluate("setInterval(window.stub, 4000)") require.NoError(t, err) require.NoError(t, page.Clock().RunFor("08")) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 2, calls.Len()) + require.Eventually(t, func() bool { return calls.Len() == 2 }, 1*time.Second, 10*time.Millisecond) }) t.Run("passes 1 minute", func(t *testing.T) { @@ -178,8 +165,7 @@ func TestPageClockRunFor(t *testing.T) { _, err := page.Evaluate("setInterval(window.stub, 6000)") require.NoError(t, err) require.NoError(t, page.Clock().RunFor("01:00")) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 10, calls.Len()) + 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) { @@ -191,8 +177,7 @@ func TestPageClockRunFor(t *testing.T) { _, err := page.Evaluate("setInterval(window.stub, 10000)") require.NoError(t, err) require.NoError(t, page.Clock().RunFor("02:34:10")) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 925, calls.Len()) + 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) { @@ -204,8 +189,7 @@ func TestPageClockRunFor(t *testing.T) { _, err := page.Evaluate("setInterval(window.stub, 10000)") require.NoError(t, err) require.Error(t, page.Clock().RunFor("12:02:34:10")) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 0, calls.Len()) + 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) { @@ -218,8 +202,9 @@ func TestPageClockRunFor(t *testing.T) { require.NoError(t, page.Clock().RunFor(value)) ret, err := page.Evaluate("Date.now()") require.NoError(t, err) - time.Sleep(100 * time.Millisecond) - require.Equal(t, value, ret) + require.EventuallyWithT(t, func(collect *assert.CollectT) { + require.Equal(collect, value, ret) + }, 1*time.Second, 10*time.Millisecond) }) } @@ -233,8 +218,7 @@ func TestPageClockFastForward(t *testing.T) { _, err := page.Evaluate("setTimeout(() => { window.stub('should not be logged'); }, 1000)") require.NoError(t, err) require.NoError(t, page.Clock().FastForward(500)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 0, calls.Len()) + 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) { @@ -246,10 +230,11 @@ func TestPageClockFastForward(t *testing.T) { _, err := page.Evaluate("setTimeout(() => { window.stub(Date.now()); }, 1000)") require.NoError(t, err) require.NoError(t, page.Clock().FastForward(2000)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, [][]any{ - {1000 + 2000}, - }, calls.Get()) + 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) { @@ -261,10 +246,11 @@ func TestPageClockFastForward(t *testing.T) { _, err := page.Evaluate("setTimeout(() => { window.stub(Date.now()); }, 100000)") require.NoError(t, err) require.NoError(t, page.Clock().FastForward("01:50")) - time.Sleep(100 * time.Millisecond) - require.Equal(t, [][]any{ - {1000 + 110000}, - }, calls.Get()) + require.EventuallyWithT(t, func(collect *assert.CollectT) { + require.Equal(collect, [][]any{ + {1000 + 110000}, + }, calls.Get()) + }, 1*time.Second, 10*time.Millisecond) }) } @@ -289,8 +275,7 @@ func TestPageClockStubTimers(t *testing.T) { _, err := page.Evaluate(`setTimeout(window.stub, 1000)`) require.NoError(t, err) require.NoError(t, page.Clock().RunFor(1000)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 1, calls.Len()) + 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) { @@ -314,8 +299,7 @@ func TestPageClockStubTimers(t *testing.T) { clearTimeout(to);`) require.NoError(t, err) require.NoError(t, page.Clock().RunFor(1000)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 0, calls.Len()) + require.Eventually(t, func() bool { return calls.Len() == 0 }, 1*time.Second, 10*time.Millisecond) }) t.Run("replaces global setInterval", func(t *testing.T) { @@ -327,8 +311,7 @@ func TestPageClockStubTimers(t *testing.T) { _, err := page.Evaluate(`setInterval(window.stub, 500)`) require.NoError(t, err) require.NoError(t, page.Clock().RunFor(1000)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 2, calls.Len()) + require.Eventually(t, func() bool { return calls.Len() == 2 }, 1*time.Second, 10*time.Millisecond) }) t.Run("replaces global clearInterval", func(t *testing.T) { @@ -341,8 +324,7 @@ func TestPageClockStubTimers(t *testing.T) { clearInterval(to);`) require.NoError(t, err) require.NoError(t, page.Clock().RunFor(1000)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, 0, calls.Len()) + 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) { @@ -560,10 +542,11 @@ func TestPageClockFixedTime(t *testing.T) { _, err = page.Evaluate(`setTimeout(() => window.stub(Date.now()))`) require.NoError(t, err) require.NoError(t, page.Clock().RunFor(0)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, [][]interface{}{ - {200}, - }, calls.Get()) + require.EventuallyWithT(t, func(collect *assert.CollectT) { + require.Equal(collect, [][]interface{}{ + {200}, + }, calls.Get()) + }, 1*time.Second, 10*time.Millisecond) }) } @@ -667,11 +650,13 @@ func TestPageClockWhileOnPause(t *testing.T) { }, 1000);`) require.NoError(t, err) require.NoError(t, page.Clock().FastForward(1000)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, [][]any{{"outer"}}, calls.Get()) + 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)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, [][]any{{"outer"}, {"inner"}}, calls.Get()) + 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) { @@ -690,11 +675,13 @@ func TestPageClockWhileOnPause(t *testing.T) { }, 1000);`) require.NoError(t, err) require.NoError(t, page.Clock().RunFor(1000)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, [][]any{{"outer"}}, calls.Get()) + 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)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, [][]any{{"outer"}, {"inner"}}, calls.Get()) + 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) { @@ -713,10 +700,12 @@ func TestPageClockWhileOnPause(t *testing.T) { }, 1000);`) require.NoError(t, err) require.NoError(t, page.Clock().RunFor(1000)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, [][]any{{"outer"}}, calls.Get()) + 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)) - time.Sleep(100 * time.Millisecond) - require.Equal(t, [][]any{{"outer"}, {"inner"}}, calls.Get()) + require.EventuallyWithT(t, func(collect *assert.CollectT) { + require.Equal(collect, [][]any{{"outer"}, {"inner"}}, calls.Get()) + }, time.Second, 10*time.Millisecond) }) } diff --git a/tests/video_test.go b/tests/video_test.go index 79925232..4556198d 100644 --- a/tests/video_test.go +++ b/tests/video_test.go @@ -4,9 +4,11 @@ import ( "os" "path/filepath" "testing" + "time" "github.com/h2non/filetype" "github.com/playwright-community/playwright-go" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -97,7 +99,9 @@ func TestVideo(t *testing.T) { path, err := video.Path() require.NoError(t, err) require.Contains(t, path, recordVideoDir) - require.FileExists(t, path) + require.EventuallyWithT(t, func(collect *assert.CollectT) { + require.FileExists(collect, path) + }, 1*time.Second, 10*time.Millisecond) }) t.Run("video should not exist when delete before close page", func(t *testing.T) { @@ -169,7 +173,9 @@ func TestVideo(t *testing.T) { //nolint:staticcheck page.WaitForTimeout(500) require.NoError(t, context.Close()) - require.FileExists(t, path) + require.EventuallyWithT(t, func(collect *assert.CollectT) { + require.FileExists(collect, path) + }, 1*time.Second, 10*time.Millisecond) }) t.Run("remote server should work with saveas", func(t *testing.T) { diff --git a/tests/websocket_test.go b/tests/websocket_test.go index b44f569a..83a99419 100644 --- a/tests/websocket_test.go +++ b/tests/websocket_test.go @@ -7,6 +7,7 @@ import ( "net" "net/http" "testing" + "time" goContext "context" @@ -119,11 +120,8 @@ func TestWebSocketShouldEmitCloseEvents(t *testing.T) { require.Equal(t, w.URL(), fmt.Sprintf("ws://localhost:%d/ws", wsServer.PORT)) }) require.Equal(t, ws.URL(), fmt.Sprintf("ws://localhost:%d/ws", wsServer.PORT)) - if !ws.IsClosed() { - _, err = ws.WaitForEvent("close") - require.NoError(t, err) - } - require.True(t, ws.IsClosed()) + + require.Eventually(t, func() bool { return ws.IsClosed() }, 1*time.Second, 10*time.Millisecond) } func TestWebSocketShouldEmitFrameEvents(t *testing.T) {