diff --git a/common/frame_manager.go b/common/frame_manager.go index 7f4673e9c..2c598b9bc 100644 --- a/common/frame_manager.go +++ b/common/frame_manager.go @@ -154,6 +154,10 @@ func (m *FrameManager) frameAttached(frameID cdp.FrameID, parentFrameID cdp.Fram } if parentFrame, ok := m.frames[parentFrameID]; ok { frame := NewFrame(m.ctx, m, parentFrame, frameID, m.logger) + + events := make(chan Event) + go m.listenFrameLifecycleEvents(frame, events) + // TODO: create a addFrame func m.frames[frameID] = frame parentFrame.addChildFrame(frame) @@ -165,6 +169,29 @@ func (m *FrameManager) frameAttached(frameID cdp.FrameID, parentFrameID cdp.Fram } } +func (m *FrameManager) listenFrameLifecycleEvents(f *Frame, events chan Event) { + f.on(m.ctx, []string{EventFrameAddLifecycle, EventFrameRemoveLifecycle}, events) + for { + select { + case <-m.ctx.Done(): + return + case ev := <-events: + lce, ok := ev.data.(LifecycleEvent) + if !ok { + continue + } + f.lifecycleEventsMu.Lock() + switch ev.data { + case EventFrameAddLifecycle: + f.lifecycleEvents[lce] = true + case EventFrameRemoveLifecycle: + delete(f.lifecycleEvents, lce) + } + f.lifecycleEventsMu.Unlock() + } + } +} + func (m *FrameManager) frameDetached(frameID cdp.FrameID) { m.logger.Debugf("FrameManager:frameDetached", "fmid:%d fid:%v", m.ID(), frameID) @@ -248,6 +275,9 @@ func (m *FrameManager) frameNavigated(frameID cdp.FrameID, parentFrameID cdp.Fra // Initial main frame navigation. frame = NewFrame(m.ctx, m, nil, frameID, m.logger) + events := make(chan Event) + go m.listenFrameLifecycleEvents(frame, events) + mainFrame = frame } else if isMainFrame && frame.ID() != string(frameID) { m.logger.Debugf("FrameManager:frameNavigated:MainFrame:delete", @@ -652,6 +682,13 @@ func (m *FrameManager) NavigateFrame(frame *Frame, url string, parsedOpts *Frame return resp, nil } +func (m *FrameManager) callForFrame(fid cdp.FrameID, call func(f *Frame)) { + m.framesMu.Lock() + defer m.framesMu.Unlock() + + call(m.frames[fid]) +} + // Page returns the page that this frame manager belongs to. func (m *FrameManager) Page() api.Page { if m.page != nil { diff --git a/common/frame_session.go b/common/frame_session.go index a88aec8f1..96fb39bb4 100644 --- a/common/frame_session.go +++ b/common/frame_session.go @@ -705,6 +705,11 @@ func (fs *FrameSession) onPageLifecycle(event *cdppage.EventLifecycleEvent) { fs.manager.frameLifecycleEvent(event.FrameID, LifecycleEventLoad) case "DOMContentLoaded": fs.manager.frameLifecycleEvent(event.FrameID, LifecycleEventDOMContentLoad) + case "networkIdle": + // TODO: maybe move this to the frame manager. + fs.manager.callForFrame(event.FrameID, func(f *Frame) { + f.emit(EventFrameAddLifecycle, LifecycleEventNetworkIdle) + }) } eventToMetric := map[string]*k6metrics.Metric{