Skip to content

Commit 7ef14d6

Browse files
committed
Fix idling? blocking on lazy iframes that Chrome never loads
Chrome fires Page.frameAttached for every iframe in the DOM, but only fires Page.frameStoppedLoading for frames it actually loads. For a loading="lazy" iframe parked outside the viewport (e.g. inside a closed <details>), Chrome never starts loading it, so it never transitions to :started_loading or :stopped_loading. It stays at state nil indefinitely. The previous idling? required every frame to be :stopped_loading, which meant any lazy iframe blocked idle detection for the full browser timeout (default 5s). Treat freshly-attached frames (state nil) as idle too — they haven't started loading, so there's nothing to wait for. Fixes #583
1 parent 25367b5 commit 7ef14d6

4 files changed

Lines changed: 27 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
### Fixed
88
- Full-page screenshots no longer resize the window, preventing focus steal on macOS [#580]
9+
- `idling?` no longer blocks for the full browser timeout when a page contains a `loading="lazy"` iframe that Chrome never starts loading [#583]
910

1011
### Removed
1112

lib/ferrum/page/frames.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ def subscribe_execution_contexts_cleared
191191
end
192192

193193
def idling?
194-
@frames.values.all? { |f| f.state == :stopped_loading }
194+
@frames.values.all? { |f| f.state.nil? || f.state == :stopped_loading }
195195
end
196196
end
197197
end

spec/frame_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,17 @@
125125
end
126126
end
127127

128+
context "with loading=lazy iframe" do
129+
it "does not block idle detection when Chrome never loads the iframe" do
130+
started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
131+
page.go_to("/lazy_iframe")
132+
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at
133+
134+
expect(elapsed).to be < 2.0
135+
expect(page.body).to include("Lazy iframe")
136+
end
137+
end
138+
128139
it "supports clicking in a frame", skip: true do
129140
page.go_to
130141
page.execute <<-JS

spec/support/views/lazy_iframe.erb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Lazy iframe</title>
5+
</head>
6+
<body>
7+
<h1>Lazy iframe</h1>
8+
9+
<details>
10+
<summary>Hidden until expanded</summary>
11+
<iframe loading="lazy" src="/slow" name="lazy_frame"></iframe>
12+
</details>
13+
</body>
14+
</html>

0 commit comments

Comments
 (0)