canvas-lms/spec/selenium/common.rb

161 lines
5.5 KiB
Ruby

#
# Copyright (C) 2011 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require "selenium-webdriver"
require "socket"
require "timeout"
require 'coffee-script'
require File.expand_path(File.dirname(__FILE__) + '/test_setup/custom_selenium_rspec_matchers')
require File.expand_path(File.dirname(__FILE__) + '/test_setup/selenium_driver_setup')
Dir[File.dirname(__FILE__) + '/test_setup/common_helper_methods/*.rb'].each {|file| require file }
include I18nUtilities
$selenium_config = ConfigFile.load("selenium") || {}
SERVER_IP = $selenium_config[:server_ip] || UDPSocket.open { |s| s.connect('8.8.8.8', 1); s.addr.last }
BIND_ADDRESS = $selenium_config[:bind_address] || '0.0.0.0'
SECONDS_UNTIL_COUNTDOWN = 5
SECONDS_UNTIL_GIVING_UP = 20
MAX_SERVER_START_TIME = 60
#NEED BETTER variable handling
THIS_ENV = ENV['TEST_ENV_NUMBER'].present? ? ENV['TEST_ENV_NUMBER'].to_i : 1
WEBSERVER = (ENV['WEBSERVER'] || 'thin').freeze
$server_port = nil
$app_host_and_port = nil
at_exit do
[1, 2, 3].each do
begin
$selenium_driver.try(:quit)
break
rescue Timeout::Error => te
puts "rescued timeout error from selenium_driver quit : #{te}"
end
end
end
shared_context "in-process server selenium tests" do
include SeleniumDriverSetup
include CustomSeleniumRspecMatchers
include OtherHelperMethods
include CustomSeleniumActions
include CustomAlertActions
include CustomPageLoaders
include CustomScreenActions
include CustomValidators
include CustomWaitMethods
include LoginAndSessionMethods
# set up so you can use rails urls helpers in your selenium tests
include Rails.application.routes.url_helpers
prepend_before :all do
SeleniumDriverSetup.allow_requests!
end
prepend_before :each do
SeleniumDriverSetup.allow_requests!
end
prepend_before :all do
$in_proc_webserver_shutdown ||= SeleniumDriverSetup.start_webserver(WEBSERVER)
end
append_before :all do
$selenium_driver ||= setup_selenium
default_url_options[:host] = $app_host_and_port
close_modal_if_present
resize_screen_to_normal
end
append_before :each do
#the driver sometimes gets in a hung state and this if almost always the first line of code to catch it
begin
tries ||= 3
driver.manage.timeouts.implicit_wait = 3
driver.manage.timeouts.script_timeout = 60
EncryptedCookieStore.test_secret = SecureRandom.hex(64)
enable_forgery_protection
rescue
if ENV['PARALLEL_EXECS'] != nil
#cleans up and provisions a new driver
puts "ERROR: thread: #{THIS_ENV} selenium server hung, attempting to recover the node"
$selenium_driver = nil
$selenium_driver ||= setup_selenium
default_url_options[:host] = $app_host_and_port
retry unless (tries -= 1).zero?
else
raise # preserve original error
end
end
end
before do
HostUrl.stubs(:default_host).returns($app_host_and_port)
HostUrl.stubs(:file_host).returns($app_host_and_port)
end
# tricksy tricksy. grab the current connection, and then always return the same one
# (even if on a different thread - i.e. the server's thread), so that it will be in
# the same transaction and see the same data
before do
if self.use_transactional_fixtures
@db_connection = ActiveRecord::Base.connection
@dj_connection = Delayed::Backend::ActiveRecord::Job.connection
# synchronize db connection methods for a modicum of thread safety
methods_to_sync = %w{execute exec_cache exec_no_cache query}
[@db_connection, @dj_connection].each do |conn|
methods_to_sync.each do |method_name|
if conn.respond_to?(method_name, true) && !conn.respond_to?("#{method_name}_with_synchronization", true)
conn.class.class_eval <<-RUBY
def #{method_name}_with_synchronization(*args)
@mutex ||= Mutex.new
@mutex.synchronize { #{method_name}_without_synchronization(*args) }
end
alias_method_chain :#{method_name}, :synchronization
RUBY
end
end
end
ActiveRecord::ConnectionAdapters::ConnectionPool.any_instance.stubs(:connection).returns(@db_connection)
Delayed::Backend::ActiveRecord::Job.stubs(:connection).returns(@dj_connection)
Delayed::Backend::ActiveRecord::Job::Failed.stubs(:connection).returns(@dj_connection)
end
end
after(:each) do
clear_timers!
# while disallow_requests! would generally get these, there's a small window
# between the ajax request starting up and the middleware actually processing it
begin
wait_for_ajax_requests
rescue Selenium::WebDriver::Error::WebDriverError
# we want to ignore selenium errors when attempting to wait here
nil
end
SeleniumDriverSetup.disallow_requests!
truncate_all_tables unless self.use_transactional_fixtures
end
end