3021: Add random part to magic string.
[arvados.git] / apps / workbench / test / integration_helper.rb
1 require 'test_helper'
2 require 'capybara/rails'
3 require 'capybara/poltergeist'
4 require 'uri'
5 require 'yaml'
6
7 Capybara.register_driver :poltergeist do |app|
8   Capybara::Poltergeist::Driver.new app, {
9     window_size: [1200, 800],
10     phantomjs_options: ['--ignore-ssl-errors=true'],
11     inspector: true,
12   }
13 end
14
15 module WaitForAjax
16   Capybara.default_wait_time = 5
17   def wait_for_ajax
18     Timeout.timeout(Capybara.default_wait_time) do
19       loop until finished_all_ajax_requests?
20     end
21   end
22
23   def finished_all_ajax_requests?
24     page.evaluate_script('jQuery.active').zero?
25   end
26 end
27
28 module AssertDomEvent
29   # Yield the supplied block, then wait for an event to arrive at a
30   # DOM element.
31   def assert_triggers_dom_event events, target='body'
32     magic = 'RXC0lObcVwEXwSvA-' + rand(2**20).to_s(36)
33     page.evaluate_script <<eos
34       $('#{target}').one('#{events}', function() {
35         $('body').append('<div id="#{magic}"></div>');
36       });
37 eos
38     yield
39     assert_selector "##{magic}"
40     page.evaluate_script "$('##{magic}').remove();";
41   end
42 end
43
44 module HeadlessHelper
45   class HeadlessSingleton
46     def self.get
47       @headless ||= Headless.new reuse: false
48     end
49   end
50
51   Capybara.default_driver = :rack_test
52
53   def self.included base
54     base.class_eval do
55       setup do
56         Capybara.use_default_driver
57         @headless = false
58       end
59
60       teardown do
61         if @headless
62           @headless.stop
63           @headless = false
64         end
65       end
66     end
67   end
68
69   def need_selenium reason=nil
70     Capybara.current_driver = :selenium
71     unless ENV['ARVADOS_TEST_HEADFUL'] or @headless
72       @headless = HeadlessSingleton.get
73       @headless.start
74     end
75   end
76
77   def need_javascript reason=nil
78     unless Capybara.current_driver == :selenium
79       Capybara.current_driver = :poltergeist
80     end
81   end
82 end
83
84 class ActionDispatch::IntegrationTest
85   # Make the Capybara DSL available in all integration tests
86   include Capybara::DSL
87   include ApiFixtureLoader
88   include WaitForAjax
89   include AssertDomEvent
90   include HeadlessHelper
91
92   @@API_AUTHS = self.api_fixture('api_client_authorizations')
93
94   def page_with_token(token, path='/')
95     # Generate a page path with an embedded API token.
96     # Typical usage: visit page_with_token('token_name', page)
97     # The token can be specified by the name of an api_client_authorizations
98     # fixture, or passed as a raw string.
99     api_token = ((@@API_AUTHS.include? token) ?
100                  @@API_AUTHS[token]['api_token'] : token)
101     sep = (path.include? '?') ? '&' : '?'
102     q_string = URI.encode_www_form('api_token' => api_token)
103     "#{path}#{sep}#{q_string}"
104   end
105
106   # Find a page element, but return false instead of raising an
107   # exception if not found. Use this with assertions to explain that
108   # the error signifies a failed test rather than an unexpected error
109   # during a testing procedure.
110   def find? *args
111     begin
112       find *args
113     rescue Capybara::ElementNotFound
114       false
115     end
116   end
117
118   @@screenshot_count = 1
119   def screenshot
120     image_file = "./tmp/workbench-fail-#{@@screenshot_count}.png"
121     begin
122       page.save_screenshot image_file
123     rescue Capybara::NotSupportedByDriverError
124       # C'est la vie.
125     else
126       puts "Saved #{image_file}"
127       @@screenshot_count += 1
128     end
129   end
130
131   teardown do
132     if not passed?
133       screenshot
134     end
135     if Capybara.current_driver == :selenium
136       page.execute_script("window.localStorage.clear()")
137     end
138     Capybara.reset_sessions!
139   end
140 end