browser_test_helper.rb 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147
  1. ENV['RAILS_ENV'] = 'test'
  2. # rubocop:disable HandleExceptions, ClassVars, NonLocalExitFromIterator
  3. require File.expand_path('../../config/environment', __FILE__)
  4. require 'selenium-webdriver'
  5. class TestCase < Test::Unit::TestCase
  6. @@debug = true
  7. def browser
  8. ENV['BROWSER'] || 'firefox'
  9. end
  10. def profile
  11. browser_profile = nil
  12. if browser == 'firefox'
  13. browser_profile = Selenium::WebDriver::Firefox::Profile.new
  14. browser_profile['intl.locale.matchOS'] = false
  15. browser_profile['intl.accept_languages'] = 'en-US'
  16. browser_profile['general.useragent.locale'] = 'en-US'
  17. elsif browser == 'chrome'
  18. # profile are only working on remote selenium
  19. if ENV['REMOTE_URL']
  20. browser_profile = Selenium::WebDriver::Chrome::Profile.new
  21. browser_profile['intl.accept_languages'] = 'en'
  22. end
  23. end
  24. browser_profile
  25. end
  26. def browser_support_cookies
  27. if browser =~ /(internet_explorer|ie)/i
  28. return false
  29. end
  30. true
  31. end
  32. def browser_url
  33. ENV['BROWSER_URL'] || 'http://localhost:3000'
  34. end
  35. def browser_instance
  36. if !@browsers
  37. @browsers = {}
  38. end
  39. if !ENV['REMOTE_URL'] || ENV['REMOTE_URL'].empty?
  40. local_browser = Selenium::WebDriver.for(browser.to_sym, profile: profile)
  41. @browsers[local_browser.hash] = local_browser
  42. browser_instance_preferences(local_browser)
  43. return local_browser
  44. end
  45. caps = Selenium::WebDriver::Remote::Capabilities.send(browser)
  46. if ENV['BROWSER_OS']
  47. caps.platform = ENV['BROWSER_OS']
  48. end
  49. if ENV['BROWSER_VERSION']
  50. caps.version = ENV['BROWSER_VERSION']
  51. end
  52. local_browser = Selenium::WebDriver.for(
  53. :remote,
  54. url: ENV['REMOTE_URL'],
  55. desired_capabilities: caps,
  56. )
  57. @browsers[local_browser.hash] = local_browser
  58. # avoid "Cannot read property 'get_Current' of undefined" issues
  59. begin
  60. browser_instance_preferences(local_browser)
  61. rescue
  62. # just try again
  63. sleep 10
  64. browser_instance_preferences(local_browser)
  65. end
  66. # upload files from remote dir
  67. local_browser.file_detector = lambda do |args|
  68. str = args.first.to_s
  69. str if File.file?(str)
  70. end
  71. local_browser
  72. end
  73. def browser_instance_close(local_browser)
  74. return if !@browsers[local_browser.hash]
  75. @browsers.delete(local_browser.hash)
  76. local_browser.quit
  77. end
  78. def browser_instance_preferences(local_browser)
  79. local_browser.manage.window.resize_to(1024, 800)
  80. if ENV['REMOTE_URL'] !~ /saucelabs|(grid|ci)\.(zammad\.org|znuny\.com)/i
  81. if @browsers.count == 1
  82. local_browser.manage.window.move_to(0, 0)
  83. else
  84. local_browser.manage.window.move_to(1024, 0)
  85. end
  86. end
  87. local_browser.manage.timeouts.implicit_wait = 3 # seconds
  88. end
  89. def teardown
  90. return if !@browsers
  91. @browsers.each { |_hash, local_browser|
  92. screenshot(browser: local_browser, comment: 'teardown')
  93. browser_instance_close(local_browser)
  94. }
  95. end
  96. def screenshot(params)
  97. instance = params[:browser] || @browser
  98. comment = params[:comment] || ''
  99. filename = "tmp/#{Time.zone.now.strftime('screenshot_%Y_%m_%d__%H_%M_%S')}_#{comment}_#{instance.hash}.png"
  100. log('screenshot', { filename: filename })
  101. instance.save_screenshot(filename)
  102. end
  103. =begin
  104. username = login(
  105. browser: browser1,
  106. username: 'someuser',
  107. password: 'somepassword',
  108. url: 'some url', # optional
  109. remember_me: true, # optional
  110. auto_wizard: false, # optional, in case of auto wizard, skip login
  111. )
  112. =end
  113. def login(params)
  114. switch_window_focus(params)
  115. log('login', params)
  116. instance = params[:browser] || @browser
  117. if params[:url]
  118. instance.get(params[:url])
  119. end
  120. element = instance.find_elements({ css: '#login input[name="username"]' })[0]
  121. if !element
  122. if params[:auto_wizard]
  123. watch_for(
  124. browser: instance,
  125. css: 'body',
  126. value: 'auto wizard is enabled',
  127. timeout: 10,
  128. )
  129. location( url: "#{browser_url}/#getting_started/auto_wizard" )
  130. sleep 10
  131. login = instance.find_elements({ css: '.user-menu .user a' })[0].attribute('title')
  132. if login != params[:username]
  133. screenshot(browser: instance, comment: 'auto wizard login failed')
  134. fail 'auto wizard login failed'
  135. end
  136. assert(true, 'auto wizard login ok')
  137. clues_close(
  138. browser: instance,
  139. optional: true,
  140. )
  141. return
  142. end
  143. screenshot(browser: instance, comment: 'login_failed')
  144. fail 'No login box found'
  145. end
  146. screenshot(browser: instance, comment: 'login')
  147. element.clear
  148. element.send_keys(params[:username])
  149. element = instance.find_elements({ css: '#login input[name="password"]' })[0]
  150. element.clear
  151. element.send_keys(params[:password])
  152. if params[:remember_me]
  153. instance.find_elements({ css: '#login .checkbox-replacement' })[0].click
  154. end
  155. instance.find_elements({ css: '#login button' })[0].click
  156. sleep 5
  157. login = instance.find_elements({ css: '.user-menu .user a' })[0].attribute('title')
  158. if login != params[:username]
  159. screenshot(browser: instance, comment: 'login_failed')
  160. fail 'login failed'
  161. end
  162. clues_close(
  163. browser: instance,
  164. optional: true,
  165. )
  166. screenshot(browser: instance, comment: 'login_ok')
  167. assert(true, 'login ok')
  168. login
  169. end
  170. =begin
  171. logout(
  172. browser: browser1
  173. )
  174. =end
  175. def logout(params = {})
  176. switch_window_focus(params)
  177. log('logout', params)
  178. instance = params[:browser] || @browser
  179. instance.find_elements({ css: 'a[href="#current_user"]' })[0].click
  180. sleep 0.1
  181. instance.find_elements({ css: 'a[href="#logout"]' })[0].click
  182. (1..6).each {
  183. sleep 1
  184. login = instance.find_elements({ css: '#login' })[0]
  185. next if !login
  186. screenshot(browser: instance, comment: 'logout_ok')
  187. assert(true, 'logout ok')
  188. return
  189. }
  190. screenshot(browser: instance, comment: 'logout_failed')
  191. fail 'no login box found, seems logout was not successfully!'
  192. end
  193. =begin
  194. clues_close(
  195. browser: browser1,
  196. optional: false,
  197. )
  198. =end
  199. def clues_close(params = {})
  200. switch_window_focus(params)
  201. log('clues_close', params)
  202. instance = params[:browser] || @browser
  203. clues = instance.find_elements({ css: '.js-modal--clue .js-close' })[0]
  204. if !params[:optional] && !clues
  205. screenshot(browser: instance, comment: 'no_clues')
  206. fail 'Unable to closes clues, no clues found!'
  207. end
  208. return if !clues
  209. instance.execute_script("$('.js-modal--clue .js-close').click()")
  210. assert(true, 'clues closed')
  211. sleep 4
  212. end
  213. =begin
  214. location(
  215. browser: browser1,
  216. url: 'http://someurl',
  217. )
  218. =end
  219. def location(params)
  220. switch_window_focus(params)
  221. log('location', params)
  222. instance = params[:browser] || @browser
  223. instance.get(params[:url])
  224. # check if reload was successfull
  225. if !instance.find_elements({ css: 'body' })[0] || instance.find_elements({ css: 'body' })[0].text =~ /unavailable or too busy/i
  226. instance.navigate.refresh
  227. end
  228. screenshot(browser: instance, comment: 'location')
  229. end
  230. =begin
  231. location_check(
  232. browser: browser1,
  233. url: 'http://someurl',
  234. )
  235. =end
  236. def location_check(params)
  237. switch_window_focus(params)
  238. log('location_check', params)
  239. instance = params[:browser] || @browser
  240. if instance.current_url !~ /#{Regexp.quote(params[:url])}/
  241. screenshot(browser: instance, comment: 'location_check_failed')
  242. fail "url #{instance.current_url} is not matching #{params[:url]}"
  243. end
  244. assert(true, "url #{instance.current_url} is matching #{params[:url]}")
  245. end
  246. =begin
  247. reload(
  248. browser: browser1,
  249. )
  250. =end
  251. def reload(params = {})
  252. switch_window_focus(params)
  253. log('reload', params)
  254. instance = params[:browser] || @browser
  255. screenshot(browser: instance, comment: 'reload_before')
  256. instance.navigate.refresh
  257. # check if reload was successfull
  258. if !instance.find_elements({ css: 'body' })[0] || instance.find_elements({ css: 'body' })[0].text =~ /unavailable or too busy/i
  259. instance.navigate.refresh
  260. end
  261. screenshot(browser: instance, comment: 'reload_after')
  262. end
  263. =begin
  264. click(
  265. browser: browser1,
  266. css: '.some_class',
  267. fast: false, # do not wait
  268. wait: 1, # wait 1 sec.
  269. )
  270. click(
  271. browser: browser1,
  272. text: '.partial_link_text',
  273. fast: false, # do not wait
  274. wait: 1, # wait 1 sec.
  275. )
  276. =end
  277. def click(params)
  278. switch_window_focus(params)
  279. log('click', params)
  280. instance = params[:browser] || @browser
  281. if params[:css]
  282. element = instance.find_elements({ css: params[:css] })[0]
  283. #instance.mouse.move_to(element)
  284. #sleep 0.2
  285. element.click
  286. # trigger also focus on input/select and textarea fields
  287. #if params[:css] =~ /(input|select|textarea)/
  288. # instance.execute_script("$('#{params[:css]}').trigger('focus')")
  289. # sleep 0.2
  290. #end
  291. else
  292. instance.find_elements({ partial_link_text: params[:text] })[0].click
  293. end
  294. sleep 0.4 if !params[:fast]
  295. sleep params[:wait] if params[:wait]
  296. end
  297. =begin
  298. scroll_to(
  299. browser: browser1,
  300. position: 'top', # botton
  301. css: '.some_class',
  302. )
  303. =end
  304. def scroll_to(params)
  305. switch_window_focus(params)
  306. log('scroll_to', params)
  307. instance = params[:browser] || @browser
  308. position = 'true'
  309. if params[:position] == 'botton'
  310. position = 'false'
  311. end
  312. execute(
  313. browser: instance,
  314. js: "\$('#{params[:css]}').get(0).scrollIntoView(#{position})",
  315. mute_log: params[:mute_log]
  316. )
  317. sleep 0.2
  318. end
  319. =begin
  320. execute(
  321. browser: browser1,
  322. js: '.some_class',
  323. )
  324. =end
  325. def execute(params)
  326. switch_window_focus(params)
  327. log('js', params)
  328. instance = params[:browser] || @browser
  329. if params[:js]
  330. return instance.execute_script(params[:js])
  331. end
  332. fail "Invalid execute params #{params.inspect}"
  333. end
  334. =begin
  335. exists(
  336. browser: browser1,
  337. css: '.some_class',
  338. )
  339. =end
  340. def exists(params)
  341. switch_window_focus(params)
  342. log('exists', params)
  343. instance = params[:browser] || @browser
  344. if !instance.find_elements({ css: params[:css] } )[0]
  345. screenshot(browser: instance, comment: 'exists_failed')
  346. fail "#{params[:css]} dosn't exist, but should"
  347. end
  348. true
  349. end
  350. =begin
  351. exists_not(
  352. browser: browser1,
  353. css: '.some_class',
  354. )
  355. =end
  356. def exists_not(params)
  357. switch_window_focus(params)
  358. log('exists_not', params)
  359. instance = params[:browser] || @browser
  360. if instance.find_elements({ css: params[:css] } )[0]
  361. screenshot(browser: instance, comment: 'exists_not_failed')
  362. fail "#{params[:css]} exists but should not"
  363. end
  364. true
  365. end
  366. =begin
  367. set(
  368. browser: browser1,
  369. css: '.some_class',
  370. value: true,
  371. slow: false,
  372. blur: true,
  373. clear: true, # todo | default: true
  374. no_click: true,
  375. )
  376. =end
  377. def set(params)
  378. switch_window_focus(params)
  379. log('set', params)
  380. instance = params[:browser] || @browser
  381. element = instance.find_elements({ css: params[:css] })[0]
  382. if !params[:no_click]
  383. element.click
  384. end
  385. element.clear
  386. if !params[:slow]
  387. element.send_keys(params[:value])
  388. else
  389. element.send_keys('')
  390. keys = params[:value].to_s.split('')
  391. keys.each {|key|
  392. instance.action.send_keys(key).perform
  393. }
  394. end
  395. if params[:blur]
  396. instance.execute_script("$('#{params[:css]}').blur()")
  397. end
  398. sleep 0.5
  399. end
  400. =begin
  401. select(
  402. browser: browser1,
  403. css: '.some_class',
  404. value: 'Some Value',
  405. )
  406. =end
  407. def select(params)
  408. switch_window_focus(params)
  409. log('select', params)
  410. instance = params[:browser] || @browser
  411. # searchable select
  412. element = instance.find_elements({ css: "#{params[:css]}.js-shadow" })[0]
  413. if element
  414. element = instance.find_elements({ css: "#{params[:css]}.js-shadow + .js-input" })[0]
  415. element.click
  416. element.clear
  417. sleep 1
  418. element.send_keys(params[:value])
  419. sleep 0.5
  420. element.send_keys(:enter)
  421. sleep 0.5
  422. return
  423. end
  424. # native select
  425. begin
  426. element = instance.find_elements({ css: params[:css] })[0]
  427. dropdown = Selenium::WebDriver::Support::Select.new(element)
  428. dropdown.select_by(:text, params[:value])
  429. puts "select - #{params.inspect}"
  430. rescue
  431. # just try again
  432. element = instance.find_elements({ css: params[:css] })[0]
  433. dropdown = Selenium::WebDriver::Support::Select.new(element)
  434. dropdown.select_by(:text, params[:value])
  435. puts "select2 - #{params.inspect}"
  436. end
  437. end
  438. =begin
  439. switch(
  440. browser: browser1,
  441. css: '.some_class',
  442. type: 'on', # 'off'
  443. )
  444. =end
  445. def switch(params)
  446. switch_window_focus(params)
  447. log('switch', params)
  448. instance = params[:browser] || @browser
  449. element = instance.find_elements({ css: "#{params[:css]} input[type=checkbox]" })[0]
  450. checked = element.attribute('checked')
  451. if !checked
  452. if params[:type] == 'on'
  453. instance.find_elements({ css: "#{params[:css]} label" })[0].click
  454. end
  455. elsif params[:type] == 'off'
  456. instance.find_elements({ css: "#{params[:css]} label" })[0].click
  457. end
  458. end
  459. =begin
  460. check(
  461. browser: browser1,
  462. css: '.some_class',
  463. )
  464. =end
  465. def check(params)
  466. switch_window_focus(params)
  467. log('check', params)
  468. instance = params[:browser] || @browser
  469. element = instance.find_elements({ css: params[:css] })[0]
  470. checked = element.attribute('checked')
  471. element.click if !checked
  472. end
  473. =begin
  474. uncheck(
  475. browser: browser1,
  476. css: '.some_class',
  477. )
  478. =end
  479. def uncheck(params)
  480. switch_window_focus(params)
  481. log('uncheck', params)
  482. instance = params[:browser] || @browser
  483. element = instance.find_elements({ css: params[:css] })[0]
  484. checked = element.attribute('checked')
  485. element.click if checked
  486. end
  487. =begin
  488. sendkey(
  489. browser: browser1,
  490. value: :enter,
  491. slow: false,
  492. )
  493. =end
  494. def sendkey(params)
  495. switch_window_focus(params)
  496. log('sendkey', params)
  497. instance = params[:browser] || @browser
  498. if params[:value].class == Array
  499. params[:value].each {|key|
  500. instance.action.send_keys(key).perform
  501. }
  502. return
  503. end
  504. instance.action.send_keys(params[:value]).perform
  505. if params[:slow]
  506. sleep 2
  507. else
  508. sleep 0.6
  509. end
  510. end
  511. =begin
  512. match(
  513. browser: browser1,
  514. css: '#content .text-1',
  515. value: 'some test for browser and some other for browser',
  516. attribute: 'some_attribute', # match on attribute
  517. should_not_match: true,
  518. no_quote: false, # use regex
  519. )
  520. =end
  521. def match(params, fallback = false)
  522. switch_window_focus(params)
  523. log('match', params)
  524. instance = params[:browser] || @browser
  525. element = instance.find_elements({ css: params[:css] })[0]
  526. if params[:css] =~ /select/
  527. dropdown = Selenium::WebDriver::Support::Select.new(element)
  528. success = false
  529. if dropdown.selected_options
  530. dropdown.selected_options.each {|option|
  531. if option.text == params[:value]
  532. success = true
  533. end
  534. }
  535. end
  536. if params[:should_not_match]
  537. if success
  538. fail "should not match '#{params[:value]}' in select list, but is matching"
  539. end
  540. elsif !success
  541. fail "not matching '#{params[:value]}' in select list"
  542. end
  543. return true
  544. end
  545. # match on attribute
  546. begin
  547. text = if params[:attribute]
  548. element.attribute(params[:attribute])
  549. elsif params[:css] =~ /(input|textarea)/i
  550. element.attribute('value')
  551. else
  552. element.text
  553. end
  554. rescue => e
  555. # just try again
  556. if !fallback
  557. return match(params, true)
  558. end
  559. raise e.inspect
  560. end
  561. # do cleanups (needed for richtext tests)
  562. if params[:cleanup]
  563. text.gsub!(/\s+$/m, '')
  564. params[:value].gsub!(/\s+$/m, '')
  565. end
  566. match = false
  567. if params[:no_quote]
  568. #puts "aaaa #{text}/#{params[:value]}"
  569. if text =~ /#{params[:value]}/i
  570. match = $1 || true
  571. end
  572. elsif text =~ /#{Regexp.quote(params[:value])}/i
  573. match = true
  574. end
  575. if match
  576. if params[:should_not_match]
  577. fail "matching '#{params[:value]}' in content '#{text}' but should not!"
  578. end
  579. elsif !params[:should_not_match]
  580. fail "not matching '#{params[:value]}' in content '#{text}' but should!"
  581. end
  582. sleep 0.8
  583. match
  584. end
  585. =begin
  586. match_not(
  587. browser: browser1,
  588. css: '#content .text-1',
  589. value: 'some test for browser and some other for browser',
  590. attribute: 'some_attribute', # match on attribute
  591. should_not_match: true,
  592. no_quote: false, # use regex
  593. )
  594. =end
  595. def match_not(params)
  596. switch_window_focus(params)
  597. log('match_not', params)
  598. params[:should_not_match] = true
  599. match(params)
  600. end
  601. =begin
  602. task_type(
  603. browser: browser1,
  604. type: 'stayOnTab',
  605. )
  606. =end
  607. def task_type(params)
  608. switch_window_focus(params)
  609. log('task_type', params)
  610. instance = params[:browser] || @browser
  611. if params[:type]
  612. instance.find_elements({ css: '.content.active .js-secondaryActionButtonLabel' })[0].click
  613. instance.find_elements({ css: ".content.active .js-secondaryActionLabel[data-type=#{params[:type]}]" })[0].click
  614. return
  615. end
  616. fail "Unknown params for task_type: #{params.inspect}"
  617. end
  618. =begin
  619. cookie(
  620. browser: browser1,
  621. name: '^_zammad.+?',
  622. value: '.+?',
  623. expires: nil,
  624. )
  625. cookie(
  626. browser: browser1,
  627. name: '^_zammad.+?',
  628. should_not_exist: true,
  629. )
  630. =end
  631. def cookie(params)
  632. switch_window_focus(params)
  633. log('cookie', params)
  634. instance = params[:browser] || @browser
  635. if !browser_support_cookies
  636. assert(true, "'#{params[:value]}' ups browser is not supporting reading cookies, go ahead")
  637. return true
  638. end
  639. cookies = instance.manage.all_cookies
  640. cookies.each {|cookie|
  641. #puts "CCC #{cookie.inspect}"
  642. # :name=>"_zammad_session_c25832f4de2", :value=>"adc31cd21615cb0a7ab269184ec8b76f", :path=>"/", :domain=>"localhost", :expires=>nil, :secure=>false}
  643. next if cookie[:name] !~ /#{params[:name]}/i
  644. if params.key?(:value ) && cookie[:value].to_s =~ /#{params[:value]}/i
  645. assert(true, "matching value '#{params[:value]}' in cookie '#{cookie}'")
  646. else
  647. fail "not matching value '#{params[:value]}' in cookie '#{cookie}'"
  648. end
  649. if params.key?(:expires) && cookie[:expires].to_s =~ /#{params[:expires]}/i
  650. assert(true, "matching expires '#{params[:expires].inspect}' in cookie '#{cookie}'")
  651. else
  652. fail "not matching expires '#{params[:expires]}' in cookie '#{cookie}'"
  653. end
  654. return if !params[:should_not_exist]
  655. fail "cookie with name '#{params[:name]}' should not exist, but exists '#{cookies}'"
  656. }
  657. if params[:should_not_exist]
  658. assert(true, "cookie with name '#{params[:name]}' is not existing")
  659. return
  660. end
  661. fail "not matching name '#{params[:name]}' in cookie '#{cookies}'"
  662. end
  663. =begin
  664. verify_title(
  665. browser: browser1,
  666. value: 'some title',
  667. )
  668. =end
  669. def verify_title(params = {})
  670. switch_window_focus(params)
  671. log('verify_title', params)
  672. instance = params[:browser] || @browser
  673. title = instance.title
  674. if title =~ /#{params[:value]}/i
  675. assert(true, "matching '#{params[:value]}' in title '#{title}'")
  676. else
  677. fail "not matching '#{params[:value]}' in title '#{title}'"
  678. end
  679. end
  680. =begin
  681. verify_task(
  682. browser: browser1,
  683. data: {
  684. title: 'some title',
  685. modified: true, # optional
  686. }
  687. )
  688. =end
  689. def verify_task(params = {}, fallback = false)
  690. switch_window_focus(params)
  691. log('verify_task', params)
  692. instance = params[:browser] || @browser
  693. data = params[:data]
  694. sleep 1
  695. begin
  696. # verify title
  697. if data[:title]
  698. title = instance.find_elements({ css: '.tasks .is-active' })[0].text.strip
  699. if title =~ /#{data[:title]}/i
  700. assert(true, "matching '#{data[:title]}' in title '#{title}'")
  701. else
  702. fail "not matching '#{data[:title]}' in title '#{title}'"
  703. end
  704. end
  705. puts "tv #{params.inspect}"
  706. # verify modified
  707. if data.key?(:modified)
  708. exists = instance.find_elements({ css: '.tasks .is-active' })[0]
  709. is_modified = instance.find_elements({ css: '.tasks .is-modified' })[0]
  710. puts "m #{data[:modified].inspect}"
  711. if exists
  712. puts ' exists'
  713. end
  714. if is_modified
  715. puts ' is_modified'
  716. end
  717. if data[:modified] == true
  718. if is_modified
  719. assert(true, "task '#{data[:title]}' is modifed")
  720. elsif !exists
  721. fail "task '#{data[:title]}' not exists, should not modified"
  722. else
  723. fail "task '#{data[:title]}' is not modifed"
  724. end
  725. elsif !is_modified
  726. assert(true, "task '#{data[:title]}' is modifed")
  727. elsif !exists
  728. fail "task '#{data[:title]}' not exists, should be not modified"
  729. else
  730. fail "task '#{data[:title]}' is modifed, but should not"
  731. end
  732. end
  733. rescue => e
  734. # just try again
  735. if !fallback
  736. verify_task(params, true)
  737. end
  738. raise 'ERROR: ' + e.inspect
  739. end
  740. true
  741. end
  742. =begin
  743. open_task(
  744. browser: browser1,
  745. data: {
  746. title: 'some title',
  747. }
  748. )
  749. =end
  750. def open_task(params = {}, _fallback = false)
  751. switch_window_focus(params)
  752. log('open_task', params)
  753. instance = params[:browser] || @browser
  754. data = params[:data]
  755. element = instance.find_elements({ partial_link_text: data[:title] })[0]
  756. if !element
  757. screenshot(browser: instance, comment: 'open_task_failed')
  758. fail "no task with title '#{data[:title]}' found"
  759. end
  760. element.click
  761. true
  762. end
  763. =begin
  764. file_upload(
  765. browser: browser1,
  766. css: '.active .attachmentPlaceholder-inputHolder input'
  767. files: ['path/in/home/some_file.ext'], # 'test/fixtures/test1.pdf'
  768. )
  769. =end
  770. def file_upload(params = {})
  771. switch_window_focus(params)
  772. log('file_upload', params)
  773. instance = params[:browser] || @browser
  774. params[:files].each {|file|
  775. instance.find_elements({ css: params[:css] })[0].send_keys "#{Rails.root}/#{file}"
  776. }
  777. sleep 2 * params[:files].count
  778. end
  779. =begin
  780. watch_for(
  781. browser: browser1,
  782. css: '#content .text-1',
  783. value: 'some text',
  784. attribute: 'some_attribute' # optional
  785. timeout: 16, # in sec, default 16
  786. )
  787. =end
  788. def watch_for(params = {})
  789. switch_window_focus(params)
  790. log('watch_for', params)
  791. instance = params[:browser] || @browser
  792. timeout = 16
  793. if params[:timeout]
  794. timeout = params[:timeout]
  795. end
  796. loops = timeout.to_i * 2
  797. text = ''
  798. (1..loops).each {
  799. element = instance.find_elements({ css: params[:css] })[0]
  800. if element #&& element.displayed?
  801. begin
  802. # match pn attribute
  803. text = if params[:attribute]
  804. element.attribute(params[:attribute])
  805. elsif params[:css] =~ /(input|textarea)/i
  806. element.attribute('value')
  807. else
  808. element.text
  809. end
  810. if text =~ /#{params[:value]}/i
  811. assert(true, "'#{params[:value]}' found in '#{text}'")
  812. sleep 0.5
  813. return true
  814. end
  815. rescue
  816. # try again
  817. end
  818. end
  819. sleep 0.5
  820. }
  821. screenshot(browser: instance, comment: 'watch_for_failed')
  822. fail "'#{params[:value]}' found in '#{text}'"
  823. end
  824. =begin
  825. wait untill selector disabppears
  826. watch_for_disappear(
  827. browser: browser1,
  828. css: '#content .text-1',
  829. timeout: 16, # in sec, default 16
  830. )
  831. wait untill text in selector disabppears
  832. watch_for_disappear(
  833. browser: browser1,
  834. css: '#content .text-1',
  835. value: 'some value as regexp',
  836. timeout: 16, # in sec, default 16
  837. )
  838. =end
  839. def watch_for_disappear(params = {})
  840. switch_window_focus(params)
  841. log('watch_for_disappear', params)
  842. instance = params[:browser] || @browser
  843. timeout = 16
  844. if params[:timeout]
  845. timeout = params[:timeout]
  846. end
  847. loops = timeout.to_i
  848. text = ''
  849. (1..loops).each {
  850. element = instance.find_elements({ css: params[:css] })[0]
  851. if !element #|| element.displayed?
  852. assert(true, 'not found')
  853. sleep 1
  854. return true
  855. end
  856. if params[:value]
  857. begin
  858. text = instance.find_elements({ css: params[:css] })[0].text
  859. if text !~ /#{params[:value]}/i
  860. assert(true, "not matching '#{params[:value]}' in text '#{text}'")
  861. sleep 1
  862. return true
  863. end
  864. rescue
  865. # try again
  866. end
  867. end
  868. sleep 1
  869. }
  870. screenshot(browser: instance, comment: 'disappear_failed')
  871. fail "#{params[:css]}) still exsists"
  872. end
  873. =begin
  874. tasks_close_all(
  875. browser: browser1,
  876. discard_changes: true,
  877. )
  878. =end
  879. def tasks_close_all(params = {})
  880. switch_window_focus(params)
  881. log('tasks_close_all', params)
  882. instance = params[:browser] || @browser
  883. (1..100).each do
  884. sleep 1
  885. begin
  886. if instance.find_elements({ css: '.navigation .tasks .task:first-child' })[0]
  887. instance.mouse.move_to(instance.find_elements({ css: '.navigation .tasks .task:first-child' })[0])
  888. sleep 0.1
  889. click_element = instance.find_elements({ css: '.navigation .tasks .task:first-child .js-close' })[0]
  890. if click_element
  891. click_element.click
  892. # accept task close warning
  893. if params[:discard_changes]
  894. sleep 1
  895. instance.find_elements({ css: '.modal button.js-submit' })[0].click
  896. end
  897. end
  898. else
  899. break
  900. end
  901. rescue
  902. # try again
  903. end
  904. end
  905. sleep 1
  906. assert(true, 'all tasks closed')
  907. end
  908. =begin
  909. ticket_customer_select(
  910. browser: browser1,
  911. css: '#content .text-1',
  912. customer: '',
  913. )
  914. =end
  915. def ticket_customer_select(params = {})
  916. switch_window_focus(params)
  917. log('ticket_customer_select', params)
  918. instance = params[:browser] || @browser
  919. element = instance.find_elements({ css: params[:css] + ' input[name="customer_id_completion"]' })[0]
  920. element.click
  921. element.clear
  922. # workaround, sometimes focus is not triggered
  923. element.send_keys(params[:customer] + '*')
  924. sleep 3.5
  925. # check if pulldown is open, it's not working stable via selenium
  926. #instance.execute_script("$('#{params[:css]} .js-recipientDropdown').addClass('open')")
  927. #sleep 0.5
  928. element.send_keys(:arrow_down)
  929. sleep 0.3
  930. element.send_keys(:enter)
  931. #instance.find_elements({ css: params[:css] + ' .recipientList-entry.js-user.is-active' })[0].click
  932. sleep 0.6
  933. assert(true, 'ticket_customer_select')
  934. end
  935. =begin
  936. username = overview_create(
  937. browser: browser1,
  938. data: {
  939. name: name,
  940. role: 'Agent',
  941. selector: {
  942. 'Priority': '1 low',
  943. },
  944. prio: 1000,
  945. 'order::direction' => 'down',
  946. }
  947. )
  948. =end
  949. def overview_create(params)
  950. switch_window_focus(params)
  951. log('overview_create', params)
  952. instance = params[:browser] || @browser
  953. data = params[:data]
  954. instance.find_elements({ css: 'a[href="#manage"]' })[0].click
  955. instance.find_elements({ css: 'a[href="#manage/overviews"]' })[0].click
  956. sleep 0.2
  957. instance.find_elements({ css: '#content a[data-type="new"]' })[0].click
  958. sleep 2
  959. if data[:name]
  960. element = instance.find_elements({ css: '.modal input[name=name]' })[0]
  961. element.clear
  962. element.send_keys(data[:name])
  963. end
  964. if data[:role]
  965. element = instance.find_elements({ css: '.modal select[name="role_id"]' })[0]
  966. dropdown = Selenium::WebDriver::Support::Select.new(element)
  967. dropdown.select_by(:text, data[:role])
  968. end
  969. if data[:selector]
  970. data[:selector].each {|key, value|
  971. element = instance.find_elements({ css: '.modal .ticket_selector .js-attributeSelector select' })[0]
  972. dropdown = Selenium::WebDriver::Support::Select.new(element)
  973. dropdown.select_by(:text, key)
  974. element = instance.find_elements({ css: '.modal .ticket_selector .js-value select' })[0]
  975. dropdown = Selenium::WebDriver::Support::Select.new(element)
  976. dropdown.deselect_all
  977. dropdown.select_by(:text, value)
  978. }
  979. end
  980. if data[:prio]
  981. element = instance.find_elements({ css: '.modal input[name=prio]' })[0]
  982. element.clear
  983. element.send_keys(data[:prio])
  984. end
  985. if data['order::direction']
  986. element = instance.find_elements({ css: '.modal select[name="order::direction"]' })[0]
  987. dropdown = Selenium::WebDriver::Support::Select.new(element)
  988. dropdown.select_by(:text, data['order::direction'])
  989. end
  990. instance.find_elements({ css: '.modal button.js-submit' })[0].click
  991. (1..12).each {
  992. element = instance.find_elements({ css: 'body' })[0]
  993. text = element.text
  994. if text =~ /#{Regexp.quote(data[:name])}/
  995. assert(true, 'overview created')
  996. overview = {
  997. name: name,
  998. }
  999. return overview
  1000. end
  1001. sleep 1
  1002. }
  1003. screenshot(browser: instance, comment: 'overview_create_failed')
  1004. fail 'overview creation failed'
  1005. end
  1006. =begin
  1007. ticket = ticket_create(
  1008. browser: browser1,
  1009. data: {
  1010. customer: 'nico',
  1011. group: 'Users',
  1012. priority: '2 normal',
  1013. title: 'overview #1',
  1014. body: 'overview #1',
  1015. },
  1016. do_not_submit: true,
  1017. )
  1018. returns (in case of submitted)
  1019. {
  1020. id: 123,
  1021. number: '100001',
  1022. title: 'overview #1',
  1023. }
  1024. =end
  1025. def ticket_create(params)
  1026. switch_window_focus(params)
  1027. log('ticket_create', params)
  1028. instance = params[:browser] || @browser
  1029. data = params[:data]
  1030. instance.find_elements({ css: 'a[href="#new"]' })[0].click
  1031. instance.find_elements({ css: 'a[href="#ticket/create"]' })[0].click
  1032. element = instance.find_elements({ css: '.active .newTicket' })[0]
  1033. if !element
  1034. screenshot(browser: instance, comment: 'ticket_create_failed')
  1035. fail 'no ticket create screen found!'
  1036. end
  1037. sleep 1
  1038. # check count of agents, should be only 1 / - selection on init screen
  1039. count = instance.find_elements({ css: '.active .newTicket select[name="owner_id"] option' }).count
  1040. assert_equal(1, count, 'check if owner selection is empty per default' )
  1041. if data[:group]
  1042. element = instance.find_elements({ css: '.active .newTicket select[name="group_id"]' })[0]
  1043. dropdown = Selenium::WebDriver::Support::Select.new(element)
  1044. dropdown.select_by(:text, data[:group])
  1045. sleep 0.2
  1046. end
  1047. if data[:priority]
  1048. element = instance.find_elements({ css: '.active .newTicket select[name="priority_id"]' })[0]
  1049. dropdown = Selenium::WebDriver::Support::Select.new(element)
  1050. dropdown.select_by(:text, data[:priority])
  1051. sleep 0.2
  1052. end
  1053. if data[:title]
  1054. element = instance.find_elements({ css: '.active .newTicket input[name="title"]' })[0]
  1055. element.clear
  1056. element.send_keys(data[:title])
  1057. sleep 0.2
  1058. end
  1059. if data[:body]
  1060. #instance.execute_script('$(".active .newTicket div[data-name=body]").focus()')
  1061. sleep 0.5
  1062. element = instance.find_elements({ css: '.active .newTicket div[data-name=body]' })[0]
  1063. element.clear
  1064. element.send_keys(data[:body])
  1065. # it's not working stable via selenium, use js
  1066. value = instance.find_elements({ css: '.content .newTicket div[data-name=body]' })[0].text
  1067. #puts "V #{value.inspect}"
  1068. if value != data[:body]
  1069. body_quoted = quote(data[:body])
  1070. instance.execute_script("$('.content.active div[data-name=body]').html('#{body_quoted}').trigger('focusout')")
  1071. end
  1072. end
  1073. if data[:customer]
  1074. element = instance.find_elements({ css: '.active .newTicket input[name="customer_id_completion"]' })[0]
  1075. element.click
  1076. element.clear
  1077. # workaround, sometimes focus is not triggered
  1078. element.send_keys(data[:customer] + '*')
  1079. sleep 3.5
  1080. # check if pulldown is open, it's not working stable via selenium
  1081. #instance.execute_script("$('.active .newTicket .js-recipientDropdown').addClass('open')")
  1082. #sleep 0.5
  1083. element.send_keys(:arrow_down)
  1084. sleep 0.3
  1085. element.send_keys(:enter)
  1086. #instance.find_elements({ css: '.active .newTicket .recipientList-entry.js-user.is-active' })[0].click
  1087. sleep 0.6
  1088. end
  1089. if data[:attachment]
  1090. file_upload(
  1091. browser: instance,
  1092. css: '#content .text-1',
  1093. value: 'some text',
  1094. )
  1095. end
  1096. if params[:do_not_submit]
  1097. assert(true, 'ticket created without submit')
  1098. return
  1099. end
  1100. sleep 0.8
  1101. #instance.execute_script('$(".content.active .newTicket form").submit();')
  1102. instance.find_elements({ css: '.active .newTicket button.js-submit' })[0].click
  1103. sleep 1
  1104. (1..10).each {
  1105. if instance.current_url =~ /#{Regexp.quote('#ticket/zoom/')}/
  1106. assert(true, 'ticket created')
  1107. sleep 2.5
  1108. id = instance.current_url
  1109. id.gsub!(//,)
  1110. id.gsub!(%r{^.+?/(\d+)$}, '\\1')
  1111. element = instance.find_elements({ css: '.active .ticketZoom-header .ticket-number' })[0]
  1112. if element
  1113. number = element.text
  1114. ticket = {
  1115. id: id,
  1116. number: number,
  1117. title: data[:title],
  1118. }
  1119. sleep 3 # wait until notify is gone
  1120. screenshot(browser: instance, comment: 'ticket_create_ok')
  1121. return ticket
  1122. end
  1123. end
  1124. sleep 1
  1125. }
  1126. screenshot(browser: instance, comment: 'ticket_create_failed')
  1127. fail "ticket creation failed, can't get zoom url (current url is '#{instance.current_url}')"
  1128. end
  1129. =begin
  1130. ticket_update(
  1131. browser: browser1,
  1132. data: {
  1133. title: '',
  1134. customer: 'some_customer@example.com',
  1135. body: 'some body',
  1136. group: 'some group',
  1137. priority: '1 low',
  1138. state: 'closed',
  1139. },
  1140. do_not_submit: true,
  1141. )
  1142. =end
  1143. def ticket_update(params)
  1144. switch_window_focus(params)
  1145. log('ticket_update', params)
  1146. instance = params[:browser] || @browser
  1147. data = params[:data]
  1148. if data[:title]
  1149. #element = instance.find_elements({ :css => '.content.active .ticketZoom-header .ticket-title-update' })[0]
  1150. #element.clear
  1151. #sleep 0.5
  1152. #element = instance.find_elements({ :css => '.content.active .ticketZoom-header .ticket-title-update' })[0]
  1153. #element.send_keys(data[:title])
  1154. #sleep 0.5
  1155. #element.send_keys(:tab)
  1156. instance.execute_script('$(".content.active .ticketZoom-header .ticket-title-update").focus()')
  1157. instance.execute_script('$(".content.active .ticketZoom-header .ticket-title-update").text("' + data[:title] + '")')
  1158. instance.execute_script('$(".content.active .ticketZoom-header .ticket-title-update").blur()')
  1159. instance.execute_script('$(".content.active .ticketZoom-header .ticket-title-update").trigger("blur")')
  1160. # {
  1161. # :where => :instance2,
  1162. # :execute => 'sendkey',
  1163. # :css => '.content.active .ticketZoom-header .ticket-title-update',
  1164. # :value => 'TTT',
  1165. # },
  1166. # {
  1167. # :where => :instance2,
  1168. # :execute => 'sendkey',
  1169. # :css => '.content.active .ticketZoom-header .ticket-title-update',
  1170. # :value => :tab,
  1171. # },
  1172. end
  1173. if data[:customer]
  1174. # select tab
  1175. click(browser: instance, css: '.active .tabsSidebar-tab[data-tab="customer"]')
  1176. click(browser: instance, css: '.active div[data-tab="customer"] .js-actions .icon-arrow-down')
  1177. click(browser: instance, css: '.active div[data-tab="customer"] .js-actions [data-type="customer-change"]')
  1178. watch_for(
  1179. browser: instance,
  1180. css: '.modal',
  1181. value: 'change',
  1182. )
  1183. element = instance.find_elements({ css: '.modal input[name="customer_id_completion"]' })[0]
  1184. element.click
  1185. element.clear
  1186. # workaround, sometimes focus is not triggered
  1187. element.send_keys(data[:customer])
  1188. sleep 3.5
  1189. # check if pulldown is open, it's not working stable via selenium
  1190. #instance.execute_script("$('.modal .user_autocompletion .js-recipientDropdown').addClass('open')")
  1191. #sleep 0.5
  1192. element.send_keys(:arrow_down)
  1193. sleep 0.6
  1194. element.send_keys(:enter)
  1195. #instance.find_elements({ css: '.modal .user_autocompletion .recipientList-entry.js-user.is-active' })[0].click
  1196. sleep 0.3
  1197. click(browser: instance, css: '.modal .js-submit')
  1198. watch_for_disappear(
  1199. browser: instance,
  1200. css: '.modal',
  1201. )
  1202. watch_for(
  1203. browser: instance,
  1204. css: '.active .tabsSidebar',
  1205. value: data[:customer],
  1206. )
  1207. # select tab
  1208. click(browser: instance, css: '.active .tabsSidebar-tab[data-tab="ticket"]')
  1209. end
  1210. if data[:body]
  1211. #instance.execute_script('$(".content.active div[data-name=body]").focus()')
  1212. sleep 0.5
  1213. element = instance.find_elements({ css: '.content.active div[data-name=body]' })[0]
  1214. element.clear
  1215. element.send_keys(data[:body])
  1216. # it's not working stable via selenium, use js
  1217. value = instance.find_elements({ css: '.content.active div[data-name=body]' })[0].text
  1218. if value != data[:body]
  1219. body_quoted = quote(data[:body])
  1220. instance.execute_script("$('.content.active div[data-name=body]').html('#{body_quoted}').trigger('focusout')")
  1221. end
  1222. end
  1223. if data[:group]
  1224. element = instance.find_elements({ css: '.active .sidebar select[name="group_id"]' })[0]
  1225. dropdown = Selenium::WebDriver::Support::Select.new(element)
  1226. dropdown.select_by(:text, data[:group])
  1227. sleep 0.2
  1228. end
  1229. if data[:priority]
  1230. element = instance.find_elements({ css: '.active .sidebar select[name="priority_id"]' })[0]
  1231. dropdown = Selenium::WebDriver::Support::Select.new(element)
  1232. dropdown.select_by(:text, data[:priority])
  1233. sleep 0.2
  1234. end
  1235. if data[:state]
  1236. element = instance.find_elements({ css: '.active .sidebar select[name="state_id"]' })[0]
  1237. dropdown = Selenium::WebDriver::Support::Select.new(element)
  1238. dropdown.select_by(:text, data[:state])
  1239. sleep 0.2
  1240. end
  1241. if data[:state] || data[:group] || data[:body]
  1242. found = nil
  1243. (1..10).each {
  1244. break if found
  1245. begin
  1246. text = instance.find_elements({ css: '.content.active .js-reset' })[0].text
  1247. if text =~ /(Discard your unsaved changes.|Verwerfen der)/
  1248. found = true
  1249. end
  1250. rescue
  1251. # try again
  1252. end
  1253. sleep 1
  1254. }
  1255. if !found
  1256. screenshot(browser: instance, comment: 'ticket_update_discard_message_failed')
  1257. fail 'no discard message found'
  1258. end
  1259. end
  1260. task_type(
  1261. browser: instance,
  1262. type: 'stayOnTab',
  1263. )
  1264. if params[:do_not_submit]
  1265. assert(true, 'ticket updated without submit')
  1266. return true
  1267. end
  1268. instance.find_elements({ css: '.content.active .js-submit' })[0].click
  1269. (1..10).each {
  1270. begin
  1271. text = instance.find_elements({ css: '.content.active .js-reset' })[0].text
  1272. if !text || text.empty?
  1273. screenshot(browser: instance, comment: 'ticket_update_ok')
  1274. return true
  1275. end
  1276. rescue
  1277. # try again
  1278. end
  1279. sleep 1
  1280. }
  1281. screenshot(browser: instance, comment: 'ticket_update_failed')
  1282. fail 'unable to update ticket'
  1283. end
  1284. =begin
  1285. ticket_verify(
  1286. browser: browser1,
  1287. data: {
  1288. title: 'some title',
  1289. body: 'some body',
  1290. ## group: 'some group',
  1291. ## state: 'closed',
  1292. },
  1293. )
  1294. =end
  1295. def ticket_verify(params)
  1296. switch_window_focus(params)
  1297. log('ticket_verify', params)
  1298. instance = params[:browser] || @browser
  1299. data = params[:data]
  1300. if data[:title]
  1301. title = instance.find_elements({ css: '.content.active .ticketZoom-header .ticket-title-update' })[0].text.strip
  1302. if title =~ /#{data[:title]}/i
  1303. assert(true, "matching '#{data[:title]}' in title '#{title}'")
  1304. else
  1305. fail "not matching '#{data[:title]}' in title '#{title}'"
  1306. end
  1307. end
  1308. if data[:body]
  1309. body = instance.find_elements({ css: '.content.active [data-name="body"]' })[0].text.strip
  1310. if body =~ /#{data[:body]}/i
  1311. assert(true, "matching '#{data[:body]}' in body '#{body}'")
  1312. else
  1313. fail "not matching '#{data[:body]}' in body '#{body}'"
  1314. end
  1315. end
  1316. true
  1317. end
  1318. =begin
  1319. ticket_open_by_overview(
  1320. browser: browser2,
  1321. number: ticket1[:number],
  1322. link: "#ticket/view/#{name}",
  1323. )
  1324. =end
  1325. def ticket_open_by_overview(params)
  1326. switch_window_focus(params)
  1327. log('ticket_open_by_overview', params)
  1328. instance = params[:browser] || @browser
  1329. instance.find_elements({ css: '.js-overviewsMenuItem' })[0].click
  1330. sleep 1
  1331. execute(
  1332. browser: instance,
  1333. js: '$(".content.active .sidebar").css("display", "block")',
  1334. )
  1335. instance.find_elements({ css: ".content.active .sidebar a[href=\"#{params[:link]}\"]" })[0].click
  1336. sleep 1
  1337. execute(
  1338. browser: instance,
  1339. js: '$(".content.active .sidebar").css("display", "none")',
  1340. )
  1341. instance.find_elements({ partial_link_text: params[:number] })[0].click
  1342. sleep 1
  1343. number = instance.find_elements({ css: '.active .ticketZoom-header .ticket-number' })[0].text
  1344. if number !~ /#{params[:number]}/
  1345. screenshot(browser: instance, comment: 'ticket_open_by_overview_failed')
  1346. fail "unable to search/find ticket #{params[:number]}!"
  1347. end
  1348. sleep 1
  1349. assert(true, "ticket #{params[:number]} found")
  1350. true
  1351. end
  1352. =begin
  1353. ticket_open_by_search(
  1354. browser: browser2,
  1355. number: ticket1[:number],
  1356. )
  1357. =end
  1358. def ticket_open_by_search(params)
  1359. switch_window_focus(params)
  1360. log('ticket_open_by_search', params)
  1361. instance = params[:browser] || @browser
  1362. # search by number
  1363. element = instance.find_elements({ css: '#global-search' })[0]
  1364. element.click
  1365. element.clear
  1366. element.send_keys(params[:number])
  1367. sleep 3
  1368. # empty search box by x
  1369. instance.find_elements({ css: '.search .empty-search' })[0].click
  1370. sleep 0.5
  1371. text = instance.find_elements({ css: '#global-search' })[0].attribute('value')
  1372. if !text
  1373. fail '#global-search is not empty!'
  1374. end
  1375. # search by number again
  1376. element = instance.find_elements({ css: '#global-search' })[0]
  1377. element.click
  1378. element.clear
  1379. element.send_keys(params[:number])
  1380. sleep 1
  1381. # open ticket
  1382. #instance.find_element({ partial_link_text: params[:number] } ).click
  1383. instance.execute_script("$(\"#global-search-result a:contains('#{params[:value]}') .nav-tab-icon\").click()")
  1384. number = instance.find_elements({ css: '.active .ticketZoom-header .ticket-number' })[0].text
  1385. if number !~ /#{params[:number]}/
  1386. screenshot(browser: instance, comment: 'ticket_open_by_search_failed')
  1387. fail "unable to search/find ticket #{params[:number]}!"
  1388. end
  1389. sleep 1
  1390. true
  1391. end
  1392. =begin
  1393. ticket_open_by_title(
  1394. browser: browser2,
  1395. title: ticket1[:title],
  1396. )
  1397. =end
  1398. def ticket_open_by_title(params)
  1399. switch_window_focus(params)
  1400. log('ticket_open_by_title', params)
  1401. instance = params[:browser] || @browser
  1402. # search by number
  1403. element = instance.find_elements({ css: '#global-search' })[0]
  1404. element.click
  1405. element.clear
  1406. element.send_keys(params[:title])
  1407. sleep 3
  1408. # open ticket
  1409. #instance.find_element({ partial_link_text: params[:title] } ).click
  1410. instance.execute_script("$(\"#global-search-result a:contains('#{params[:title]}') .nav-tab-icon\").click()")
  1411. title = instance.find_elements({ css: '.active .ticketZoom-header .ticket-title-update' })[0].text
  1412. if title !~ /#{params[:title]}/
  1413. screenshot(browser: instance, comment: 'ticket_open_by_title_failed')
  1414. fail "unable to search/find ticket #{params[:title]}!"
  1415. end
  1416. sleep 1
  1417. true
  1418. end
  1419. =begin
  1420. overview_count = overview_counter(
  1421. browser: browser2,
  1422. )
  1423. returns
  1424. {
  1425. '#ticket/view/all_unassigned' => 42,
  1426. }
  1427. =end
  1428. def overview_counter(params = {})
  1429. switch_window_focus(params)
  1430. log('overview_counter', params)
  1431. instance = params[:browser] || @browser
  1432. instance.find_elements({ css: '.js-overviewsMenuItem' })[0].click
  1433. sleep 2
  1434. execute(
  1435. browser: instance,
  1436. js: '$(".content.active .sidebar").css("display", "block")',
  1437. )
  1438. #execute(
  1439. # browser: instance,
  1440. # js: '$(".content.active .overview-header").css("display", "none")',
  1441. #)
  1442. overviews = {}
  1443. instance.find_elements({ css: '.content.active .sidebar a[href]' }).each {|element|
  1444. url = element.attribute('href')
  1445. url.gsub!(%r{(http|https)://.+?/(.+?)$}, '\\2')
  1446. overviews[url] = 0
  1447. #puts url.inspect
  1448. #puts element.inspect
  1449. }
  1450. overviews.each {|url, _value|
  1451. count = instance.find_elements({ css: ".content.active .sidebar a[href=\"#{url}\"] .badge" })[0].text
  1452. overviews[url] = count.to_i
  1453. }
  1454. log('overview_counter', overviews)
  1455. overviews
  1456. end
  1457. =begin
  1458. organization_open_by_search(
  1459. browser: browser2,
  1460. value: 'some value',
  1461. )
  1462. =end
  1463. def organization_open_by_search(params = {})
  1464. switch_window_focus(params)
  1465. log('organization_open_by_search', params)
  1466. instance = params[:browser] || @browser
  1467. element = instance.find_elements({ css: '#global-search' })[0]
  1468. element.click
  1469. element.clear
  1470. element.send_keys(params[:value])
  1471. sleep 3
  1472. instance.find_elements({ css: '.search .empty-search' })[0].click
  1473. sleep 0.5
  1474. text = instance.find_elements({ css: '#global-search' })[0].attribute('value')
  1475. if !text
  1476. fail '#global-search is not empty!'
  1477. end
  1478. element = instance.find_elements({ css: '#global-search' })[0]
  1479. element.click
  1480. element.clear
  1481. element.send_keys(params[:value])
  1482. sleep 2
  1483. #instance.find_element({ partial_link_text: params[:value] } ).click
  1484. instance.execute_script("$(\"#global-search-result a:contains('#{params[:value]}') .nav-tab-icon\").click()")
  1485. name = instance.find_elements({ css: '.active h1' })[0].text
  1486. if name !~ /#{params[:value]}/
  1487. screenshot(browser: instance, comment: 'organization_open_by_search_failed')
  1488. fail "unable to search/find org #{params[:value]}!"
  1489. end
  1490. assert(true, "org #{params[:value]} found")
  1491. sleep 2
  1492. true
  1493. end
  1494. =begin
  1495. user_open_by_search(
  1496. browser: browser2,
  1497. value: 'some value',
  1498. )
  1499. =end
  1500. def user_open_by_search(params = {})
  1501. switch_window_focus(params)
  1502. log('user_open_by_search', params)
  1503. instance = params[:browser] || @browser
  1504. element = instance.find_elements({ css: '#global-search' })[0]
  1505. element.click
  1506. element.clear
  1507. element.send_keys(params[:value])
  1508. sleep 3
  1509. #instance.find_element({ partial_link_text: params[:value] }).click
  1510. instance.execute_script("$(\"#global-search-result a:contains('#{params[:value]}') .nav-tab-icon\").click()")
  1511. name = instance.find_elements({ css: '.active h1' })[0].text
  1512. if name !~ /#{params[:value]}/
  1513. screenshot(browser: instance, comment: 'user_open_by_search_failed')
  1514. fail "unable to search/find user #{params[:value]}!"
  1515. end
  1516. assert(true, "user #{params[:term]} found")
  1517. sleep 2
  1518. true
  1519. end
  1520. =begin
  1521. user_create(
  1522. browser: browser2,
  1523. data: {
  1524. #login: 'some login' + random,
  1525. firstname: 'Manage Firstname' + random,
  1526. lastname: 'Manage Lastname' + random,
  1527. email: user_email,
  1528. password: 'some-pass',
  1529. },
  1530. )
  1531. =end
  1532. def user_create(params = {})
  1533. switch_window_focus(params)
  1534. log('user_create', params)
  1535. instance = params[:browser] || @browser
  1536. data = params[:data]
  1537. instance.find_elements({ css: 'a[href="#manage"]' })[0].click
  1538. sleep 1
  1539. instance.find_elements({ css: 'a[href="#manage/users"]' })[0].click
  1540. sleep 2
  1541. instance.find_elements({ css: 'a[data-type="new"]' })[0].click
  1542. sleep 2
  1543. element = instance.find_elements({ css: '.modal input[name=firstname]' })[0]
  1544. element.clear
  1545. element.send_keys(data[:firstname])
  1546. element = instance.find_elements({ css: '.modal input[name=lastname]' })[0]
  1547. element.clear
  1548. element.send_keys(data[:lastname])
  1549. element = instance.find_elements({ css: '.modal input[name=email]' })[0]
  1550. element.clear
  1551. element.send_keys(data[:email])
  1552. element = instance.find_elements({ css: '.modal input[name=password]' })[0]
  1553. element.clear
  1554. element.send_keys(data[:password])
  1555. element = instance.find_elements({ css: '.modal input[name=password_confirm]' })[0]
  1556. element.clear
  1557. element.send_keys(data[:password])
  1558. instance.find_elements({ css: '.modal input[name="role_ids"][value="3"]' })[0].click
  1559. instance.find_elements({ css: '.modal button.js-submit' })[0].click
  1560. sleep 3.5
  1561. set(
  1562. browser: instance,
  1563. css: '.content .js-search',
  1564. value: data[:email],
  1565. )
  1566. watch_for(
  1567. browser: instance,
  1568. css: 'body',
  1569. value: data[:lastname],
  1570. )
  1571. assert(true, 'user created')
  1572. end
  1573. =begin
  1574. sla_create(
  1575. browser: browser2,
  1576. data: {
  1577. name: 'some sla' + random,
  1578. first_response_time_in_text: 61
  1579. },
  1580. )
  1581. =end
  1582. def sla_create(params = {})
  1583. switch_window_focus(params)
  1584. log('sla_create', params)
  1585. instance = params[:browser] || @browser
  1586. data = params[:data]
  1587. instance.find_elements({ css: 'a[href="#manage"]' })[0].click
  1588. sleep 1
  1589. instance.find_elements({ css: 'a[href="#manage/slas"]' })[0].click
  1590. sleep 2
  1591. instance.find_elements({ css: 'a.js-new' })[0].click
  1592. sleep 2
  1593. element = instance.find_elements({ css: '.modal input[name=name]' })[0]
  1594. element.clear
  1595. element.send_keys(data[:name])
  1596. element = instance.find_elements({ css: '.modal input[name=first_response_time_in_text]' })[0]
  1597. element.clear
  1598. element.send_keys(data[:first_response_time_in_text])
  1599. instance.find_elements({ css: '.modal button.js-submit' })[0].click
  1600. (1..8).each {
  1601. element = instance.find_elements({ css: 'body' })[0]
  1602. text = element.text
  1603. if text =~ /#{Regexp.quote(data[:name])}/
  1604. assert(true, 'sla created')
  1605. return true
  1606. end
  1607. sleep 1
  1608. }
  1609. screenshot(browser: instance, comment: 'sla_create_failed')
  1610. fail 'sla creation failed'
  1611. end
  1612. =begin
  1613. text_module_create(
  1614. browser: browser2,
  1615. data: {
  1616. name: 'some sla' + random,
  1617. keywords: 'some keywords',
  1618. content: 'some content',
  1619. },
  1620. )
  1621. =end
  1622. def text_module_create(params = {})
  1623. switch_window_focus(params)
  1624. log('text_module_create', params)
  1625. instance = params[:browser] || @browser
  1626. data = params[:data]
  1627. instance.find_elements({ css: 'a[href="#manage"]' })[0].click
  1628. sleep 1
  1629. instance.find_elements({ css: 'a[href="#manage/text_modules"]' })[0].click
  1630. sleep 2
  1631. instance.find_elements({ css: 'a[data-type="new"]' })[0].click
  1632. sleep 2
  1633. element = instance.find_elements({ css: '.modal input[name=name]' })[0]
  1634. element.clear
  1635. element.send_keys(data[:name])
  1636. element = instance.find_elements({ css: '.modal input[name=keywords]' })[0]
  1637. element.clear
  1638. element.send_keys(data[:keywords])
  1639. element = instance.find_elements({ css: '.modal textarea[name=content]' })[0]
  1640. element.clear
  1641. element.send_keys(data[:content])
  1642. instance.find_elements({ css: '.modal button.js-submit' })[0].click
  1643. (1..8).each {
  1644. element = instance.find_elements({ css: 'body' })[0]
  1645. text = element.text
  1646. if text =~ /#{Regexp.quote(data[:name])}/
  1647. assert(true, 'text module created')
  1648. return true
  1649. end
  1650. sleep 1
  1651. }
  1652. screenshot(browser: instance, comment: 'text_module_create_failed')
  1653. fail 'text module creation failed'
  1654. end
  1655. =begin
  1656. signature_create(
  1657. browser: browser2,
  1658. data: {
  1659. name: 'some sla' + random,
  1660. body: 'some body',
  1661. },
  1662. )
  1663. =end
  1664. def signature_create(params = {})
  1665. switch_window_focus(params)
  1666. log('signature_create', params)
  1667. instance = params[:browser] || @browser
  1668. data = params[:data]
  1669. instance.find_elements({ css: 'a[href="#manage"]' })[0].click
  1670. sleep 1
  1671. instance.find_elements({ css: 'a[href="#channels/email"]' })[0].click
  1672. sleep 1
  1673. instance.find_elements({ css: 'a[href="#c-signature"]' })[0].click
  1674. sleep 8
  1675. instance.find_elements({ css: '#content #c-signature a[data-type="new"]' })[0].click
  1676. sleep 2
  1677. element = instance.find_elements({ css: '.modal input[name=name]' })[0]
  1678. element.clear
  1679. element.send_keys(data[:name])
  1680. element = instance.find_elements({ css: '.modal textarea[name=body]' })[0]
  1681. element.clear
  1682. element.send_keys(data[:body])
  1683. instance.find_elements({ css: '.modal button.js-submit' })[0].click
  1684. (1..12).each {
  1685. element = instance.find_elements({ css: 'body' })[0]
  1686. text = element.text
  1687. if text =~ /#{Regexp.quote(data[:name])}/
  1688. assert(true, 'signature created')
  1689. return true
  1690. end
  1691. sleep 1
  1692. }
  1693. screenshot(browser: instance, comment: 'signature_create_failed')
  1694. fail 'signature creation failed'
  1695. end
  1696. =begin
  1697. group_create(
  1698. browser: browser2,
  1699. data: {
  1700. name: 'some sla' + random,
  1701. signature: 'some signature bame',
  1702. member: [
  1703. 'some_user_login',
  1704. ],
  1705. },
  1706. )
  1707. =end
  1708. def group_create(params = {})
  1709. switch_window_focus(params)
  1710. log('group_create', params)
  1711. instance = params[:browser] || @browser
  1712. data = params[:data]
  1713. instance.find_elements({ css: 'a[href="#manage"]' })[0].click
  1714. sleep 0.5
  1715. instance.find_elements({ css: 'a[href="#manage/groups"]' })[0].click
  1716. sleep 2
  1717. instance.find_elements({ css: 'a[data-type="new"]' })[0].click
  1718. sleep 2
  1719. element = instance.find_elements({ css: '.modal input[name=name]' })[0]
  1720. element.clear
  1721. element.send_keys(data[:name])
  1722. element = instance.find_elements({ css: '.modal select[name="email_address_id"]' })[0]
  1723. dropdown = Selenium::WebDriver::Support::Select.new(element)
  1724. dropdown.select_by(:index, 1)
  1725. #dropdown.select_by(:text, action[:group])
  1726. if data[:signature]
  1727. element = instance.find_elements({ css: '.modal select[name="signature_id"]' })[0]
  1728. dropdown = Selenium::WebDriver::Support::Select.new(element)
  1729. dropdown.select_by(:text, data[:signature])
  1730. end
  1731. instance.find_elements({ css: '.modal button.js-submit' })[0].click
  1732. (1..12).each {
  1733. element = instance.find_elements({ css: 'body' })[0]
  1734. text = element.text
  1735. if text =~ /#{Regexp.quote(data[:name])}/
  1736. assert(true, 'group created')
  1737. # add member
  1738. if data[:member]
  1739. data[:member].each {|login|
  1740. instance.find_elements({ css: 'a[href="#manage"]' })[0].click
  1741. sleep 0.5
  1742. instance.find_elements({ css: 'a[href="#manage/users"]' })[0].click
  1743. sleep 3
  1744. element = instance.find_elements({ css: '#content [name="search"]' })[0]
  1745. element.clear
  1746. element.send_keys(login)
  1747. sleep 3
  1748. #instance.find_elements({ :css => '#content table [data-id]' })[0].click
  1749. instance.execute_script('$("#content table [data-id] td").first().click()')
  1750. sleep 3
  1751. #instance.find_elements({ :css => 'label:contains(" ' + action[:name] + '")' })[0].click
  1752. instance.execute_script('$(\'label:contains(" ' + data[:name] + '")\').first().click()')
  1753. instance.find_elements({ css: '.modal button.js-submit' })[0].click
  1754. }
  1755. end
  1756. end
  1757. sleep 1
  1758. return true
  1759. }
  1760. screenshot(browser: instance, comment: 'group_create_failed')
  1761. fail 'group creation failed'
  1762. end
  1763. def quote(string)
  1764. string_quoted = string
  1765. string_quoted.gsub!(/&/, '&amp;')
  1766. string_quoted.gsub!(/</, '&lt;')
  1767. string_quoted.gsub!(/>/, '&gt;')
  1768. string_quoted
  1769. end
  1770. def switch_window_focus(params)
  1771. instance = params[:browser] || @browser
  1772. if instance != @last_used_browser
  1773. log('switch browser window focus', {})
  1774. instance.switch_to.window(instance.window_handles.first)
  1775. end
  1776. @last_used_browser = instance
  1777. end
  1778. def log(method, params)
  1779. return if !@@debug
  1780. return if params[:mute_log]
  1781. puts "#{Time.zone.now}/#{method}: #{params.inspect}"
  1782. end
  1783. end