Maintenance: Switch to headless Selenium in CI.

This commit is contained in:
Martin Gruner 2022-03-04 14:49:17 +01:00
parent 25c971ed00
commit f84ac43cdd
8 changed files with 163 additions and 194 deletions

View file

@ -22,6 +22,7 @@
variables:
REMOTE_URL: "http://selenium-firefox:4444/wd/hub"
BROWSER: "firefox"
START_XVFB: "false" # not needed for headless mode
SE_NODE_MAX_SESSIONS: "5"
SE_NODE_OVERRIDE_MAX_SESSIONS: "true"
@ -29,6 +30,7 @@
variables:
REMOTE_URL: "http://selenium-chrome:4444/wd/hub"
BROWSER: chrome
START_XVFB: "false" # not needed for headless mode
SE_NODE_MAX_SESSIONS: "5"
SE_NODE_OVERRIDE_MAX_SESSIONS: "true"

View file

@ -152,16 +152,6 @@ module CapybaraCustomExtensions
def page(...)
ZammadCapybaraSessionDelegator.new(element: super, context: self)
end
# Work around an issue with failures in Capybara if different specs of the same rspec run
# use using_session with the same name, e.g. :second_browser. Solve by prepending the test name.
def using_session(name_or_session, &block)
if !(name_or_session.is_a? Capybara::Session)
# self.class.name refers to the RSpec test case.
name_or_session = (self.class.name + "::#{name_or_session}").to_sym
end
Capybara.using_session(name_or_session, &block)
end
end
RSpec.configure do |config|

View file

@ -35,10 +35,19 @@ RSpec.configure do |config|
browser_height = 1000
end
# Firefox and Chrome effective screen sizes are slightly different
# accomodate that by reducing declared screen size on Firefox
browser_height -= 44 if browser_name == 'firefox'
page.driver.browser.manage.window.resize_to(browser_width, browser_height)
end
config.after(:each, type: :system) do
# Make sure additional sessions (from using_sessions) are always ended
# after every test and not kept alive. Selenium will automatically close
# idle sessions which can cause 404 errors later.
# (see https://github.com/teamcapybara/capybara/issues/2237)
Capybara.send(:session_pool).reverse_each do |_mode, session|
if !session.eql?(Capybara.current_session)
session.quit
end
end
end
end

View file

@ -8,13 +8,15 @@ Capybara.register_driver(:zammad_chrome) do |app|
# Turn on browser logs
options = Selenium::WebDriver::Chrome::Options.new(
logging_prefs: {
logging_prefs: {
browser: 'ALL'
},
prefs: {
prefs: {
'intl.accept_languages' => 'en-US',
'profile.default_content_setting_values.notifications' => 1, # ALLOW notifications
},
# Disable the "Chrome is controlled by automation software" info bar.
excludeSwitches: ['enable-automation'],
)
options = {
@ -25,6 +27,7 @@ Capybara.register_driver(:zammad_chrome) do |app|
if ENV['REMOTE_URL'].present?
options[:browser] = :remote
options[:url] = ENV['REMOTE_URL']
options[:options].headless!
end
ENV['FAKE_SELENIUM_LOGIN_USER_ID'] = nil
@ -51,6 +54,7 @@ Capybara.register_driver(:zammad_firefox) do |app|
if ENV['REMOTE_URL'].present?
options[:browser] = :remote
options[:url] = ENV['REMOTE_URL']
options[:options].headless!
end
ENV['FAKE_SELENIUM_LOGIN_USER_ID'] = nil
@ -60,16 +64,3 @@ Capybara.register_driver(:zammad_firefox) do |app|
driver.browser.file_detector = nil if ENV['REMOTE_URL'].present?
end
end
class Capybara::Selenium::Driver
alias original_quit quit
def quit
original_quit
rescue Selenium::WebDriver::Error::ServerError
# Work around a possible capybara/Selenium bug. driver.quit() fails because there is already no session any more;
# not sure why that happens.
ensure
@browser = nil
end
end

View file

@ -37,7 +37,12 @@ RSpec.describe 'Chat Handling', type: :system do
end
def send_agent_message(message)
find('.active .chat-window .js-customerChatInput').send_keys(message)
input = find('.active .chat-window .js-customerChatInput')
input.send_keys(message)
# Work around an obsure bug of send_keys sometimes not working on Firefox headless.
if input.text != message
input.execute_script("this.textContent = '#{message}'")
end
click '.active .chat-window .js-send'
end
@ -45,13 +50,13 @@ RSpec.describe 'Chat Handling', type: :system do
it 'check that button is hidden after idle timeout', authenticated_as: :authenticate do
click agent_chat_switch_selector
open_window_and_switch
using_session :customer do
visit chat_url
visit chat_url
expect(page).to have_css('.zammad-chat', visible: :all)
expect(page).to have_css('.zammad-chat-is-hidden', visible: :all)
expect(page).to have_no_css('.open-zammad-chat:not([style*="display: none"]', visible: :all)
expect(page).to have_css('.zammad-chat', visible: :all)
expect(page).to have_css('.zammad-chat-is-hidden', visible: :all)
expect(page).to have_no_css('.open-zammad-chat:not([style*="display: none"]', visible: :all)
end
end
end
@ -59,13 +64,10 @@ RSpec.describe 'Chat Handling', type: :system do
it 'messages in each direction, starting on agent side', authenticated_as: :authenticate do
enable_agent_chat
open_window_and_switch
visit chat_url
open_chat_dialog
switch_to_window_index(1)
using_session :customer do
visit chat_url
open_chat_dialog
end
click '.active .js-acceptChat'
@ -74,14 +76,11 @@ RSpec.describe 'Chat Handling', type: :system do
send_agent_message('my name is me')
switch_to_window_index(2)
check_content('.zammad-chat .zammad-chat-agent-status', 'Online')
check_content('.zammad-chat', 'my name is me')
send_customer_message('my name is customer')
switch_to_window_index(1)
using_session :customer do
check_content('.zammad-chat .zammad-chat-agent-status', 'Online')
check_content('.zammad-chat', 'my name is me')
send_customer_message('my name is customer')
end
check_content('.active .chat-window', 'my name is customer')
expect(page).to have_css('.active .chat-window .chat-status.is-modified')
@ -90,11 +89,9 @@ RSpec.describe 'Chat Handling', type: :system do
expect(page).to have_no_css('.active .chat-window .chat-status.is-modified')
switch_to_window_index(2)
click '.js-chat-toggle .zammad-chat-header-icon'
switch_to_window_index(1)
using_session :customer do
click '.js-chat-toggle .zammad-chat-header-icon'
end
check_content('.active .chat-window', 'closed the conversation')
end
@ -102,13 +99,12 @@ RSpec.describe 'Chat Handling', type: :system do
it 'messages in each direction, starting on customer side', authenticated_as: :authenticate do
enable_agent_chat
open_window_and_switch
using_session :customer do
visit chat_url
visit chat_url
open_chat_dialog
switch_to_window_index(1)
open_chat_dialog
end
click '.active .js-acceptChat'
@ -117,13 +113,10 @@ RSpec.describe 'Chat Handling', type: :system do
# Keep focus outside of chat window to check .chat-status.is-modified later.
click '#global-search'
switch_to_window_index(2)
check_content('.zammad-chat .zammad-chat-agent-status', 'Online')
send_customer_message('my name is customer')
switch_to_window_index(1)
using_session :customer do
check_content('.zammad-chat .zammad-chat-agent-status', 'Online')
send_customer_message('my name is customer')
end
expect(page).to have_css('.active .chat-window .chat-status.is-modified')
check_content('.active .chat-window', 'my name is customer')
@ -131,27 +124,24 @@ RSpec.describe 'Chat Handling', type: :system do
send_agent_message('my name is me')
expect(page).to have_no_css('.active .chat-window .chat-status.is-modified')
switch_to_window_index(2)
check_content('.zammad-chat', 'my name is me')
switch_to_window_index(1)
using_session :customer do
check_content('.zammad-chat', 'my name is me')
end
click '.active .chat-window .js-disconnect:not(.is-hidden)'
click '.active .chat-window .js-close'
switch_to_window_index(2)
using_session :customer do
check_content('.zammad-chat .zammad-chat-agent-status', 'Offline')
check_content('.zammad-chat', %r{(Chat closed by|Chat beendet von)})
check_content('.zammad-chat .zammad-chat-agent-status', 'Offline')
check_content('.zammad-chat', %r{(Chat closed by|Chat beendet von)})
click '.zammad-chat .js-chat-toggle .zammad-chat-header-icon'
click '.zammad-chat .js-chat-toggle .zammad-chat-header-icon'
expect(page).to have_no_css('.zammad-chat-is-open')
expect(page).to have_no_css('.zammad-chat-is-open')
open_chat_dialog
switch_to_window_index(1)
open_chat_dialog
end
click '.active .js-acceptChat'
@ -163,25 +153,25 @@ RSpec.describe 'Chat Handling', type: :system do
it 'open the chat', authenticated_as: :authenticate do
enable_agent_chat
open_window_and_switch
using_session :customer do
visit chat_url
visit chat_url
expect(page).to have_css('.zammad-chat', visible: :all)
expect(page).to have_css('.zammad-chat-is-hidden', visible: :all)
expect(page).to have_no_css('.zammad-chat-is-shown', visible: :all)
expect(page).to have_no_css('.zammad-chat-is-open', visible: :all)
expect(page).to have_css('.zammad-chat', visible: :all)
expect(page).to have_css('.zammad-chat-is-hidden', visible: :all)
expect(page).to have_no_css('.zammad-chat-is-shown', visible: :all)
expect(page).to have_no_css('.zammad-chat-is-open', visible: :all)
click '.open-zammad-chat'
click '.open-zammad-chat'
expect(page).to have_css('.zammad-chat-is-shown', visible: :all)
expect(page).to have_css('.zammad-chat-is-open', visible: :all)
check_content('.zammad-chat-modal-text', %r{(waiting|Warte)})
expect(page).to have_css('.zammad-chat-is-shown', visible: :all)
expect(page).to have_css('.zammad-chat-is-open', visible: :all)
check_content('.zammad-chat-modal-text', %r{(waiting|Warte)})
click '.zammad-chat-header-icon-close'
click '.zammad-chat-header-icon-close'
expect(page).to have_no_css('.zammad-chat-is-shown', visible: :all)
expect(page).to have_no_css('.zammad-chat-is-open', visible: :all)
expect(page).to have_no_css('.zammad-chat-is-shown', visible: :all)
expect(page).to have_no_css('.zammad-chat-is-open', visible: :all)
end
end
end
@ -189,60 +179,56 @@ RSpec.describe 'Chat Handling', type: :system do
it 'check different timeouts', authenticated_as: :authenticate do
enable_agent_chat
open_window_and_switch
using_session :customer do
visit chat_url
visit chat_url
# No customer action, hide the widget.
expect(page).to have_css('.zammad-chat')
# No customer action, hide the widget.
expect(page).to have_css('.zammad-chat')
expect(page).to have_no_css('.zammad-chat')
expect(page).to have_no_css('.zammad-chat')
refresh
refresh
# No agent action, show sorry screen.
open_chat_dialog
# No agent action, show sorry screen.
open_chat_dialog
check_content('.zammad-chat-modal-text', %r{(waiting|Warte)})
check_content('.zammad-chat-modal-text', %r{(takes longer|dauert länger)})
check_content('.zammad-chat-modal-text', %r{(waiting|Warte)})
check_content('.zammad-chat-modal-text', %r{(takes longer|dauert länger)})
refresh
refresh
# No customer action, show sorry screen.
open_chat_dialog
switch_to_window_index(1)
# No customer action, show sorry screen.
open_chat_dialog
end
click '.active .js-acceptChat'
send_agent_message('agent is asking')
switch_to_window_index(2)
using_session :customer do
check_content('.zammad-chat', 'agent is asking')
check_content('.zammad-chat', 'agent is asking')
check_content('.zammad-chat-modal-text', %r{(Since you didn't respond|Da Sie in den letzten)}, wait: 30)
check_content('.zammad-chat-modal-text', %r{(Since you didn't respond|Da Sie in den letzten)}, wait: 30)
end
# Test the restart of inactive chat.
switch_to_window_index(1)
click '.active .chat-window .js-close'
switch_to_window_index(2)
using_session :customer do
click '.js-restart'
open_chat_dialog
switch_to_window_index(1)
click '.js-restart'
open_chat_dialog
end
click '.active .js-acceptChat'
send_agent_message('my name is me')
switch_to_window_index(2)
check_content('.zammad-chat', 'my name is me')
using_session :customer do
check_content('.zammad-chat', 'my name is me')
end
end
end
@ -254,55 +240,51 @@ RSpec.describe 'Chat Handling', type: :system do
expect(page).to have_no_css(agent_chat_switch_selector)
open_window_and_switch
using_session :customer do
visit chat_url
visit chat_url
check_content('.settings', '{"state":"chat_disabled"}')
switch_to_window_index(1)
check_content('.settings', '{"state":"chat_disabled"}')
end
click '.content.active .js-chatSetting'
expect(page).to have_css(agent_chat_switch_selector)
switch_to_window_index(2)
using_session :customer do
refresh
refresh
expect(page).to have_no_css('.zammad-chat')
check_content('.settings', '{"state":"chat_disabled"}', should_match: false)
check_content('.settings', '{"event":"chat_status_customer","data":{"state":"offline"}}')
switch_to_window_index(1)
expect(page).to have_no_css('.zammad-chat')
check_content('.settings', '{"state":"chat_disabled"}', should_match: false)
check_content('.settings', '{"event":"chat_status_customer","data":{"state":"offline"}}')
end
click agent_chat_switch_selector
click 'a[href="#customer_chat"]'
switch_to_window_index(2)
using_session :customer do
refresh
refresh
expect(page).to have_css('.zammad-chat')
check_content('.settings', '{"event":"chat_status_customer","data":{"state":"offline"}}', should_match: false)
check_content('.settings', '{"state":"online"}')
expect(page).to have_css('.zammad-chat')
check_content('.settings', '{"event":"chat_status_customer","data":{"state":"offline"}}', should_match: false)
check_content('.settings', '{"state":"online"}')
click '.zammad-chat .js-chat-open'
click '.zammad-chat .js-chat-open'
expect(page).to have_css('.zammad-chat-is-shown')
check_content('.zammad-chat-modal-text', %r{(waiting|Warte)})
switch_to_window_index(1)
expect(page).to have_css('.zammad-chat-is-shown')
check_content('.zammad-chat-modal-text', %r{(waiting|Warte)})
end
check_content('.js-chatMenuItem .counter', '1')
switch_to_window_index(2)
using_session :customer do
click '.zammad-chat .js-chat-toggle .zammad-chat-header-icon'
click '.zammad-chat .js-chat-toggle .zammad-chat-header-icon'
check_content('.zammad-chat-modal-text', %r{(waiting|Warte)}, should_match: false)
switch_to_window_index(1)
check_content('.zammad-chat-modal-text', %r{(waiting|Warte)}, should_match: false)
end
expect(page).to have_no_css('.js-chatMenuItem .counter')
end
@ -321,39 +303,35 @@ RSpec.describe 'Chat Handling', type: :system do
modal_disappear
open_window_and_switch
using_session :customer do
visit chat_url
visit chat_url
open_chat_dialog
switch_to_window_index(1)
open_chat_dialog
end
click '.active .js-acceptChat'
expect(page).to have_css('.active .chat-window .chat-status')
switch_to_window_index(2)
check_content('.zammad-chat', %r{(Hi Stranger|My Greeting)})
switch_to_window_index(1)
using_session :customer do
check_content('.zammad-chat', %r{(Hi Stranger|My Greeting)})
end
send_agent_message('my name is me')
switch_to_window_index(2)
using_session :customer do
check_content('.zammad-chat', 'my name is me')
check_content('.zammad-chat', 'my name is me')
refresh
refresh
expect(page).to have_css('.zammad-chat')
check_content('.zammad-chat', %r{(Hi Stranger|My Greeting)})
check_content('.zammad-chat', 'my name is me')
expect(page).to have_css('.zammad-chat')
check_content('.zammad-chat', %r{(Hi Stranger|My Greeting)})
check_content('.zammad-chat', 'my name is me')
visit "#{chat_url}#new_hash"
switch_to_window_index(1)
visit "#{chat_url}#new_hash"
end
check_content('.active .chat-window .js-body', "#{chat_url}#new_hash")
end
@ -373,7 +351,7 @@ RSpec.describe 'Chat Handling', type: :system do
end
end
context 'when none jquery variant is used' do
context 'when no-jquery variant is used' do
let(:chat_url_type) { 'znuny-no-jquery' }
context 'when normal mode is used' do
@ -393,13 +371,14 @@ RSpec.describe 'Chat Handling', type: :system do
shared_examples 'test issue #2471' do
it 'is able to close to the dialog after a idleTimeout happened' do
click agent_chat_switch_selector
open_window_and_switch
using_session :customer do
visit chat_url
click '.zammad-chat .js-chat-open'
expect(page).to have_selector('.js-restart', wait: 60)
click '.js-chat-toggle .zammad-chat-header-icon'
expect(page).to have_no_selector('zammad-chat-is-open', wait: 60)
visit chat_url
click '.zammad-chat .js-chat-open'
expect(page).to have_selector('.js-restart', wait: 60)
click '.js-chat-toggle .zammad-chat-header-icon'
expect(page).to have_no_selector('zammad-chat-is-open', wait: 60)
end
end
end
@ -407,7 +386,7 @@ RSpec.describe 'Chat Handling', type: :system do
include_examples 'test issue #2471'
end
context 'wihtout jquery' do
context 'without jquery' do
let(:chat_url_type) { 'znuny-no-jquery' }
include_examples 'test issue #2471'

View file

@ -146,9 +146,7 @@ class AgentOrganizationProfileTest < TestCase
css: '.active .profile [data-name="note"]',
slow: true,
value: message,
)
empty_search(
browser: browser1,
blur: true
)
# verify

View file

@ -139,9 +139,7 @@ class AgentUserProfileTest < TestCase
browser: browser1,
css: '.active [data-name="note"]',
value: message,
)
empty_search(
browser: browser1,
blur: true,
)
watch_for(

View file

@ -91,16 +91,6 @@ class TestCase < ActiveSupport::TestCase
params = {
profile: profile,
}
if ENV['BROWSER_HEADLESS'].present?
case browser
when 'firefox'
params[:options] = Selenium::WebDriver::Firefox::Options.new
params[:options].add_argument('-headless')
when 'chrome'
params[:options] = Selenium::WebDriver::Chrome::Options.new
params[:options].add_argument('-headless')
end
end
local_browser = Selenium::WebDriver.for(browser.to_sym, params)
@browsers[local_browser.hash] = local_browser
browser_instance_preferences(local_browser)
@ -135,12 +125,24 @@ class TestCase < ActiveSupport::TestCase
open_timeout: 120,
read_timeout: 120
)
case browser
when 'firefox'
options = Selenium::WebDriver::Firefox::Options.new
options.headless!
when 'chrome'
options = Selenium::WebDriver::Chrome::Options.new(
# Disable the "Chrome is controlled by automation software" info bar.
excludeSwitches: ['enable-automation'],
)
options.headless!
end
local_browser = Selenium::WebDriver.for(
:remote,
url: ENV['REMOTE_URL'],
desired_capabilities: caps,
http_client: http_client,
options: options,
)
@browsers[local_browser.hash] = local_browser
browser_instance_preferences(local_browser)