Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c8613da
commit 0ef7951
Showing
3 changed files
with
359 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,334 @@ | ||
require 'spec_helper' | ||
|
||
RSpec.describe Puppeteer::Frame do | ||
context 'with empty page' do | ||
sinatra do | ||
get('/') do | ||
'<html><body>Hello puppeteer!</body></html>' | ||
end | ||
end | ||
|
||
describe '#execution_context' do | ||
include Utils::AttachFrame | ||
|
||
it 'should work' do | ||
page.goto('http://127.0.0.1:4567/') | ||
attach_frame(page, 'frame1', '/') | ||
expect(page.frames.size).to eq(2) | ||
|
||
frames = page.frames | ||
contexts = frames.map(&:execution_context) | ||
expect(contexts).to all(be_truthy) | ||
expect(contexts.first).not_to eq(contexts.last) | ||
expect(contexts.map(&:frame)).to eq(frames) | ||
|
||
contexts.each_with_index do |context, i| | ||
context.evaluate("() => (globalThis.a = #{i + 1})") | ||
end | ||
values = contexts.map { |context| context.evaluate('() => globalThis.a') } | ||
expect(values).to eq([1, 2]) | ||
end | ||
end | ||
|
||
describe '#evaluate_handle' do | ||
it 'should work' do | ||
page.goto('http://127.0.0.1:4567/') | ||
main_frame = page.main_frame | ||
window_handle = main_frame.evaluate_handle('() => window') | ||
expect(window_handle).to be_truthy | ||
end | ||
end | ||
|
||
describe '#evaluate' do | ||
include Utils::AttachFrame | ||
include Utils::DetachFrame | ||
|
||
it 'should throw for detached frames' do | ||
page.goto('http://127.0.0.1:4567/') | ||
frame1 = attach_frame(page, 'frame1', '/') | ||
detach_frame(page, 'frame1') | ||
expect { | ||
frame1.evaluate('() => 7 * 8') | ||
}.to raise_error(/Execution Context is not available in detached frame/) | ||
end | ||
end | ||
end | ||
|
||
context 'with nested frames page' do | ||
sinatra do | ||
get('/nested-frames.html') do | ||
<<~HTML | ||
<style> | ||
body { | ||
display: flex; | ||
} | ||
body iframe { | ||
flex-grow: 1; | ||
flex-shrink: 1; | ||
} | ||
::-webkit-scrollbar{ | ||
display: none; | ||
} | ||
html { /* for Firefox */ | ||
scrollbar-width: none; | ||
} | ||
</style> | ||
<script> | ||
async function attachFrame(frameId, url) { | ||
var frame = document.createElement('iframe'); | ||
frame.src = url; | ||
frame.id = frameId; | ||
document.body.appendChild(frame); | ||
await new Promise(x => frame.onload = x); | ||
return 'kazakh'; | ||
} | ||
</script> | ||
<iframe src='./two-frames.html' name='2frames'></iframe> | ||
<iframe src='./frame.html' name='aframe'></iframe> | ||
HTML | ||
end | ||
get('/two-frames.html') do | ||
<<~HTML | ||
<style> | ||
body { | ||
display: flex; | ||
flex-direction: column; | ||
} | ||
body iframe { | ||
flex-grow: 1; | ||
flex-shrink: 1; | ||
} | ||
html { /* for Firefox */ | ||
scrollbar-width: none; | ||
} | ||
</style> | ||
<iframe src='./frame.html' name='uno'></iframe> | ||
<iframe src='./frame.html' name='dos'></iframe> | ||
HTML | ||
end | ||
get('/frame.html') do | ||
<<~HTML | ||
<script src='./script.js' type='text/javascript'></script> | ||
<style> | ||
div { | ||
color: blue; | ||
line-height: 18px; | ||
} | ||
</style> | ||
<div>Hi, I'm frame</div> | ||
HTML | ||
end | ||
end | ||
|
||
include Utils::DumpFrames | ||
|
||
it 'should handle nested frames' do | ||
page.goto('http://127.0.0.1:4567/nested-frames.html') | ||
expect(dump_frames(page.main_frame)).to eq([ | ||
'http://127.0.0.1:<PORT>/nested-frames.html', | ||
' http://127.0.0.1:<PORT>/two-frames.html (2frames)', | ||
' http://127.0.0.1:<PORT>/frame.html (uno)', | ||
' http://127.0.0.1:<PORT>/frame.html (dos)', | ||
' http://127.0.0.1:<PORT>/frame.html (aframe)', | ||
]) | ||
end | ||
end | ||
|
||
# itFailsFirefox( | ||
# 'should send events when frames are manipulated dynamically', | ||
# async () => { | ||
# const { page, server } = getTestState(); | ||
|
||
# await page.goto(server.EMPTY_PAGE); | ||
# // validate frameattached events | ||
# const attachedFrames = []; | ||
# page.on('frameattached', (frame) => attachedFrames.push(frame)); | ||
# await utils.attachFrame(page, 'frame1', './assets/frame.html'); | ||
# expect(attachedFrames.length).toBe(1); | ||
# expect(attachedFrames[0].url()).toContain('/assets/frame.html'); | ||
|
||
# // validate framenavigated events | ||
# const navigatedFrames = []; | ||
# page.on('framenavigated', (frame) => navigatedFrames.push(frame)); | ||
# await utils.navigateFrame(page, 'frame1', './empty.html'); | ||
# expect(navigatedFrames.length).toBe(1); | ||
# expect(navigatedFrames[0].url()).toBe(server.EMPTY_PAGE); | ||
|
||
# // validate framedetached events | ||
# const detachedFrames = []; | ||
# page.on('framedetached', (frame) => detachedFrames.push(frame)); | ||
# await utils.detachFrame(page, 'frame1'); | ||
# expect(detachedFrames.length).toBe(1); | ||
# expect(detachedFrames[0].isDetached()).toBe(true); | ||
# } | ||
# ); | ||
# itFailsFirefox( | ||
# 'should send "framenavigated" when navigating on anchor URLs', | ||
# async () => { | ||
# const { page, server } = getTestState(); | ||
|
||
# await page.goto(server.EMPTY_PAGE); | ||
# await Promise.all([ | ||
# page.goto(server.EMPTY_PAGE + '#foo'), | ||
# utils.waitEvent(page, 'framenavigated'), | ||
# ]); | ||
# expect(page.url()).toBe(server.EMPTY_PAGE + '#foo'); | ||
# } | ||
# ); | ||
# it('should persist mainFrame on cross-process navigation', async () => { | ||
# const { page, server } = getTestState(); | ||
|
||
# await page.goto(server.EMPTY_PAGE); | ||
# const mainFrame = page.mainFrame(); | ||
# await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html'); | ||
# expect(page.mainFrame() === mainFrame).toBeTruthy(); | ||
# }); | ||
# it('should not send attach/detach events for main frame', async () => { | ||
# const { page, server } = getTestState(); | ||
|
||
# let hasEvents = false; | ||
# page.on('frameattached', () => (hasEvents = true)); | ||
# page.on('framedetached', () => (hasEvents = true)); | ||
# await page.goto(server.EMPTY_PAGE); | ||
# expect(hasEvents).toBe(false); | ||
# }); | ||
# itFailsFirefox('should detach child frames on navigation', async () => { | ||
# const { page, server } = getTestState(); | ||
|
||
# let attachedFrames = []; | ||
# let detachedFrames = []; | ||
# let navigatedFrames = []; | ||
# page.on('frameattached', (frame) => attachedFrames.push(frame)); | ||
# page.on('framedetached', (frame) => detachedFrames.push(frame)); | ||
# page.on('framenavigated', (frame) => navigatedFrames.push(frame)); | ||
# await page.goto(server.PREFIX + '/frames/nested-frames.html'); | ||
# expect(attachedFrames.length).toBe(4); | ||
# expect(detachedFrames.length).toBe(0); | ||
# expect(navigatedFrames.length).toBe(5); | ||
|
||
# attachedFrames = []; | ||
# detachedFrames = []; | ||
# navigatedFrames = []; | ||
# await page.goto(server.EMPTY_PAGE); | ||
# expect(attachedFrames.length).toBe(0); | ||
# expect(detachedFrames.length).toBe(4); | ||
# expect(navigatedFrames.length).toBe(1); | ||
# }); | ||
# itFailsFirefox('should support framesets', async () => { | ||
# const { page, server } = getTestState(); | ||
|
||
# let attachedFrames = []; | ||
# let detachedFrames = []; | ||
# let navigatedFrames = []; | ||
# page.on('frameattached', (frame) => attachedFrames.push(frame)); | ||
# page.on('framedetached', (frame) => detachedFrames.push(frame)); | ||
# page.on('framenavigated', (frame) => navigatedFrames.push(frame)); | ||
# await page.goto(server.PREFIX + '/frames/frameset.html'); | ||
# expect(attachedFrames.length).toBe(4); | ||
# expect(detachedFrames.length).toBe(0); | ||
# expect(navigatedFrames.length).toBe(5); | ||
|
||
# attachedFrames = []; | ||
# detachedFrames = []; | ||
# navigatedFrames = []; | ||
# await page.goto(server.EMPTY_PAGE); | ||
# expect(attachedFrames.length).toBe(0); | ||
# expect(detachedFrames.length).toBe(4); | ||
# expect(navigatedFrames.length).toBe(1); | ||
# }); | ||
# itFailsFirefox('should report frame from-inside shadow DOM', async () => { | ||
# const { page, server } = getTestState(); | ||
|
||
# await page.goto(server.PREFIX + '/shadow.html'); | ||
# await page.evaluate(async (url: string) => { | ||
# const frame = document.createElement('iframe'); | ||
# frame.src = url; | ||
# document.body.shadowRoot.appendChild(frame); | ||
# await new Promise((x) => (frame.onload = x)); | ||
# }, server.EMPTY_PAGE); | ||
# expect(page.frames().length).toBe(2); | ||
# expect(page.frames()[1].url()).toBe(server.EMPTY_PAGE); | ||
# }); | ||
|
||
context 'with empty page' do | ||
include Utils::AttachFrame | ||
|
||
sinatra do | ||
get('/') do | ||
'<html><body>Hello puppeteer!</body></html>' | ||
end | ||
end | ||
|
||
before { page.goto('http://127.0.0.1:4567/') } | ||
|
||
it 'should report frame.name()' do | ||
attach_frame(page, 'theFrameId', '/') | ||
js = <<~JAVASCRIPT | ||
function (url) { | ||
const frame = document.createElement('iframe'); | ||
frame.name = 'theFrameName'; | ||
frame.src = url; | ||
document.body.appendChild(frame); | ||
return new Promise((x) => (frame.onload = x)); | ||
} | ||
JAVASCRIPT | ||
page.evaluate(js, '/') | ||
expect(page.frames.map(&:name)).to eq(['', 'theFrameId', 'theFrameName']) | ||
end | ||
|
||
it 'should report frame.parent()' do | ||
attach_frame(page, 'frame1', '/') | ||
attach_frame(page, 'frame2', '/') | ||
expect(page.frames.map(&:parent_frame)).to eq([nil, page.main_frame, page.main_frame]) | ||
end | ||
|
||
it 'should report different frame instance when frame re-attaches' do | ||
frame1 = attach_frame(page, 'frame1', '/') | ||
js = <<~JAVASCRIPT | ||
() => { | ||
globalThis.frame = document.querySelector('#frame1'); | ||
globalThis.frame.remove(); | ||
} | ||
JAVASCRIPT | ||
page.evaluate(js) | ||
expect(frame1).to be_detached | ||
|
||
frame2 = await_all( | ||
resolvable_future { |f| page.once('frameattached') { |frame| f.fulfill(frame) }}, | ||
page.async_evaluate('() => document.body.appendChild(globalThis.frame)'), | ||
).first | ||
expect(frame2).not_to be_detached | ||
expect(frame1).not_to eq(frame2) | ||
end | ||
end | ||
|
||
context 'with one-frame-url-fragment page' do | ||
sinatra do | ||
get('/one-frame-url-fragment.html') do | ||
"<iframe src='./frame.html?param=value#fragment'></iframe>" | ||
end | ||
get('/frame.html') do | ||
<<~HTML | ||
<link rel='stylesheet' href='./style.css'> | ||
<script src='./script.js' type='text/javascript'></script> | ||
<style> | ||
div { | ||
line-height: 18px; | ||
} | ||
</style> | ||
<div>Hi, I'm frame</div> | ||
HTML | ||
end | ||
end | ||
|
||
it 'should support url fragment' do | ||
page.goto('http://127.0.0.1:4567/one-frame-url-fragment.html') | ||
|
||
expect(page.frames.size).to eq(2) | ||
expect(page.frames.last.url).to eq('http://127.0.0.1:4567/frame.html?param=value#fragment') | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters