diff --git a/lib/puppeteer/execution_context.rb b/lib/puppeteer/execution_context.rb
index dcb8a737..9cdee1cf 100644
--- a/lib/puppeteer/execution_context.rb
+++ b/lib/puppeteer/execution_context.rb
@@ -2,7 +2,7 @@ class Puppeteer::ExecutionContext
include Puppeteer::IfPresent
using Puppeteer::DefineAsyncMethod
- EVALUATION_SCRIPT_URL = '__puppeteer_evaluation_script__'
+ EVALUATION_SCRIPT_URL = 'pprt://__puppeteer_evaluation_script__'
SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m
# @param client [Puppeteer::CDPSession]
diff --git a/lib/puppeteer/frame_manager.rb b/lib/puppeteer/frame_manager.rb
index 8257aba4..63edcbf5 100644
--- a/lib/puppeteer/frame_manager.rb
+++ b/lib/puppeteer/frame_manager.rb
@@ -71,11 +71,17 @@ def initialize(client, page, ignore_https_errors, timeout_settings)
private def init(cdp_session = nil)
client = cdp_session || @client
- results = await_all(
+ promises = [
client.async_send_message('Page.enable'),
client.async_send_message('Page.getFrameTree'),
- )
- frame_tree = results.last['frameTree']
+ cdp_session&.async_send_message('Target.setAutoAttach', {
+ autoAttach: true,
+ waitForDebuggerOnStart: false,
+ flatten: true,
+ }),
+ ].compact
+ results = await_all(*promises)
+ frame_tree = results[1]['frameTree']
handle_frame_tree(client, frame_tree)
await_all(
client.async_send_message('Page.setLifecycleEventsEnabled', enabled: true),
diff --git a/lib/puppeteer/page.rb b/lib/puppeteer/page.rb
index 68d1e83d..979bd89b 100644
--- a/lib/puppeteer/page.rb
+++ b/lib/puppeteer/page.rb
@@ -814,6 +814,10 @@ def wait_for_frame(url: nil, predicate: nil, timeout: nil)
predicate
end
+ frames.each do |frame|
+ return frame if frame_predicate.call(frame)
+ end
+
wait_for_frame_manager_event(
FrameManagerEmittedEvents::FrameAttached,
FrameManagerEmittedEvents::FrameNavigated,
diff --git a/spec/assets/inner-frame1.html b/spec/assets/inner-frame1.html
new file mode 100644
index 00000000..00f19ec1
--- /dev/null
+++ b/spec/assets/inner-frame1.html
@@ -0,0 +1,10 @@
+
diff --git a/spec/assets/inner-frame2.html b/spec/assets/inner-frame2.html
new file mode 100644
index 00000000..9a236cc4
--- /dev/null
+++ b/spec/assets/inner-frame2.html
@@ -0,0 +1 @@
+
diff --git a/spec/assets/main-frame.html b/spec/assets/main-frame.html
new file mode 100644
index 00000000..0c50feff
--- /dev/null
+++ b/spec/assets/main-frame.html
@@ -0,0 +1,10 @@
+
diff --git a/spec/integration/oopif_spec.rb b/spec/integration/oopif_spec.rb
index 0ef265d9..a32f4d4c 100644
--- a/spec/integration/oopif_spec.rb
+++ b/spec/integration/oopif_spec.rb
@@ -145,6 +145,16 @@ def oopifs(context)
expect(page.frames.size).to eq(2)
end
+ it 'should wait for inner OOPIFs' do
+ predicate = -> (frame) { frame.url&.end_with?('/inner-frame2.html') }
+ frame2 = page.wait_for_frame(predicate: predicate) do
+ page.goto("http://mainframe:#{server_port}/main-frame.html")
+ end
+ expect(oopifs(browser_context).size).to eq(2)
+ expect(page.frames.count { |frame| frame.oop_frame? }).to eq(2)
+ expect(frame2.evaluate('() => document.querySelectorAll("button").length')).to eq(1)
+ end
+
it 'should load oopif iframes with subresources and request interception' do
predicate = -> (frame) { frame.url&.end_with?('/oopif.html') }
frame_promise = page.async_wait_for_frame(predicate: predicate)
@@ -211,4 +221,12 @@ def oopifs(context)
expect(result_bounding_box.x).to be > 150 # padding + margin + border left
expect(result_bounding_box.y).to be > 150 # padding + margin + border top
end
+
+ it 'should resolve immediately if the frame already exists' do
+ page.goto(server_empty_page)
+ attach_frame(page, 'frame2', "#{server_cross_process_prefix}/empty.html")
+ predicate = ->(frame) { frame.url&.end_with?('/empty.html') }
+ frame = page.wait_for_frame(predicate: predicate)
+ expect(frame.url).to end_with("/empty.html")
+ end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 098e5bac..99c27f20 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -78,6 +78,7 @@ def firefox?
if example.metadata[:enable_site_per_process_flag]
args = launch_options[:args] || []
args << '--site-per-process'
+ args << '--host-rules=MAP * 127.0.0.1'
launch_options[:args] = args
end
@@ -150,7 +151,7 @@ def default_launch_options
config.include PuppeteerMethods, type: :puppeteer
test_with_sinatra = Module.new do
- attr_reader :server_prefix, :server_cross_process_prefix, :server_empty_page, :sinatra
+ attr_reader :server_port, :server_prefix, :server_cross_process_prefix, :server_empty_page, :sinatra
end
config.include(test_with_sinatra, sinatra: true)
config.around(sinatra: true) do |example|
@@ -163,8 +164,9 @@ def default_launch_options
sinatra_app.set(:quiet, true)
sinatra_app.set(:public_folder, File.join(__dir__, 'assets'))
sinatra_app.set(:logging, false)
- @server_prefix = "http://localhost:4567"
- @server_cross_process_prefix = "http://127.0.0.1:4567"
+ @server_port = 4567
+ @server_prefix = "http://localhost:#{@server_port}"
+ @server_cross_process_prefix = "http://127.0.0.1:#{@server_port}"
@server_empty_page = "#{@server_prefix}/empty.html"
sinatra_app.get('/_ping') { '_pong' }