From a61790eac20fc60ce014eda02956ce84d74b9159 Mon Sep 17 00:00:00 2001
From: Thomas Walpole
+
diff --git a/spec/selenium_spec_safari.rb b/spec/selenium_spec_safari.rb new file mode 100644 index 00000000..050f13b6 --- /dev/null +++ b/spec/selenium_spec_safari.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'selenium-webdriver' +require 'shared_selenium_session' +require 'rspec/shared_spec_matchers' + +SAFARI_DRIVER = :selenium_safari + +::Selenium::WebDriver::Safari.driver_path = '/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver' + +browser_options = ::Selenium::WebDriver::Safari::Options.new +# browser_options.headless! if ENV['HEADLESS'] +# browser_options.add_option(:w3c, !!ENV['W3C']) + +Capybara.register_driver :selenium_safari do |app| + Capybara::Selenium::Driver.new(app, browser: :safari, options: browser_options, timeout: 30).tap do |driver| + # driver.browser.download_path = Capybara.save_path + end +end + +Capybara.register_driver :selenium_safari_not_clear_storage do |app| + safari_options = { + browser: :safari, + options: browser_options + } + Capybara::Selenium::Driver.new(app, safari_options.merge(clear_local_storage: false, clear_session_storage: false)) +end + +module TestSessions + Safari = Capybara::Session.new(SAFARI_DRIVER, TestApp) +end + +skipped_tests = %i[response_headers status_code trigger windows drag] + +$stdout.puts `#{Selenium::WebDriver::Safari.driver_path} --version` if ENV['CI'] + +Capybara::SpecHelper.run_specs TestSessions::Safari, SAFARI_DRIVER.to_s, capybara_skip: skipped_tests do |example| + case example.metadata[:full_description] + when /click_link can download a file/ + skip "safaridriver doesn't provide a way to set the download directory" + when /Capybara::Session selenium_safari Capybara::Window#maximize/ + pending "Safari headless doesn't support maximize" if ENV['HEADLESS'] + when /Capybara::Session selenium_safari #visit without a server/, + /Capybara::Session selenium_safari #visit with Capybara.app_host set should override server/, + /Capybara::Session selenium_safari #reset_session! When reuse_server == false raises any standard errors caught inside the server during a second session/ + skip "Safari webdriver doesn't support multiple sessions" + when /Capybara::Session selenium_safari #click_link with alternative text given to a contained image/, + 'Capybara::Session selenium_safari #click_link_or_button with enable_aria_label should click on link' + pending 'safaridriver thinks these links are non-interactable for some unknown reason' + when /Capybara::Session selenium_safari #attach_file with a block can upload by clicking the file input/ + skip "safaridriver doesn't allow clicking on file inputs" + when /Capybara::Session selenium_safari #attach_file with a block can upload by clicking the label/ + skip 'hangs tests' + when /Capybara::Session selenium_safari #check when checkbox hidden with Capybara.automatic_label_click == false with allow_label_click == true should check via the label if input is visible but blocked by another element/, + 'Capybara::Session selenium_safari node #click should not retry clicking when wait is disabled', + 'Capybara::Session selenium_safari node #click should allow to retry longer', + 'Capybara::Session selenium_safari node #click should retry clicking' + pending "safaridriver doesn't return a specific enough error to deal with this" + when /Capybara::Session selenium_safari #within_frame should find multiple nested frames/, + /Capybara::Session selenium_safari #within_frame works if the frame is closed/, + /Capybara::Session selenium_safari #switch_to_frame works if the frame is closed/ + skip 'switch_to_frame(:parent) appears to go to the root in Safari rather than parent' + when /Capybara::Session selenium_safari #reset_session! removes ALL cookies/ + skip 'Safari webdriver can only remove cookies for the current domain' + when /Capybara::Session selenium_safari #refresh it reposts/ + skip "Safari opens an alert that can't be closed" + when 'Capybara::Session selenium_safari node #double_click should allow to adjust the offset', + 'Capybara::Session selenium_safari node #double_click should double click an element' + pending "safardriver doesn't generate a double click event" + when 'Capybara::Session selenium_safari node #click should allow multiple modifiers', + /Capybara::Session selenium_safari node #(click|right_click|double_click) should allow modifiers/ + pending "safaridriver doesn't take key state into account when clicking" + when 'Capybara::Session selenium_safari #fill_in on a pre-populated textfield with a reformatting onchange should trigger change when clearing field' + pending "safardriver clear doesn't generate change event" + when 'Capybara::Session selenium_safari #go_back should fetch a response from the driver from the previous page', + 'Capybara::Session selenium_safari #go_forward should fetch a response from the driver from the previous page' + skip 'safaridriver loses the ability to find elements in the document after `go_back`' + when 'Capybara::Session selenium_safari node #send_keys should hold modifiers at top level' + skip 'Need to look into this' + end +end + +RSpec.describe 'Capybara::Session with safari' do + include Capybara::SpecHelper + include_examples 'Capybara::Session', TestSessions::Safari, SAFARI_DRIVER + include_examples Capybara::RSpecMatchers, TestSessions::Safari, SAFARI_DRIVER + + context 'storage' do + describe '#reset!' do + it 'clears storage by default' do + session = TestSessions::Safari + session.visit('/with_js') + session.find(:css, '#set-storage').click + session.reset! + session.visit('/with_js') + expect(session.evaluate_script('Object.keys(localStorage)')).to be_empty + expect(session.evaluate_script('Object.keys(sessionStorage)')).to be_empty + end + + it 'does not clear storage when false' do + skip "Safari webdriver doesn't support multiple sessions" + session = Capybara::Session.new(:selenium_safari_not_clear_storage, TestApp) + session.visit('/with_js') + session.find(:css, '#set-storage').click + session.reset! + session.visit('/with_js') + expect(session.evaluate_script('Object.keys(localStorage)')).not_to be_empty + expect(session.evaluate_script('Object.keys(sessionStorage)')).not_to be_empty + end + end + end + + context 'timeout' do + it 'sets the http client read timeout' do + expect(TestSessions::Safari.driver.browser.send(:bridge).http.read_timeout).to eq 30 + end + end + + describe 'filling in Safari-specific date and time fields with keystrokes' do + let(:datetime) { Time.new(1983, 6, 19, 6, 30) } + let(:session) { TestSessions::Safari } + + before do + skip 'Too many other things broken currently' + session.visit('/form') + end + + it 'should fill in a date input with a String' do + session.fill_in('form_date', with: '06/19/1983') + session.click_button('awesome') + expect(Date.parse(extract_results(session)['date'])).to eq datetime.to_date + end + + it 'should fill in a time input with a String' do + session.fill_in('form_time', with: '06:30A') + session.click_button('awesome') + results = extract_results(session)['time'] + expect(Time.parse(results).strftime('%r')).to eq datetime.strftime('%r') + end + + it 'should fill in a datetime input with a String' do + session.fill_in('form_datetime', with: "06/19/1983\t06:30A") + session.click_button('awesome') + expect(Time.parse(extract_results(session)['datetime'])).to eq datetime + end + end +end diff --git a/spec/shared_selenium_session.rb b/spec/shared_selenium_session.rb index 2a79b67f..46dc613d 100644 --- a/spec/shared_selenium_session.rb +++ b/spec/shared_selenium_session.rb @@ -72,6 +72,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode| context '#fill_in_with empty string and no options' do it 'should trigger change when clearing a field' do + pending "safaridriver doesn't trigger change for clear" if safari?(session) session.visit('/with_js') session.fill_in('with_change_event', with: '') # click outside the field to trigger the change event @@ -116,6 +117,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode| it 'should only trigger onchange once' do session.visit('/with_js') + sleep 2 if safari?(session) # Safari needs a delay (to load event handlers maybe ???) session.fill_in('with_change_event', with: 'some value', fill_options: { clear: :backspace }) @@ -140,13 +142,16 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode| with: '', fill_options: { clear: :backspace }) # click outside the field to trigger the change event - session.find(:css, 'body').click + # session.find(:css, 'body').click + session.find(:css, 'h1', text: 'FooBar').click expect(session).to have_xpath('//p[@class="input_event_triggered"]', count: 13) end end context '#fill_in with { clear: :none } fill_options' do it 'should append to content in a field' do + pending 'Safari overwrites by default - need to figure out a workaround' if safari?(session) + session.visit('/form') session.fill_in('form_first_name', with: 'Harry', @@ -166,17 +171,20 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode| }); JS # work around weird FF issue where it would create an extra focus issue in some cases - session.find(:css, 'body').click + session.find(:css, 'h1', text: 'Form').click + # session.find(:css, 'body').click end it 'should generate standard events on changing value' do pending "IE 11 doesn't support date input type" if ie?(session) + pending "Safari doesn't support date input type" if safari?(session) session.fill_in('form_date', with: Date.today) expect(session.evaluate_script('window.capybara_formDateFiredEvents')).to eq %w[focus input change] end it 'should not generate input and change events if the value is not changed' do pending "IE 11 doesn't support date input type" if ie?(session) + pending "Safari doesn't support date input type" if safari?(session) session.fill_in('form_date', with: Date.today) session.fill_in('form_date', with: Date.today) # Chrome adds an extra focus for some reason - ok for now @@ -264,6 +272,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode| describe '#evaluate_async_script' do it 'will timeout if the script takes too long' do + skip 'safaridriver returns the wrong error type' if safari?(session) session.visit('/with_js') expect do session.using_wait_time(1) do @@ -298,6 +307,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode| before do skip "Firefox < 62 doesn't support a DataTransfer constuctor" if firefox_lt?(62.0, session) skip "IE doesn't support a DataTransfer constuctor" if ie?(session) + skip "Safari doesn't support" if safari?(session) end it 'should HTML5 drag and drop an object' do @@ -351,6 +361,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode| pending "Headless Chrome doesn't support directory upload - https://bugs.chromium.org/p/chromedriver/issues/detail?id=2521&q=directory%20upload&colspec=ID%20Status%20Pri%20Owner%20Summary" if chrome?(session) && ENV['HEADLESS'] pending "IE doesn't support uploading a directory" if ie?(session) pending 'Chrome/chromedriver 73 breaks this' unless chrome_lt?(73, session) + pending "Safari doesn't support uploading a directory" if safari?(session) session.visit('/form') test_file_dir = File.expand_path('./fixtures', File.dirname(__FILE__)) @@ -372,6 +383,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode| describe 'Capybara#disable_animation' do context 'when set to `true`' do before(:context) do # rubocop:disable RSpec/BeforeAfterAll + skip "Safari doesn't support multiple sessions" if safari?(session) # NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false, # it doesn't affect any of these tests because the settings are applied per-session Capybara.disable_animation = true @@ -393,6 +405,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode| context 'if we pass in css that matches elements' do before(:context) do # rubocop:disable RSpec/BeforeAfterAll + skip "safaridriver doesn't support multiple sessions" if safari?(session) # NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false, # it doesn't affect any of these tests because the settings are applied per-session Capybara.disable_animation = '#with_animation a' @@ -414,6 +427,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode| context 'if we pass in css that does not match elements' do before(:context) do # rubocop:disable RSpec/BeforeAfterAll + skip "Safari doesn't support multiple sessions" if safari?(session) # NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false, # it doesn't affect any of these tests because the settings are applied per-session Capybara.disable_animation = '.this-class-matches-nothing' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d4e1ac36..a4d34dd1 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -40,6 +40,10 @@ module Capybara %i[internet_explorer ie].include?(browser_name(session)) end + def safari?(session) + %i[safari Safari Safari_Technology_Preview].include?(browser_name(session)) + end + def browser_name(session) session.driver.browser.browser if session.respond_to?(:driver) end