spec/arachni/browser_spec.rb in arachni-1.3.2 vs spec/arachni/browser_spec.rb in arachni-1.4
- old
+ new
@@ -12,11 +12,12 @@
end
after( :each ) do
Arachni::Options.reset
Arachni::Framework.reset
- @browser.shutdown
+ @browser.shutdown if @browser
+ described_class.asset_domains.clear
clear_hit_count
end
let(:subject) { @browser }
let(:ua) { Arachni::Options.http.user_agent }
@@ -25,11 +26,11 @@
transitions.map do |t|
element, event = t.first.to_a
options = {}
if element == :page && event == :load
- options.merge!( url: @browser.watir.url, cookies: {} )
+ options.merge!( url: @browser.dom_url, cookies: {} )
end
if element.is_a? Hash
element = described_class::ElementLocator.new( element )
end
@@ -58,10 +59,50 @@
pages_should_have_form_with_input( pages, 'ajax-token' )
pages_should_have_form_with_input( pages, 'by-ajax' )
end
+ context 'when the browser dies' do
+ it 'kills the lifeline too' do
+ Arachni::Processes::Manager.kill subject.browser_pid
+ expect(Arachni::Processes::Manager.alive?(subject.lifeline_pid)).to be_falsey
+ end
+ end
+
+ context 'when the lifeline dies' do
+ it 'kills the browser too' do
+ Arachni::Processes::Manager.kill subject.lifeline_pid
+ expect(Arachni::Processes::Manager.alive?(subject.browser_pid)).to be_falsey
+ end
+ end
+
+ describe '#alive?' do
+ context 'when the lifeline is alive' do
+ it 'returns true' do
+ expect(Arachni::Processes::Manager.alive?(subject.lifeline_pid)).to be_truthy
+ expect(subject).to be_alive
+ end
+ end
+
+ context 'when the browser is dead' do
+ it 'returns false' do
+ Arachni::Processes::Manager.kill subject.browser_pid
+
+ expect(subject).to_not be_alive
+ end
+ end
+
+ context 'when the lifeline is dead' do
+ it 'returns false' do
+ Arachni::Processes::Manager << subject.browser_pid
+ Arachni::Processes::Manager.kill subject.lifeline_pid
+
+ expect(subject).to_not be_alive
+ end
+ end
+ end
+
describe '.has_executable?' do
context 'when there is no executable browser' do
it 'returns false' do
allow(Selenium::WebDriver::PhantomJS).to receive(:path){ false }
expect(described_class.has_executable?).to be_falsey
@@ -83,16 +124,16 @@
expect(described_class.executable).to eq(stub)
end
end
describe '#initialize' do
- describe :concurrency do
+ describe ':concurrency' do
it 'sets the HTTP request concurrency'
end
- describe :ignore_scope do
- context true do
+ describe ':ignore_scope' do
+ context 'true' do
it 'ignores scope restrictions' do
@browser.shutdown
@browser = described_class.new( ignore_scope: true )
@@ -101,11 +142,11 @@
subject.load @url + '/ajax_sleep'
expect(subject.to_page).to be_truthy
end
end
- context false do
+ context 'false' do
it 'enforces scope restrictions' do
@browser.shutdown
@browser = described_class.new( ignore_scope: false )
@@ -114,11 +155,11 @@
subject.load @url + '/ajax_sleep'
expect(subject.to_page.code).to eq(0)
end
end
- context :default do
+ context ':default' do
it 'enforces scope restrictions' do
@browser.shutdown
@browser = described_class.new( ignore_scope: false )
@@ -128,39 +169,49 @@
expect(subject.to_page.code).to eq(0)
end
end
end
- describe :width do
+ describe ':width' do
it 'sets the window width' do
@browser.shutdown
width = 100
@browser = described_class.new( width: width )
+
+ subject.load @url
+
expect(subject.javascript.run('return window.innerWidth')).to eq(width)
end
it 'defaults to 1600' do
+ subject.load @url
+
expect(subject.javascript.run('return window.innerWidth')).to eq(1600)
end
end
- describe :height do
+ describe ':height' do
it 'sets the window height' do
@browser.shutdown
height = 100
@browser = described_class.new( height: height )
+
+ subject.load @url
+
expect(subject.javascript.run('return window.innerHeight')).to eq(height)
end
it 'defaults to 1200' do
+ subject.load @url
+
expect(subject.javascript.run('return window.innerHeight')).to eq(1200)
end
end
- describe :store_pages do
+ describe ':store_pages' do
describe 'default' do
it 'stores snapshot pages' do
@browser.shutdown
@browser = described_class.new
expect(@browser.load( @url + '/explore' ).flush_pages).to be_any
@@ -172,11 +223,11 @@
@browser.start_capture
expect(@browser.load( @url + '/with-ajax' ).flush_pages).to be_any
end
end
- describe true do
+ describe 'true' do
it 'stores snapshot pages' do
@browser.shutdown
@browser = described_class.new( store_pages: true )
expect(@browser.load( @url + '/explore' ).trigger_events.flush_pages).to be_any
end
@@ -187,11 +238,11 @@
@browser.start_capture
expect(@browser.load( @url + '/with-ajax' ).flush_pages).to be_any
end
end
- describe false do
+ describe 'false' do
it 'stores snapshot pages' do
@browser.shutdown
@browser = described_class.new( store_pages: false )
expect(@browser.load( @url + '/explore' ).trigger_events.flush_pages).to be_empty
end
@@ -290,11 +341,11 @@
expect(captured).to eq(received)
end
context '#store_pages?' do
- context true do
+ context 'true' do
subject { @browser.shutdown; @browser = described_class.new( store_pages: true )}
it 'stores it in #page_snapshots' do
captured = subject.capture_snapshot
@@ -305,11 +356,11 @@
expect(captured.size).to eq(1)
expect(captured.first).to eq(subject.to_page)
end
end
- context false do
+ context 'false' do
subject { @browser.shutdown; @browser = described_class.new( store_pages: false ) }
it 'does not store it' do
subject.capture_snapshot
@@ -363,20 +414,20 @@
expect(sinks.size).to eq(2)
end
end
context '#store_pages?' do
- context true do
+ context 'true' do
subject { @browser.shutdown; @browser = described_class.new( store_pages: true )}
it 'stores it in #page_snapshots_with_sinks' do
subject.capture_snapshot
expect(subject.page_snapshots_with_sinks).to be_any
end
end
- context false do
+ context 'false' do
subject { @browser.shutdown; @browser = described_class.new( store_pages: false )}
it 'does not store it in #page_snapshots_with_sinks' do
subject.capture_snapshot
expect(subject.page_snapshots_with_sinks).to be_empty
@@ -397,28 +448,25 @@
expect(captured.first.dom.transitions).to include transition
end
end
context 'when there are multiple windows open' do
- before :each do
- subject.load( ajax_url, take_snapshot: false )
- end
it 'captures snapshots from all windows' do
- subject.javascript.run( 'window.open()' )
- subject.watir.windows.last.use
- subject.load sink_url, take_snapshot: false
+ url = "#{@url}open-new-window"
+ subject.load url, take_snapshot: false
+
expect(subject.capture_snapshot.map(&:url).sort).to eq(
- [ajax_url, sink_url].sort
+ [url, "#{@url}with-ajax"].sort
)
end
end
context 'when an error occurs' do
it 'ignores it' do
- allow(subject.watir).to receive(:windows) { raise }
+ allow(subject).to receive(:to_page) { raise }
expect(subject.capture_snapshot( blah: :stuff )).to be_empty
end
end
end
@@ -494,12 +542,12 @@
calls = []
@browser.on_fire_event do |element, event|
calls << [element.opening_tag, event]
end
- @browser.fire_event @browser.watir.div( id: 'my-div' ), :click
- @browser.fire_event @browser.watir.div( id: 'my-div' ), :mouseover
+ @browser.fire_event @browser.selenium.find_element( id: 'my-div' ), :click
+ @browser.fire_event @browser.selenium.find_element( id: 'my-div' ), :mouseover
expect(calls).to eq([
[ "<div id=\"my-div\" onclick=\"addForm();\">", :click ],
[ "<div id=\"my-div\" onclick=\"addForm();\">", :mouseover ]
])
@@ -588,11 +636,11 @@
{
{
tag_name: 'a',
attributes: {
'onmouseover' => 'writeButton();',
- 'href' => 'javascript:level3();'
+ 'href' => '#'
}
} => :mouseover
}
],
[
@@ -601,15 +649,15 @@
{ "#{@url}level2" => :request },
{
{
tag_name: 'a',
attributes: {
- 'onmouseover' => 'writeButton();',
'href' => 'javascript:level3();'
}
} => :click
},
+ { "#{@url}level4" => :request },
{ "#{@url}level4" => :request }
],
[
{ :page => :load },
{ "#{@url}deep-dom" => :request },
@@ -617,11 +665,11 @@
{
{
tag_name: 'a',
attributes: {
'onmouseover' => 'writeButton();',
- 'href' => 'javascript:level3();'
+ 'href' => '#'
}
} => :mouseover
},
{
{
@@ -638,16 +686,16 @@
{ "#{@url}level2" => :request },
{
{
tag_name: 'a',
attributes: {
- 'onmouseover' => 'writeButton();',
'href' => 'javascript:level3();'
}
} => :click
},
{ "#{@url}level4" => :request },
+ { "#{@url}level4" => :request },
{
{
tag_name: 'div',
attributes: {
'onclick' => 'level6();',
@@ -678,11 +726,11 @@
{
{
tag_name: 'a',
attributes: {
'onmouseover' => 'writeButton();',
- 'href' => 'javascript:level3();'
+ 'href' => '#'
}
} => :mouseover
}
],
[
@@ -691,15 +739,15 @@
{ "#{@url}level2" => :request },
{
{
tag_name: 'a',
attributes: {
- 'onmouseover' => 'writeButton();',
'href' => 'javascript:level3();'
}
} => :click
},
+ { "#{@url}level4" => :request },
{ "#{@url}level4" => :request }
]
].map { |transitions| transitions_from_array( transitions ) })
end
end
@@ -989,19 +1037,66 @@
context "when the response takes more than #{Arachni::OptionGroups::HTTP}#request_timeout" do
it 'returns nil'
end
- context 'when the resource is out-of-scope' do
+ context 'when the resource is out of scope' do
it 'returns nil' do
Arachni::Options.url = @url
- @browser.load 'http://google.com/'
+ @browser.load @url
+
+ subject.javascript.run( 'window.location = "http://google.com/";' )
+ sleep 1
+
expect(@browser.response).to be_nil
end
end
end
+ describe '#state' do
+ it 'returns a Page::DOM with enough info to reproduce the current state' do
+ @browser.load "#{web_server_url_for( :taint_tracer )}/debug" <<
+ "?input=#{@browser.javascript.log_execution_flow_sink_stub(1)}"
+
+ dom = subject.to_page.dom
+ state = subject.state
+
+ expect(state.page).to be_nil
+ expect(state.url).to eq dom.url
+ expect(state.digest).to eq dom.digest
+ expect(state.transitions).to eq dom.transitions
+ expect(state.skip_states).to eq dom.skip_states
+ expect(state.data_flow_sinks).to be_empty
+ expect(state.execution_flow_sinks).to be_empty
+ end
+
+ context 'when the URL is about:blank' do
+ it 'returns nil' do
+ Arachni::Options.url = @url
+ subject.load @url
+
+ subject.javascript.run( 'window.location = "about:blank";' )
+ sleep 1
+
+ expect(subject.state).to be_nil
+ end
+ end
+
+ context 'when the resource is out-of-scope' do
+ it 'returns an empty page' do
+ Arachni::Options.url = @url
+ subject.load @url
+
+ subject.javascript.run( 'window.location = "http://google.com/";' )
+ sleep 1
+
+ expect(subject.state).to be_nil
+ end
+ end
+
+ end
+
describe '#to_page' do
it "converts the working window to an #{Arachni::Page}" do
ua = Arachni::Options.http.user_agent
@browser.load( @url )
@@ -1015,14 +1110,16 @@
end
it "assigns the proper #{Arachni::Page::DOM}#digest" do
@browser.load( @url )
expect(@browser.to_page.dom.instance_variable_get(:@digest)).to eq(
- '<HTML><HEAD><SCRIPT src=http://javascript.browser.arachni/' <<
- 'taint_tracer.js><SCRIPT src=http://javascript.' <<
- 'browser.arachni/dom_monitor.js><SCRIPT><TITLE><BODY><' <<
- 'DIV><SCRIPT type=text/javascript><SCRIPT type=text/javascript>'
+ '<HTML><HEAD><SCRIPT src=http://' <<
+ 'javascript.browser.arachni/polyfills.js><SCRIPT src=http://' <<
+ 'javascript.browser.arachni/' <<
+ 'taint_tracer.js><SCRIPT src=http://javascript.' <<
+ 'browser.arachni/dom_monitor.js><SCRIPT><TITLE><BODY><' <<
+ 'DIV><SCRIPT type=text/javascript><SCRIPT type=text/javascript>'
)
end
it "assigns the proper #{Arachni::Page::DOM}#transitions" do
@browser.load( @url )
@@ -1076,11 +1173,11 @@
end
context 'when the page has' do
context "#{Arachni::Element::UIForm} elements" do
context "and #{Arachni::OptionGroups::Audit}#inputs is" do
- context true do
+ context 'true' do
before do
Arachni::Options.audit.elements :ui_forms
end
context '<input> button' do
@@ -1124,11 +1221,11 @@
end
end
end
end
- context false do
+ context 'false' do
before do
Arachni::Options.audit.skip_elements :ui_forms
end
it 'ignores them' do
@@ -1139,11 +1236,11 @@
end
end
context "#{Arachni::Element::UIInput} elements" do
context "and #{Arachni::OptionGroups::Audit}#inputs is" do
- context true do
+ context 'true' do
before do
Arachni::Options.audit.elements :ui_inputs
end
context '<input>' do
@@ -1187,11 +1284,11 @@
end
end
end
end
- context false do
+ context 'false' do
before do
Arachni::Options.audit.skip_elements :ui_inputs
end
it 'ignores them' do
@@ -1202,11 +1299,11 @@
end
end
context "#{Arachni::Element::Form::DOM} elements" do
context "and #{Arachni::OptionGroups::Audit}#forms is" do
- context true do
+ context 'true' do
before do
Arachni::Options.audit.elements :forms
end
context 'and JavaScript action' do
@@ -1229,11 +1326,11 @@
expect(@browser.to_page.forms.first.skip_dom).to be_truthy
end
end
end
- context false do
+ context 'false' do
before do
Arachni::Options.audit.skip_elements :forms
end
it 'does not set #skip_dom' do
@@ -1246,11 +1343,11 @@
context "#{Arachni::Element::Cookie::DOM} elements" do
let(:cookies) { @browser.to_page.cookies }
context "and #{Arachni::OptionGroups::Audit}#cookies is" do
- context true do
+ context 'true' do
before do
Arachni::Options.audit.elements :cookies
@browser.load "#{@url}/#{page}"
@browser.load "#{@url}/#{page}"
@@ -1259,45 +1356,61 @@
context 'with DOM processing of cookie' do
context 'names' do
let(:page) { 'dom-cookies-names' }
it 'does not set #skip_dom' do
- expect(cookies.find { |c| c.name == 'my-cookie' }.skip_dom).to be_nil
- expect(cookies.find { |c| c.name == 'my-cookie2' }.skip_dom).to be_nil
+ expect(cookies.find { |c| c.name == 'js_cookie1' }.skip_dom).to be_nil
+ expect(cookies.find { |c| c.name == 'js_cookie2' }.skip_dom).to be_nil
end
+
+ it 'does not track HTTP-only cookies' do
+ expect(cookies.find { |c| c.name == 'http_only_cookie' }.skip_dom).to be true
+ end
+
+ it 'does not track cookies for other paths' do
+ expect(cookies.find { |c| c.name == 'other_path' }.skip_dom).to be true
+ end
end
context 'values' do
let(:page) { 'dom-cookies-values' }
it 'does not set #skip_dom' do
- expect(cookies.find { |c| c.name == 'my-cookie' }.skip_dom).to be_nil
- expect(cookies.find { |c| c.name == 'my-cookie2' }.skip_dom).to be_nil
+ expect(cookies.find { |c| c.name == 'js_cookie1' }.skip_dom).to be_nil
+ expect(cookies.find { |c| c.name == 'js_cookie2' }.skip_dom).to be_nil
end
+
+ it 'does not track HTTP-only cookies' do
+ expect(cookies.find { |c| c.name == 'http_only_cookie' }.skip_dom).to be true
+ end
+
+ it 'does not track cookies for other paths' do
+ expect(cookies.find { |c| c.name == 'other_path' }.skip_dom).to be true
+ end
end
end
context 'without DOM processing of cookie' do
context 'names' do
let(:page) { 'dom-cookies-names' }
it 'does not set #skip_dom' do
- expect(cookies.find { |c| c.name == 'my-cookie3' }.skip_dom).to be_truthy
+ expect(cookies.find { |c| c.name == 'js_cookie3' }.skip_dom).to be_truthy
end
end
context 'values' do
let(:page) { 'dom-cookies-values' }
it 'does not set #skip_dom' do
- expect(cookies.find { |c| c.name == 'my-cookie3' }.skip_dom).to be_truthy
+ expect(cookies.find { |c| c.name == 'js_cookie3' }.skip_dom).to be_truthy
end
end
end
end
- context false do
+ context 'false' do
before do
Arachni::Options.audit.skip_elements :cookies
@browser.load "#{@url}/#{page}"
@browser.load "#{@url}/#{page}"
@@ -1317,17 +1430,21 @@
end
context 'when the resource is out-of-scope' do
it 'returns an empty page' do
Arachni::Options.url = @url
- subject.load 'http://google.com/'
+ subject.load @url
+
+ subject.javascript.run( 'window.location = "http://google.com/";' )
+ sleep 1
+
page = subject.to_page
expect(page.code).to eq(0)
- expect(page.url).to eq(subject.url)
+ expect(page.url).to eq('http://google.com/')
expect(page.body).to be_empty
- expect(page.dom.url).to eq(subject.watir.url)
+ expect(page.dom.url).to eq('http://google.com/')
end
end
end
describe '#fire_event' do
@@ -1335,41 +1452,80 @@
before(:each) do
@browser.load url
end
it 'fires the given event' do
- @browser.fire_event @browser.watir.div( id: 'my-div' ), :click
+ @browser.fire_event @browser.selenium.find_element( id: 'my-div' ), :click
pages_should_have_form_with_input [@browser.to_page], 'by-ajax'
end
it 'accepts events without the "on" prefix' do
pages_should_not_have_form_with_input [@browser.to_page], 'by-ajax'
- @browser.fire_event @browser.watir.div( id: 'my-div' ), :onclick
+ @browser.fire_event @browser.selenium.find_element( id: 'my-div' ), :onclick
pages_should_have_form_with_input [@browser.to_page], 'by-ajax'
- @browser.fire_event @browser.watir.div( id: 'my-div' ), :click
+ @browser.fire_event @browser.selenium.find_element( id: 'my-div' ), :click
pages_should_have_form_with_input [@browser.to_page], 'by-ajax'
end
it 'returns a playable transition' do
- transition = @browser.fire_event @browser.watir.div( id: 'my-div' ), :click
+ transition = @browser.fire_event @browser.selenium.find_element( id: 'my-div' ), :click
pages_should_have_form_with_input [@browser.to_page], 'by-ajax'
@browser.load( url ).start_capture
pages_should_not_have_form_with_input [@browser.to_page], 'by-ajax'
transition.play @browser
pages_should_have_form_with_input [@browser.to_page], 'by-ajax'
end
- context 'when the element is not visible' do
- it 'returns nil' do
- element = @browser.watir.div( id: 'my-div' )
+ context 'when new timers are introduced' do
+ let(:url) { "#{@url}/trigger_events/with_new_timers/3000" }
- allow(element).to receive(:visible?) { false }
+ it 'waits for them' do
+ @browser.fire_event @browser.selenium.find_element( id: 'my-div' ), :click
+ pages_should_have_form_with_input [@browser.to_page], 'by-ajax'
+ end
+ context 'when a new timer exceeds Options.http.request_timeout' do
+ let(:url) { "#{@url}/trigger_events/with_new_timers/#{Arachni::Options.http.request_timeout + 5000}" }
+
+ it 'waits for Options.http.request_timeout' do
+ t = Time.now
+
+ @browser.fire_event @browser.selenium.find_element( id: 'my-div' ), :click
+ pages_should_not_have_form_with_input [@browser.to_page], 'by-ajax'
+
+ expect(Time.now - t).to be <= Arachni::Options.http.request_timeout
+ end
+ end
+ end
+
+ context 'when cookies are set' do
+ let(:url) { @url + '/each_element_with_events/set-cookie' }
+
+ it 'sets them globally' do
+ expect(Arachni::HTTP::Client.cookies).to be_empty
+
+ @browser.fire_event described_class::ElementLocator.new(
+ tag_name: :button,
+ attributes: {
+ onclick: 'setCookie()'
+ }
+ ), :click
+
+ cookie = Arachni::HTTP::Client.cookies.first
+ expect(cookie.name).to eq 'cookie_name'
+ expect(cookie.value).to eq 'cookie value'
+ end
+ end
+
+ context 'when the element is not visible' do
+ it 'returns nil' do
+ @browser.goto "#{url}/invisible-div"
+ element = @browser.selenium.find_element( id: 'invisible-div' )
expect(@browser.fire_event( element, :click )).to be_nil
end
end
context "when the element is an #{described_class::ElementLocator}" do
@@ -1380,61 +1536,49 @@
attributes: { 'id' => 'blahblah' }
)
allow(element).to receive(:locate){ raise Selenium::WebDriver::Error::WebDriverError }
expect(@browser.fire_event( element, :click )).to be_nil
-
- allow(element).to receive(:locate){ raise Watir::Exception::Error }
- expect(@browser.fire_event( element, :click )).to be_nil
end
end
end
- context 'when the element never appears' do
- it 'returns nil' do
- element = @browser.watir.div( id: 'my-div' )
-
- allow(element).to receive(:exists?) { false }
-
- expect(@browser.fire_event( element, :click )).to be_nil
- end
- end
-
context 'when the trigger fails with' do
- let(:element) { @browser.watir.div( id: 'my-div' ) }
+ let(:element) { @browser.selenium.find_element( id: 'my-div' ) }
- context Selenium::WebDriver::Error::WebDriverError do
+ context 'Selenium::WebDriver::Error::WebDriverError' do
it 'returns nil' do
- allow(element).to receive(:fire_event){ raise Selenium::WebDriver::Error::WebDriverError }
- expect(@browser.fire_event( element, :click )).to be_nil
- end
- end
+ allow(@browser).to receive(:wait_for_pending_requests) do
+ raise Selenium::WebDriver::Error::WebDriverError
+ end
- context Watir::Exception::Error do
- it 'returns nil' do
- allow(element).to receive(:fire_event){ raise Watir::Exception::Error }
expect(@browser.fire_event( element, :click )).to be_nil
end
end
end
context 'form' do
- context :submit do
+ context ':submit' do
let(:url) { "#{@url}/fire_event/form/onsubmit" }
context 'when option' do
- describe :inputs do
+ describe ':inputs' do
+
+ def element
+ @browser.selenium.find_element(:tag_name, :form)
+ end
+
context 'is given' do
let(:inputs) do
{
- name: "The Dude",
+ name: 'The Dude',
email: 'the.dude@abides.com'
}
end
before(:each) do
- @browser.fire_event @browser.watir.form, :submit, inputs: inputs
+ @browser.fire_event element, :submit, inputs: inputs
end
it 'fills in its inputs with the given values' do
expect(@browser.watir.div( id: 'container-name' ).text).to eq(
inputs[:name]
@@ -1445,11 +1589,11 @@
end
it 'returns a playable transition' do
@browser.load url
- transition = @browser.fire_event @browser.watir.form, :submit, inputs: inputs
+ transition = @browser.fire_event element, :submit, inputs: inputs
@browser.load url
expect(@browser.watir.div( id: 'container-name' ).text).to be_empty
expect(@browser.watir.div( id: 'container-email' ).text).to be_empty
@@ -1511,11 +1655,11 @@
expect(@browser.watir.div( id: 'container-email' ).text).to be_empty
end
it 'returns a playable transition' do
@browser.load url
- transition = @browser.fire_event @browser.watir.form, :submit, inputs: inputs
+ transition = @browser.fire_event element, :submit, inputs: inputs
@browser.load url
expect(@browser.watir.div( id: 'container-name' ).text).to be_empty
expect(@browser.watir.div( id: 'container-email' ).text).to be_empty
@@ -1539,11 +1683,11 @@
expect(@browser.watir.div( id: 'container-email' ).text).to be_empty
end
it 'returns a playable transition' do
@browser.load url
- transition = @browser.fire_event @browser.watir.form, :submit, inputs: inputs
+ transition = @browser.fire_event element, :submit, inputs: inputs
@browser.load url
expect(@browser.watir.div( id: 'container-name' ).text).to be_empty
expect(@browser.watir.div( id: 'container-email' ).text).to be_empty
@@ -1568,11 +1712,11 @@
end
context 'is not given' do
it 'fills in its inputs with sample values' do
@browser.load url
- @browser.fire_event @browser.watir.form, :submit
+ @browser.fire_event element, :submit
expect(@browser.watir.div( id: 'container-name' ).text).to eq(
Arachni::Options.input.value_for_name( 'name' )
)
expect(@browser.watir.div( id: 'container-email' ).text).to eq(
@@ -1580,11 +1724,11 @@
)
end
it 'returns a playable transition' do
@browser.load url
- transition = @browser.fire_event @browser.watir.form, :submit
+ transition = @browser.fire_event element, :submit
@browser.load url
expect(@browser.watir.div( id: 'container-name' ).text).to be_empty
expect(@browser.watir.div( id: 'container-email' ).text).to be_empty
@@ -1601,11 +1745,11 @@
context 'and has disabled inputs' do
let(:url) { "#{@url}/fire_event/form/disabled_inputs" }
it 'is skips those inputs' do
- @browser.fire_event @browser.watir.form, :submit
+ @browser.fire_event element, :submit
expect(@browser.watir.div( id: 'container-name' ).text).to eq(
Arachni::Options.input.value_for_name( 'name' )
)
expect(@browser.watir.div( id: 'container-email' ).text).to be_empty
@@ -1615,25 +1759,29 @@
end
end
end
context 'image button' do
- context :click do
+ context ':click' do
before( :each ) { @browser.start_capture }
let(:url) { "#{@url}fire_event/form/image-input" }
+ def element
+ @browser.selenium.find_element( :xpath, '//input[@type="image"]')
+ end
+
it 'submits the form with x, y coordinates' do
@browser.load( url )
- @browser.fire_event @browser.watir.input( type: 'image'), :click
+ @browser.fire_event element, :click
pages_should_have_form_with_input @browser.captured_pages, 'myImageButton.x'
pages_should_have_form_with_input @browser.captured_pages, 'myImageButton.y'
end
it 'returns a playable transition' do
@browser.load( url )
- transition = @browser.fire_event @browser.watir.input( type: 'image'), :click
+ transition = @browser.fire_event element, :click
captured_pages = @browser.flush_pages
pages_should_have_form_with_input captured_pages, 'myImageButton.x'
pages_should_have_form_with_input captured_pages, 'myImageButton.y'
@browser.shutdown
@@ -1656,33 +1804,37 @@
calculate_expectation = proc do |string|
[:onkeypress, :onkeydown].include?( event ) ?
string[0...-1] : string
end
- context event do
+ context event.to_s do
let( :url ) { "#{@url}/fire_event/input/#{event}" }
context 'when option' do
- describe :inputs do
+ describe ':inputs' do
+ def element
+ @browser.selenium.find_element(:tag_name, :input)
+ end
+
context 'is given' do
let(:value) do
'The Dude'
end
before(:each) do
- @browser.fire_event @browser.watir.input, event, value: value
+ @browser.fire_event element, event, value: value
end
it 'fills in its inputs with the given values' do
expect(@browser.watir.div( id: 'container' ).text).to eq(
calculate_expectation.call( value )
)
end
it 'returns a playable transition' do
@browser.load url
- transition = @browser.fire_event @browser.watir.input, event, value: value
+ transition = @browser.fire_event element, event, value: value
@browser.load url
expect(@browser.watir.div( id: 'container' ).text).to be_empty
transition.play @browser
@@ -1700,11 +1852,11 @@
expect(@browser.watir.div( id: 'container' ).text).to be_empty
end
it 'returns a playable transition' do
@browser.load url
- transition = @browser.fire_event @browser.watir.input, event, value: value
+ transition = @browser.fire_event element, event, value: value
@browser.load url
expect(@browser.watir.div( id: 'container' ).text).to be_empty
transition.play @browser
@@ -1713,20 +1865,20 @@
end
end
context 'is not given' do
it 'fills in a sample value' do
- @browser.fire_event @browser.watir.input, event
+ @browser.fire_event element, event
expect(@browser.watir.div( id: 'container' ).text).to eq(
calculate_expectation.call( Arachni::Options.input.value_for_name( 'name' ) )
)
end
it 'returns a playable transition' do
@browser.load url
- transition = @browser.fire_event @browser.watir.input, event
+ transition = @browser.fire_event element, event
@browser.load url
expect(@browser.watir.div( id: 'container' ).text).to be_empty
transition.play @browser
@@ -1740,10 +1892,48 @@
end
end
end
end
+ describe '#elements_with_events' do
+ before :each do
+ @browser.load url
+ end
+
+ let(:elements_with_events) do
+ elements_with_events = {}
+ @browser.each_element_with_events do |locator, events|
+ elements_with_events[locator] = events
+ end
+ elements_with_events
+ end
+
+ let(:url) { @url + '/trigger_events' }
+
+ it 'returns all elements with associated events' do
+ expect(subject.elements_with_events.to_s).to eq elements_with_events.to_s
+ end
+
+ it 'caches results' do
+ expect(subject).to receive(:each_element_with_events)
+ subject.elements_with_events
+
+ expect(subject).to_not receive(:each_element_with_events)
+ subject.elements_with_events
+ end
+
+ context 'when passed true' do
+ it 'clears the cache' do
+ expect(subject).to receive(:each_element_with_events)
+ subject.elements_with_events
+
+ expect(subject).to receive(:each_element_with_events)
+ subject.elements_with_events( true )
+ end
+ end
+ end
+
describe '#each_element_with_events' do
before :each do
@browser.load url
end
let(:elements_with_events) do
@@ -1760,23 +1950,23 @@
[
described_class::ElementLocator.new(
tag_name: 'body',
attributes: { 'onmouseover' => 'makePOST();' }
),
- [[:onmouseover, 'makePOST();']]
+ { onmouseover: ['makePOST();'] }
],
[
described_class::ElementLocator.new(
tag_name: 'div',
attributes: { 'id' => 'my-div', 'onclick' => 'addForm();' }
),
- [[:onclick, 'addForm();']]
+ { onclick: ['addForm();']}
]
])
end
- context :a do
+ context ':a' do
context 'and the href is not empty' do
context 'and it starts with javascript:' do
let(:url) { @url + '/each_element_with_events/a/href/javascript' }
it 'includes the :click event' do
@@ -1784,11 +1974,11 @@
[
described_class::ElementLocator.new(
tag_name: 'a',
attributes: { 'href' => 'javascript:doStuff()' }
),
- [[:click, 'javascript:doStuff()']]
+ {click: [ 'javascript:doStuff()']}
]
])
end
end
@@ -1808,12 +1998,12 @@
end
end
end
end
- context :form do
- context :input do
+ context ':form' do
+ context ':input' do
context 'of type "image"' do
let(:url) { @url + '/each_element_with_events/form/input/image' }
it 'includes the :click event' do
expect(elements_with_events).to eq([
@@ -1824,11 +2014,11 @@
'type' => 'image',
'name' => 'myImageButton',
'src' => '/__sinatra__/404.png'
}
),
- [[:click, 'image']]
+ {click: ['image']}
]
])
end
end
end
@@ -1844,28 +2034,28 @@
tag_name: 'form',
attributes: {
'action' => 'javascript:doStuff()'
}
),
- [[:submit, 'javascript:doStuff()']]
+ {submit: ['javascript:doStuff()']}
]
])
end
end
context 'and it does not start with javascript:' do
let(:url) { @url + '/each_element_with_events/form/action/regular' }
- it 'is ignored'do
+ it 'is ignored' do
expect(elements_with_events).to be_empty
end
end
context 'and is out of scope' do
let(:url) { @url + '/each_element_with_events/form/action/out-of-scope' }
- it 'is ignored'do
+ it 'is ignored' do
expect(elements_with_events).to be_empty
end
end
end
end
@@ -1874,11 +2064,11 @@
describe '#trigger_event' do
it 'triggers the given event on the given tag and captures snapshots' do
@browser.load( @url + '/trigger_events' ).start_capture
locators = []
- @browser.watir.elements.each do |element|
+ @browser.selenium.find_elements(:css, '*').each do |element|
begin
locators << described_class::ElementLocator.from_html( element.opening_tag )
rescue
end
end
@@ -1897,10 +2087,14 @@
pages_should_have_form_with_input @browser.captured_pages, 'ajax-token'
end
end
describe '#trigger_events' do
+ it 'returns self' do
+ expect(@browser.load( @url + '/explore' ).trigger_events).to eq(@browser)
+ end
+
it 'waits for AJAX requests to complete' do
@browser.load( @url + '/trigger_events-wait-for-ajax' ).start_capture.trigger_events
pages_should_have_form_with_input @browser.captured_pages, 'ajax-token'
pages_should_have_form_with_input @browser.page_snapshots, 'by-ajax'
@@ -1914,10 +2108,11 @@
pages_should_have_form_with_input @browser.captured_pages, 'post-name'
end
it 'assigns the proper page transitions' do
pages = @browser.load( @url + '/explore' ).trigger_events.page_snapshots
+
expect(pages.map(&:dom).map(&:transitions)).to eq([
[
{ :page => :load },
{ "#{@url}explore" => :request }
],
@@ -1931,11 +2126,12 @@
'id' => 'my-div',
'onclick' => 'addForm();'
}
} => :click
},
- { "#{@url}get-ajax?ajax-token=my-token" => :request }
+ { "#{@url}get-ajax?ajax-token=my-token" => :request },
+ { "#{@url}post-ajax" => :request }
],
[
{ :page => :load },
{ "#{@url}explore" => :request },
{
@@ -1945,10 +2141,12 @@
'href' => 'javascript:inHref();'
}
} => :click
},
{ "#{@url}href-ajax" => :request },
+ { "#{@url}post-ajax" => :request },
+ { "#{@url}href-ajax" => :request }
]
].map { |transitions| transitions_from_array( transitions ) })
end
it 'follows all javascript links' do
@@ -1973,14 +2171,10 @@
@browser.load( "#{@url}form-with-image-button" ).start_capture.trigger_events
pages_should_have_form_with_input @browser.captured_pages, 'myImageButton.x'
pages_should_have_form_with_input @browser.captured_pages, 'myImageButton.y'
end
end
-
- it 'returns self' do
- expect(@browser.load( @url + '/explore' ).trigger_events).to eq(@browser)
- end
end
describe '#source' do
it 'returns the evaluated HTML source' do
@browser.load @url
@@ -2188,11 +2382,11 @@
expect(@browser.watir.element( css: '#matchThis' ).tag_name).to eq('button')
end
it "waits a maximum of #{Arachni::OptionGroups::BrowserCluster}#job_timeout" do
- Arachni::Options.browser_cluster.job_timeout = 4
+ Arachni::Options.browser_cluster.job_timeout = 2
t = Time.now
@browser.goto( @url + '/wait_for_elements#stuff/here' )
expect(Time.now - t).to be < 5
@@ -2214,11 +2408,11 @@
end
end
end
context "#{Arachni::OptionGroups::BrowserCluster}#ignore_images" do
- context true do
+ context 'true' do
it 'does not load images' do
Arachni::Options.browser_cluster.ignore_images = true
@browser.shutdown
@browser = described_class.new( disk_cache: false )
@@ -2226,11 +2420,11 @@
expect(image_hit_count).to eq(0)
end
end
- context false do
+ context 'false' do
it 'loads images' do
Arachni::Options.browser_cluster.ignore_images = false
@browser.shutdown
@browser = described_class.new( disk_cache: false )
@@ -2264,45 +2458,35 @@
end
context "with #{Arachni::OptionGroups::Scope}#auto_redundant_paths has bee configured" do
it 'respects scope restrictions' do
Arachni::Options.scope.auto_redundant_paths = 0
- expect(@browser.load( @url + '/explore?test=1&test2=2' ).response.code).to eq(0)
+ expect(@browser.load( @url + '/explore?test=1&test2=2' ).response).to be_nil
end
end
- describe :cookies do
+ describe ':cookies' do
it 'loads the given cookies' do
cookie = { 'myname' => 'myvalue' }
@browser.goto @url, cookies: cookie
- expect(@browser.cookies.find { |c| c.name == cookie.keys.first }.inputs).to eq(cookie)
+ cookie_data = @browser.cookies.
+ find { |c| c.name == cookie.keys.first }.inputs
+
+ expect(cookie_data).to eq(cookie)
end
it 'includes them in the transition' do
cookie = { 'myname' => 'myvalue' }
transition = @browser.goto( @url, cookies: cookie )
expect(transition.options[:cookies]).to eq(cookie)
end
-
- context 'when auditing existing cookies' do
- it 'preserves the HttpOnly attribute' do
- @browser.goto( @url )
- expect(@browser.cookies.size).to eq(1)
-
- cookies = { @browser.cookies.first.name => 'updated' }
- @browser.goto( @url, cookies: cookies )
-
- @browser.cookies.first.value == 'updated'
- expect(@browser.cookies.first).to be_http_only
- end
- end
end
- describe :take_snapshot do
- describe true do
+ describe ':take_snapshot' do
+ describe 'true' do
it 'captures a snapshot of the loaded page' do
@browser.goto @url, take_snapshot: true
pages = @browser.page_snapshots
expect(pages.size).to eq(1)
@@ -2311,11 +2495,11 @@
{ @url => :request }
]))
end
end
- describe false do
+ describe 'false' do
it 'does not capture a snapshot of the loaded page' do
@browser.goto @url, take_snapshot: false
expect(@browser.page_snapshots).to be_empty
end
end
@@ -2332,19 +2516,19 @@
]))
end
end
end
- describe :update_transitions do
- describe true do
+ describe ':update_transitions' do
+ describe 'true' do
it 'pushes the page load to the transitions' do
t = @browser.goto( @url, update_transitions: true )
expect(@browser.to_page.dom.transitions).to include t
end
end
- describe false do
+ describe 'false' do
it 'does not push the page load to the transitions' do
t = @browser.goto( @url, update_transitions: false )
expect(@browser.to_page.dom.transitions).to be_empty
end
end
@@ -2361,21 +2545,30 @@
describe '#load' do
it 'returns self' do
expect(@browser.load( @url )).to eq(@browser)
end
- describe :cookies do
+ it 'updates the global cookie-jar' do
+ @browser.load @url
+
+ cookie = Arachni::HTTP::Client.cookies.find(&:http_only?)
+
+ expect(cookie.name).to eq('This name should be updated; and properly escaped')
+ expect(cookie.value).to eq('This value should be updated; and properly escaped')
+ end
+
+ describe ':cookies' do
it 'loads the given cookies' do
cookie = { 'myname' => 'myvalue' }
@browser.load @url, cookies: cookie
expect(@browser.cookies.find { |c| c.name == cookie.keys.first }.inputs).to eq(cookie)
end
end
- describe :take_snapshot do
- describe true do
+ describe ':take_snapshot' do
+ describe 'true' do
it 'captures a snapshot of the loaded page' do
@browser.load @url, take_snapshot: true
pages = @browser.page_snapshots
expect(pages.size).to eq(1)
@@ -2384,11 +2577,11 @@
{ @url => :request }
]))
end
end
- describe false do
+ describe 'false' do
it 'does not capture a snapshot of the loaded page' do
@browser.load @url, take_snapshot: false
expect(@browser.page_snapshots).to be_empty
end
end
@@ -2406,11 +2599,11 @@
end
end
end
context 'when given a' do
- describe String do
+ describe 'String' do
it 'treats it as a URL' do
expect(hit_count).to eq(0)
@browser.load @url
expect(@browser.source).to include( ua )
@@ -2418,11 +2611,11 @@
expect(hit_count).to eq(1)
end
end
- describe Arachni::HTTP::Response do
+ describe 'Arachni::HTTP::Response' do
it 'loads it' do
expect(hit_count).to eq(0)
@browser.load Arachni::HTTP::Client.get( @url, mode: :sync )
expect(@browser.source).to include( ua )
@@ -2430,38 +2623,93 @@
expect(hit_count).to eq(1)
end
end
- describe Arachni::Page do
+ describe 'Arachni::Page::DOM' do
it 'loads it' do
expect(hit_count).to eq(0)
- @browser.load Arachni::HTTP::Client.get( @url, mode: :sync ).to_page
+ page = Arachni::HTTP::Client.get( @url, mode: :sync ).to_page
+
+ expect(hit_count).to eq(1)
+
+ @browser.load page.dom
+
expect(@browser.source).to include( ua )
expect(@browser.preloads).not_to include( @url )
+ expect(hit_count).to eq(2)
+ end
+
+ it 'replays its #transitions' do
+ @browser.load "#{@url}play-transitions"
+ page = @browser.explore_and_flush.last
+ expect(page.body).to include ua
+
+ @browser.load page.dom
+ expect(@browser.source).to include ua
+
+ page.dom.transitions.clear
+ @browser.load page.dom
+ expect(@browser.source).not_to include ua
+ end
+
+ it 'loads its #skip_states' do
+ @browser.load( @url )
+ pages = @browser.load( @url + '/explore' ).trigger_events.
+ page_snapshots
+
+ page = pages.last
+ expect(page.dom.skip_states).to be_subset @browser.skip_states
+
+ token = @browser.generate_token
+
+ dpage = page.dup
+ dpage.dom.skip_states << token
+
+ @browser.load dpage.dom
+ expect(@browser.skip_states).to include token
+ end
+ end
+
+ describe 'Arachni::Page' do
+ it 'loads it' do
+ expect(hit_count).to eq(0)
+
+ page = Arachni::HTTP::Client.get( @url, mode: :sync ).to_page
+
expect(hit_count).to eq(1)
+
+ @browser.load page
+
+ expect(@browser.source).to include( ua )
+ expect(@browser.preloads).not_to include( @url )
+
+ expect(hit_count).to eq(2)
end
it 'uses its #cookie_jar' do
expect(@browser.cookies).to be_empty
+ cookie = Arachni::Cookie.new(
+ url: @url,
+ inputs: {
+ 'my-name' => 'my-value'
+ }
+ )
+
page = Arachni::Page.from_data(
url: @url,
- cookie_jar: [
- Arachni::Cookie.new(
- url: @url,
- inputs: {
- 'my-name' => 'my-value'
- }
- )
- ]
+ cookie_jar: [ cookie ]
)
+ expect(@browser.cookies).to_not include cookie
+
@browser.load( page )
- expect(@browser.cookies).to eq(page.cookie_jar)
+
+ expect(@browser.cookies).to include cookie
end
it 'replays its DOM#transitions' do
@browser.load "#{@url}play-transitions"
page = @browser.explore_and_flush.last
@@ -2489,11 +2737,10 @@
dpage.dom.skip_states << token
@browser.load dpage
expect(@browser.skip_states).to include token
end
-
end
describe 'other' do
it 'raises Arachni::Browser::Error::Load' do
expect { @browser.load [] }.to raise_error Arachni::Browser::Error::Load
@@ -2532,11 +2779,11 @@
@browser.load response.url
expect(@browser.source).to include( ua )
end
context 'when given a' do
- describe Arachni::HTTP::Response do
+ describe 'Arachni::HTTP::Response' do
it 'preloads it' do
@browser.preload Arachni::HTTP::Client.get( @url, mode: :sync )
clear_hit_count
expect(hit_count).to eq(0)
@@ -2547,11 +2794,11 @@
expect(hit_count).to eq(0)
end
end
- describe Arachni::Page do
+ describe 'Arachni::Page' do
it 'preloads it' do
@browser.preload Arachni::Page.from_url( @url )
clear_hit_count
expect(hit_count).to eq(0)
@@ -2603,11 +2850,11 @@
expect(@browser.source).to include( ua )
expect(@browser.cache).to include( response.url )
end
context 'when given a' do
- describe Arachni::HTTP::Response do
+ describe 'Arachni::HTTP::Response' do
it 'caches it' do
@browser.cache Arachni::HTTP::Client.get( @url, mode: :sync )
clear_hit_count
expect(hit_count).to eq(0)
@@ -2618,11 +2865,11 @@
expect(hit_count).to eq(0)
end
end
- describe Arachni::Page do
+ describe 'Arachni::Page' do
it 'caches it' do
@browser.cache Arachni::Page.from_url( @url )
clear_hit_count
expect(hit_count).to eq(0)
@@ -2793,33 +3040,88 @@
end
end
end
describe '#cookies' do
- it 'returns the browser cookies' do
+ it 'returns cookies visible via JavaScript' do
@browser.load @url
- expect(@browser.cookies.size).to eq(1)
+
cookie = @browser.cookies.first
+ expect(cookie.name).to eq 'cookie_name'
+ expect(cookie.value).to eq 'cookie value'
+ expect(cookie.raw_name).to eq 'cookie_name'
+ expect(cookie.raw_value).to eq '"cookie value"'
+ end
- expect(cookie).to be_kind_of Arachni::Cookie
- expect(cookie.name).to eq('This name should be updated; and properly escaped')
- expect(cookie.value).to eq('This value should be updated; and properly escaped')
+ it 'preserves expiration value' do
+ @browser.load "#{@url}/cookies/expires"
+
+ cookie = @browser.cookies.first
+ expect(cookie.name).to eq 'without_expiration'
+ expect(cookie.value).to eq 'stuff'
+ expect(cookie.expires).to be_nil
+
+ cookie = @browser.cookies.last
+ expect(cookie.name).to eq 'with_expiration'
+ expect(cookie.value).to eq 'bar'
+ expect(cookie.expires.to_s).to eq Time.parse( '2047-08-01 09:30:11 +0000' ).to_s
end
- it 'preserves the HttpOnly attribute' do
- @browser.load @url
- expect(@browser.cookies.first).to be_http_only
+ it 'preserves the domain' do
+ @browser.load "#{@url}/cookies/domains"
+
+ cookies = @browser.cookies
+
+ cookie = cookies.find { |c| c.name == 'include_subdomains' }
+ expect(cookie.name).to eq 'include_subdomains'
+ expect(cookie.value).to eq 'bar1'
+ expect(cookie.domain).to eq '.127.0.0.2'
end
+ it 'ignores cookies for other domains' do
+ @browser.load "#{@url}/cookies/domains"
+
+ cookies = @browser.cookies
+ expect(cookies.find { |c| c.name == 'other_domain' }).to be_nil
+ end
+
+ it 'preserves the path' do
+ @browser.load "#{@url}/cookies/under/path"
+
+ cookie = @browser.cookies.first
+ expect(cookie.name).to eq 'cookie_under_path'
+ expect(cookie.value).to eq 'value'
+ expect(cookie.path).to eq '/cookies/under/'
+ end
+
+ it 'preserves httpOnly' do
+ @browser.load "#{@url}/cookies/under/path"
+
+ cookie = @browser.cookies.first
+ expect(cookie.name).to eq 'cookie_under_path'
+ expect(cookie.value).to eq 'value'
+ expect(cookie.path).to eq '/cookies/under/'
+ expect(cookie).to_not be_http_only
+
+ @browser.load "#{@url}/cookies/httpOnly"
+
+ cookie = @browser.cookies.first
+ expect(cookie.name).to eq 'http_only'
+ expect(cookie.value).to eq 'stuff'
+ expect(cookie).to be_http_only
+ end
+
context 'when parsing v1 cookies' do
it 'removes the quotes' do
cookie = 'rsession="06142010_0%3Ae275d357943e9a2de0"'
@browser.load @url
@browser.javascript.run( "document.cookie = '#{cookie}';" )
- expect(@browser.cookies.first.value).to eq('06142010_0:e275d357943e9a2de0')
+ cookie = @browser.cookies.find { |c| c.name == 'rsession' }
+ expect(cookie.value).to eq('06142010_0:e275d357943e9a2de0')
+ expect(cookie.raw_value).to eq('"06142010_0%3Ae275d357943e9a2de0"')
end
end
context 'when no page is available' do
it 'returns an empty Array' do
@@ -2827,27 +3129,48 @@
end
end
end
describe '#snapshot_id' do
- before(:each) { Arachni::Options.url = @url }
+ before(:each) do
+ Arachni::Options.url = @url
+ @empty_snapshot_id ||= @browser.load( empty_snapshot_id_url ).snapshot_id
+
+ @snapshot_id = @browser.load( url ).snapshot_id
+ end
+
let(:empty_snapshot_id_url) { @url + '/snapshot_id/default' }
let(:empty_snapshot_id) do
- @browser.load( empty_snapshot_id_url ).snapshot_id
+ @empty_snapshot_id
end
let(:snapshot_id) do
- @browser.load( url ).snapshot_id
+ @snapshot_id
end
let(:url) { @url + '/trigger_events' }
it 'returns a DOM digest' do
expect(snapshot_id).to eq(@browser.load( url ).snapshot_id)
end
- context :a do
+ context 'when there are new cookies' do
+ let(:url) { @url + '/each_element_with_events/set-cookie' }
+
+ it 'takes them into account' do
+ @browser.fire_event described_class::ElementLocator.new(
+ tag_name: :button,
+ attributes: {
+ onclick: 'setCookie()'
+ }
+ ), :click
+
+ expect(@browser.snapshot_id).not_to eq(snapshot_id)
+ end
+ end
+
+ context ':a' do
context 'and the href is not empty' do
context 'and it starts with javascript:' do
let(:url) { @url + '/each_element_with_events/a/href/javascript' }
it 'takes it into account' do
@@ -2879,13 +3202,13 @@
expect(snapshot_id).not_to eq(empty_snapshot_id)
end
end
end
- context :form do
+ context ':form' do
let(:empty_snapshot_id_url) { @url + '/snapshot_id/form/default' }
- context :input do
+ context ':input' do
context 'of type "image"' do
let(:url) { @url + '/each_element_with_events/form/input/image' }
it 'takes it into account' do
expect(snapshot_id).not_to eq(empty_snapshot_id)