Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit 03a6747

Browse files
authored
Merge pull request #623 from grafana/bug/622-waituntil-reload
Fix waituntil for page.reload
2 parents 32f3774 + e05b8d6 commit 03a6747

File tree

6 files changed

+380
-159
lines changed

6 files changed

+380
-159
lines changed

common/page.go

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -687,34 +687,54 @@ func (p *Page) Reload(opts goja.Value) api.Response {
687687
k6ext.Panic(p.ctx, "parsing reload options: %w", err)
688688
}
689689

690-
ch, evCancelFn := createWaitForEventHandler(p.ctx,
691-
p.frameManager.MainFrame(),
692-
[]string{EventFrameNavigation}, func(data any) bool {
690+
timeoutCtx, timeoutCancelFn := context.WithTimeout(p.ctx, parsedOpts.Timeout)
691+
defer timeoutCancelFn()
692+
693+
ch, evCancelFn := createWaitForEventHandler(
694+
timeoutCtx, p.frameManager.MainFrame(), []string{EventFrameNavigation},
695+
func(data any) bool {
693696
return true // Both successful and failed navigations are considered
694697
},
695698
)
696699
defer evCancelFn() // Remove event handler
697700

701+
lifecycleEvtCh, lifecycleEvtCancel := createWaitForEventPredicateHandler(
702+
timeoutCtx, p.frameManager.MainFrame(), []string{EventFrameAddLifecycle},
703+
func(data any) bool {
704+
if le, ok := data.(LifecycleEvent); ok {
705+
return le == parsedOpts.WaitUntil
706+
}
707+
return false
708+
})
709+
defer lifecycleEvtCancel()
710+
698711
action := cdppage.Reload()
699712
if err := action.Do(cdp.WithExecutor(p.ctx, p.session)); err != nil {
700713
k6ext.Panic(p.ctx, "reloading page: %w", err)
701714
}
702715

716+
wrapTimeoutError := func(err error) error {
717+
if errors.Is(err, context.DeadlineExceeded) {
718+
err = &k6ext.UserFriendlyError{
719+
Err: err,
720+
Timeout: parsedOpts.Timeout,
721+
}
722+
return fmt.Errorf("reloading page: %w", err)
723+
}
724+
p.logger.Debugf("Page:Reload", "timeoutCtx done: %v", err)
725+
726+
return err // TODO maybe wrap this as well?
727+
}
728+
703729
var event *NavigationEvent
704730
select {
705731
case <-p.ctx.Done():
706-
case <-time.After(parsedOpts.Timeout):
707-
k6ext.Panic(p.ctx, "%w", ErrTimedOut)
732+
case <-timeoutCtx.Done():
733+
k6ext.Panic(p.ctx, "%w", wrapTimeoutError(timeoutCtx.Err()))
708734
case data := <-ch:
709735
event = data.(*NavigationEvent)
710736
}
711737

712-
if p.frameManager.mainFrame.hasSubtreeLifecycleEventFired(parsedOpts.WaitUntil) {
713-
_, _ = waitForEvent(p.ctx, p.frameManager.MainFrame(), []string{EventFrameAddLifecycle}, func(data any) bool {
714-
return data.(LifecycleEvent) == parsedOpts.WaitUntil
715-
}, parsedOpts.Timeout)
716-
}
717-
718738
var resp *Response
719739
req := event.newDocument.request
720740
if req != nil {
@@ -723,6 +743,12 @@ func (p *Page) Reload(opts goja.Value) api.Response {
723743
req.responseMu.RUnlock()
724744
}
725745

746+
select {
747+
case <-lifecycleEvtCh:
748+
case <-timeoutCtx.Done():
749+
k6ext.Panic(p.ctx, "%w", wrapTimeoutError(timeoutCtx.Err()))
750+
}
751+
726752
applySlowMo(p.ctx)
727753

728754
return resp

tests/frame_test.go

Lines changed: 0 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
11
package tests
22

33
import (
4-
"fmt"
5-
"net/http"
6-
"sync"
74
"testing"
8-
"time"
95

10-
"github.com/stretchr/testify/assert"
116
"github.com/stretchr/testify/require"
12-
13-
"github.com/grafana/xk6-browser/api"
14-
"github.com/grafana/xk6-browser/common"
157
)
168

179
func TestFramePress(t *testing.T) {
@@ -29,130 +21,3 @@ func TestFramePress(t *testing.T) {
2921

3022
require.Equal(t, "AbC", f.InputValue("#text1", nil))
3123
}
32-
33-
func TestLifecycleNetworkIdle(t *testing.T) {
34-
t.Parallel()
35-
36-
assertHome := func(tb *testBrowser, p api.Page, check func()) {
37-
var resolved, rejected bool
38-
err := tb.await(func() error {
39-
opts := tb.toGojaValue(common.FrameGotoOptions{
40-
WaitUntil: common.LifecycleEventNetworkIdle,
41-
Timeout: 30 * time.Second,
42-
})
43-
tb.promise(p.Goto(tb.URL("/home"), opts)).then(
44-
func() {
45-
check()
46-
resolved = true
47-
},
48-
func() {
49-
rejected = true
50-
},
51-
)
52-
53-
return nil
54-
})
55-
require.NoError(t, err)
56-
57-
assert.True(t, resolved)
58-
assert.False(t, rejected)
59-
}
60-
61-
t.Run("doesn't timeout waiting for networkIdle", func(t *testing.T) {
62-
t.Parallel()
63-
64-
tb := newTestBrowser(t, withHTTPServer())
65-
p := tb.NewPage(nil)
66-
tb.withHandler("/home", func(w http.ResponseWriter, _ *http.Request) {
67-
fmt.Fprintf(w, `
68-
<html>
69-
<head></head>
70-
<body>
71-
<div id="serverMsg">Waiting...</div>
72-
<script src="/ping.js" async></script>
73-
</body>
74-
</html>
75-
`)
76-
})
77-
78-
tb.withHandler("/ping.js", func(w http.ResponseWriter, _ *http.Request) {
79-
fmt.Fprintf(w, `
80-
var serverMsgOutput = document.getElementById("serverMsg");
81-
serverMsgOutput.innerText = "ping.js loaded from server";
82-
`)
83-
})
84-
85-
assertHome(tb, p, func() {
86-
result := p.TextContent("#serverMsg", nil)
87-
assert.EqualValues(t, "ping.js loaded from server", result)
88-
})
89-
})
90-
91-
t.Run("doesn't unblock wait for networkIdle too early", func(t *testing.T) {
92-
t.Parallel()
93-
94-
tb := newTestBrowser(t, withFileServer())
95-
p := tb.NewPage(nil)
96-
tb.withHandler("/home", func(w http.ResponseWriter, r *http.Request) {
97-
http.Redirect(w, r, tb.staticURL("prolonged_network_idle.html"), http.StatusMovedPermanently)
98-
})
99-
100-
var counter int64
101-
ch := make(chan bool)
102-
tb.withHandler("/ping", func(w http.ResponseWriter, _ *http.Request) {
103-
<-ch
104-
105-
var counterMu sync.Mutex
106-
counterMu.Lock()
107-
defer counterMu.Unlock()
108-
109-
time.Sleep(time.Millisecond * 50)
110-
111-
counter++
112-
fmt.Fprintf(w, "pong %d", counter)
113-
})
114-
115-
tb.withHandler("/ping.js", func(w http.ResponseWriter, _ *http.Request) {
116-
fmt.Fprintf(w, `
117-
var serverMsgOutput = document.getElementById("serverMsg");
118-
serverMsgOutput.innerText = "ping.js loaded from server";
119-
`)
120-
close(ch)
121-
})
122-
123-
assertHome(tb, p, func() {
124-
result := p.TextContent("#prolongNetworkIdleLoad", nil)
125-
assert.EqualValues(t, "Waiting... pong 4 - for loop complete", result)
126-
127-
result = p.TextContent("#serverMsg", nil)
128-
assert.EqualValues(t, "ping.js loaded from server", result)
129-
})
130-
})
131-
132-
t.Run("doesn't unblock wait on networkIdle early when load and domcontentloaded complete at once", func(t *testing.T) {
133-
t.Parallel()
134-
135-
tb := newTestBrowser(t, withFileServer())
136-
p := tb.NewPage(nil)
137-
tb.withHandler("/home", func(w http.ResponseWriter, r *http.Request) {
138-
http.Redirect(w, r, tb.staticURL("prolonged_network_idle_10.html"), http.StatusMovedPermanently)
139-
})
140-
141-
var counterMu sync.Mutex
142-
var counter int64
143-
tb.withHandler("/ping", func(w http.ResponseWriter, _ *http.Request) {
144-
counterMu.Lock()
145-
defer counterMu.Unlock()
146-
147-
time.Sleep(time.Millisecond * 50)
148-
149-
counter++
150-
fmt.Fprintf(w, "pong %d", counter)
151-
})
152-
153-
assertHome(tb, p, func() {
154-
result := p.TextContent("#prolongNetworkIdleLoad", nil)
155-
assert.EqualValues(t, "Waiting... pong 10 - for loop complete", result)
156-
})
157-
})
158-
}

0 commit comments

Comments
 (0)