Added browser tests for customer chat.
This commit is contained in:
parent
0cb6e34870
commit
7831f1c1f8
18 changed files with 1418 additions and 566 deletions
|
@ -24,7 +24,7 @@ class App.ChannelChat extends App.Controller
|
|||
'.js-code': 'code'
|
||||
'.js-palette': 'palette'
|
||||
'.js-color': 'colorField'
|
||||
'.js-chatSetting': 'chatSetting'
|
||||
'.js-chatSetting input': 'chatSetting'
|
||||
|
||||
apiOptions: [
|
||||
{
|
||||
|
@ -279,6 +279,8 @@ class App.ChannelChat extends App.Controller
|
|||
setting.state_current = { value: value }
|
||||
setting.save()
|
||||
@Config.set('chat', value)
|
||||
delay = -> App.Event.trigger('ui:rerender')
|
||||
@delay(delay, 200)
|
||||
|
||||
updateParams: =>
|
||||
quote = (value) ->
|
||||
|
|
|
@ -7,7 +7,7 @@ class App.ChannelForm extends App.Controller
|
|||
|
||||
elements:
|
||||
'.js-paramsBlock': 'paramsBlock'
|
||||
'.js-formSetting': 'formSetting'
|
||||
'.js-formSetting input': 'formSetting'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
|
|
@ -11,14 +11,6 @@ class App.CustomerChat extends App.Controller
|
|||
constructor: ->
|
||||
super
|
||||
|
||||
# access check
|
||||
if !@isRole('Chat')
|
||||
@renderScreenUnauthorized(objectName: 'Chat')
|
||||
return
|
||||
if !@Config.get('chat')
|
||||
@renderScreenError(detail: 'Feature disabled!')
|
||||
return
|
||||
|
||||
@chatWindows = {}
|
||||
@maxChatWindows = 4
|
||||
preferences = @Session.get('preferences')
|
||||
|
@ -49,7 +41,6 @@ class App.CustomerChat extends App.Controller
|
|||
|
||||
# add new chat window
|
||||
@bind('chat_session_start', (data) =>
|
||||
console.log('chat_session_start', data)
|
||||
if data.session
|
||||
@addChat(data.session)
|
||||
)
|
||||
|
@ -78,6 +69,13 @@ class App.CustomerChat extends App.Controller
|
|||
)
|
||||
|
||||
render: ->
|
||||
if !@isRole('Chat')
|
||||
@renderScreenUnauthorized(objectName: 'Chat')
|
||||
return
|
||||
if !@Config.get('chat')
|
||||
@renderScreenError(detail: 'Feature disabled!')
|
||||
return
|
||||
|
||||
@html App.view('customer_chat/index')()
|
||||
|
||||
show: (params) =>
|
||||
|
|
|
@ -82,7 +82,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
)
|
||||
|
||||
# bind on switch changes and execute it on controller
|
||||
@$('.js-menu .js-switch').bind('change', (e) ->
|
||||
@$('.js-menu .js-switch input').bind('change', (e) ->
|
||||
val = $(e.target).prop('checked')
|
||||
key = $(e.target).closest('.menu-item').data('key')
|
||||
return if !key
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
<h2><%- @T('Enable') %>/<%- @T('Disable') %></h2>
|
||||
<form>
|
||||
<div class="zammad-switch">
|
||||
<input name="chat" type="checkbox" id="setting-chat" class="js-chatSetting" <% if @chatSetting: %>checked<% end %>>
|
||||
<div class="zammad-switch js-chatSetting">
|
||||
<input name="chat" type="checkbox" id="setting-chat" <% if @chatSetting: %>checked<% end %>>
|
||||
<label for="setting-chat"></label>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
<h2><%- @T('Enable') %>/<%- @T('Disable') %></h2>
|
||||
<form>
|
||||
<div class="zammad-switch">
|
||||
<input name="form_ticket_create" type="checkbox" id="setting-form" class="js-formSetting" <% if @formSetting: %>checked<% end %>>
|
||||
<div class="zammad-switch js-formSetting">
|
||||
<input name="form_ticket_create" type="checkbox" id="setting-form" <% if @formSetting: %>checked<% end %>>
|
||||
<label for="setting-form"></label>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
<span class="counter badge badge--big"><%= item.counter %></span>
|
||||
<% end %>
|
||||
<% if item.switch isnt undefined: %>
|
||||
<span class="zammad-switch zammad-switch--dark zammad-switch--small zammad-switch--green">
|
||||
<input type="checkbox" id="<%- item.class %>-switch" class="js-switch" <% if item.switch: %>checked<% end %>>
|
||||
<span class="zammad-switch zammad-switch--dark zammad-switch--small zammad-switch--green js-switch">
|
||||
<input type="checkbox" id="<%- item.class %>-switch" <% if item.switch: %>checked<% end %>>
|
||||
<label for="<%- item.class %>-switch"></label>
|
||||
</span>
|
||||
<% end %>
|
||||
|
|
|
@ -18,6 +18,18 @@ class Chat::Session < ApplicationModel
|
|||
preferences[:participants]
|
||||
end
|
||||
|
||||
def recipients_active?
|
||||
return true if !preferences
|
||||
return true if !preferences[:participants]
|
||||
count = 0
|
||||
preferences[:participants].each {|client_id|
|
||||
next if !Sessions.session_exists?(client_id)
|
||||
count += 1
|
||||
}
|
||||
return true if count >= 2
|
||||
false
|
||||
end
|
||||
|
||||
def send_to_recipients(message, ignore_client_id = nil)
|
||||
preferences[:participants].each {|local_client_id|
|
||||
next if local_client_id == ignore_client_id
|
||||
|
|
36
app/models/observer/chat/leave/background_job.rb
Normal file
36
app/models/observer/chat/leave/background_job.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
# encoding: utf-8
|
||||
|
||||
class Observer::Chat::Leave::BackgroundJob
|
||||
def initialize(chat_session_id, client_id, session)
|
||||
@chat_session_id = chat_session_id
|
||||
@client_id = client_id
|
||||
@session = session
|
||||
end
|
||||
|
||||
def perform
|
||||
|
||||
# check if customer has permanently left the conversation
|
||||
chat_session = Chat::Session.find_by(id: @chat_session_id)
|
||||
return if !chat_session
|
||||
return if chat_session.recipients_active?
|
||||
chat_session.state = 'closed'
|
||||
chat_session.save
|
||||
|
||||
realname = 'Anonymous'
|
||||
if @session && @session['id']
|
||||
realname = User.lookup(id: @session['id']).fullname
|
||||
end
|
||||
|
||||
# notifiy participients
|
||||
message = {
|
||||
event: 'chat_session_left',
|
||||
data: {
|
||||
realname: realname,
|
||||
session_id: chat_session.session_id,
|
||||
},
|
||||
}
|
||||
chat_session.send_to_recipients(message, @client_id)
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -16,7 +16,11 @@ class Setting < ApplicationModel
|
|||
@@current = {} # rubocop:disable Style/ClassVars
|
||||
@@change_id = nil # rubocop:disable Style/ClassVars
|
||||
@@lookup_at = nil # rubocop:disable Style/ClassVars
|
||||
if ENV['ZAMMAD_SETTING_TTL']
|
||||
@@lookup_timeout = ENV['ZAMMAD_SETTING_TTL'].to_i # rubocop:disable Style/ClassVars
|
||||
else
|
||||
@@lookup_timeout = 2.minutes # rubocop:disable Style/ClassVars
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
|
|
|
@ -5,8 +5,135 @@ do($ = window.jQuery, window) ->
|
|||
scriptHost = myScript.src.match('.*://([^:/]*).*')[1]
|
||||
|
||||
# Define the plugin class
|
||||
class ZammadChat
|
||||
class Base
|
||||
defaults:
|
||||
debug: false
|
||||
|
||||
constructor: (options) ->
|
||||
@options = $.extend {}, @defaults, options
|
||||
@log = new Log(debug: @options.debug, logPrefix: @options.logPrefix || @logPrefix)
|
||||
|
||||
class Log
|
||||
defaults:
|
||||
debug: false
|
||||
|
||||
constructor: (options) ->
|
||||
@options = $.extend {}, @defaults, options
|
||||
|
||||
debug: (items...) =>
|
||||
return if !@options.debug && level is 'debug'
|
||||
@log('debug', items)
|
||||
|
||||
notice: (items...) =>
|
||||
@log('notice', items)
|
||||
|
||||
error: (items...) =>
|
||||
@log('error', items)
|
||||
return if !@options.debug && level is 'debug'
|
||||
items.unshift(level)
|
||||
console.log.apply console, string
|
||||
|
||||
log: (level, items) =>
|
||||
items.unshift('||')
|
||||
items.unshift(level)
|
||||
items.unshift(@options.logPrefix)
|
||||
console.log.apply console, items
|
||||
|
||||
return if !@options.debug
|
||||
logString = ''
|
||||
for item in items
|
||||
logString += ' '
|
||||
if typeof item is 'object'
|
||||
logString += JSON.stringify(item)
|
||||
else if item && item.toString
|
||||
logString += item.toString()
|
||||
else
|
||||
logString += item
|
||||
$('.js-chatLogDisplay').prepend('<div>' + logString + '</div>')
|
||||
|
||||
class Timeout extends Base
|
||||
timeoutStartedAt: null
|
||||
logPrefix: 'timeout'
|
||||
defaults:
|
||||
debug: false
|
||||
timeout: 4
|
||||
timeoutIntervallCheck: 0.5
|
||||
|
||||
constructor: (options) ->
|
||||
super(options)
|
||||
|
||||
start: =>
|
||||
@stop()
|
||||
timeoutStartedAt = new Date
|
||||
check = =>
|
||||
timeLeft = new Date - new Date(timeoutStartedAt.getTime() + @options.timeout * 1000 * 60)
|
||||
@log.debug "Timeout check for #{@options.timeout} minutes (left #{timeLeft/1000} sec.)"#, new Date
|
||||
return if timeLeft < 0
|
||||
@stop()
|
||||
@options.callback()
|
||||
@log.debug "Start timeout in #{@options.timeout} minutes"#, new Date
|
||||
@intervallId = setInterval(check, @options.timeoutIntervallCheck * 1000 * 60)
|
||||
|
||||
stop: =>
|
||||
return if !@intervallId
|
||||
@log.debug "Stop timeout of #{@options.timeout} minutes at"#, new Date
|
||||
clearInterval(@intervallId)
|
||||
|
||||
class Io extends Base
|
||||
logPrefix: 'io'
|
||||
constructor: (options) ->
|
||||
super(options)
|
||||
|
||||
set: (params) =>
|
||||
for key, value of params
|
||||
@options[key] = value
|
||||
|
||||
detectHost: ->
|
||||
protocol = 'ws://'
|
||||
if window.location.protocol is 'https:'
|
||||
protocol = 'wss://'
|
||||
@options.host = "#{ protocol }#{ scriptHost }/ws"
|
||||
|
||||
connect: =>
|
||||
@detectHost() if !@options.host
|
||||
|
||||
@log.debug "Connecting to #{@options.host}"
|
||||
@ws = new window.WebSocket("#{@options.host}")
|
||||
@ws.onopen = (e) =>
|
||||
@log.debug 'on open', e
|
||||
@options.onOpen(e)
|
||||
|
||||
@ws.onmessage = (e) =>
|
||||
pipes = JSON.parse(e.data)
|
||||
@log.debug 'on message', e.data
|
||||
if @options.onMessage
|
||||
@options.onMessage(pipes)
|
||||
|
||||
@ws.onclose = (e) =>
|
||||
@log.debug 'close websocket connection'
|
||||
if @options.onClose
|
||||
@options.onClose(e)
|
||||
|
||||
@ws.onerror = (e) =>
|
||||
@log.debug 'onerror', e
|
||||
if @options.onError
|
||||
@options.onError(e)
|
||||
|
||||
close: =>
|
||||
@ws.close()
|
||||
|
||||
reconnect: =>
|
||||
@ws.close()
|
||||
@connect()
|
||||
|
||||
send: (event, data = {}) =>
|
||||
@log.debug 'send', event, data
|
||||
msg = JSON.stringify
|
||||
event: event
|
||||
data: data
|
||||
@ws.send msg
|
||||
|
||||
class ZammadChat extends Base
|
||||
defaults:
|
||||
chatId: undefined
|
||||
show: true
|
||||
|
@ -21,9 +148,14 @@ do($ = window.jQuery, window) ->
|
|||
buttonClass: 'open-zammad-chat'
|
||||
inactiveClass: 'is-inactive'
|
||||
title: '<strong>Chat</strong> with us!'
|
||||
idleTimeout: 4
|
||||
inactiveTimeout: 20
|
||||
idleTimeout: 8
|
||||
idleTimeoutIntervallCheck: 0.5
|
||||
inactiveTimeout: 8
|
||||
inactiveTimeoutIntervallCheck: 0.5
|
||||
waitingListTimeout: 4
|
||||
waitingListTimeoutIntervallCheck: 0.5
|
||||
|
||||
logPrefix: 'chat'
|
||||
_messageCount: 0
|
||||
isOpen: true
|
||||
blinkOnlineInterval: null
|
||||
|
@ -35,7 +167,6 @@ do($ = window.jQuery, window) ->
|
|||
isTyping: false
|
||||
state: 'offline'
|
||||
initialQueueDelay: 10000
|
||||
wsReconnectEnable: true
|
||||
translations:
|
||||
de:
|
||||
'<strong>Chat</strong> with us!': '<strong>Chat</strong> mit uns!'
|
||||
|
@ -57,22 +188,17 @@ do($ = window.jQuery, window) ->
|
|||
T: (string, items...) =>
|
||||
if @options.lang && @options.lang isnt 'en'
|
||||
if !@translations[@options.lang]
|
||||
@log 'notice', "Translation '#{@options.lang}' needed!"
|
||||
@log.notice "Translation '#{@options.lang}' needed!"
|
||||
else
|
||||
translations = @translations[@options.lang]
|
||||
if !translations[string]
|
||||
@log 'notice', "Translation needed for '#{string}'"
|
||||
@log.notice "Translation needed for '#{string}'"
|
||||
string = translations[string] || string
|
||||
if items
|
||||
for item in items
|
||||
string = string.replace(/%s/, item)
|
||||
string
|
||||
|
||||
log: (level, string...) =>
|
||||
return if !@options.debug && level is 'debug'
|
||||
string.unshift(level)
|
||||
console.log.apply console, string
|
||||
|
||||
view: (name) =>
|
||||
return (options) =>
|
||||
if !options
|
||||
|
@ -86,19 +212,20 @@ do($ = window.jQuery, window) ->
|
|||
|
||||
constructor: (options) ->
|
||||
@options = $.extend {}, @defaults, options
|
||||
super(@options)
|
||||
|
||||
# check prerequisites
|
||||
if !$
|
||||
@state = 'unsupported'
|
||||
@log 'notice', 'Chat: no jquery found!'
|
||||
@log.notice 'Chat: no jquery found!'
|
||||
return
|
||||
if !window.WebSocket or !sessionStorage
|
||||
@state = 'unsupported'
|
||||
@log 'notice', 'Chat: Browser not supported!'
|
||||
@log.notice 'Chat: Browser not supported!'
|
||||
return
|
||||
if !@options.chatId
|
||||
@state = 'unsupported'
|
||||
@log 'error', 'Chat: need chatId as option!'
|
||||
@log.error 'Chat: need chatId as option!'
|
||||
return
|
||||
|
||||
# detect language
|
||||
|
@ -106,8 +233,19 @@ do($ = window.jQuery, window) ->
|
|||
@options.lang = $('html').attr('lang')
|
||||
if @options.lang
|
||||
@options.lang = @options.lang.replace(/-.+?$/, '') # replace "-xx" of xx-xx
|
||||
@log 'debug', "lang: #{@options.lang}"
|
||||
@log.debug "lang: #{@options.lang}"
|
||||
|
||||
@loadCss()
|
||||
|
||||
@io = new Io(@options)
|
||||
@io.set(
|
||||
onOpen: @render
|
||||
onClose: @hide
|
||||
onMessage: @onWebSocketMessage
|
||||
)
|
||||
@io.connect()
|
||||
|
||||
render: =>
|
||||
@el = $(@view('chat')(
|
||||
title: @options.title
|
||||
))
|
||||
|
@ -124,10 +262,20 @@ do($ = window.jQuery, window) ->
|
|||
@input.on
|
||||
keydown: @checkForEnter
|
||||
input: @onInput
|
||||
$(window).on('beforeunload', =>
|
||||
@onLeaveTemporary()
|
||||
)
|
||||
@setAgentOnlineState 'online'
|
||||
|
||||
@wsConnect()
|
||||
@log.debug 'widget rendered'
|
||||
|
||||
@loadCss()
|
||||
@startTimeoutObservers()
|
||||
@idleTimeout.start()
|
||||
|
||||
# get current chat status
|
||||
@sessionId = sessionStorage.getItem('sessionId')
|
||||
@send 'chat_status_customer',
|
||||
session_id: @sessionId
|
||||
|
||||
checkForEnter: (event) =>
|
||||
if not event.shiftKey and event.keyCode is 13
|
||||
|
@ -136,22 +284,16 @@ do($ = window.jQuery, window) ->
|
|||
|
||||
send: (event, data = {}) =>
|
||||
data.chat_id = @options.chatId
|
||||
@log 'debug', 'ws:send', event, data
|
||||
pipe = JSON.stringify
|
||||
event: event
|
||||
data: data
|
||||
@ws.send pipe
|
||||
|
||||
onWebSocketMessage: (e) =>
|
||||
pipes = JSON.parse( e.data )
|
||||
@io.send(event, data)
|
||||
|
||||
onWebSocketMessage: (pipes) =>
|
||||
for pipe in pipes
|
||||
@log 'debug', 'ws:onmessage', pipe
|
||||
@log.debug 'ws:onmessage', pipe
|
||||
switch pipe.event
|
||||
when 'chat_error'
|
||||
@log 'notice', pipe.data
|
||||
@log.notice pipe.data
|
||||
if pipe.data && pipe.data.state is 'chat_disabled'
|
||||
@wsClose()
|
||||
@destroy(hide: true)
|
||||
when 'chat_session_message'
|
||||
return if pipe.data.self_written
|
||||
@receiveMessage pipe.data
|
||||
|
@ -171,38 +313,35 @@ do($ = window.jQuery, window) ->
|
|||
when 'online'
|
||||
@sessionId = undefined
|
||||
@onReady()
|
||||
@log 'debug', 'Zammad Chat: ready'
|
||||
when 'offline'
|
||||
@onError 'Zammad Chat: No agent online'
|
||||
@state = 'off'
|
||||
@hide()
|
||||
@wsClose()
|
||||
@destroy(hide: true)
|
||||
when 'chat_disabled'
|
||||
@onError 'Zammad Chat: Chat is disabled'
|
||||
@state = 'off'
|
||||
@hide()
|
||||
@wsClose()
|
||||
@destroy(hide: true)
|
||||
when 'no_seats_available'
|
||||
@onError "Zammad Chat: Too many clients in queue. Clients in queue: #{pipe.data.queue}"
|
||||
@state = 'off'
|
||||
@hide()
|
||||
@wsClose()
|
||||
@destroy(hide: true)
|
||||
when 'reconnect'
|
||||
@log 'debug', 'old messages', pipe.data.session
|
||||
@log.debug 'old messages', pipe.data.session
|
||||
@reopenSession pipe.data
|
||||
|
||||
onReady: =>
|
||||
@log.debug 'widget ready for use'
|
||||
$(".#{ @options.buttonClass }").click(@open).removeClass(@inactiveClass)
|
||||
|
||||
if @options.show
|
||||
@show()
|
||||
|
||||
onError: (message) =>
|
||||
@log 'debug', message
|
||||
@log.debug message
|
||||
$(".#{ @options.buttonClass }").hide()
|
||||
|
||||
reopenSession: (data) =>
|
||||
@inactiveTimeoutStart()
|
||||
@inactiveTimeout.start()
|
||||
|
||||
unfinishedMessage = sessionStorage.getItem 'unfinished_message'
|
||||
|
||||
|
@ -246,7 +385,7 @@ do($ = window.jQuery, window) ->
|
|||
@isTyping = new Date()
|
||||
@send 'chat_session_typing',
|
||||
session_id: @sessionId
|
||||
@inactiveTimeoutStart()
|
||||
@inactiveTimeout.start()
|
||||
|
||||
onSubmit: (event) =>
|
||||
event.preventDefault()
|
||||
|
@ -256,7 +395,7 @@ do($ = window.jQuery, window) ->
|
|||
message = @input.val()
|
||||
return if !message
|
||||
|
||||
@inactiveTimeoutStart()
|
||||
@inactiveTimeout.start()
|
||||
|
||||
sessionStorage.removeItem 'unfinished_message'
|
||||
|
||||
|
@ -286,7 +425,7 @@ do($ = window.jQuery, window) ->
|
|||
session_id: @sessionId
|
||||
|
||||
receiveMessage: (data) =>
|
||||
@inactiveTimeoutStart()
|
||||
@inactiveTimeout.start()
|
||||
|
||||
# hide writing indicator
|
||||
@onAgentTypingEnd()
|
||||
|
@ -305,6 +444,7 @@ do($ = window.jQuery, window) ->
|
|||
@scrollToBottom()
|
||||
|
||||
open: =>
|
||||
@log.debug 'open widget'
|
||||
if @isOpen
|
||||
@show()
|
||||
|
||||
|
@ -322,12 +462,14 @@ do($ = window.jQuery, window) ->
|
|||
@isOpen = true
|
||||
|
||||
if !@sessionId
|
||||
@sessionInit()
|
||||
@send('chat_session_init')
|
||||
|
||||
onOpenAnimationEnd: =>
|
||||
@idleTimeoutStop()
|
||||
@idleTimeout.stop()
|
||||
|
||||
close: (event) =>
|
||||
@log.debug 'close widget'
|
||||
|
||||
return @state if @state is 'off' or @state is 'unsupported'
|
||||
event.stopPropagation() if event
|
||||
|
||||
|
@ -339,7 +481,8 @@ do($ = window.jQuery, window) ->
|
|||
session_id: @sessionId
|
||||
|
||||
# stop timer
|
||||
@inactiveTimeoutStop()
|
||||
@inactiveTimeout.stop()
|
||||
@waitingListTimeout.stop()
|
||||
|
||||
# delete input store
|
||||
sessionStorage.removeItem 'unfinished_message'
|
||||
|
@ -360,13 +503,19 @@ do($ = window.jQuery, window) ->
|
|||
|
||||
onCloseAnimationEnd: =>
|
||||
@el.removeClass('zammad-chat-is-visible')
|
||||
@disconnect()
|
||||
|
||||
@showLoader()
|
||||
@el.find('.zammad-chat-welcome').removeClass('zammad-chat-is-hidden')
|
||||
@el.find('.zammad-chat-agent').addClass('zammad-chat-is-hidden')
|
||||
@el.find('.zammad-chat-agent-status').addClass('zammad-chat-is-hidden')
|
||||
|
||||
@isOpen = false
|
||||
|
||||
# restart connection
|
||||
@onWebSocketOpen()
|
||||
@io.reconnect()
|
||||
|
||||
hide: ->
|
||||
if @el
|
||||
@el.removeClass('zammad-chat-is-shown')
|
||||
|
||||
show: ->
|
||||
|
@ -397,6 +546,9 @@ do($ = window.jQuery, window) ->
|
|||
# delay initial queue position, show connecting first
|
||||
show = =>
|
||||
@onQueue data
|
||||
console.log('onQueueScreen')
|
||||
@waitingListTimeout.start()
|
||||
|
||||
if @initialQueueDelay && !@onInitialQueueDelayId
|
||||
@onInitialQueueDelayId = setTimeout(show, @initialQueueDelay)
|
||||
return
|
||||
|
@ -409,7 +561,7 @@ do($ = window.jQuery, window) ->
|
|||
show()
|
||||
|
||||
onQueue: (data) =>
|
||||
@log 'notice', 'onQueue', data.position
|
||||
@log.notice 'onQueue', data.position
|
||||
@inQueue = true
|
||||
|
||||
@el.find('.zammad-chat-body').html @view('waiting')
|
||||
|
@ -432,6 +584,11 @@ do($ = window.jQuery, window) ->
|
|||
onAgentTypingEnd: =>
|
||||
@el.find('.zammad-chat-message--typing').remove()
|
||||
|
||||
onLeaveTemporary: =>
|
||||
return if !@sessionId
|
||||
@send 'chat_session_leave_temporary',
|
||||
session_id: @sessionId
|
||||
|
||||
maybeAddTimestamp: ->
|
||||
timestamp = Date.now()
|
||||
|
||||
|
@ -470,59 +627,38 @@ do($ = window.jQuery, window) ->
|
|||
scrollToBottom: ->
|
||||
@el.find('.zammad-chat-body').scrollTop($('.zammad-chat-body').prop('scrollHeight'))
|
||||
|
||||
sessionInit: ->
|
||||
@send('chat_session_init')
|
||||
|
||||
detectHost: ->
|
||||
protocol = 'ws://'
|
||||
if window.location.protocol is 'https:'
|
||||
protocol = 'wss://'
|
||||
@options.host = "#{ protocol }#{ scriptHost }/ws"
|
||||
|
||||
wsConnect: =>
|
||||
@detectHost() if !@options.host
|
||||
destroy: (params = {}) =>
|
||||
@log.debug 'destroy widget'
|
||||
console.log('el', @el)
|
||||
if params.hide
|
||||
if @el
|
||||
@el.remove()
|
||||
@wsReconnectStop()
|
||||
@io.close()
|
||||
|
||||
@log 'debug', "Connecting to #{@options.host}"
|
||||
@ws = new window.WebSocket("#{@options.host}")
|
||||
@ws.onopen = @onWebSocketOpen
|
||||
|
||||
@ws.onmessage = @onWebSocketMessage
|
||||
|
||||
@ws.onclose = (e) =>
|
||||
@log 'debug', 'close websocket connection'
|
||||
if @wsReconnectEnable
|
||||
@reconnect()
|
||||
|
||||
@ws.onerror = (e) =>
|
||||
@log 'debug', 'ws:onerror', e
|
||||
|
||||
wsClose: =>
|
||||
@wsReconnectEnable = false
|
||||
@ws.close()
|
||||
|
||||
wsReconnect: =>
|
||||
wsReconnectStart: =>
|
||||
@wsReconnectStop()
|
||||
if @reconnectDelayId
|
||||
clearTimeout(@reconnectDelayId)
|
||||
@reconnectDelayId = setTimeout(@wsConnect, 5000)
|
||||
@reconnectDelayId = setTimeout(@io.connect(), 5000)
|
||||
|
||||
onWebSocketOpen: =>
|
||||
@idleTimeoutStart()
|
||||
@sessionId = sessionStorage.getItem('sessionId')
|
||||
@log 'debug', 'ws connected'
|
||||
|
||||
@send 'chat_status_customer',
|
||||
session_id: @sessionId
|
||||
|
||||
@setAgentOnlineState 'online'
|
||||
wsReconnectStop: =>
|
||||
if @reconnectDelayId
|
||||
clearTimeout(@reconnectDelayId)
|
||||
|
||||
reconnect: =>
|
||||
# set status to connecting
|
||||
@log 'notice', 'reconnecting'
|
||||
@log.notice 'reconnecting'
|
||||
@disableInput()
|
||||
@lastAddedType = 'status'
|
||||
@setAgentOnlineState 'connecting'
|
||||
@addStatus @T('Connection lost')
|
||||
@wsReconnect()
|
||||
|
||||
onConnectionReestablished: =>
|
||||
# set status back to online
|
||||
|
@ -534,13 +670,7 @@ do($ = window.jQuery, window) ->
|
|||
@addStatus @T('Chat closed by %s', data.realname)
|
||||
@disableInput()
|
||||
@setAgentOnlineState 'offline'
|
||||
@inactiveTimeoutStop()
|
||||
|
||||
disconnect: ->
|
||||
@showLoader()
|
||||
@el.find('.zammad-chat-welcome').removeClass('zammad-chat-is-hidden')
|
||||
@el.find('.zammad-chat-agent').addClass('zammad-chat-is-hidden')
|
||||
@el.find('.zammad-chat-agent-status').addClass('zammad-chat-is-hidden')
|
||||
@inactiveTimeout.stop()
|
||||
|
||||
setSessionId: (id) =>
|
||||
@sessionId = id
|
||||
|
@ -573,8 +703,12 @@ do($ = window.jQuery, window) ->
|
|||
|
||||
@setAgentOnlineState 'online'
|
||||
|
||||
showTimeout: ->
|
||||
@el.find('.zammad-chat-body').html @view('timeout')
|
||||
@waitingListTimeout.stop()
|
||||
@idleTimeout.stop()
|
||||
@inactiveTimeout.start()
|
||||
|
||||
showCustomerTimeout: ->
|
||||
@el.find('.zammad-chat-body').html @view('customer_timeout')
|
||||
agent: @agent.name
|
||||
delay: @options.inactiveTimeout
|
||||
@close()
|
||||
|
@ -582,6 +716,14 @@ do($ = window.jQuery, window) ->
|
|||
location.reload()
|
||||
@el.find('.js-restart').click reload
|
||||
|
||||
showWaitingListTimeout: ->
|
||||
@el.find('.zammad-chat-body').html @view('waiting_list_timeout')
|
||||
delay: @options.watingListTimeout
|
||||
@close()
|
||||
reload = ->
|
||||
location.reload()
|
||||
@el.find('.js-restart').click reload
|
||||
|
||||
showLoader: ->
|
||||
@el.find('.zammad-chat-body').html @view('loader')()
|
||||
|
||||
|
@ -603,42 +745,47 @@ do($ = window.jQuery, window) ->
|
|||
.replace(/\/ws/i, '')
|
||||
url += '/assets/chat/chat.css'
|
||||
|
||||
@log 'debug', "load css from '#{url}'"
|
||||
@log.debug "load css from '#{url}'"
|
||||
styles = "@import url('#{url}');"
|
||||
newSS = document.createElement('link')
|
||||
newSS.rel = 'stylesheet'
|
||||
newSS.href = 'data:text/css,' + escape(styles)
|
||||
document.getElementsByTagName('head')[0].appendChild(newSS)
|
||||
|
||||
inactiveTimeoutStart: =>
|
||||
@inactiveTimeoutStop()
|
||||
delay = =>
|
||||
@log 'debug', "Inactive timeout of #{@options.inactiveTimeout} minutes, show timeout screen.", new Date
|
||||
startTimeoutObservers: =>
|
||||
@idleTimeout = new Timeout(
|
||||
logPrefix: 'idleTimeout'
|
||||
debug: @options.debug
|
||||
timeout: @options.idleTimeout
|
||||
timeoutIntervallCheck: @options.idleTimeoutIntervallCheck
|
||||
callback: =>
|
||||
@log.debug 'Idle timeout reached, hide widget', new Date
|
||||
@state = 'off'
|
||||
@destroy(hide: true)
|
||||
)
|
||||
@inactiveTimeout = new Timeout(
|
||||
logPrefix: 'inactiveTimeout'
|
||||
debug: @options.debug
|
||||
timeout: @options.inactiveTimeout
|
||||
timeoutIntervallCheck: @options.inactiveTimeoutIntervallCheck
|
||||
callback: =>
|
||||
@log.debug 'Inactive timeout reached, show timeout screen.', new Date
|
||||
@state = 'off'
|
||||
@setAgentOnlineState 'offline'
|
||||
@showTimeout()
|
||||
@wsClose()
|
||||
@log 'debug', "Start inactive timeout in #{@options.inactiveTimeout} minutes", new Date
|
||||
@inactiveTimeoutStopDelayId = setTimeout(delay, @options.inactiveTimeout * 1000 * 60)
|
||||
|
||||
inactiveTimeoutStop: =>
|
||||
return if !@inactiveTimeoutStopDelayId
|
||||
@log 'debug', "Stop inactive timeout of #{@options.inactiveTimeout} minutes at", new Date
|
||||
clearTimeout(@inactiveTimeoutStopDelayId)
|
||||
|
||||
idleTimeoutStart: =>
|
||||
@idleTimeoutStop()
|
||||
delay = =>
|
||||
@log 'debug', "Idle timeout of #{@options.idleTimeout} minutes, hide widget", new Date
|
||||
@showCustomerTimeout()
|
||||
@destroy(hide:false)
|
||||
)
|
||||
@waitingListTimeout = new Timeout(
|
||||
logPrefix: 'waitingListTimeout'
|
||||
debug: @options.debug
|
||||
timeout: @options.waitingListTimeout
|
||||
timeoutIntervallCheck: @options.waitingListTimeoutIntervallCheck
|
||||
callback: =>
|
||||
@log.debug 'Waiting list timeout reached, show timeout screen.', new Date
|
||||
@state = 'off'
|
||||
@hide()
|
||||
@wsClose()
|
||||
@log 'debug', "Start idle timeout in #{@options.idleTimeout} minutes", new Date
|
||||
@idleTimeoutStopDelayId = setTimeout(delay, @options.idleTimeout * 1000 * 60)
|
||||
|
||||
idleTimeoutStop: =>
|
||||
return if !@idleTimeoutStopDelayId
|
||||
@log 'debug', "Stop idle timeout of #{@options.idleTimeout} minutes at", new Date
|
||||
clearTimeout(@idleTimeoutStopDelayId)
|
||||
@setAgentOnlineState 'offline'
|
||||
@showWaitingListTimeout()
|
||||
@destroy(hide:false)
|
||||
)
|
||||
|
||||
window.ZammadChat = ZammadChat
|
||||
|
|
File diff suppressed because it is too large
Load diff
3
public/assets/chat/chat.min.js
vendored
3
public/assets/chat/chat.min.js
vendored
File diff suppressed because one or more lines are too long
7
public/assets/chat/views/waiting_list_timeout.eco
Normal file
7
public/assets/chat/views/waiting_list_timeout.eco
Normal file
|
@ -0,0 +1,7 @@
|
|||
<div class="zammad-chat-modal">
|
||||
<div class="zammad-chat-modal-text">
|
||||
<%- @T('We are sorry, it takes longer as expected to get an empty slot. Please try again later or send us an email. Thank you!') %>
|
||||
<br>
|
||||
<div class="zammad-chat-button js-restart"<%= " style='background: #{ @background }'" if @background %>><%- @T('Start new conversation') %></div>
|
||||
</div>
|
||||
</div>
|
|
@ -25,6 +25,7 @@
|
|||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 3px 10px rgba(0,0,0,.3);
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.settings input {
|
||||
|
@ -39,6 +40,12 @@
|
|||
padding-right: 0;
|
||||
}
|
||||
|
||||
table td.log {
|
||||
text-align: left;
|
||||
padding-right: 0;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 5px;
|
||||
}
|
||||
|
@ -73,8 +80,8 @@
|
|||
<div class="settings">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<td><h2>Settings</h2>
|
||||
<td>
|
||||
<tr>
|
||||
<td>
|
||||
<input id="flat" type="checkbox" data-option="flat">
|
||||
|
@ -100,6 +107,11 @@
|
|||
<tr>
|
||||
<td>
|
||||
<td><button class="open-zammad-chat">Open Chat</button>
|
||||
<tr>
|
||||
<td class="log"><h2>Log</h2>
|
||||
<td>
|
||||
<tr>
|
||||
<td colspan="2" class="log js-chatLogDisplay">
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
@ -113,7 +125,13 @@
|
|||
debug: true,
|
||||
background: '#494d52',
|
||||
flat: true,
|
||||
shown: false
|
||||
shown: false,
|
||||
idleTimeout: 1,
|
||||
idleTimeoutIntervallCheck: 0.5,
|
||||
inactiveTimeout: 2,
|
||||
inactiveTimeoutIntervallCheck: 0.5,
|
||||
waitingListTimeout: 1.2,
|
||||
waitingListTimeoutIntervallCheck: 0.5,
|
||||
});
|
||||
|
||||
$('.settings :input').on({
|
||||
|
|
|
@ -257,6 +257,7 @@ EventMachine.run {
|
|||
}
|
||||
|
||||
elsif data['event']
|
||||
log 'notice', "execute event '#{data['event']}'", client_id
|
||||
message = Sessions::Event.run(data['event'], data, @clients[client_id][:session], client_id)
|
||||
if message
|
||||
websocket_send(client_id, message)
|
||||
|
|
|
@ -1,128 +1,428 @@
|
|||
# encoding: utf-8
|
||||
# rubocop:disable all
|
||||
require 'browser_test_helper'
|
||||
|
||||
class ChatTest < TestCase
|
||||
def test_websocket
|
||||
return # TODO: temp disable
|
||||
message = 'message 1äöüß ' + rand(99_999_999_999_999_999).to_s
|
||||
tests = [
|
||||
{
|
||||
name: 'start',
|
||||
instance1: browser_instance,
|
||||
instance2: browser_instance,
|
||||
instance1_username: 'master@example.com',
|
||||
instance1_password: 'test',
|
||||
instance2_username: 'agent1@example.com',
|
||||
instance2_password: 'test',
|
||||
|
||||
def test_basic
|
||||
agent = browser_instance
|
||||
login(
|
||||
browser: agent,
|
||||
username: 'master@example.com',
|
||||
password: 'test',
|
||||
url: browser_url,
|
||||
action: [
|
||||
{
|
||||
where: :instance1,
|
||||
execute: 'check',
|
||||
css: '#login',
|
||||
result: false,
|
||||
},
|
||||
{
|
||||
where: :instance2,
|
||||
execute: 'check',
|
||||
css: '#login',
|
||||
result: false,
|
||||
},
|
||||
{
|
||||
execute: 'wait',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
where: :instance1,
|
||||
execute: 'click',
|
||||
css: '#chat_toogle',
|
||||
},
|
||||
{
|
||||
execute: 'wait',
|
||||
value: 8,
|
||||
},
|
||||
{
|
||||
where: :instance1,
|
||||
execute: 'click',
|
||||
css: '#chat_toogle',
|
||||
},
|
||||
{
|
||||
execute: 'wait',
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
where: :instance2,
|
||||
execute: 'click',
|
||||
css: '#chat_toogle',
|
||||
},
|
||||
{
|
||||
where: :instance1,
|
||||
execute: 'click',
|
||||
css: '#chat_toogle',
|
||||
},
|
||||
{
|
||||
execute: 'wait',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
where: :instance1,
|
||||
execute: 'set',
|
||||
css: 'input[name="chat_message"]',
|
||||
value: message,
|
||||
},
|
||||
{
|
||||
where: :instance1,
|
||||
execute: 'send_key',
|
||||
css: 'input[name="chat_message"]',
|
||||
value: :enter,
|
||||
},
|
||||
{
|
||||
execute: 'wait',
|
||||
value: 6,
|
||||
},
|
||||
{
|
||||
where: :instance1,
|
||||
execute: 'match',
|
||||
css: '#chat_log_container',
|
||||
value: message,
|
||||
match_result: true,
|
||||
},
|
||||
{
|
||||
where: :instance2,
|
||||
execute: 'match',
|
||||
css: '#chat_log_container',
|
||||
value: message,
|
||||
match_result: true,
|
||||
},
|
||||
{
|
||||
where: :instance1,
|
||||
execute: 'navigate',
|
||||
to: browser_url,
|
||||
},
|
||||
{
|
||||
execute: 'wait',
|
||||
value: 8,
|
||||
},
|
||||
{
|
||||
where: :instance1,
|
||||
execute: 'click',
|
||||
css: '#chat_toogle',
|
||||
},
|
||||
{
|
||||
execute: 'wait',
|
||||
value: 8,
|
||||
},
|
||||
{
|
||||
where: :instance1,
|
||||
execute: 'match',
|
||||
css: '#chat_log_container',
|
||||
value: message,
|
||||
match_result: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
browser_double_test(tests)
|
||||
)
|
||||
tasks_close_all(
|
||||
browser: agent,
|
||||
)
|
||||
|
||||
# disable chat
|
||||
click(
|
||||
browser: agent,
|
||||
css: 'a[href="#manage"]',
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: 'a[href="#channels/chat"]',
|
||||
)
|
||||
switch(
|
||||
browser: agent,
|
||||
css: '#content .js-chatSetting',
|
||||
type: 'off',
|
||||
)
|
||||
sleep 25 # wait for rerendering
|
||||
click(
|
||||
browser: agent,
|
||||
css: 'a[href="#customer_chat"]',
|
||||
)
|
||||
match(
|
||||
browser: agent,
|
||||
css: '.active.content',
|
||||
value: 'disabled',
|
||||
)
|
||||
|
||||
customer = browser_instance
|
||||
location(
|
||||
browser: customer,
|
||||
url: "#{browser_url}/assets/chat/znuny.html",
|
||||
)
|
||||
sleep 4
|
||||
exists_not(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
)
|
||||
match(
|
||||
browser: customer,
|
||||
css: '.settings',
|
||||
value: '{"state":"chat_disabled"}',
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: 'a[href="#manage"]',
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: 'a[href="#channels/chat"]',
|
||||
)
|
||||
switch(
|
||||
browser: agent,
|
||||
css: '#content .js-chatSetting',
|
||||
type: 'on',
|
||||
)
|
||||
sleep 15 # wait for rerendering
|
||||
switch(
|
||||
browser: agent,
|
||||
css: '#navigation .js-switch',
|
||||
type: 'off',
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: 'a[href="#customer_chat"]',
|
||||
wait: 2,
|
||||
)
|
||||
match_not(
|
||||
browser: agent,
|
||||
css: '.active.content',
|
||||
value: 'disabled',
|
||||
)
|
||||
|
||||
reload(
|
||||
browser: customer,
|
||||
)
|
||||
sleep 4
|
||||
exists_not(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
)
|
||||
match_not(
|
||||
browser: customer,
|
||||
css: '.settings',
|
||||
value: '{"state":"chat_disabled"}',
|
||||
)
|
||||
match(
|
||||
browser: customer,
|
||||
css: '.settings',
|
||||
value: '{"event":"chat_status_customer","data":{"state":"offline"}}',
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: 'a[href="#customer_chat"]',
|
||||
)
|
||||
switch(
|
||||
browser: agent,
|
||||
css: '#navigation .js-switch',
|
||||
type: 'on',
|
||||
)
|
||||
reload(
|
||||
browser: customer,
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
timeout: 5,
|
||||
)
|
||||
match_not(
|
||||
browser: customer,
|
||||
css: '.settings',
|
||||
value: '{"state":"chat_disabled"}',
|
||||
)
|
||||
match_not(
|
||||
browser: customer,
|
||||
css: '.settings',
|
||||
value: '{"event":"chat_status_customer","data":{"state":"offline"}}',
|
||||
)
|
||||
match(
|
||||
browser: customer,
|
||||
css: '.settings',
|
||||
value: '"data":{"state":"online"}',
|
||||
)
|
||||
|
||||
# init chat
|
||||
click(
|
||||
browser: customer,
|
||||
css: '.js-chat-open',
|
||||
)
|
||||
exists(
|
||||
browser: customer,
|
||||
css: '.zammad-chat-is-shown',
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
value: '(waiting|warte)',
|
||||
)
|
||||
watch_for(
|
||||
browser: agent,
|
||||
css: '.js-chatMenuItem .counter',
|
||||
value: '1',
|
||||
)
|
||||
click(
|
||||
browser: customer,
|
||||
css: '.js-chat-close',
|
||||
)
|
||||
watch_for_disappear(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
value: '(waiting|warte)',
|
||||
)
|
||||
watch_for_disappear(
|
||||
browser: agent,
|
||||
css: '.js-chatMenuItem .counter',
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def test_basic_usecase1
|
||||
agent = browser_instance
|
||||
login(
|
||||
browser: agent,
|
||||
username: 'master@example.com',
|
||||
password: 'test',
|
||||
url: browser_url,
|
||||
)
|
||||
tasks_close_all(
|
||||
browser: agent,
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: 'a[href="#customer_chat"]',
|
||||
)
|
||||
agent.find_elements( { css: '.active .chat-window .js-close' } ).each(&:click)
|
||||
|
||||
customer = browser_instance
|
||||
location(
|
||||
browser: customer,
|
||||
url: "#{browser_url}/assets/chat/znuny.html",
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
timeout: 5,
|
||||
)
|
||||
click(
|
||||
browser: customer,
|
||||
css: '.js-chat-open',
|
||||
)
|
||||
exists(
|
||||
browser: customer,
|
||||
css: '.zammad-chat-is-shown',
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
value: '(waiting|warte)',
|
||||
)
|
||||
|
||||
click(
|
||||
browser: agent,
|
||||
css: '.active .js-acceptChat',
|
||||
)
|
||||
sleep 2
|
||||
exists_not(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .chat-status.is-modified',
|
||||
)
|
||||
set(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .js-customerChatInput',
|
||||
value: 'my name is me',
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .js-send',
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat .zammad-chat-agent-status',
|
||||
value: 'online',
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
value: 'my name is me',
|
||||
)
|
||||
set(
|
||||
browser: customer,
|
||||
css: '.zammad-chat .zammad-chat-input',
|
||||
value: 'my name is customer',
|
||||
)
|
||||
click(
|
||||
browser: customer,
|
||||
css: '.zammad-chat .zammad-chat-send',
|
||||
)
|
||||
watch_for(
|
||||
browser: agent,
|
||||
css: '.active .chat-window',
|
||||
value: 'my name is customer',
|
||||
)
|
||||
exists(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .chat-status.is-modified',
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .js-customerChatInput',
|
||||
)
|
||||
exists_not(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .chat-status.is-modified',
|
||||
)
|
||||
click(
|
||||
browser: customer,
|
||||
css: '.js-chat-close',
|
||||
)
|
||||
watch_for(
|
||||
browser: agent,
|
||||
css: '.active .chat-window',
|
||||
value: 'has left the conversation',
|
||||
)
|
||||
end
|
||||
|
||||
def test_basic_usecase2
|
||||
agent = browser_instance
|
||||
login(
|
||||
browser: agent,
|
||||
username: 'master@example.com',
|
||||
password: 'test',
|
||||
url: browser_url,
|
||||
)
|
||||
tasks_close_all(
|
||||
browser: agent,
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: 'a[href="#customer_chat"]',
|
||||
)
|
||||
agent.find_elements( { css: '.active .chat-window .js-close' } ).each(&:click)
|
||||
|
||||
customer = browser_instance
|
||||
location(
|
||||
browser: customer,
|
||||
url: "#{browser_url}/assets/chat/znuny.html",
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
timeout: 5,
|
||||
)
|
||||
click(
|
||||
browser: customer,
|
||||
css: '.js-chat-open',
|
||||
)
|
||||
exists(
|
||||
browser: customer,
|
||||
css: '.zammad-chat-is-shown',
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
value: '(waiting|warte)',
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: '.active .js-acceptChat',
|
||||
)
|
||||
sleep 2
|
||||
exists_not(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .chat-status.is-modified',
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat .zammad-chat-agent-status',
|
||||
value: 'online',
|
||||
)
|
||||
set(
|
||||
browser: customer,
|
||||
css: '.zammad-chat .zammad-chat-input',
|
||||
value: 'my name is customer',
|
||||
)
|
||||
click(
|
||||
browser: customer,
|
||||
css: '.zammad-chat .zammad-chat-send',
|
||||
)
|
||||
watch_for(
|
||||
browser: agent,
|
||||
css: '.active .chat-window',
|
||||
value: 'my name is customer',
|
||||
)
|
||||
exists(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .chat-status.is-modified',
|
||||
)
|
||||
set(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .js-customerChatInput',
|
||||
value: 'my name is me',
|
||||
)
|
||||
exists_not(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .chat-status.is-modified',
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .js-send',
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
value: 'my name is me',
|
||||
)
|
||||
click(
|
||||
browser: agent,
|
||||
css: '.active .chat-window .js-close',
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat .zammad-chat-agent-status',
|
||||
value: 'offline',
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
value: 'Chat closed by',
|
||||
)
|
||||
end
|
||||
|
||||
def test_timeouts
|
||||
customer = browser_instance
|
||||
location(
|
||||
browser: customer,
|
||||
url: "#{browser_url}/assets/chat/znuny.html",
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
timeout: 5,
|
||||
)
|
||||
watch_for_disappear(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
timeout: 75,
|
||||
)
|
||||
reload(
|
||||
browser: customer,
|
||||
)
|
||||
exists(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
)
|
||||
click(
|
||||
browser: customer,
|
||||
css: '.js-chat-open',
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
value: '(waiting|warte)',
|
||||
timeout: 35,
|
||||
)
|
||||
watch_for(
|
||||
browser: customer,
|
||||
css: '.zammad-chat',
|
||||
value: '(takes longer|dauert länger)',
|
||||
timeout: 90,
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue