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

Commit d2a81df

Browse files
committed
Fix an issue with WaitForLoadState
This fixes an issue when we actually have to wait for a lifecycle event to be received from the browser since we've not received one yet and so we can't rely on the frame's state. The logic to wait for the lifecycle event has been copied from FrameManager.NavigateFrame.
1 parent 4c7bbf6 commit d2a81df

File tree

2 files changed

+66
-4
lines changed

2 files changed

+66
-4
lines changed

common/frame.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,6 +1818,7 @@ func (f *Frame) WaitForFunction(fn goja.Value, opts goja.Value, jsArgs ...goja.V
18181818
}
18191819

18201820
// WaitForLoadState waits for the given load state to be reached.
1821+
// This will unblock if that lifecycle event has already been received.
18211822
func (f *Frame) WaitForLoadState(state string, opts goja.Value) {
18221823
f.log.Debugf("Frame:WaitForLoadState", "fid:%s furl:%q state:%s", f.ID(), f.URL(), state)
18231824
defer f.log.Debugf("Frame:WaitForLoadState:return", "fid:%s furl:%q state:%s", f.ID(), f.URL(), state)
@@ -1828,21 +1829,33 @@ func (f *Frame) WaitForLoadState(state string, opts goja.Value) {
18281829
k6ext.Panic(f.ctx, "parsing waitForLoadState %q options: %v", state, err)
18291830
}
18301831

1832+
timeoutCtx, timeoutCancel := context.WithTimeout(f.ctx, parsedOpts.Timeout)
1833+
defer timeoutCancel()
1834+
18311835
waitUntil := LifecycleEventLoad
18321836
if state != "" {
18331837
if err = waitUntil.UnmarshalText([]byte(state)); err != nil {
18341838
k6ext.Panic(f.ctx, "waiting for load state: %v", err)
18351839
}
18361840
}
18371841

1842+
lifecycleEvtCh, lifecycleEvtCancel := createWaitForEventPredicateHandler(
1843+
timeoutCtx, f, []string{EventFrameAddLifecycle},
1844+
func(data any) bool {
1845+
if le, ok := data.(LifecycleEvent); ok {
1846+
return le == waitUntil
1847+
}
1848+
return false
1849+
})
1850+
defer lifecycleEvtCancel()
1851+
18381852
if f.hasLifecycleEventFired(waitUntil) {
18391853
return
18401854
}
18411855

1842-
_, err = waitForEvent(f.ctx, f, []string{EventFrameAddLifecycle}, func(data any) bool {
1843-
return data.(LifecycleEvent) == waitUntil
1844-
}, parsedOpts.Timeout)
1845-
if err != nil {
1856+
select {
1857+
case <-lifecycleEvtCh:
1858+
case <-timeoutCtx.Done():
18461859
k6ext.Panic(f.ctx, "waiting for load state %q: %v", state, err)
18471860
}
18481861
}

tests/lifecycle_wait_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,55 @@ func TestLifecycleWaitForLoadStateNetworkIdle(t *testing.T) {
174174
})
175175
}
176176

177+
func TestLifecycleWaitForLoadStateDOMContentLoadedThenNetworkIdle(t *testing.T) {
178+
// Test description
179+
//
180+
// 1. goto /home and wait for the domcontentloaded lifecycle event.
181+
// 2. use WaitForLoadState with networkidle to now wait for the
182+
// lifecycle event from the browser.
183+
//
184+
// Success criteria: We want to quickly move to calling WaitForLoadState
185+
// so that we block until a networkidle lifecycle
186+
// event is received from the browser.
187+
188+
t.Parallel()
189+
190+
tb := newTestBrowser(t, withFileServer())
191+
p := tb.NewPage(nil)
192+
tb.withHandler("/home", func(w http.ResponseWriter, r *http.Request) {
193+
http.Redirect(w, r, tb.staticURL("wait_for_nav_lifecycle.html"), http.StatusMovedPermanently)
194+
})
195+
196+
var counter int64
197+
var counterMu sync.Mutex
198+
tb.withHandler("/ping", func(w http.ResponseWriter, _ *http.Request) {
199+
counterMu.Lock()
200+
defer counterMu.Unlock()
201+
202+
time.Sleep(time.Millisecond * 100)
203+
204+
counter++
205+
fmt.Fprintf(w, "pong %d", counter)
206+
})
207+
208+
tb.withHandler("/ping.js", func(w http.ResponseWriter, _ *http.Request) {
209+
fmt.Fprintf(w, `
210+
var pingJSTextOutput = document.getElementById("pingJSText");
211+
pingJSTextOutput.innerText = "ping.js loaded from server";
212+
`)
213+
})
214+
215+
assertHome(t, tb, p, common.LifecycleEventDOMContentLoad, func() {
216+
p.WaitForLoadState(common.LifecycleEventNetworkIdle.String(), nil)
217+
218+
result := p.TextContent("#pingRequestText", nil)
219+
assert.EqualValues(t, "Waiting... pong 10 - for loop complete", result)
220+
221+
result = p.TextContent("#pingJSText", nil)
222+
assert.EqualValues(t, "ping.js loaded from server", result)
223+
})
224+
}
225+
177226
func TestLifecycleReloadLoad(t *testing.T) {
178227
t.Parallel()
179228

0 commit comments

Comments
 (0)