lib/releaf/rspec/helpers.rb
module Releaf::Test
# Releaf::TestHelpers provides a facility to simplify admin functionality testing
module Helpers
def postgresql?
adapter_name == 'PostgreSQL'
end
def mysql?
adapter_name == "Mysql2"
end
def adapter_name
ActiveRecord::Base.connection.adapter_name
end
def auth_as_user(full_login = false, factory_or_instance = :user)
if factory_or_instance.is_a?(Symbol) || factory_or_instance.is_a?(String)
user = create(factory_or_instance)
else
user = factory_or_instance
end
if full_login
visit "/"
within("form.login") do
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
end
click_button 'Sign in'
else
login_as user
end
user
end
def stub_settings(values)
unless @releaf_settings_default_stubbed
allow(Releaf::Settings).to receive(:[]).and_call_original
@releaf_settings_default_stubbed = true
end
values.each_pair do|key, value|
allow(Releaf::Settings).to receive(:[]).with(key).and_return(value)
end
end
def update_resource
within "form.edit-resource" do
yield
end
save_and_check_response "Update succeeded"
end
def create_resource
click_link "Create new resource" unless first("form.new-resource", minimum: 0)
within "form.new-resource" do
yield
end
save_and_check_response "Create succeeded"
end
def within_search
within("form.search") do
yield
end
end
def search(text)
within_search do
fill_in 'search', with: text
end
end
def within_dialog
within(".dialog.initialized") do
yield
end
end
def close_dialog
within_dialog do
find("a[data-type='cancel']").click
end
expect(page).to have_no_css(".dialog")
end
def wait_for_all_richtexts
# wait for all ckeditors to fully initialize before moving on.
# otherwise the page sometimes produces random js errors in fast tests
number_of_normal_richtexts = page.all('.field.type-richtext:not(.i18n)', wait: false).length
number_of_localized_richtexts = page.all('.field.type-richtext.i18n .localization', wait: false, visible: false).length
# some richtexts may have been inside nested association items that have been removed (they actually only get hidden).
# they must be included in the count because they retain their 'ckeditor-initialized' class even after the editor has been unloaded
number_of_removed_normal_richtexts = page.all('fieldset.item.type-association.removed .field.type-richtext:not(.i18n)', wait: false, visible: false).length
number_of_initialized_richtexts = number_of_normal_richtexts + number_of_localized_richtexts + number_of_removed_normal_richtexts
if number_of_initialized_richtexts > 0
# expect _at least_ that many richtexts. others may have been initialized and hidden by some custom code
expect(page).to have_css(".ckeditor-initialized", visible: false, minimum: number_of_initialized_richtexts)
end
end
def switch_admin_locale(locale)
switch = page.first('.localization-switch')
current_locale = switch.text.downcase
new_locale = locale.to_s.downcase
if current_locale == new_locale
return current_locale
end
within( switch ) do
click_button current_locale
end
menu = page.find(:xpath, '/html//menu[@class="localization-menu-items"]')
within( menu ) do
click_button new_locale.capitalize
end
wait_for_all_richtexts
end
def close_all_notifications
page.all('body > .notifications .notification[data-id="resource_status"]', wait: false).each do |notification|
within(notification) { find('button.close').click }
end
expect(page).to have_no_css('body > .notifications .notification[data-id="resource_status"]')
end
def save_and_check_response(status_text, button_text = "Save")
wait_for_all_richtexts
# close any existing notifications
close_all_notifications
within page.document.find("form[data-remote-validation-initialized='true']") do
click_button button_text
end
notification = find('body > .notifications .notification[data-id="resource_status"][data-type="success"]', text: status_text)
within(notification) { find('button.close').click }
expect(page).to have_no_css('body > .notifications .notification[data-id="resource_status"]')
wait_for_all_richtexts
end
def open_toolbox_dialog(item_name, resource = nil, resource_selector_scope = ".view-index .table tr")
open_toolbox(item_name, resource, resource_selector_scope)
expect(page).to have_css('.dialog.initialized')
end
def open_toolbox(item_name, resource = nil, resource_selector_scope = ".view-index .table tr")
if resource
find(resource_selector_scope + '[data-id="' + resource.id.to_s + '"] .toolbox.initialized button.trigger').click
else
find('main section header .toolbox-wrap .toolbox.initialized button.trigger').click
end
within('menu.toolbox-items') do
click_on(item_name)
end
end
def fill_in_date(field_locator, options)
date = options[:with]
if date.is_a? Time
date = date.to_date
elsif date.is_a? Date
# do nothing
else
# try to convert it to string
date = Date.parse(date.to_s)
end
# wrapper = find('.field.type-date')
field = find_field( field_locator )
field_id = field[:id]
if Capybara.current_driver == Capybara.javascript_driver
execute_script('$("#' + field_id + '").trigger("focus")')
expect(page.document).to have_css('.ui-datepicker-year')
expect(page.document).to have_css('.ui-datepicker-month')
year_string = date.year.to_s
execute_script('$(".ui-datepicker-year").val(' + year_string + ').change()')
expect(evaluate_script('$(".ui-datepicker-year").val();')).to eq year_string
month_string = (date.month - 1).to_s
execute_script('$(".ui-datepicker-month").val("' + month_string + '").change()')
expect(evaluate_script('$(".ui-datepicker-month").val();')).to eq month_string
execute_script('$("a.ui-state-default:contains(' + date.day.to_s + ')").filter(function() { return $(this).text() == "' + date.day.to_s + '"}).trigger("click")')
expect(page.document).to have_no_css('.ui-datepicker-year')
else
fill_in field_locator, with: date.to_s
end
end
def fill_in_richtext(locator, options = {} )
# locator can be anything that is normally accepted by fill_in
# e.g., the label text or the id of the textarea
expect(page).to have_css('.field.type-richtext label')
# locate possibly hidden textarea among active/visible richtext fields ignoring hidden localization versions
textareas = []
richtext_boxes = all(".field.type-richtext:not(.i18n), .field.type-richtext.i18n .localization.active", wait: false)
richtext_boxes.each do |richtext_box|
textarea = richtext_box.first(:field, locator, visible: false, minimum: 0)
textareas << textarea if textarea.present?
end
if textareas.count > 1
raise Capybara::Ambiguous.new("Ambiguous match, found #{target_textareas.count} richtext boxes matching #{locator}")
elsif textareas.count < 1
raise Capybara::ElementNotFound.new("Unable to find richtext box #{locator}")
end
textarea_id = textareas.first[:id].to_s
expect(page).to have_css("##{textarea_id}.ckeditor-initialized", visible: false) # wait for ckeditor appearance
html = options[:with].to_s
page.execute_script("CKEDITOR.instances['#{textarea_id}'].setData(#{html.to_json});")
end
def scroll_to_bottom_of_page
execute_script('window.scrollTo(0, document.body.scrollHeight);')
end
def add_nested_item(block_name, expected_item_index)
scroll_to_bottom_of_page
all('button', text: 'Add item', wait: false).last.click # use last button in case of multiple nested items
wait_for_nested_item block_name, expected_item_index
if block_given?
within_nested_item block_name, expected_item_index do
yield
end
end
end
def within_nested_item block_name, item_index
within(".item[data-name='#{block_name}'][data-index='#{item_index}']") do
yield
end
end
def remove_nested_item(block_name, item_index)
base_selector = ".item[data-name=\"#{block_name}\"][data-index=\"#{item_index}\"]"
page.find("#{base_selector} > .remove-item-box button.remove-nested-item").click
# wait for js to finish hiding the block
# the opacity and display styles may get set in different order, so select both orders
expect(page).to have_css("#{base_selector}[style=\"display: none; opacity: 0;\"], #{base_selector}[style=\"opacity: 0; display: none;\"]", visible: false)
end
def wait_for_nested_item(block_name, item_index)
# wait for js to finish initializing the block
expect(page).to have_css(".item[data-name=\"#{block_name}\"][data-index=\"#{item_index}\"][style=\"opacity: 1; display: block;\"]")
end
def download_file(url)
require "open-uri"
file = Tempfile.new
file.binmode
file.write(URI.open(url).read)
file.flush
file
end
end
end