browser_test_helper.rb 119 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699
  1. ENV['RAILS_ENV'] = 'test'
  2. # rubocop:disable HandleExceptions, NonLocalExitFromIterator, Style/GuardClause, Lint/MissingCopEnableDirective
  3. require File.expand_path('../config/environment', __dir__)
  4. require 'selenium-webdriver'
  5. require 'json'
  6. require 'net/http'
  7. require 'uri'
  8. class TestCase < Test::Unit::TestCase
  9. DEBUG = true
  10. def browser
  11. ENV['BROWSER'] || 'firefox'
  12. end
  13. def profile
  14. browser_profile = nil
  15. if browser == 'firefox'
  16. browser_profile = Selenium::WebDriver::Firefox::Profile.new
  17. browser_profile['intl.locale.matchOS'] = false
  18. browser_profile['intl.accept_languages'] = 'en-US'
  19. browser_profile['general.useragent.locale'] = 'en-US'
  20. # currently console log not working for firefox
  21. # https://github.com/SeleniumHQ/selenium/issues/1161
  22. #browser_profile['loggingPref'] = { browser: :all }
  23. elsif browser == 'chrome'
  24. # profile are only working on remote selenium
  25. if ENV['REMOTE_URL']
  26. browser_profile = Selenium::WebDriver::Chrome::Profile.new
  27. browser_profile['intl.accept_languages'] = 'en'
  28. browser_profile['loggingPref'] = { browser: :all }
  29. end
  30. end
  31. browser_profile
  32. end
  33. def browser_support_cookies
  34. if browser.match?(/(internet_explorer|ie)/i)
  35. return false
  36. end
  37. true
  38. end
  39. def browser_url
  40. return ENV['BROWSER_URL'] if ENV['BROWSER_URL'].present?
  41. "http://#{host}:3000"
  42. end
  43. def host
  44. return 'localhost' if ENV['CI'].blank?
  45. Socket.ip_address_list.detect(&:ipv4_private?).ip_address
  46. end
  47. def browser_instance
  48. @browsers ||= {}
  49. if ENV['REMOTE_URL'].blank?
  50. params = {
  51. profile: profile,
  52. }
  53. if ENV['BROWSER_HEADLESS'].present?
  54. if browser == 'firefox'
  55. params[:options] = Selenium::WebDriver::Firefox::Options.new
  56. params[:options].add_argument('-headless')
  57. elsif browser == 'chrome'
  58. params[:options] = Selenium::WebDriver::Chrome::Options.new
  59. params[:options].add_argument('-headless')
  60. end
  61. end
  62. local_browser = Selenium::WebDriver.for(browser.to_sym, params)
  63. @browsers[local_browser.hash] = local_browser
  64. browser_instance_preferences(local_browser)
  65. return local_browser
  66. end
  67. # avoid "Cannot read property 'get_Current' of undefined" issues
  68. (1..5).each do |count|
  69. begin
  70. local_browser = browser_instance_remote
  71. break
  72. rescue => e
  73. wait_until_ready = rand(5..13)
  74. log('browser_instance', { rescure: true, count: count, sleep: wait_until_ready, exception: e })
  75. sleep wait_until_ready
  76. end
  77. end
  78. local_browser
  79. end
  80. def browser_instance_remote
  81. caps = Selenium::WebDriver::Remote::Capabilities.send(browser)
  82. if ENV['BROWSER_OS']
  83. caps.platform = ENV['BROWSER_OS']
  84. end
  85. if ENV['BROWSER_VERSION']
  86. caps.version = ENV['BROWSER_VERSION']
  87. end
  88. # (ironically) required for timeout checks
  89. # https://github.com/zalando/zalenium/issues/469#issuecomment-371417340
  90. # https://opensource.zalando.com/zalenium/#usage
  91. caps['idleTimeout'] = 300
  92. http_client = Selenium::WebDriver::Remote::Http::Default.new(
  93. open_timeout: 120,
  94. read_timeout: 120
  95. )
  96. local_browser = Selenium::WebDriver.for(
  97. :remote,
  98. url: ENV['REMOTE_URL'],
  99. desired_capabilities: caps,
  100. http_client: http_client,
  101. )
  102. @browsers[local_browser.hash] = local_browser
  103. browser_instance_preferences(local_browser)
  104. # upload files from remote dir
  105. local_browser.file_detector = lambda do |args|
  106. str = args.first.to_s
  107. str if File.file?(str)
  108. end
  109. local_browser
  110. end
  111. def browser_instance_close(local_browser)
  112. return if !@browsers[local_browser.hash]
  113. @browsers.delete(local_browser.hash)
  114. local_browser.quit
  115. end
  116. def browser_instance_preferences(local_browser)
  117. browser_width = ENV['BROWSER_WIDTH'] || 1024
  118. browser_height = ENV['BROWSER_HEIGHT'] || 800
  119. local_browser.manage.window.resize_to(browser_width, browser_height)
  120. if !ENV['REMOTE_URL']&.match?(/saucelabs|(grid|ci)\.(zammad\.org|znuny\.com)/i)
  121. if @browsers.count == 1
  122. local_browser.manage.window.move_to(0, 0)
  123. else
  124. local_browser.manage.window.move_to(browser_width, 0)
  125. end
  126. end
  127. local_browser.manage.timeouts.implicit_wait = 3 # seconds
  128. end
  129. def teardown
  130. return if !@browsers
  131. @browsers.each_value do |local_browser|
  132. screenshot(browser: local_browser, comment: 'teardown')
  133. browser_instance_close(local_browser)
  134. end
  135. end
  136. def screenshot(params = {})
  137. instance = params[:browser] || @browser
  138. comment = params[:comment] || ''
  139. filename = "tmp/#{Time.zone.now.strftime('screenshot_%Y_%m_%d__%H_%M_%S_%L')}_#{comment}#{instance.hash}.png"
  140. log('screenshot', { filename: filename })
  141. instance.save_screenshot(filename)
  142. end
  143. =begin
  144. username = login(
  145. browser: browser1,
  146. username: 'someuser',
  147. password: 'somepassword',
  148. url: 'some url', # optional, in case of aleady opened brower a reload is done because url is called again
  149. remember_me: true, # optional
  150. auto_wizard: false, # optional, in case of auto wizard, skip login
  151. success: false, #optional
  152. )
  153. =end
  154. def login(params)
  155. switch_window_focus(params)
  156. log('login', params)
  157. instance = params[:browser] || @browser
  158. if params[:url]
  159. instance.get(params[:url])
  160. end
  161. # submit logs anyway
  162. instance.execute_script('App.Track.force()')
  163. element = instance.find_elements(css: '#login input[name="username"]')[0]
  164. if !element
  165. if params[:auto_wizard]
  166. watch_for(
  167. browser: instance,
  168. css: 'body',
  169. value: 'auto wizard is enabled',
  170. timeout: 10,
  171. )
  172. location(url: "#{browser_url}/#getting_started/auto_wizard")
  173. sleep 10
  174. login = instance.find_elements(css: '.user-menu .user a')[0].attribute('title')
  175. if login != params[:username]
  176. screenshot(browser: instance, comment: 'auto wizard login failed')
  177. raise 'auto wizard login failed'
  178. end
  179. assert(true, 'auto wizard login ok')
  180. clues_close(
  181. browser: instance,
  182. optional: true,
  183. )
  184. return
  185. end
  186. screenshot(browser: instance, comment: 'login_failed')
  187. raise 'No login box found'
  188. end
  189. element.clear
  190. element.send_keys(params[:username])
  191. element = instance.find_elements(css: '#login input[name="password"]')[0]
  192. element.clear
  193. element.send_keys(params[:password])
  194. if params[:remember_me]
  195. instance.find_elements(css: '#login .checkbox-replacement')[0].click
  196. end
  197. instance.find_elements(css: '#login button')[0].click
  198. sleep 4
  199. login_failed = false
  200. if !instance.find_elements(css: '.user-menu .user a')[0]
  201. login_failed = true
  202. else
  203. login = instance.find_elements(css: '.user-menu .user a')[0].attribute('title')
  204. if login != params[:username]
  205. login_failed = true
  206. end
  207. end
  208. if login_failed
  209. if params[:success] == false
  210. assert(true, 'login not successfull, like wanted')
  211. return true
  212. end
  213. screenshot(browser: instance, comment: 'login_failed')
  214. raise 'login failed'
  215. end
  216. if params[:success] == false
  217. raise 'login successfull but should not'
  218. end
  219. clues_close(
  220. browser: instance,
  221. optional: true,
  222. )
  223. assert(true, 'login ok')
  224. login
  225. end
  226. =begin
  227. logout(
  228. browser: browser1
  229. )
  230. =end
  231. def logout(params = {})
  232. switch_window_focus(params)
  233. log('logout', params)
  234. instance = params[:browser] || @browser
  235. click(
  236. browser: instance,
  237. css: 'a[href="#current_user"]',
  238. mute_log: true,
  239. )
  240. click(
  241. browser: instance,
  242. css: 'a[href="#logout"]',
  243. mute_log: true,
  244. )
  245. 5.times do
  246. sleep 1
  247. login = instance.find_elements(css: '#login')[0]
  248. next if !login
  249. assert(true, 'logout ok')
  250. return
  251. end
  252. screenshot(browser: instance, comment: 'logout_failed')
  253. raise 'no login box found, seems logout was not successfully!'
  254. end
  255. =begin
  256. clues_close(
  257. browser: browser1,
  258. optional: false,
  259. )
  260. =end
  261. def clues_close(params = {})
  262. switch_window_focus(params)
  263. log('clues_close', params)
  264. instance = params[:browser] || @browser
  265. clues = instance.find_elements(css: '.js-modal--clue .js-close')[0]
  266. if !params[:optional] && !clues
  267. screenshot(browser: instance, comment: 'no_clues')
  268. raise 'Unable to closes clues, no clues found!'
  269. end
  270. return if !clues
  271. instance.execute_script("$('.js-modal--clue .js-close').click()")
  272. assert(true, 'clues closed')
  273. sleep 1
  274. end
  275. =begin
  276. notify_close(
  277. browser: browser1,
  278. optional: false,
  279. )
  280. =end
  281. def notify_close(params = {})
  282. switch_window_focus(params)
  283. log('notify_close', params)
  284. instance = params[:browser] || @browser
  285. notify = instance.find_elements(css: '.noty_inline_layout_container.i-am-new')[0]
  286. if !params[:optional] && !notify
  287. screenshot(browser: instance, comment: 'no_notify')
  288. raise 'Unable to closes notify, no notify found!'
  289. end
  290. return if !notify
  291. notify.click
  292. assert(true, 'notify closed')
  293. sleep 1
  294. end
  295. =begin
  296. location(
  297. browser: browser1,
  298. url: 'http://someurl',
  299. )
  300. =end
  301. def location(params)
  302. switch_window_focus(params)
  303. log('location', params)
  304. instance = params[:browser] || @browser
  305. instance.get(params[:url])
  306. # check if reload was successfull
  307. if !instance.find_elements(css: 'body')[0] || instance.find_elements(css: 'body')[0].text =~ /unavailable or too busy/i
  308. instance.navigate.refresh
  309. end
  310. end
  311. =begin
  312. location_check(
  313. browser: browser1,
  314. url: 'http://someurl',
  315. )
  316. =end
  317. def location_check(params)
  318. switch_window_focus(params)
  319. log('location_check', params)
  320. instance = params[:browser] || @browser
  321. sleep 0.7
  322. current_url = instance.current_url
  323. if !current_url.match?(/#{Regexp.quote(params[:url])}/)
  324. screenshot(browser: instance, comment: 'location_check_failed')
  325. raise "url #{current_url} is not matching #{params[:url]}"
  326. end
  327. assert(true, "url #{current_url} is matching #{params[:url]}")
  328. end
  329. =begin
  330. reload(
  331. browser: browser1,
  332. )
  333. =end
  334. def reload(params = {})
  335. switch_window_focus(params)
  336. log('reload', params)
  337. instance = params[:browser] || @browser
  338. instance.navigate.refresh
  339. # check if reload was successfull
  340. if !instance.find_elements(css: 'body')[0] || instance.find_elements(css: 'body')[0].text =~ /unavailable or too busy/i
  341. instance.navigate.refresh
  342. end
  343. screenshot(browser: instance, comment: 'reload_after')
  344. end
  345. =begin
  346. click(
  347. browser: browser1,
  348. css: '.some_class',
  349. fast: false, # do not wait
  350. wait: 1, # wait 1 sec.
  351. )
  352. click(
  353. browser: browser1,
  354. xpath: '//a[contains(@class,".text-1")]',
  355. fast: false, # do not wait
  356. wait: 1, # wait 1 sec.
  357. )
  358. click(
  359. browser: browser1,
  360. text: '.partial_link_text',
  361. fast: false, # do not wait
  362. wait: 1, # wait 1 sec.
  363. )
  364. =end
  365. def click(params)
  366. switch_window_focus(params)
  367. log('click', params)
  368. instance = params[:browser] || @browser
  369. if params.include?(:css)
  370. param_key = :css
  371. find_element_key = :css
  372. elsif params.include?(:xpath)
  373. param_key = :xpath
  374. find_element_key = :xpath
  375. else
  376. param_key = :text
  377. find_element_key = :partial_link_text
  378. sleep 0.5
  379. end
  380. begin
  381. elements = instance.find_elements(find_element_key => params[param_key])
  382. .tap { |e| e.slice!(1..-1) unless params[:all] }
  383. if elements.empty?
  384. return if params[:only_if_exists] == true
  385. raise "No such element '#{params[param_key]}'"
  386. end
  387. # a clumsy substitute for elements.each(&:click)
  388. # (we need to refresh element references after each element.click
  389. # because if clicks alter page content,
  390. # subsequent element.clicks will raise a StaleElementReferenceError)
  391. elements.length.times do |i|
  392. instance.find_elements(find_element_key => params[param_key])[i].try(:click)
  393. end
  394. rescue => e
  395. raise e if (fail_count ||= 0).positive?
  396. fail_count += 1
  397. log('click', { rescure: true })
  398. sleep 0.5
  399. retry
  400. end
  401. sleep 0.2 if !params[:fast]
  402. sleep params[:wait] if params[:wait]
  403. end
  404. =begin
  405. perform_macro('Close & Tag as Spam')
  406. # or
  407. perform_macro(
  408. name: 'Close & Tag as Spam',
  409. browser: browser1,
  410. )
  411. =end
  412. def perform_macro(params)
  413. switch_window_focus(params)
  414. log('perform_macro', params)
  415. instance = params[:browser] || @browser
  416. click(
  417. browser: instance,
  418. css: '.active.content .js-submitDropdown .js-openDropdownMacro'
  419. )
  420. click(
  421. browser: instance,
  422. xpath: "//div[contains(@class, 'content') and contains(@class, 'active')]//li[contains(@class, 'js-dropdownActionMacro') and contains(text(), '#{params[:name]}')]"
  423. )
  424. end
  425. =begin
  426. scroll_to(
  427. browser: browser1,
  428. position: 'top', # botton
  429. css: '.some_class',
  430. )
  431. =end
  432. def scroll_to(params)
  433. switch_window_focus(params)
  434. log('scroll_to', params)
  435. instance = params[:browser] || @browser
  436. position = 'true'
  437. if params[:position] == 'botton'
  438. position = 'false'
  439. end
  440. execute(
  441. browser: instance,
  442. js: "\$('#{params[:css]}').get(0).scrollIntoView(#{position})",
  443. mute_log: params[:mute_log]
  444. )
  445. sleep 0.3
  446. screenshot(browser: instance, comment: 'scroll_to_after')
  447. end
  448. =begin
  449. modal_close(
  450. browser: browser1,
  451. )
  452. =end
  453. def modal_close(params = {})
  454. switch_window_focus(params)
  455. log('modal_close', params)
  456. instance = params[:browser] || @browser
  457. element = instance.find_elements(css: '.modal .js-close')[0]
  458. raise "No such modal to close #{params.inspect}" if !element
  459. element.click
  460. end
  461. =begin
  462. modal_ready(
  463. browser: browser1,
  464. )
  465. =end
  466. def modal_ready(params = {})
  467. switch_window_focus(params)
  468. log('modal_ready', params)
  469. instance = params[:browser] || @browser
  470. watch_for(
  471. browser: instance,
  472. css: '.modal.in',
  473. timeout: params[:timeout] || 4,
  474. )
  475. end
  476. =begin
  477. modal_disappear(
  478. browser: browser1,
  479. timeout: 12, # default 8
  480. )
  481. =end
  482. def modal_disappear(params = {})
  483. switch_window_focus(params)
  484. log('modal_disappear', params)
  485. instance = params[:browser] || @browser
  486. watch_for_disappear(
  487. browser: instance,
  488. css: '.modal',
  489. timeout: params[:timeout] || 8,
  490. )
  491. end
  492. =begin
  493. execute(
  494. browser: browser1,
  495. js: '.some_class',
  496. )
  497. =end
  498. def execute(params)
  499. switch_window_focus(params)
  500. log('js', params)
  501. instance = params[:browser] || @browser
  502. if params[:js]
  503. return instance.execute_script(params[:js])
  504. end
  505. raise "Invalid execute params #{params.inspect}"
  506. end
  507. =begin
  508. exists(
  509. browser: browser1,
  510. css: '.some_class',
  511. )
  512. exists(
  513. displayed: false, # true|false
  514. browser: browser1,
  515. css: '.some_class',
  516. displayed: true, # true|false
  517. )
  518. =end
  519. def exists(params)
  520. retries ||= 0
  521. switch_window_focus(params)
  522. log('exists', params)
  523. instance = params[:browser] || @browser
  524. if !instance.find_elements(css: params[:css])[0]
  525. screenshot(browser: instance, comment: 'exists_failed')
  526. raise "#{params[:css]} dosn't exist, but should"
  527. end
  528. if params.key?(:displayed)
  529. if params[:displayed] == true && !instance.find_elements(css: params[:css])[0].displayed?
  530. raise "#{params[:css]} is not displayed, but should"
  531. end
  532. if params[:displayed] == false && instance.find_elements(css: params[:css])[0].displayed?
  533. raise "#{params[:css]} is displayed, but should not"
  534. end
  535. end
  536. true
  537. rescue Selenium::WebDriver::Error::StaleElementReferenceError
  538. sleep retries
  539. retries += 1
  540. retry if retries < 3
  541. end
  542. =begin
  543. exists_not(
  544. browser: browser1,
  545. css: '.some_class',
  546. )
  547. =end
  548. def exists_not(params)
  549. switch_window_focus(params)
  550. log('exists_not', params)
  551. instance = params[:browser] || @browser
  552. if instance.find_elements(css: params[:css])[0]
  553. screenshot(browser: instance, comment: 'exists_not_failed')
  554. raise "#{params[:css]} exists but should not"
  555. end
  556. true
  557. end
  558. =begin
  559. set(
  560. browser: browser1,
  561. css: '.some_class',
  562. value: true,
  563. slow: false,
  564. blur: true, # default false
  565. clear: true, # todo | default: true
  566. no_click: true,
  567. )
  568. =end
  569. def set(params)
  570. switch_window_focus(params)
  571. log('set', params)
  572. instance = params[:browser] || @browser
  573. element = instance.find_elements(css: params[:css])[0]
  574. if !params[:no_click]
  575. element.click
  576. end
  577. element.clear
  578. begin
  579. if !params[:slow]
  580. element.send_keys(params[:value])
  581. else
  582. element.send_keys('')
  583. keys = params[:value].to_s.split('')
  584. keys.each do |key|
  585. instance.action.send_keys(key).perform
  586. end
  587. end
  588. rescue => e
  589. sleep 0.5
  590. # just try again
  591. log('set', { rescure: true })
  592. element = instance.find_elements(css: params[:css])[0]
  593. raise "No such element '#{params[:css]}'" if !element
  594. if !params[:slow]
  595. element.send_keys(params[:value])
  596. else
  597. element.send_keys('')
  598. keys = params[:value].to_s.split('')
  599. keys.each do |key|
  600. instance.action.send_keys(key).perform
  601. end
  602. end
  603. end
  604. # it's not working stable with ff via selenium, use js
  605. if browser =~ /firefox/i && params[:css] =~ /\[data-name=/
  606. log('set_ff_trigger_workaround', params)
  607. instance.execute_script("$('#{params[:css]}').trigger('focusout')")
  608. end
  609. if params[:blur]
  610. instance.execute_script("$('#{params[:css]}').blur()")
  611. end
  612. sleep 0.2
  613. end
  614. =begin
  615. select(
  616. browser: browser1,
  617. css: '.some_class',
  618. value: 'Some Value',
  619. deselect_all: false, # default false
  620. )
  621. =end
  622. def select(params)
  623. switch_window_focus(params)
  624. log('select', params)
  625. instance = params[:browser] || @browser
  626. # searchable select
  627. element = instance.find_elements(css: "#{params[:css]}.js-shadow")[0]
  628. if element
  629. element = instance.find_elements(css: "#{params[:css]}.js-shadow + .js-input")[0]
  630. element.click
  631. element.clear
  632. sleep 0.2
  633. element.send_keys(params[:value])
  634. sleep 0.2
  635. element.send_keys(:enter)
  636. sleep 0.2
  637. return
  638. end
  639. # native select
  640. begin
  641. element = instance.find_elements(css: params[:css])[0]
  642. dropdown = Selenium::WebDriver::Support::Select.new(element)
  643. if params[:deselect_all]
  644. dropdown.deselect_all
  645. end
  646. dropdown.select_by(:text, params[:value])
  647. #puts "select - #{params.inspect}"
  648. rescue
  649. sleep 0.4
  650. # just try again
  651. log('select', { rescure: true })
  652. element = instance.find_elements(css: params[:css])[0]
  653. dropdown = Selenium::WebDriver::Support::Select.new(element)
  654. if params[:deselect_all]
  655. dropdown.deselect_all
  656. end
  657. dropdown.select_by(:text, params[:value])
  658. #puts "select2 - #{params.inspect}"
  659. end
  660. end
  661. =begin
  662. switch(
  663. browser: browser1,
  664. css: '.some_class',
  665. type: 'on', # 'off'
  666. no_check: true, # do not check is switch has changed, in case if js alert
  667. )
  668. =end
  669. def switch(params)
  670. switch_window_focus(params)
  671. log('switch', params)
  672. instance = params[:browser] || @browser
  673. element = instance.find_elements(css: "#{params[:css]} input[type=checkbox]")[0]
  674. checked = element.attribute('checked')
  675. if !checked
  676. if params[:type] == 'on'
  677. instance.find_elements(css: "#{params[:css]} label")[0].click
  678. sleep 2
  679. if params[:no_check] != true
  680. element = instance.find_elements(css: "#{params[:css]} input[type=checkbox]")[0]
  681. checked = element.attribute('checked')
  682. raise 'Switch not on!' if !checked
  683. end
  684. end
  685. elsif params[:type] == 'off'
  686. instance.find_elements(css: "#{params[:css]} label")[0].click
  687. sleep 2
  688. if params[:no_check] != true
  689. element = instance.find_elements(css: "#{params[:css]} input[type=checkbox]")[0]
  690. checked = element.attribute('checked')
  691. raise 'Switch not off!' if checked
  692. end
  693. end
  694. end
  695. =begin
  696. check(
  697. browser: browser1,
  698. css: '.some_class',
  699. )
  700. =end
  701. def check(params)
  702. switch_window_focus(params)
  703. log('check', params)
  704. instance = params[:browser] || @browser
  705. instance.execute_script("$('#{params[:css]}:not(:checked)').click()")
  706. #element = instance.find_elements(css: params[:css])[0]
  707. #checked = element.attribute('checked')
  708. #element.click if !checked
  709. end
  710. =begin
  711. uncheck(
  712. browser: browser1,
  713. css: '.some_class',
  714. )
  715. =end
  716. def uncheck(params)
  717. switch_window_focus(params)
  718. log('uncheck', params)
  719. instance = params[:browser] || @browser
  720. instance.execute_script("$('#{params[:css]}:checked').click()")
  721. #element = instance.find_elements(css: params[:css])[0]
  722. #checked = element.attribute('checked')
  723. #element.click if checked
  724. end
  725. =begin
  726. sendkey(
  727. browser: browser1,
  728. value: :enter,
  729. slow: false, # default false
  730. )
  731. =end
  732. def sendkey(params)
  733. switch_window_focus(params)
  734. log('sendkey', params)
  735. instance = params[:browser] || @browser
  736. element = nil
  737. if params[:css]
  738. element = instance.find_elements(css: params[:css])[0]
  739. end
  740. if params[:value].class == Array
  741. params[:value].each do |key|
  742. if element
  743. element.send_keys(key)
  744. else
  745. instance.action.send_keys(key).perform
  746. end
  747. end
  748. return
  749. end
  750. if element
  751. element.send_keys(params[:value])
  752. else
  753. instance.action.send_keys(params[:value]).perform
  754. end
  755. if params[:slow]
  756. sleep 1.5
  757. else
  758. sleep 0.2
  759. end
  760. end
  761. =begin
  762. match(
  763. browser: browser1,
  764. css: '#content .text-1',
  765. value: 'some test for browser and some other for browser',
  766. attribute: 'some_attribute', # match on attribute
  767. should_not_match: true,
  768. no_quote: false, # use regex
  769. )
  770. =end
  771. def match(params, fallback = false)
  772. switch_window_focus(params)
  773. log('match', params)
  774. instance = params[:browser] || @browser
  775. element = instance.find_elements(css: params[:css])[0]
  776. if params[:css].match?(/select/)
  777. dropdown = Selenium::WebDriver::Support::Select.new(element)
  778. success = false
  779. dropdown.selected_options&.each do |option|
  780. if option.text == params[:value]
  781. success = true
  782. end
  783. end
  784. if params[:should_not_match]
  785. if success
  786. screenshot(browser: instance, comment: 'match_failed')
  787. raise "should not match '#{params[:value]}' in select list, but is matching"
  788. end
  789. elsif !success
  790. screenshot(browser: instance, comment: 'match_failed')
  791. raise "not matching '#{params[:value]}' in select list"
  792. end
  793. return true
  794. end
  795. # match on attribute
  796. begin
  797. text = if params[:attribute]
  798. element.attribute(params[:attribute])
  799. elsif params[:css].match?(/(input|textarea)/i)
  800. element.attribute('value')
  801. else
  802. element.text
  803. end
  804. rescue => e
  805. # just try again
  806. if !fallback
  807. return match(params, true)
  808. end
  809. raise e.inspect
  810. end
  811. # do cleanups (needed for richtext tests)
  812. if params[:cleanup]
  813. text.gsub!(/\s+$/m, '')
  814. params[:value].gsub!(/\s+$/m, '')
  815. end
  816. match = false
  817. if params[:no_quote]
  818. #puts "aaaa #{text}/#{params[:value]}"
  819. if text =~ /#{params[:value]}/i
  820. match = $1 || true
  821. end
  822. elsif text.match?(/#{Regexp.quote(params[:value])}/i)
  823. match = true
  824. end
  825. if match
  826. if params[:should_not_match]
  827. screenshot(browser: instance, comment: 'match_failed')
  828. raise "matching '#{params[:value]}' in content '#{text}' but should not!"
  829. end
  830. elsif !params[:should_not_match]
  831. screenshot(browser: instance, comment: 'match_failed')
  832. raise "not matching '#{params[:value]}' in content '#{text}' but should!"
  833. end
  834. sleep 0.2
  835. match
  836. end
  837. =begin
  838. match_not(
  839. browser: browser1,
  840. css: '#content .text-1',
  841. value: 'some test for browser and some other for browser',
  842. attribute: 'some_attribute', # match on attribute
  843. should_not_match: true,
  844. no_quote: false, # use regex
  845. )
  846. =end
  847. def match_not(params)
  848. switch_window_focus(params)
  849. log('match_not', params)
  850. params[:should_not_match] = true
  851. match(params)
  852. end
  853. =begin
  854. Get the on-screen pixel coordinates of a given DOM element. Can be used to compare
  855. the relative location of table rows before and after sort, for example.
  856. Returns a Selenium::WebDriver::Point object. Use result.x and result.y to access
  857. its X and Y coordinates respectively.
  858. get_location(
  859. browser: browser1,
  860. css: '.some_class',
  861. )
  862. =end
  863. def get_location(params)
  864. switch_window_focus(params)
  865. log('exists', params)
  866. instance = params[:browser] || @browser
  867. if params[:css]
  868. query = { css: params[:css] }
  869. end
  870. if params[:xpath]
  871. query = { xpath: params[:xpath] }
  872. end
  873. if !instance.find_elements(query)[0]
  874. screenshot(browser: instance, comment: 'exists_failed')
  875. raise "#{query} dosn't exist, but should"
  876. end
  877. instance.find_elements(query)[0].location
  878. end
  879. =begin
  880. set type of task (closeTab, closeNextInOverview, stayOnTab)
  881. task_type(
  882. browser: browser1,
  883. type: 'stayOnTab',
  884. )
  885. =end
  886. def task_type(params)
  887. switch_window_focus(params)
  888. log('task_type', params)
  889. instance = params[:browser] || @browser
  890. if params[:type]
  891. instance.find_elements(css: '.content.active .js-secondaryActionButtonLabel')[0].click
  892. instance.find_elements(css: ".content.active .js-secondaryActionLabel[data-type=#{params[:type]}]")[0].click
  893. return
  894. end
  895. raise "Unknown params for task_type: #{params.inspect}"
  896. end
  897. =begin
  898. cookie(
  899. browser: browser1,
  900. name: '^_zammad.+?',
  901. value: '.+?',
  902. expires: nil,
  903. )
  904. cookie(
  905. browser: browser1,
  906. name: '^_zammad.+?',
  907. should_not_exist: true,
  908. )
  909. =end
  910. def cookie(params)
  911. switch_window_focus(params)
  912. log('cookie', params)
  913. instance = params[:browser] || @browser
  914. if !browser_support_cookies
  915. assert(true, "'#{params[:value]}' ups browser is not supporting reading cookies, go ahead")
  916. return true
  917. end
  918. cookies = instance.manage.all_cookies
  919. cookies.each do |cookie|
  920. # :name=>"_zammad_session_c25832f4de2", :value=>"adc31cd21615cb0a7ab269184ec8b76f", :path=>"/", :domain=>"localhost", :expires=>nil, :secure=>false}
  921. next if cookie[:name] !~ /#{params[:name]}/i
  922. if params.key?(:value) && cookie[:value].to_s =~ /#{params[:value]}/i
  923. assert(true, "matching value '#{params[:value]}' in cookie '#{cookie}'")
  924. else
  925. raise "not matching value '#{params[:value]}' in cookie '#{cookie}'"
  926. end
  927. if params.key?(:expires) && cookie[:expires].to_s =~ /#{params[:expires]}/i
  928. assert(true, "matching expires '#{params[:expires].inspect}' in cookie '#{cookie}'")
  929. else
  930. raise "not matching expires '#{params[:expires]}' in cookie '#{cookie}'"
  931. end
  932. return if !params[:should_not_exist]
  933. raise "cookie with name '#{params[:name]}' should not exist, but exists '#{cookies}'"
  934. end
  935. if params[:should_not_exist]
  936. assert(true, "cookie with name '#{params[:name]}' is not existing")
  937. return
  938. end
  939. raise "not matching name '#{params[:name]}' in cookie '#{cookies}'"
  940. end
  941. =begin
  942. verify_title(
  943. browser: browser1,
  944. value: 'some title',
  945. )
  946. =end
  947. def verify_title(params = {})
  948. switch_window_focus(params)
  949. log('verify_title', params)
  950. instance = params[:browser] || @browser
  951. title = instance.title
  952. if title.match?(/#{params[:value]}/i)
  953. assert(true, "matching '#{params[:value]}' in title '#{title}'")
  954. else
  955. raise "not matching '#{params[:value]}' in title '#{title}'"
  956. end
  957. end
  958. =begin
  959. verify_task(
  960. browser: browser1,
  961. data: {
  962. title: 'some title',
  963. modified: true, # optional
  964. }
  965. )
  966. =end
  967. def verify_task(params = {}, fallback = false)
  968. switch_window_focus(params)
  969. log('verify_task', params)
  970. instance = params[:browser] || @browser
  971. data = params[:data]
  972. sleep 1
  973. begin
  974. # verify title
  975. if data[:title]
  976. title = instance.find_elements(css: '.tasks .is-active')[0].text.strip
  977. if title.match?(/#{data[:title]}/i)
  978. assert(true, "matching '#{data[:title]}' in title '#{title}'")
  979. else
  980. screenshot(browser: instance, comment: 'verify_task_failed')
  981. raise "not matching '#{data[:title]}' in title '#{title}'"
  982. end
  983. end
  984. # verify modified
  985. if data.key?(:modified)
  986. exists = instance.find_elements(css: '.tasks .is-active')[0]
  987. is_modified = instance.find_elements(css: '.tasks .is-modified')[0]
  988. puts "m #{data[:modified].inspect}"
  989. if exists
  990. puts ' exists'
  991. end
  992. if is_modified
  993. puts ' is_modified'
  994. end
  995. if data[:modified] == true
  996. if is_modified
  997. assert(true, "task '#{data[:title]}' is modifed")
  998. elsif !exists
  999. screenshot(browser: instance, comment: 'verify_task_failed')
  1000. raise "task '#{data[:title]}' not exists, should not modified"
  1001. else
  1002. screenshot(browser: instance, comment: 'verify_task_failed')
  1003. raise "task '#{data[:title]}' is not modifed"
  1004. end
  1005. elsif !is_modified
  1006. assert(true, "task '#{data[:title]}' is modifed")
  1007. elsif !exists
  1008. screenshot(browser: instance, comment: 'verify_task_failed')
  1009. raise "task '#{data[:title]}' not exists, should be not modified"
  1010. else
  1011. screenshot(browser: instance, comment: 'verify_task_failed')
  1012. raise "task '#{data[:title]}' is modifed, but should not"
  1013. end
  1014. end
  1015. rescue => e
  1016. # just try again
  1017. if !fallback
  1018. verify_task(params, true)
  1019. end
  1020. raise 'ERROR: ' + e.inspect
  1021. end
  1022. true
  1023. end
  1024. =begin
  1025. open_task(
  1026. browser: browser1,
  1027. data: {
  1028. title: 'some title',
  1029. }
  1030. )
  1031. =end
  1032. def open_task(params = {})
  1033. switch_window_focus(params)
  1034. log('open_task', params)
  1035. instance = params[:browser] || @browser
  1036. data = params[:data]
  1037. element = instance.find_element(css: '#navigation').find_element(partial_link_text: data[:title])
  1038. if !element
  1039. screenshot(browser: instance, comment: 'open_task_failed')
  1040. raise "no task with title '#{data[:title]}' found"
  1041. end
  1042. # firefix/marionette issue with Selenium::WebDriver::Error::ElementNotInteractableError: could not be scrolled into view
  1043. # use js workaround instead of native click
  1044. instance.execute_script("$('#navigation .tasks .task:contains(\"#{data[:title]}\") .nav-tab-name').click()")
  1045. #element.click
  1046. true
  1047. end
  1048. =begin
  1049. close_task(
  1050. browser: browser1,
  1051. data: {
  1052. title: 'some title',
  1053. },
  1054. discard_changes: true,
  1055. )
  1056. =end
  1057. def close_task(params = {})
  1058. switch_window_focus(params)
  1059. log('close_task', params)
  1060. instance = params[:browser] || @browser
  1061. data = params[:data]
  1062. element = instance.find_element(css: '#navigation').find_element(partial_link_text: data[:title])
  1063. if !element
  1064. screenshot(browser: instance, comment: 'close_task_failed')
  1065. raise "no task with title '#{data[:title]}' found"
  1066. end
  1067. instance.action.move_to(element).release.perform
  1068. sleep 0.1
  1069. instance.execute_script("$('#navigation .tasks .task:contains(\"#{data[:title]}\") .js-close').click()")
  1070. # accept task close warning
  1071. if params[:discard_changes]
  1072. modal_ready(browser: instance)
  1073. instance.find_elements(css: '.modal button.js-submit')[0].click
  1074. modal_disappear(browser: instance)
  1075. end
  1076. true
  1077. end
  1078. =begin
  1079. file_upload(
  1080. browser: browser1,
  1081. css: '.content.active .attachmentPlaceholder-inputHolder input'
  1082. files: ['path/in/home/some_file.ext'], # 'test/data/pdf/test1.pdf'
  1083. )
  1084. =end
  1085. def file_upload(params = {})
  1086. switch_window_focus(params)
  1087. log('file_upload', params)
  1088. instance = params[:browser] || @browser
  1089. params[:files].each do |file|
  1090. instance.find_elements(css: params[:css])[0].send_keys(Rails.root.join(file))
  1091. end
  1092. return if params[:no_sleep]
  1093. sleep 2 * params[:files].count
  1094. end
  1095. =begin
  1096. watch_for(
  1097. browser: browser1,
  1098. container: element # optional, defaults to browser, must exist at the time of dispatch
  1099. css: '#content .text-1', # xpath or css required
  1100. xpath: '/content[contains(@class,".text-1")]', # xpath or css required
  1101. value: 'some text',
  1102. attribute: 'some_attribute' # optional
  1103. timeout: 16, # in sec, default 16
  1104. )
  1105. =end
  1106. def watch_for(params = {})
  1107. switch_window_focus(params)
  1108. log('watch_for', params)
  1109. browser = params[:browser] || @browser
  1110. instance = params[:container] || browser
  1111. selector = params[:css] || params[:xpath]
  1112. selector_type = if params.key?(:css)
  1113. :css
  1114. elsif params.key?(:xpath)
  1115. :xpath
  1116. end
  1117. timeout = 16
  1118. if params[:timeout]
  1119. timeout = params[:timeout]
  1120. end
  1121. loops = timeout.to_i * 2
  1122. text = ''
  1123. (1..loops).each do
  1124. element = instance.find_elements(selector_type => selector)[0]
  1125. if element #&& element.displayed?
  1126. begin
  1127. # watch for selector
  1128. if !params[:attribute] && !params[:value]
  1129. assert(true, "'#{selector}' found")
  1130. sleep 0.5
  1131. return true
  1132. # match an attribute
  1133. else
  1134. text = if params[:attribute]
  1135. element.attribute(params[:attribute])
  1136. elsif selector.match?(/(input|textarea)/i)
  1137. element.attribute('value')
  1138. else
  1139. element.text
  1140. end
  1141. if text.match?(/#{params[:value]}/i)
  1142. assert(true, "'#{params[:value]}' found in '#{text}'")
  1143. sleep 0.5
  1144. return true
  1145. end
  1146. end
  1147. rescue
  1148. # try again
  1149. end
  1150. end
  1151. sleep 0.5
  1152. end
  1153. screenshot(browser: browser, comment: 'watch_for_failed')
  1154. if !params[:attribute] && !params[:value]
  1155. raise "'#{selector}' not found"
  1156. end
  1157. raise "'#{params[:value]}' not found in '#{text}'"
  1158. end
  1159. =begin
  1160. wait untill selector disabppears
  1161. watch_for_disappear(
  1162. browser: browser1,
  1163. css: '#content .text-1',
  1164. timeout: 16, # in sec, default 16
  1165. )
  1166. wait untill text in selector disabppears
  1167. watch_for_disappear(
  1168. browser: browser1,
  1169. css: '#content .text-1',
  1170. value: 'some value as regexp',
  1171. timeout: 16, # in sec, default 16
  1172. )
  1173. =end
  1174. def watch_for_disappear(params = {})
  1175. switch_window_focus(params)
  1176. log('watch_for_disappear', params)
  1177. instance = params[:browser] || @browser
  1178. timeout = 16
  1179. if params[:timeout]
  1180. timeout = params[:timeout]
  1181. end
  1182. loops = timeout.to_i
  1183. text = ''
  1184. (1..loops).each do
  1185. element = instance.find_elements(css: params[:css])[0]
  1186. if !element #|| element.displayed?
  1187. assert(true, 'not found')
  1188. sleep 1
  1189. return true
  1190. end
  1191. if params[:value]
  1192. begin
  1193. text = instance.find_elements(css: params[:css])[0].text
  1194. if !text.match?(/#{params[:value]}/i)
  1195. assert(true, "not matching '#{params[:value]}' in text '#{text}'")
  1196. sleep 1
  1197. return true
  1198. end
  1199. rescue
  1200. # try again
  1201. end
  1202. end
  1203. sleep 1
  1204. end
  1205. screenshot(browser: instance, comment: 'disappear_failed')
  1206. raise "#{params[:css]}) still exsists"
  1207. end
  1208. =begin
  1209. shortcut(
  1210. browser: browser1,
  1211. key: 'x',
  1212. )
  1213. =end
  1214. def shortcut(params = {})
  1215. switch_window_focus(params)
  1216. log('shortcut', params)
  1217. instance = params[:browser] || @browser
  1218. screenshot(browser: instance, comment: 'shortcut_before')
  1219. instance.action.key_down(:control)
  1220. .key_down(:shift)
  1221. .send_keys(params[:key])
  1222. .key_up(:shift)
  1223. .key_up(:control)
  1224. .perform
  1225. screenshot(browser: instance, comment: 'shortcut_after')
  1226. end
  1227. =begin
  1228. window_keys(
  1229. browser: browser1,
  1230. value: 'x',
  1231. )
  1232. =end
  1233. def window_keys(params = {})
  1234. switch_window_focus(params)
  1235. log('window_keys', params)
  1236. instance = params[:browser] || @browser
  1237. instance.action.send_keys(params[:value]).perform
  1238. end
  1239. =begin
  1240. tasks_close_all(
  1241. browser: browser1,
  1242. )
  1243. =end
  1244. def tasks_close_all(params = {})
  1245. switch_window_focus(params)
  1246. log('tasks_close_all', params)
  1247. instance = params[:browser] || @browser
  1248. 99.times do
  1249. #sleep 0.5
  1250. begin
  1251. if instance.find_elements(css: '#navigation .tasks .task:first-child')[0]
  1252. instance.action.move_to(instance.find_elements(css: '#navigation .tasks .task:first-child')[0]).release.perform
  1253. click_element = instance.find_elements(css: '#navigation .tasks .task:first-child .js-close')[0]
  1254. if click_element
  1255. click_element.click
  1256. # accept task close warning
  1257. if instance.find_elements(css: '.modal button.js-submit')[0]
  1258. sleep 0.4
  1259. instance.find_elements(css: '.modal button.js-submit')[0].click
  1260. end
  1261. end
  1262. else
  1263. break
  1264. end
  1265. rescue
  1266. # try again
  1267. end
  1268. end
  1269. assert(true, 'all tasks closed')
  1270. end
  1271. =begin
  1272. close_online_notitifcation(
  1273. browser: browser1,
  1274. data: {
  1275. #title: 'some title',
  1276. position: 3,
  1277. },
  1278. )
  1279. =end
  1280. def close_online_notitifcation(params = {})
  1281. switch_window_focus(params)
  1282. log('close_online_notitifcation', params)
  1283. instance = params[:browser] || @browser
  1284. data = params[:data]
  1285. if data[:title]
  1286. element = instance.find_elements(partial_link_text: data[:title])[0]
  1287. if !element
  1288. screenshot(browser: instance, comment: 'close_online_notitifcation')
  1289. raise "no online notification with title '#{data[:title]}' found"
  1290. end
  1291. instance.action.move_to(element).release.perform
  1292. sleep 0.1
  1293. instance.execute_script("$('.js-notificationsContainer .js-items .js-item .activity-text:contains(\"#{data[:title]}\") .js-remove').first().click()")
  1294. else
  1295. css = ".js-notificationsContainer .js-items .js-item:nth-child(#{data[:position]})"
  1296. element = instance.find_elements(css: css)[0]
  1297. if !element
  1298. screenshot(browser: instance, comment: 'close_online_notitifcation')
  1299. raise "no online notification with postion '#{css}' found"
  1300. end
  1301. instance.action.move_to(element).release.perform
  1302. sleep 0.1
  1303. instance.find_elements(css: "#{css} .js-remove")[0].click
  1304. end
  1305. true
  1306. end
  1307. =begin
  1308. online_notitifcation_close_all(
  1309. browser: browser1,
  1310. )
  1311. =end
  1312. def online_notitifcation_close_all(params = {})
  1313. switch_window_focus(params)
  1314. log('online_notitifcation_close_all', params)
  1315. instance = params[:browser] || @browser
  1316. 99.times do
  1317. sleep 0.5
  1318. begin
  1319. if instance.find_elements(css: '.js-notificationsContainer .js-item:first-child')[0]
  1320. instance.action.move_to(instance.find_elements(css: '.js-notificationsContainer .js-item:first-child')[0]).perform
  1321. sleep 0.1
  1322. click_element = instance.find_elements(css: '.js-notificationsContainer .js-item:first-child .js-remove')[0]
  1323. click_element&.click
  1324. else
  1325. break
  1326. end
  1327. rescue
  1328. # try again
  1329. end
  1330. end
  1331. assert(true, 'all online notification closed')
  1332. end
  1333. =begin
  1334. empty_search(
  1335. browser: browser1,
  1336. )
  1337. =end
  1338. def empty_search(params = {})
  1339. switch_window_focus(params)
  1340. log('empty_search', params)
  1341. instance = params[:browser] || @browser
  1342. # empty search box by x
  1343. begin
  1344. instance.find_elements(css: '.search .js-emptySearch')[0].click
  1345. rescue
  1346. # in issues with ff & selenium, sometimes exeption appears
  1347. # "Element is not currently visible and so may not be interacted with"
  1348. log('empty_search via js')
  1349. instance.execute_script('$(".search .js-emptySearch").click()')
  1350. end
  1351. sleep 0.5
  1352. text = instance.find_elements(css: '#global-search')[0].attribute('value')
  1353. if !text
  1354. raise '#global-search is not empty!'
  1355. end
  1356. true
  1357. end
  1358. =begin
  1359. ticket_customer_select(
  1360. browser: browser1,
  1361. css: '#content .text-1',
  1362. customer: '',
  1363. )
  1364. =end
  1365. def ticket_customer_select(params = {})
  1366. switch_window_focus(params)
  1367. log('ticket_customer_select', params)
  1368. instance = params[:browser] || @browser
  1369. element = instance.find_elements(css: params[:css] + ' input[name="customer_id_completion"]')[0]
  1370. element.click
  1371. element.clear
  1372. element.send_keys(params[:customer])
  1373. sleep 2.5
  1374. element.send_keys(:enter)
  1375. #instance.find_elements(css: params[:css] + ' .recipientList-entry.js-object.is-active')[0].click
  1376. sleep 0.4
  1377. assert(true, 'ticket_customer_select')
  1378. end
  1379. =begin
  1380. overview_create(
  1381. browser: browser1,
  1382. data: {
  1383. name: name,
  1384. roles: ['Agent'],
  1385. selector: {
  1386. 'Priority': '1 low',
  1387. },
  1388. 'order::direction' => 'down',
  1389. }
  1390. )
  1391. =end
  1392. def overview_create(params)
  1393. switch_window_focus(params)
  1394. log('overview_create', params)
  1395. instance = params[:browser] || @browser
  1396. data = params[:data]
  1397. click(
  1398. browser: instance,
  1399. css: 'a[href="#manage"]',
  1400. mute_log: true,
  1401. )
  1402. click(
  1403. browser: instance,
  1404. css: '.content.active a[href="#manage/overviews"]',
  1405. mute_log: true,
  1406. )
  1407. click(
  1408. browser: instance,
  1409. css: '.content.active a[data-type="new"]',
  1410. mute_log: true,
  1411. )
  1412. modal_ready(browser: instance)
  1413. if data[:name]
  1414. set(
  1415. browser: instance,
  1416. css: '.modal input[name=name]',
  1417. value: data[:name],
  1418. mute_log: true,
  1419. )
  1420. end
  1421. if data[:roles]
  1422. 99.times do
  1423. begin
  1424. element = instance.find_elements(css: '.modal .js-selected[data-name=role_ids] .js-option:not(.is-hidden)')[0]
  1425. break if !element
  1426. element.click
  1427. sleep 0.1
  1428. end
  1429. end
  1430. data[:roles].each do |role|
  1431. instance.execute_script("$(\".modal [data-name=role_ids] .js-pool .js-option:not(.is-hidden):contains('#{role}')\").first().click()")
  1432. end
  1433. end
  1434. data[:selector]&.each do |key, value|
  1435. select(
  1436. browser: instance,
  1437. css: '.modal .ticket_selector .js-attributeSelector select',
  1438. value: key,
  1439. mute_log: true,
  1440. )
  1441. sleep 0.5
  1442. if data.key?('text_input')
  1443. set(
  1444. browser: instance,
  1445. css: '.modal .ticket_selector .js-value input',
  1446. value: value,
  1447. mute_log: true,
  1448. )
  1449. else
  1450. select(
  1451. browser: instance,
  1452. css: '.modal .ticket_selector .js-value select',
  1453. value: value,
  1454. deselect_all: true,
  1455. mute_log: true,
  1456. )
  1457. end
  1458. end
  1459. if data['order::direction']
  1460. select(
  1461. browser: instance,
  1462. css: '.modal select[name="order::direction"]',
  1463. value: data['order::direction'],
  1464. mute_log: true,
  1465. )
  1466. end
  1467. if data[:group_by]
  1468. select(
  1469. browser: instance,
  1470. css: '.modal select[name="group_by"]',
  1471. value: data[:group_by],
  1472. mute_log: true,
  1473. )
  1474. end
  1475. if data[:group_direction]
  1476. select(
  1477. browser: instance,
  1478. css: '.modal select[name="group_direction"]',
  1479. value: data[:group_direction],
  1480. mute_log: true,
  1481. )
  1482. end
  1483. instance.find_elements(css: '.modal button.js-submit')[0].click
  1484. modal_disappear(browser: instance)
  1485. 11.times do
  1486. element = instance.find_elements(css: 'body')[0]
  1487. text = element.text
  1488. if text.match?(/#{Regexp.quote(data[:name])}/)
  1489. assert(true, 'overview created')
  1490. overview = {
  1491. name: name,
  1492. }
  1493. sleep 1
  1494. return overview
  1495. end
  1496. sleep 1
  1497. end
  1498. screenshot(browser: instance, comment: 'overview_create_failed')
  1499. raise 'overview creation failed'
  1500. end
  1501. =begin
  1502. overview_update(
  1503. browser: browser1,
  1504. data: {
  1505. name: name,
  1506. roles: ['Agent'],
  1507. selector: {
  1508. 'Priority': '1 low',
  1509. },
  1510. 'order::direction' => 'down',
  1511. }
  1512. )
  1513. =end
  1514. def overview_update(params)
  1515. switch_window_focus(params)
  1516. log('overview_create', params)
  1517. instance = params[:browser] || @browser
  1518. data = params[:data]
  1519. click(
  1520. browser: instance,
  1521. css: 'a[href="#manage"]',
  1522. mute_log: true,
  1523. )
  1524. click(
  1525. browser: instance,
  1526. css: '.content.active a[href="#manage/overviews"]',
  1527. mute_log: true,
  1528. )
  1529. instance.execute_script("$(\".content.active td:contains('#{data[:name]}')\").first().click()")
  1530. sleep 2
  1531. if data[:name]
  1532. set(
  1533. browser: instance,
  1534. css: '.modal input[name=name]',
  1535. value: data[:name],
  1536. mute_log: true,
  1537. )
  1538. end
  1539. if data[:roles]
  1540. 99.times do
  1541. begin
  1542. element = instance.find_elements(css: '.modal .js-selected[data-name=role_ids] .js-option:not(.is-hidden)')[0]
  1543. break if !element
  1544. element.click
  1545. sleep 0.1
  1546. end
  1547. end
  1548. data[:roles].each do |role|
  1549. instance.execute_script("$(\".modal [data-name=role_ids] .js-pool .js-option:not(.is-hidden):contains('#{role}')\").first().click()")
  1550. end
  1551. end
  1552. data[:selector]&.each do |key, value|
  1553. select(
  1554. browser: instance,
  1555. css: '.modal .ticket_selector .js-attributeSelector select',
  1556. value: key,
  1557. mute_log: true,
  1558. )
  1559. sleep 0.5
  1560. select(
  1561. browser: instance,
  1562. css: '.modal .ticket_selector .js-value select',
  1563. value: value,
  1564. deselect_all: true,
  1565. mute_log: true,
  1566. )
  1567. end
  1568. if data['order::direction']
  1569. select(
  1570. browser: instance,
  1571. css: '.modal select[name="order::direction"]',
  1572. value: data['order::direction'],
  1573. mute_log: true,
  1574. )
  1575. end
  1576. if data[:group_direction]
  1577. select(
  1578. browser: instance,
  1579. css: '.modal select[name="group_direction"]',
  1580. value: data[:group_direction],
  1581. mute_log: true,
  1582. )
  1583. end
  1584. instance.find_elements(css: '.modal button.js-submit')[0].click
  1585. modal_disappear(browser: instance)
  1586. 11.times do
  1587. element = instance.find_elements(css: 'body')[0]
  1588. text = element.text
  1589. if text.match?(/#{Regexp.quote(data[:name])}/)
  1590. assert(true, 'overview updated')
  1591. overview = {
  1592. name: name,
  1593. }
  1594. sleep 1
  1595. return overview
  1596. end
  1597. sleep 1
  1598. end
  1599. screenshot(browser: instance, comment: 'overview_update_failed')
  1600. raise 'overview update failed'
  1601. end
  1602. =begin
  1603. ticket = ticket_create(
  1604. browser: browser1,
  1605. data: {
  1606. customer: 'nico',
  1607. group: 'Users', # optional / '-NONE-' # if group selection should not be shown
  1608. priority: '2 normal',
  1609. state: 'open',
  1610. title: 'overview #1',
  1611. body: 'overview #1',
  1612. },
  1613. do_not_submit: true,
  1614. )
  1615. returns (in case of submitted)
  1616. {
  1617. id: 123,
  1618. number: '100001',
  1619. title: 'overview #1',
  1620. }
  1621. ticket = ticket_create(
  1622. browser: browser1,
  1623. data: {
  1624. customer: 'nico',
  1625. group: 'Users', # optional / '-NONE-' # if group selection should not be shown
  1626. priority: '2 normal',
  1627. state: 'open',
  1628. title: 'overview #1',
  1629. body: 'overview #1',
  1630. },
  1631. custom_data_select: {
  1632. key1: 'some value',
  1633. },
  1634. custom_data_input: {
  1635. key1: 'some value',
  1636. },
  1637. custom_data_date: {
  1638. key!: '02/28/2018',
  1639. }
  1640. disable_group_check: true,
  1641. )
  1642. =end
  1643. def ticket_create(params)
  1644. switch_window_focus(params)
  1645. log('ticket_create', params)
  1646. instance = params[:browser] || @browser
  1647. data = params[:data]
  1648. click(
  1649. browser: instance,
  1650. css: 'a[href="#new"]',
  1651. mute_log: true,
  1652. only_if_exists: true,
  1653. )
  1654. click(
  1655. browser: instance,
  1656. css: 'a[href="#ticket/create"]',
  1657. mute_log: true,
  1658. )
  1659. found = false
  1660. 7.times do
  1661. element = instance.find_elements(css: '.content.active .newTicket')[0]
  1662. if element
  1663. found = true
  1664. break
  1665. end
  1666. sleep 1
  1667. end
  1668. if !found
  1669. screenshot(browser: instance, comment: 'ticket_create_failed')
  1670. raise 'no ticket create screen found!'
  1671. end
  1672. if data[:group]
  1673. if data[:group] == '-NONE-'
  1674. # check if owner selection exists
  1675. count = instance.find_elements(css: '.content.active .newTicket select[name="group_id"] option').count
  1676. if count.nonzero?
  1677. instance.find_elements(css: '.content.active .newTicket select[name="group_id"] option').each do |element|
  1678. log('ticket_create invalid group count', text: element.text)
  1679. end
  1680. end
  1681. assert_equal(0, count, 'owner selection should not be showm')
  1682. # check count of agents, should be only 3 / - selection + master + agent on init screen
  1683. count = instance.find_elements(css: '.content.active .newTicket select[name="owner_id"] option').count
  1684. if count != 3
  1685. instance.find_elements(css: '.content.active .newTicket select[name="owner_id"] option').each do |element|
  1686. log('ticket_create invalid owner count', text: element.text)
  1687. end
  1688. end
  1689. assert_equal(3, count, 'check if owner selection is - selection + master + agent per default')
  1690. else
  1691. # check count of agents, should be only 1 selection, the "-" selection on init screen
  1692. if !params[:disable_group_check]
  1693. count = instance.find_elements(css: '.content.active .newTicket select[name="owner_id"] option').count
  1694. if count != 1
  1695. instance.find_elements(css: '.content.active .newTicket select[name="owner_id"] option').each do |element|
  1696. log('ticket_create invalid owner count', text: element.text)
  1697. end
  1698. end
  1699. assert_equal(1, count, 'check if owner selection is empty per default')
  1700. end
  1701. select(
  1702. browser: instance,
  1703. css: '.content.active .newTicket select[name="group_id"]',
  1704. value: data[:group],
  1705. mute_log: true,
  1706. )
  1707. end
  1708. end
  1709. if data[:priority]
  1710. select(
  1711. browser: instance,
  1712. css: '.content.active .newTicket select[name="priority_id"]',
  1713. value: data[:priority],
  1714. mute_log: true,
  1715. )
  1716. end
  1717. if data[:state]
  1718. select(
  1719. browser: instance,
  1720. css: '.content.active .newTicket select[name="state_id"]',
  1721. value: data[:state],
  1722. mute_log: true,
  1723. )
  1724. end
  1725. if data[:title]
  1726. set(
  1727. browser: instance,
  1728. css: '.content.active .newTicket input[name="title"]',
  1729. value: data[:title],
  1730. clear: true,
  1731. mute_log: true,
  1732. )
  1733. end
  1734. if data[:body]
  1735. set(
  1736. browser: instance,
  1737. css: '.content.active .newTicket div[data-name=body]',
  1738. value: data[:body],
  1739. clear: true,
  1740. mute_log: true,
  1741. )
  1742. end
  1743. if data[:customer]
  1744. element = instance.find_elements(css: '.content.active .newTicket input[name="customer_id_completion"]')[0]
  1745. element.click
  1746. element.clear
  1747. # ff issue, sometimes focus event gets dropped
  1748. # if drowdown is not open, try it again
  1749. if !instance.find_elements(css: '.content.active .newTicket .js-recipientDropdown.open')[0]
  1750. instance.execute_script('$(".active .newTicket .js-recipientDropdown").addClass("open")')
  1751. end
  1752. element.send_keys(data[:customer])
  1753. sleep 2.5
  1754. element.send_keys(:enter)
  1755. sleep 0.2
  1756. # ff issue, sometimes enter event gets dropped
  1757. # take user manually
  1758. if instance.find_elements(css: '.content.active .newTicket .js-recipientDropdown.open')[0]
  1759. instance.find_elements(css: '.content.active .newTicket .recipientList-entry.js-object.is-active')[0].click
  1760. sleep 0.4
  1761. end
  1762. end
  1763. params[:custom_data_select]&.each do |local_key, local_value|
  1764. select(
  1765. browser: instance,
  1766. css: ".content.active .newTicket select[name=\"#{local_key}\"]",
  1767. value: local_value,
  1768. )
  1769. end
  1770. params[:custom_data_input]&.each do |local_key, local_value|
  1771. set(
  1772. browser: instance,
  1773. css: ".content.active .newTicket input[name=\"#{local_key}\"]",
  1774. value: local_value,
  1775. clear: true,
  1776. )
  1777. end
  1778. params[:custom_data_date]&.each do |local_key, local_value|
  1779. set(
  1780. browser: instance,
  1781. css: ".content.active .newTicket div[data-name=\"#{local_key}\"] input[data-item=\"date\"]",
  1782. value: local_value,
  1783. clear: true,
  1784. )
  1785. end
  1786. if data[:attachment]
  1787. file_upload(
  1788. browser: instance,
  1789. css: '.content.active .text-1',
  1790. value: 'some text',
  1791. )
  1792. end
  1793. if params[:do_not_submit]
  1794. assert(true, 'ticket created without submit')
  1795. return
  1796. end
  1797. #instance.execute_script('$(".content.active .newTicket form").submit();')
  1798. click(
  1799. browser: instance,
  1800. css: '.content.active .newTicket button.js-submit',
  1801. mute_log: true,
  1802. )
  1803. screenshot(browser: instance, comment: 'ticket_create_after_submit_1')
  1804. sleep 1
  1805. screenshot(browser: instance, comment: 'ticket_create_after_submit_2')
  1806. 9.times do
  1807. if instance.current_url.match?(/#{Regexp.quote('#ticket/zoom/')}/)
  1808. assert(true, 'ticket created')
  1809. sleep 2
  1810. id = instance.current_url
  1811. id.gsub!(//,)
  1812. id.gsub!(%r{^.+?/(\d+)$}, '\\1')
  1813. element = instance.find_elements(css: '.content.active .ticketZoom-header .ticket-number')[0]
  1814. if element
  1815. number = element.text
  1816. ticket = {
  1817. id: id,
  1818. number: number,
  1819. title: data[:title],
  1820. }
  1821. sleep 2 # wait until notify is gone
  1822. return ticket
  1823. end
  1824. end
  1825. sleep 1
  1826. end
  1827. screenshot(browser: instance, comment: 'ticket_create_failed')
  1828. raise "ticket creation failed, can't get zoom url (current url is '#{instance.current_url}')"
  1829. end
  1830. =begin
  1831. ticket_update(
  1832. browser: browser1,
  1833. data: {
  1834. title: '',
  1835. customer: 'some_customer@example.com',
  1836. body: 'some body',
  1837. group: 'some group', # optional
  1838. priority: '1 low',
  1839. state: 'closed',
  1840. },
  1841. do_not_submit: true,
  1842. )
  1843. ticket_update(
  1844. browser: browser1,
  1845. data: {
  1846. title: '',
  1847. customer: 'some_customer@example.com',
  1848. body: 'some body',
  1849. group: 'some group', # optional
  1850. priority: '1 low',
  1851. state: 'closed',
  1852. },
  1853. custom_data_select: {
  1854. key1: 'some value',
  1855. },
  1856. custom_data_input: {
  1857. key1: 'some value',
  1858. },
  1859. custom_data_date: {
  1860. key1: '02/21/2018',
  1861. },
  1862. do_not_submit: true,
  1863. task_type: 'stayOnTab', # default: stayOnTab / possible: closeTab, closeNextInOverview, stayOnTab
  1864. )
  1865. =end
  1866. def ticket_update(params)
  1867. switch_window_focus(params)
  1868. log('ticket_update', params)
  1869. instance = params[:browser] || @browser
  1870. data = params[:data]
  1871. if data[:title]
  1872. #element = instance.find_elements(:css => '.content.active .ticketZoom-header .js-objectTitle')[0]
  1873. #element.clear
  1874. #sleep 0.5
  1875. #element = instance.find_elements(:css => '.content.active .ticketZoom-header .js-objectTitle')[0]
  1876. #element.send_keys(data[:title])
  1877. #sleep 0.5
  1878. #element.send_keys(:tab)
  1879. instance.execute_script('$(".content.active .ticketZoom-header .js-objectTitle").focus()')
  1880. instance.execute_script('$(".content.active .ticketZoom-header .js-objectTitle").text("' + data[:title] + '")')
  1881. instance.execute_script('$(".content.active .ticketZoom-header .js-objectTitle").blur()')
  1882. instance.execute_script('$(".content.active .ticketZoom-header .js-objectTitle").trigger("blur")')
  1883. # {
  1884. # :where => :instance2,
  1885. # :execute => 'sendkey',
  1886. # :css => '.content.active .ticketZoom-header .js-objectTitle',
  1887. # :value => 'TTT',
  1888. # },
  1889. # {
  1890. # :where => :instance2,
  1891. # :execute => 'sendkey',
  1892. # :css => '.content.active .ticketZoom-header .js-objectTitle',
  1893. # :value => :tab,
  1894. # },
  1895. end
  1896. if data[:customer]
  1897. # select tab
  1898. click(browser: instance, css: '.content.active .tabsSidebar-tab[data-tab="customer"]')
  1899. click(browser: instance, css: '.content.active div[data-tab="customer"] .js-actions .icon-arrow-down')
  1900. click(browser: instance, css: '.content.active div[data-tab="customer"] .js-actions [data-type="customer-change"]')
  1901. watch_for(
  1902. browser: instance,
  1903. css: '.modal',
  1904. value: 'change',
  1905. )
  1906. element = instance.find_elements(css: '.modal input[name="customer_id_completion"]')[0]
  1907. element.click
  1908. element.clear
  1909. element.send_keys(data[:customer])
  1910. sleep 2.5
  1911. element.send_keys(:enter)
  1912. #instance.find_elements(css: '.modal .user_autocompletion .recipientList-entry.js-object.is-active')[0].click
  1913. sleep 0.2
  1914. click(browser: instance, css: '.modal .js-submit')
  1915. modal_disappear(browser: instance)
  1916. watch_for(
  1917. browser: instance,
  1918. css: '.content.active .tabsSidebar',
  1919. value: data[:customer],
  1920. )
  1921. # select tab
  1922. click(browser: instance, css: '.content.active .tabsSidebar-tab[data-tab="ticket"]')
  1923. end
  1924. if data[:body]
  1925. set(
  1926. browser: instance,
  1927. css: '.content.active div[data-name=body]',
  1928. value: data[:body],
  1929. no_click: true,
  1930. mute_log: true,
  1931. )
  1932. # it's not working stable via selenium, use js
  1933. value = instance.find_elements(css: '.content.active div[data-name=body]')[0].text
  1934. if value != data[:body]
  1935. body_quoted = quote(data[:body])
  1936. instance.execute_script("$('.content.active div[data-name=body]').html('#{body_quoted}').trigger('focusout')")
  1937. end
  1938. end
  1939. if data[:group]
  1940. if data[:group] == '-NONE-'
  1941. # check if owner selection exists
  1942. count = instance.find_elements(css: '.content.active .sidebar select[name="group_id"] option').count
  1943. assert_equal(0, count, 'owner selection should not be showm')
  1944. # check count of agents, should be only 3 / - selection + master + agent on init screen
  1945. count = instance.find_elements(css: '.content.active .sidebar select[name="owner_id"] option').count
  1946. assert_equal(3, count, 'check if owner selection is - selection + master + agent per default')
  1947. else
  1948. select(
  1949. browser: instance,
  1950. css: '.content.active .sidebar select[name="group_id"]',
  1951. value: data[:group],
  1952. mute_log: true,
  1953. )
  1954. sleep 0.2
  1955. end
  1956. end
  1957. if data[:priority]
  1958. select(
  1959. browser: instance,
  1960. css: '.content.active .sidebar select[name="priority_id"]',
  1961. value: data[:priority],
  1962. mute_log: true,
  1963. )
  1964. end
  1965. if data[:state]
  1966. select(
  1967. browser: instance,
  1968. css: '.content.active .sidebar select[name="state_id"]',
  1969. value: data[:state],
  1970. mute_log: true,
  1971. )
  1972. end
  1973. if data[:files]
  1974. file_upload(
  1975. css: '.content.active .attachmentPlaceholder-inputHolder input',
  1976. files: data[:files],
  1977. )
  1978. end
  1979. params[:custom_data_select]&.each do |local_key, local_value|
  1980. select(
  1981. browser: instance,
  1982. css: ".active .sidebar select[name=\"#{local_key}\"]",
  1983. value: local_value,
  1984. )
  1985. end
  1986. params[:custom_data_input]&.each do |local_key, local_value|
  1987. set(
  1988. browser: instance,
  1989. css: ".active .sidebar input[name=\"#{local_key}\"]",
  1990. value: local_value,
  1991. clear: true,
  1992. )
  1993. end
  1994. params[:custom_data_date]&.each do |local_key, local_value|
  1995. click(
  1996. browser: instance,
  1997. css: ".active .sidebar div[data-name=\"#{local_key}\"] input[data-item=\"date\"]",
  1998. mute_log: true,
  1999. )
  2000. # weird bug where you cannot "clear" for date/time input
  2001. # this is specific chrome problem, chrome bug report: https://bugs.chromium.org/p/chromedriver/issues/detail?id=1319#c2
  2002. # indirect issue: https://github.com/angular/protractor/issues/562#issuecomment-47745263
  2003. 11.times do
  2004. sendkey(
  2005. value: :backspace,
  2006. )
  2007. end
  2008. set(
  2009. browser: instance,
  2010. css: ".active .sidebar div[data-name=\"#{local_key}\"] input[data-item=\"date\"]",
  2011. value: local_value,
  2012. )
  2013. end
  2014. if data[:state] || data[:group] || data[:body] || params[:custom_data_select].present? || params[:custom_data_input].present?
  2015. found = nil
  2016. 9.times do
  2017. break if found
  2018. begin
  2019. text = instance.find_elements(css: '.content.active .js-reset')[0].text
  2020. if text.match?(/(Discard your unsaved changes.|Verwerfen der)/)
  2021. found = true
  2022. end
  2023. rescue
  2024. # try again
  2025. end
  2026. sleep 1
  2027. end
  2028. if !found
  2029. screenshot(browser: instance, comment: 'ticket_update_discard_message_failed')
  2030. raise 'no discard message found'
  2031. end
  2032. end
  2033. task_type(
  2034. browser: instance,
  2035. type: params[:task_type] || 'stayOnTab',
  2036. )
  2037. if params[:do_not_submit]
  2038. assert(true, 'ticket updated without submit')
  2039. return true
  2040. end
  2041. instance.find_elements(css: '.content.active .js-submit')[0].click
  2042. # do not stay on tab
  2043. if params[:task_type] == 'closeTab' || params[:task_type] == 'closeNextInOverview'
  2044. sleep 1
  2045. return
  2046. end
  2047. 9.times do
  2048. begin
  2049. text = instance.find_elements(css: '.content.active .js-reset')[0].text
  2050. if text.blank?
  2051. sleep 1
  2052. return true
  2053. end
  2054. rescue
  2055. # try again
  2056. end
  2057. sleep 1
  2058. end
  2059. screenshot(browser: instance, comment: 'ticket_update_failed')
  2060. raise 'unable to update ticket'
  2061. end
  2062. =begin
  2063. ticket_verify(
  2064. browser: browser1,
  2065. data: {
  2066. title: 'some title',
  2067. body: 'some body',
  2068. ## group: 'some group',
  2069. ## state: 'closed',
  2070. custom_data_select: {
  2071. key1: 'some value',
  2072. },
  2073. custom_data_input: {
  2074. key1: 'some value',
  2075. },
  2076. },
  2077. )
  2078. =end
  2079. def ticket_verify(params)
  2080. switch_window_focus(params)
  2081. log('ticket_verify', params)
  2082. instance = params[:browser] || @browser
  2083. data = params[:data]
  2084. if data[:title]
  2085. title = instance.find_elements(css: '.content.active .ticketZoom-header .js-objectTitle').first.text.strip
  2086. if title.match?(/#{data[:title]}/i)
  2087. assert(true, "matching '#{data[:title]}' in title '#{title}'")
  2088. else
  2089. raise "not matching '#{data[:title]}' in title '#{title}'"
  2090. end
  2091. end
  2092. if data[:body]
  2093. body = instance.find_elements(css: '.content.active [data-name="body"]').first.text.strip
  2094. if body.match?(/#{data[:body]}/i)
  2095. assert(true, "matching '#{data[:body]}' in body '#{body}'")
  2096. else
  2097. raise "not matching '#{data[:body]}' in body '#{body}'"
  2098. end
  2099. end
  2100. params[:custom_data_select]&.each do |local_key, local_value|
  2101. element = instance.find_elements(css: ".active .sidebar select[name=\"#{local_key}\"] option[selected]").first
  2102. value = element.text.strip
  2103. if value.match?(/#{local_value}/i)
  2104. assert(true, "matching '#{value}' in #{local_key} '#{local_value}'")
  2105. else
  2106. raise "not matching '#{value}' in #{local_key} '#{local_value}'"
  2107. end
  2108. end
  2109. params[:custom_data_input]&.each do |local_key, local_value|
  2110. element = instance.find_elements(css: ".active .sidebar input[name=\"#{local_key}\"]").first
  2111. value = element.text.strip
  2112. if value.match?(/#{local_value}/i)
  2113. assert(true, "matching '#{value}' in #{local_key} '#{local_value}'")
  2114. else
  2115. raise "not matching '#{value}' in #{local_key} '#{local_value}'"
  2116. end
  2117. end
  2118. true
  2119. end
  2120. =begin
  2121. overview_open(
  2122. browser: browser2,
  2123. name: overview_name,
  2124. )
  2125. overview_open(
  2126. browser: browser2,
  2127. link: "#ticket/view/some_special_name",
  2128. )
  2129. =end
  2130. def overview_open(params)
  2131. switch_window_focus(params)
  2132. log('overview_open', params)
  2133. instance = params[:browser] || @browser
  2134. # click on overview task in sidebar
  2135. instance.find_elements(css: '.js-overviewsMenuItem')[0].click
  2136. # show larger overview selection list
  2137. sleep 0.5
  2138. execute(
  2139. browser: instance,
  2140. js: '$(".content.active .sidebar").css("display", "block")',
  2141. )
  2142. link = if params[:link]
  2143. params[:link]
  2144. elsif params[:name]
  2145. "\#ticket/view/#{params[:name]}"
  2146. end
  2147. # switch to overview
  2148. instance.find_elements(css: ".content.active .sidebar a[href=\"#{link}\"]")[0].click
  2149. # hide larger overview selection list again
  2150. sleep 0.5
  2151. execute(
  2152. browser: instance,
  2153. js: '$(".content.active .sidebar").css("display", "none")',
  2154. )
  2155. end
  2156. =begin
  2157. ticket_open_by_overview(
  2158. browser: browser2,
  2159. number: ticket1[:number],
  2160. link: "#ticket/view/#{name}",
  2161. )
  2162. ticket_open_by_overview(
  2163. browser: browser2,
  2164. number: ticket1[:number],
  2165. text: title,
  2166. link: "#ticket/view/#{name}",
  2167. )
  2168. =end
  2169. def ticket_open_by_overview(params)
  2170. switch_window_focus(params)
  2171. log('ticket_open_by_overview', params)
  2172. instance = params[:browser] || @browser
  2173. overview_open(params)
  2174. if params[:title]
  2175. element = instance.find_element(css: '.content.active').find_element(partial_link_text: params[:title])
  2176. if !element
  2177. screenshot(browser: instance, comment: 'ticket_open_by_overview_no_ticket_failed')
  2178. raise "unable to find ticket #{params[:title]} in overview #{params[:link]}!"
  2179. end
  2180. else
  2181. element = instance.find_elements(partial_link_text: params[:number])[0]
  2182. if !element
  2183. screenshot(browser: instance, comment: 'ticket_open_by_overview_no_ticket_failed')
  2184. raise "unable to find ticket #{params[:number]} in overview #{params[:link]}!"
  2185. end
  2186. end
  2187. element.click
  2188. sleep 1
  2189. number = instance.find_elements(css: '.content.active .ticketZoom-header .ticket-number')[0].text
  2190. if !number.match?(/#{params[:number]}/)
  2191. screenshot(browser: instance, comment: 'ticket_open_by_overview_open_failed_failed')
  2192. raise "unable to open ticket #{params[:number]}!"
  2193. end
  2194. assert(true, "ticket #{params[:number]} found")
  2195. true
  2196. end
  2197. =begin
  2198. ticket_open_by_search(
  2199. browser: browser2,
  2200. number: ticket1[:number],
  2201. )
  2202. =end
  2203. def ticket_open_by_search(params)
  2204. switch_window_focus(params)
  2205. log('ticket_open_by_search', params)
  2206. instance = params[:browser] || @browser
  2207. # search by number
  2208. element = instance.find_elements(css: '#global-search')[0]
  2209. element.click
  2210. element.clear
  2211. element.send_keys(params[:number])
  2212. sleep 3
  2213. # open ticket
  2214. #instance.find_element(partial_link_text: params[:number] } ).click
  2215. instance.execute_script("$(\".js-global-search-result a:contains('#{params[:number]}') .nav-tab-name\").first().click()")
  2216. watch_for(
  2217. browser: instance,
  2218. css: '.content.active .ticketZoom-header .ticket-number'
  2219. )
  2220. number = instance.find_elements(css: '.content.active .ticketZoom-header .ticket-number')[0].text
  2221. if !number.match?(/#{params[:number]}/)
  2222. screenshot(browser: instance, comment: 'ticket_open_by_search_failed')
  2223. raise "unable to search/find ticket #{params[:number]}!"
  2224. end
  2225. true
  2226. end
  2227. =begin
  2228. ticket_open_by_title(
  2229. browser: browser2,
  2230. title: ticket1[:title],
  2231. )
  2232. =end
  2233. def ticket_open_by_title(params)
  2234. switch_window_focus(params)
  2235. log('ticket_open_by_title', params)
  2236. instance = params[:browser] || @browser
  2237. # search by number
  2238. element = instance.find_elements(css: '#global-search')[0]
  2239. element.click
  2240. element.clear
  2241. element.send_keys(params[:title])
  2242. sleep 3
  2243. # open ticket
  2244. #instance.find_element(partial_link_text: params[:title] } ).click
  2245. instance.execute_script("$(\".js-global-search-result a:contains('#{params[:title]}') .nav-tab-name\").first().click()")
  2246. sleep 1
  2247. title = instance.find_elements(css: '.content.active .ticketZoom-header .js-objectTitle')[0].text
  2248. if !title.match?(/#{params[:title]}/)
  2249. screenshot(browser: instance, comment: 'ticket_open_by_title_failed')
  2250. raise "unable to search/find ticket #{params[:title]}!"
  2251. end
  2252. true
  2253. end
  2254. =begin
  2255. overview_count = overview_counter(
  2256. browser: browser2,
  2257. )
  2258. returns
  2259. {
  2260. '#ticket/view/all_unassigned' => 42,
  2261. }
  2262. =end
  2263. def overview_counter(params = {})
  2264. switch_window_focus(params)
  2265. log('overview_counter', params)
  2266. instance = params[:browser] || @browser
  2267. instance.find_elements(css: '.js-overviewsMenuItem')[0].click
  2268. sleep 2
  2269. execute(
  2270. browser: instance,
  2271. js: '$(".content.active .sidebar").css("display", "block")',
  2272. )
  2273. #execute(
  2274. # browser: instance,
  2275. # js: '$(".content.active .overview-header").css("display", "none")',
  2276. #)
  2277. overviews = {}
  2278. instance.find_elements(css: '.content.active .sidebar a[href]').each do |element|
  2279. url = element.attribute('href')
  2280. url.gsub!(%r{(http|https)://.+?/(.+?)$}, '\\2')
  2281. overviews[url] = 0
  2282. #puts url.inspect
  2283. #puts element.inspect
  2284. end
  2285. overviews.each_key do |url|
  2286. count = instance.find_elements(css: ".content.active .sidebar a[href=\"#{url}\"] .badge")[0].text
  2287. overviews[url] = count.to_i
  2288. end
  2289. log('overview_counter', overviews)
  2290. overviews
  2291. end
  2292. =begin
  2293. organization_open_by_search(
  2294. browser: browser2,
  2295. value: 'some value',
  2296. )
  2297. =end
  2298. def organization_open_by_search(params = {})
  2299. switch_window_focus(params)
  2300. log('organization_open_by_search', params)
  2301. instance = params[:browser] || @browser
  2302. element = instance.find_elements(css: '#global-search')[0]
  2303. element.click
  2304. element.clear
  2305. element.send_keys(params[:value])
  2306. sleep 3
  2307. empty_search(browser: instance)
  2308. element = instance.find_elements(css: '#global-search')[0]
  2309. element.click
  2310. element.clear
  2311. element.send_keys(params[:value])
  2312. sleep 2
  2313. #instance.find_element(partial_link_text: params[:value] } ).click
  2314. instance.execute_script("$(\".js-global-search-result a:contains('#{params[:value]}') .nav-tab-name\").first().click()")
  2315. watch_for(
  2316. browser: instance,
  2317. css: '.content.active h1'
  2318. )
  2319. name = instance.find_elements(css: '.content.active h1')[0].text
  2320. if !name.match?(/#{params[:value]}/)
  2321. screenshot(browser: instance, comment: 'organization_open_by_search_failed')
  2322. raise "unable to search/find org #{params[:value]}!"
  2323. end
  2324. assert(true, "org #{params[:value]} found")
  2325. true
  2326. end
  2327. =begin
  2328. user_open_by_search(
  2329. browser: browser2,
  2330. value: 'some value',
  2331. )
  2332. =end
  2333. def user_open_by_search(params = {})
  2334. switch_window_focus(params)
  2335. log('user_open_by_search', params)
  2336. instance = params[:browser] || @browser
  2337. element = instance.find_elements(css: '#global-search')[0]
  2338. element.click
  2339. element.clear
  2340. element.send_keys(params[:value])
  2341. sleep 3
  2342. #instance.find_element(partial_link_text: params[:value]).click
  2343. instance.execute_script("$(\".js-global-search-result a:contains('#{params[:value]}') .nav-tab-name\").first().click()")
  2344. watch_for(
  2345. browser: instance,
  2346. css: '.content.active h1'
  2347. )
  2348. name = instance.find_elements(css: '.content.active h1')[0].text
  2349. if !name.match?(/#{params[:value]}/)
  2350. screenshot(browser: instance, comment: 'user_open_by_search_failed')
  2351. raise "unable to search/find user #{params[:value]}!"
  2352. end
  2353. assert(true, "user #{params[:term]} found")
  2354. true
  2355. end
  2356. =begin
  2357. user_create(
  2358. browser: browser2,
  2359. data: {
  2360. #login: 'some login' + random,
  2361. firstname: 'Manage Firstname' + random,
  2362. lastname: 'Manage Lastname' + random,
  2363. email: user_email,
  2364. password: 'some-pass',
  2365. role: 'Admin', # optional, choose among [Admin, Agent, Customer]
  2366. # defaults to Customer if not provided
  2367. },
  2368. )
  2369. user_create(
  2370. browser: browser2,
  2371. data: {
  2372. #login: 'some login' + random,
  2373. firstname: 'Manage Firstname' + random,
  2374. lastname: 'Manage Lastname' + random,
  2375. email: user_email,
  2376. password: 'some-pass',
  2377. role: 'Agent', # when the role is Agent an array of permissions for each group is optionally accepted
  2378. permissions: { 1 => %w[read create overview],
  2379. 2 => ['full'], }
  2380. },
  2381. )
  2382. =end
  2383. def user_create(params = {})
  2384. switch_window_focus(params)
  2385. log('user_create', params)
  2386. instance = params[:browser] || @browser
  2387. data = params[:data]
  2388. raise 'user_create() requires either email or phone' if data[:email].blank? && data[:phone].blank?
  2389. click(
  2390. browser: instance,
  2391. css: 'a[href="#manage"]',
  2392. mute_log: true,
  2393. )
  2394. click(
  2395. browser: instance,
  2396. css: '.content.active a[href="#manage/users"]',
  2397. mute_log: true,
  2398. )
  2399. click(
  2400. browser: instance,
  2401. css: '.content.active a[data-type="new"]',
  2402. mute_log: true,
  2403. )
  2404. modal_ready(browser: instance)
  2405. element = instance.find_elements(css: '.modal input[name=firstname]')[0]
  2406. element.clear
  2407. element.send_keys(data[:firstname])
  2408. element = instance.find_elements(css: '.modal input[name=lastname]')[0]
  2409. element.clear
  2410. element.send_keys(data[:lastname])
  2411. element = instance.find_elements(css: '.modal input[name=email]')[0]
  2412. element.clear
  2413. element.send_keys(data[:email])
  2414. element = instance.find_elements(css: '.modal input[name=password]')[0]
  2415. element.clear
  2416. element.send_keys(data[:password])
  2417. element = instance.find_elements(css: '.modal input[name=password_confirm]')[0]
  2418. element.clear
  2419. element.send_keys(data[:password])
  2420. element = instance.find_elements(css: '.modal input[name=phone]')[0]
  2421. element.clear
  2422. element.send_keys(data[:phone])
  2423. if data[:active] == false
  2424. select(css: 'select[name="active"]', value: 'inactive')
  2425. end
  2426. if data[:organization]
  2427. begin
  2428. target = nil
  2429. retries ||= 0
  2430. 5.times do
  2431. element = instance.find_elements(css: '.modal input.searchableSelect-main')[0]
  2432. element.clear
  2433. element.send_keys(data[:organization])
  2434. 10.times do
  2435. sleep 0.5
  2436. target = instance.find_elements(css: ".modal li[title='#{data[:organization]}']")[0]
  2437. break if target
  2438. end
  2439. break if target
  2440. end
  2441. raise "Can't find organization #{data[:organization]}" if target.blank?
  2442. target.click()
  2443. rescue Selenium::WebDriver::Error::StaleElementReferenceError
  2444. sleep retries
  2445. retries += 1
  2446. retry if retries < 3
  2447. end
  2448. end
  2449. if data[:role]
  2450. if data[:role] == 'Admin'
  2451. check(
  2452. browser: instance,
  2453. css: '.modal input[name=role_ids][value=1]',
  2454. )
  2455. elsif data[:role] == 'Customer'
  2456. check(
  2457. browser: instance,
  2458. css: '.modal input[name=role_ids][value=3]',
  2459. )
  2460. elsif data[:role] == 'Agent'
  2461. check(
  2462. browser: instance,
  2463. css: '.modal input[name=role_ids][value=2]',
  2464. )
  2465. data[:permissions].each do |key, value|
  2466. value.each do |permission|
  2467. check(
  2468. browser: instance,
  2469. css: ".modal input[name=\"group_ids::#{key}\"][value=\"#{permission}\"]",
  2470. )
  2471. end
  2472. end
  2473. else
  2474. raise "Unknown :role \"#{data[:role]}\" in user_create()"
  2475. end
  2476. else
  2477. check(
  2478. browser: instance,
  2479. css: '.modal input[name=role_ids][value=3]',
  2480. )
  2481. end
  2482. click(
  2483. browser: instance,
  2484. css: '.modal .js-submit',
  2485. )
  2486. modal_disappear(
  2487. browser: instance,
  2488. timeout: 10,
  2489. )
  2490. if data[:email]
  2491. search_query = data[:email]
  2492. search_target = data[:email]
  2493. search_css = '.content.active .user-list .js-tableBody td:first-child'
  2494. else
  2495. search_query = data[:phone]
  2496. search_target = data[:firstname]
  2497. search_css = '.content.active .user-list .js-tableBody td:nth-child(2)'
  2498. end
  2499. 60.times do |i|
  2500. if (i % 10).zero?
  2501. set(
  2502. browser: instance,
  2503. css: '.content.active .js-search',
  2504. value: search_query,
  2505. )
  2506. end
  2507. sleep 1
  2508. search_result = instance.find_elements(css: search_css).map(&:text).map(&:strip)
  2509. break if search_result.include? search_target
  2510. raise 'user creation failed' if i >= 19
  2511. log "new user #{search_query} not found on the #{i.ordinalize} try, retrying"
  2512. end
  2513. assert(true, 'user created')
  2514. end
  2515. =begin
  2516. user_edit(
  2517. browser: browser2,
  2518. data: {
  2519. login: 'some login' + random,
  2520. firstname: 'Manage Firstname' + random,
  2521. lastname: 'Manage Lastname' + random,
  2522. email: user_email,
  2523. password: 'some-pass',
  2524. role: 'Agent', # when the role is Agent an array of permissions for each group is optionally accepted
  2525. permissions: { 1 => %w[read create overview],
  2526. 2 => ['full'], }
  2527. },
  2528. )
  2529. =end
  2530. def user_edit(params = {})
  2531. switch_window_focus(params)
  2532. log('user_edit', params)
  2533. instance = params[:browser] || @browser
  2534. data = params[:data]
  2535. click(
  2536. browser: instance,
  2537. css: 'a[href="#manage"]',
  2538. mute_log: true,
  2539. )
  2540. click(
  2541. browser: instance,
  2542. css: '.content.active a[href="#manage/users"]',
  2543. mute_log: true,
  2544. )
  2545. instance.find_elements(css: '.content.active .user-list td:first-child').each do |element|
  2546. next if element.text.strip != data[:login]
  2547. element.click
  2548. break
  2549. end
  2550. modal_ready(browser: instance)
  2551. if data[:firstname]
  2552. element = instance.find_elements(css: '.modal input[name=firstname]')[0]
  2553. element.clear
  2554. element.send_keys(data[:firstname])
  2555. end
  2556. if data[:lastname]
  2557. element = instance.find_elements(css: '.modal input[name=lastname]')[0]
  2558. element.clear
  2559. element.send_keys(data[:lastname])
  2560. end
  2561. if data[:email]
  2562. element = instance.find_elements(css: '.modal input[name=email]')[0]
  2563. element.clear
  2564. element.send_keys(data[:email])
  2565. end
  2566. if data[:password]
  2567. element = instance.find_elements(css: '.modal input[name=password]')[0]
  2568. element.clear
  2569. element.send_keys(data[:password])
  2570. element = instance.find_elements(css: '.modal input[name=password_confirm]')[0]
  2571. element.clear
  2572. element.send_keys(data[:password])
  2573. end
  2574. if data[:phone]
  2575. element = instance.find_elements(css: '.modal input[name=phone]')[0]
  2576. element.clear
  2577. element.send_keys(data[:phone])
  2578. end
  2579. if data[:active].present?
  2580. select(css: 'select[name="active"]', value: data[:active] ? 'active' : 'inactive' )
  2581. end
  2582. if data[:organization]
  2583. element = instance.find_elements(css: '.modal input.searchableSelect-main')[0]
  2584. element.clear
  2585. element.send_keys(data[:organization])
  2586. begin
  2587. retries ||= 0
  2588. target = nil
  2589. until target
  2590. sleep 0.5
  2591. target = instance.find_elements(css: ".modal li[title='#{data[:organization]}']")[0]
  2592. end
  2593. target.click()
  2594. rescue Selenium::WebDriver::Error::StaleElementReferenceError
  2595. sleep retries
  2596. retries += 1
  2597. retry if retries < 3
  2598. end
  2599. end
  2600. if data[:role]
  2601. if data[:role] == 'Admin'
  2602. check(
  2603. browser: instance,
  2604. css: '.modal input[name=role_ids][value=1]',
  2605. )
  2606. elsif data[:role] == 'Customer'
  2607. check(
  2608. browser: instance,
  2609. css: '.modal input[name=role_ids][value=3]',
  2610. )
  2611. elsif data[:role] == 'Agent'
  2612. check(
  2613. browser: instance,
  2614. css: '.modal input[name=role_ids][value=2]',
  2615. )
  2616. else
  2617. raise "Unknown :role \"#{data[:role]}\" in user_create()"
  2618. end
  2619. end
  2620. if data[:permissions].present?
  2621. data[:permissions].each do |key, value|
  2622. value.each do |permission|
  2623. check(
  2624. browser: instance,
  2625. css: ".modal input[name=\"group_ids::#{key}\"][value=\"#{permission}\"]",
  2626. )
  2627. end
  2628. end
  2629. end
  2630. click(
  2631. browser: instance,
  2632. css: '.modal .js-submit',
  2633. )
  2634. modal_disappear(
  2635. browser: instance,
  2636. timeout: 10,
  2637. )
  2638. assert(true, 'user updated')
  2639. end
  2640. =begin
  2641. organization_create(
  2642. browser: browser2,
  2643. data: {
  2644. name: 'Test Organization',
  2645. }
  2646. )
  2647. =end
  2648. def organization_create(params = {})
  2649. switch_window_focus(params)
  2650. log('organization_create', params)
  2651. instance = params[:browser] || @browser
  2652. data = params[:data]
  2653. click(
  2654. browser: instance,
  2655. css: 'a[href="#manage"]',
  2656. mute_log: true,
  2657. )
  2658. click(
  2659. browser: instance,
  2660. css: '.content.active a[href="#manage/organizations"]',
  2661. mute_log: true,
  2662. )
  2663. click(
  2664. browser: instance,
  2665. css: '.content.active a[data-type="new"]',
  2666. mute_log: true,
  2667. )
  2668. modal_ready(browser: instance)
  2669. element = instance.find_elements(css: '.modal input[name=name]')[0]
  2670. element.clear
  2671. element.send_keys(data[:name])
  2672. instance.find_elements(css: '.modal button.js-submit')[0].click
  2673. modal_disappear(
  2674. browser: instance,
  2675. timeout: 5,
  2676. )
  2677. watch_for(
  2678. browser: instance,
  2679. css: 'body',
  2680. value: data[:name],
  2681. )
  2682. end
  2683. =begin
  2684. calendar_create(
  2685. browser: browser2,
  2686. data: {
  2687. name: 'some calendar' + random,
  2688. first_response_time_in_text: 61
  2689. },
  2690. )
  2691. =end
  2692. def calendar_create(params = {})
  2693. switch_window_focus(params)
  2694. log('calendar_create', params)
  2695. instance = params[:browser] || @browser
  2696. data = params[:data]
  2697. click(
  2698. browser: instance,
  2699. css: 'a[href="#manage"]',
  2700. mute_log: true,
  2701. )
  2702. click(
  2703. browser: instance,
  2704. css: '.content.active a[href="#manage/calendars"]',
  2705. mute_log: true,
  2706. )
  2707. sleep 4
  2708. click(
  2709. browser: instance,
  2710. css: '.content.active a.js-new',
  2711. mute_log: true,
  2712. )
  2713. modal_ready(browser: instance)
  2714. element = instance.find_elements(css: '.content.active .modal input[name=name]')[0]
  2715. element.clear
  2716. element.send_keys(data[:name])
  2717. element = instance.find_elements(css: '.content.active .modal .js-input')[0]
  2718. element.clear
  2719. element.send_keys(data[:timezone])
  2720. element.send_keys(:enter)
  2721. instance.find_elements(css: '.modal button.js-submit')[0].click
  2722. modal_disappear(browser: instance)
  2723. 7.times do
  2724. element = instance.find_elements(css: 'body')[0]
  2725. text = element.text
  2726. if text.match?(/#{Regexp.quote(data[:name])}/)
  2727. assert(true, 'calendar created')
  2728. sleep 1
  2729. return true
  2730. end
  2731. sleep 1
  2732. end
  2733. screenshot(browser: instance, comment: 'calendar_create_failed')
  2734. raise 'calendar creation failed'
  2735. end
  2736. =begin
  2737. sla_create(
  2738. browser: browser2,
  2739. data: {
  2740. name: 'some sla' + random,
  2741. calendar: 'some calendar name',
  2742. first_response_time_in_text: 61
  2743. },
  2744. )
  2745. =end
  2746. def sla_create(params = {})
  2747. switch_window_focus(params)
  2748. log('sla_create', params)
  2749. instance = params[:browser] || @browser
  2750. data = params[:data]
  2751. click(
  2752. browser: instance,
  2753. css: 'a[href="#manage"]',
  2754. mute_log: true,
  2755. )
  2756. click(
  2757. browser: instance,
  2758. css: '.content.active a[href="#manage/slas"]',
  2759. mute_log: true,
  2760. )
  2761. click(
  2762. browser: instance,
  2763. css: '.content.active a.js-new',
  2764. mute_log: true,
  2765. )
  2766. modal_ready(browser: instance)
  2767. element = instance.find_elements(css: '.modal input[name=name]')[0]
  2768. element.clear
  2769. element.send_keys(data[:name])
  2770. if data[:calendar].present?
  2771. element = instance.find_elements(css: '.modal select[name="calendar_id"]')[0]
  2772. dropdown = Selenium::WebDriver::Support::Select.new(element)
  2773. dropdown.select_by(:text, data[:calendar])
  2774. end
  2775. element = instance.find_elements(css: '.modal input[name=first_response_time_in_text]')[0]
  2776. element.clear
  2777. element.send_keys(data[:first_response_time_in_text])
  2778. instance.find_elements(css: '.modal button.js-submit')[0].click
  2779. modal_disappear(browser: instance)
  2780. 7.times do
  2781. element = instance.find_elements(css: 'body')[0]
  2782. text = element.text
  2783. if text.match?(/#{Regexp.quote(data[:name])}/)
  2784. assert(true, 'sla created')
  2785. sleep 1
  2786. return true
  2787. end
  2788. sleep 1
  2789. end
  2790. screenshot(browser: instance, comment: 'sla_create_failed')
  2791. raise 'sla creation failed'
  2792. end
  2793. =begin
  2794. text_module_create(
  2795. browser: browser2,
  2796. data: {
  2797. name: 'some sla' + random,
  2798. keywords: 'some keywords',
  2799. content: 'some content',
  2800. },
  2801. )
  2802. =end
  2803. def text_module_create(params = {})
  2804. switch_window_focus(params)
  2805. log('text_module_create', params)
  2806. instance = params[:browser] || @browser
  2807. data = params[:data]
  2808. click(
  2809. browser: instance,
  2810. css: 'a[href="#manage"]',
  2811. mute_log: true,
  2812. )
  2813. click(
  2814. browser: instance,
  2815. css: '.content.active a[href="#manage/text_modules"]',
  2816. mute_log: true,
  2817. )
  2818. click(
  2819. browser: instance,
  2820. css: '.content.active a[data-type="new"]',
  2821. mute_log: true,
  2822. )
  2823. modal_ready(browser: instance)
  2824. set(
  2825. browser: instance,
  2826. css: '.modal input[name=name]',
  2827. value: data[:name],
  2828. )
  2829. set(
  2830. browser: instance,
  2831. css: '.modal input[name=keywords]',
  2832. value: data[:keywords],
  2833. )
  2834. set(
  2835. browser: instance,
  2836. css: '.modal [data-name=content]',
  2837. value: data[:content],
  2838. )
  2839. instance.find_elements(css: '.modal button.js-submit')[0].click
  2840. modal_disappear(browser: instance)
  2841. 7.times do
  2842. element = instance.find_elements(css: 'body')[0]
  2843. text = element.text
  2844. if text.match?(/#{Regexp.quote(data[:name])}/)
  2845. assert(true, 'text module created')
  2846. sleep 1
  2847. return true
  2848. end
  2849. sleep 1
  2850. end
  2851. screenshot(browser: instance, comment: 'text_module_create_failed')
  2852. raise 'text module creation failed'
  2853. end
  2854. =begin
  2855. signature_create(
  2856. browser: browser2,
  2857. data: {
  2858. name: 'some sla' + random,
  2859. body: 'some body',
  2860. },
  2861. )
  2862. =end
  2863. def signature_create(params = {})
  2864. switch_window_focus(params)
  2865. log('signature_create', params)
  2866. instance = params[:browser] || @browser
  2867. data = params[:data]
  2868. click(
  2869. browser: instance,
  2870. css: 'a[href="#manage"]',
  2871. mute_log: true,
  2872. )
  2873. click(
  2874. browser: instance,
  2875. css: '.content.active a[href="#channels/email"]',
  2876. mute_log: true,
  2877. )
  2878. click(
  2879. browser: instance,
  2880. css: '.content.active a[href="#c-signature"]',
  2881. mute_log: true,
  2882. )
  2883. sleep 4
  2884. click(
  2885. browser: instance,
  2886. css: '.content.active #c-signature a[data-type="new"]',
  2887. mute_log: true,
  2888. )
  2889. modal_ready(browser: instance)
  2890. set(
  2891. browser: instance,
  2892. css: '.modal input[name=name]',
  2893. value: data[:name],
  2894. )
  2895. set(
  2896. browser: instance,
  2897. css: '.modal [data-name=body]',
  2898. value: data[:body],
  2899. )
  2900. instance.find_elements(css: '.modal button.js-submit')[0].click
  2901. modal_disappear(browser: instance)
  2902. 11.times do
  2903. element = instance.find_elements(css: 'body')[0]
  2904. text = element.text
  2905. if text.match?(/#{Regexp.quote(data[:name])}/)
  2906. assert(true, 'signature created')
  2907. sleep 1
  2908. return true
  2909. end
  2910. sleep 1
  2911. end
  2912. screenshot(browser: instance, comment: 'signature_create_failed')
  2913. raise 'signature creation failed'
  2914. end
  2915. =begin
  2916. group_create(
  2917. browser: browser2,
  2918. data: {
  2919. name: 'some sla' + random,
  2920. signature: 'some signature bame',
  2921. member: [
  2922. {
  2923. login: 'some_user_login',
  2924. access: 'all',
  2925. },
  2926. ],
  2927. },
  2928. )
  2929. =end
  2930. def group_create(params = {})
  2931. switch_window_focus(params)
  2932. log('group_create', params)
  2933. instance = params[:browser] || @browser
  2934. data = params[:data]
  2935. click(
  2936. browser: instance,
  2937. css: 'a[href="#manage"]',
  2938. mute_log: true,
  2939. )
  2940. click(
  2941. browser: instance,
  2942. css: '.content.active a[href="#manage/groups"]',
  2943. mute_log: true,
  2944. )
  2945. click(
  2946. browser: instance,
  2947. css: '.content.active a[data-type="new"]',
  2948. mute_log: true,
  2949. )
  2950. modal_ready(browser: instance)
  2951. element = instance.find_elements(css: '.modal input[name=name]')[0]
  2952. element.clear
  2953. element.send_keys(data[:name])
  2954. element = instance.find_elements(css: '.modal select[name="email_address_id"]')[0]
  2955. dropdown = Selenium::WebDriver::Support::Select.new(element)
  2956. dropdown.select_by(:index, 1)
  2957. #dropdown.select_by(:text, action[:group])
  2958. if data[:signature]
  2959. element = instance.find_elements(css: '.modal select[name="signature_id"]')[0]
  2960. dropdown = Selenium::WebDriver::Support::Select.new(element)
  2961. dropdown.select_by(:text, data[:signature])
  2962. end
  2963. instance.find_elements(css: '.modal button.js-submit')[0].click
  2964. modal_disappear(browser: instance)
  2965. 11.times do
  2966. element = instance.find_elements(css: 'body')[0]
  2967. text = element.text
  2968. if text.match?(/#{Regexp.quote(data[:name])}/)
  2969. assert(true, 'group created')
  2970. modal_disappear(browser: instance) # wait until modal has gone
  2971. # add member
  2972. data[:member]&.each do |member|
  2973. instance.find_elements(css: 'a[href="#manage"]')[0].click
  2974. sleep 1
  2975. instance.find_elements(css: '.content.active a[href="#manage/users"]')[0].click
  2976. sleep 3
  2977. element = instance.find_elements(css: '.content.active [name="search"]')[0]
  2978. element.clear
  2979. element.send_keys(member[:login])
  2980. sleep 3
  2981. #instance.find_elements(:css => '.content.active table [data-id]')[0].click
  2982. instance.execute_script('$(".content.active table [data-id] td").first().click()')
  2983. modal_ready(browser: instance)
  2984. #instance.find_elements(:css => 'label:contains(" ' + action[:name] + '")')[0].click
  2985. instance.execute_script('$(".js-groupList tr:contains(\"' + data[:name] + '\") .js-groupListItem[value=' + member[:access] + ']").prop("checked", true)')
  2986. instance.find_elements(css: '.modal button.js-submit')[0].click
  2987. modal_disappear(browser: instance)
  2988. end
  2989. end
  2990. sleep 1
  2991. return true
  2992. end
  2993. screenshot(browser: instance, comment: 'group_create_failed')
  2994. raise 'group creation failed'
  2995. end
  2996. =begin
  2997. macro_create(
  2998. browser: browser1,
  2999. name: 'Emmanuel Macro',
  3000. ux_flow_next_up: 'Stay on tab', # possible: 'Stay on tab', 'Close tab', 'Advance to next ticket from overview'
  3001. actions: {
  3002. 'Tags' => { # currently only 'Tags' is supported
  3003. operator: 'add',
  3004. value: 'spam',
  3005. }
  3006. }
  3007. )
  3008. =end
  3009. def macro_create(params)
  3010. switch_window_focus(params)
  3011. log('macro_create', params)
  3012. instance = params[:browser] || @browser
  3013. click(
  3014. browser: instance,
  3015. css: 'a[href="#manage"]',
  3016. mute_log: true,
  3017. )
  3018. click(
  3019. browser: instance,
  3020. css: '.sidebar a[href="#manage/macros"]',
  3021. mute_log: true,
  3022. )
  3023. click(
  3024. browser: instance,
  3025. css: '.page-header-meta > a[data-type="new"]'
  3026. )
  3027. sendkey(
  3028. browser: instance,
  3029. css: '.modal-body input[name="name"]',
  3030. value: params[:name]
  3031. )
  3032. params[:actions]&.each do |attribute, changes|
  3033. select(
  3034. browser: instance,
  3035. css: '.modal .ticket_perform_action .js-filterElement .js-attributeSelector select',
  3036. value: attribute,
  3037. mute_log: true,
  3038. )
  3039. next if attribute != 'Tags'
  3040. select(
  3041. browser: instance,
  3042. css: '.modal .ticket_perform_action .js-filterElement .js-operator select',
  3043. value: changes[:operator],
  3044. mute_log: true,
  3045. )
  3046. sendkey(
  3047. browser: instance,
  3048. css: '.modal .ticket_perform_action .js-filterElement .js-value .token-input',
  3049. value: changes[:value],
  3050. mute_log: true,
  3051. )
  3052. sendkey(
  3053. browser: instance,
  3054. value: :enter,
  3055. )
  3056. end
  3057. select(
  3058. browser: instance,
  3059. css: '.modal-body select[name="ux_flow_next_up"]',
  3060. value: params[:ux_flow_next_up]
  3061. )
  3062. click(
  3063. browser: instance,
  3064. css: '.modal-footer button[type="submit"]'
  3065. )
  3066. watch_for(
  3067. browser: instance,
  3068. css: 'body',
  3069. value: params[:name],
  3070. )
  3071. assert(true, 'macro created')
  3072. end
  3073. =begin
  3074. role_create(
  3075. browser: browser2,
  3076. data: {
  3077. name: 'some role' + random,
  3078. default_at_signup: false,
  3079. permission: {
  3080. 'admin.group' => true,
  3081. 'preferences.password' => true,
  3082. },
  3083. member: [
  3084. 'some_user_login',
  3085. ],
  3086. },
  3087. )
  3088. =end
  3089. def role_create(params = {})
  3090. switch_window_focus(params)
  3091. log('role_create', params)
  3092. instance = params[:browser] || @browser
  3093. data = params[:data]
  3094. click(
  3095. browser: instance,
  3096. css: 'a[href="#manage"]',
  3097. mute_log: true,
  3098. )
  3099. click(
  3100. browser: instance,
  3101. css: '.content.active a[href="#manage/roles"]',
  3102. mute_log: true,
  3103. )
  3104. click(
  3105. browser: instance,
  3106. css: '.content.active a[data-type="new"]',
  3107. mute_log: true,
  3108. )
  3109. modal_ready(browser: instance)
  3110. element = instance.find_elements(css: '.modal input[name=name]')[0]
  3111. element.clear
  3112. element.send_keys(data[:name])
  3113. if data.key?(:default_at_signup)
  3114. element = instance.find_elements(css: '.modal select[name="default_at_signup"]')[0]
  3115. dropdown = Selenium::WebDriver::Support::Select.new(element)
  3116. if data[:default_at_signup] == true
  3117. dropdown.select_by(:text, 'yes')
  3118. else
  3119. dropdown.select_by(:text, 'no')
  3120. end
  3121. end
  3122. if data.key?(:permission)
  3123. data[:permission].each do |permission_name, permission_value|
  3124. if permission_value == false
  3125. uncheck(
  3126. browser: instance,
  3127. css: ".modal [data-permission-name=\"#{permission_name}\"]",
  3128. )
  3129. else
  3130. check(
  3131. browser: instance,
  3132. css: ".modal [data-permission-name=\"#{permission_name}\"]",
  3133. )
  3134. end
  3135. end
  3136. end
  3137. if data[:active] == false
  3138. select(css: 'select[name="active"]', value: 'inactive')
  3139. end
  3140. instance.find_elements(css: '.modal button.js-submit')[0].click
  3141. modal_disappear(browser: instance)
  3142. 11.times do
  3143. element = instance.find_elements(css: 'body')[0]
  3144. text = element.text
  3145. if text.match?(/#{Regexp.quote(data[:name])}/)
  3146. assert(true, 'role created')
  3147. modal_disappear(browser: instance) # wait until modal has gone
  3148. # add member
  3149. data[:member]&.each do |login|
  3150. instance.find_elements(css: 'a[href="#manage"]')[0].click
  3151. sleep 1
  3152. instance.find_elements(css: '.content.active a[href="#manage/users"]')[0].click
  3153. sleep 3
  3154. element = instance.find_elements(css: '.content.active [name="search"]')[0]
  3155. element.clear
  3156. element.send_keys(login)
  3157. sleep 3
  3158. #instance.find_elements(:css => '.content.active table [data-id]')[0].click
  3159. instance.execute_script('$(".content.active table [data-id] td").first().click()')
  3160. sleep 3
  3161. #instance.find_elements(:css => 'label:contains(" ' + action[:name] + '")')[0].click
  3162. instance.execute_script('$(\'label:contains(" ' + data[:name] + '")\').first().click()')
  3163. instance.find_elements(css: '.modal button.js-submit')[0].click
  3164. modal_disappear(browser: instance)
  3165. end
  3166. end
  3167. sleep 1
  3168. return true
  3169. end
  3170. screenshot(browser: instance, comment: 'role_create_failed')
  3171. raise 'role creation failed'
  3172. end
  3173. =begin
  3174. role_create(
  3175. browser: browser2,
  3176. data: {
  3177. name: 'some role' + random,
  3178. default_at_signup: false,
  3179. permission: {
  3180. 'admin.group' => true,
  3181. 'preferences.password' => true,
  3182. },
  3183. member: [
  3184. 'some_user_login',
  3185. ],
  3186. },
  3187. )
  3188. =end
  3189. def role_edit(params = {})
  3190. switch_window_focus(params)
  3191. log('role_edit', params)
  3192. instance = params[:browser] || @browser
  3193. data = params[:data]
  3194. click(
  3195. browser: instance,
  3196. css: 'a[href="#manage"]',
  3197. mute_log: true,
  3198. )
  3199. click(
  3200. browser: instance,
  3201. css: '.content.active a[href="#manage/roles"]',
  3202. mute_log: true,
  3203. )
  3204. instance.execute_script('$(\'.content.active table tr td:contains(" ' + data[:name] + '")\').first().click()')
  3205. modal_ready(browser: instance)
  3206. element = instance.find_elements(css: '.modal input[name=name]')[0]
  3207. element.clear
  3208. element.send_keys(data[:name])
  3209. if data.key?(:default_at_signup)
  3210. element = instance.find_elements(css: '.modal select[name="default_at_signup"]')[0]
  3211. dropdown = Selenium::WebDriver::Support::Select.new(element)
  3212. if data[:default_at_signup] == true
  3213. dropdown.select_by(:text, 'yes')
  3214. else
  3215. dropdown.select_by(:text, 'no')
  3216. end
  3217. end
  3218. if data.key?(:permission)
  3219. data[:permission].each do |permission_name, permission_value|
  3220. if permission_value == false
  3221. uncheck(
  3222. browser: instance,
  3223. css: ".modal [data-permission-name=\"#{permission_name}\"]",
  3224. )
  3225. else
  3226. check(
  3227. browser: instance,
  3228. css: ".modal [data-permission-name=\"#{permission_name}\"]",
  3229. )
  3230. end
  3231. end
  3232. end
  3233. if data.key?(:group_permissions)
  3234. data[:group_permissions].each do |key, value|
  3235. value.each do |permission|
  3236. check(
  3237. browser: instance,
  3238. css: ".modal input[name=\"group_ids::#{key}\"][value=\"#{permission}\"]",
  3239. )
  3240. end
  3241. end
  3242. end
  3243. if data.key?(:active)
  3244. element = instance.find_elements(css: '.modal select[name="active"]')[0]
  3245. dropdown = Selenium::WebDriver::Support::Select.new(element)
  3246. if data[:active] == true
  3247. dropdown.select_by(:text, 'active')
  3248. else
  3249. dropdown.select_by(:text, 'inactive')
  3250. end
  3251. end
  3252. instance.find_elements(css: '.modal button.js-submit')[0].click
  3253. modal_disappear(browser: instance)
  3254. 11.times do
  3255. element = instance.find_elements(css: 'body')[0]
  3256. text = element.text
  3257. if text.match?(/#{Regexp.quote(data[:name])}/)
  3258. assert(true, 'role created')
  3259. modal_disappear(browser: instance) # wait until modal has gone
  3260. # add member
  3261. data[:member]&.each do |login|
  3262. instance.find_elements(css: 'a[href="#manage"]')[0].click
  3263. sleep 1
  3264. instance.find_elements(css: '.content.active a[href="#manage/users"]')[0].click
  3265. sleep 3
  3266. element = instance.find_elements(css: '.content.active [name="search"]')[0]
  3267. element.clear
  3268. element.send_keys(login)
  3269. sleep 3
  3270. #instance.find_elements(:css => '.content.active table [data-id]')[0].click
  3271. instance.execute_script('$(".content.active table [data-id] td").first().click()')
  3272. sleep 3
  3273. #instance.find_elements(:css => 'label:contains(" ' + action[:name] + '")')[0].click
  3274. instance.execute_script('$(\'label:contains(" ' + data[:name] + '")\').first().click()')
  3275. instance.find_elements(css: '.modal button.js-submit')[0].click
  3276. modal_disappear(browser: instance)
  3277. end
  3278. end
  3279. sleep 1
  3280. return true
  3281. end
  3282. screenshot(browser: instance, comment: 'role_edit_failed')
  3283. raise 'role edit failed'
  3284. end
  3285. =begin
  3286. report_profile_create(
  3287. browser: browser2,
  3288. data: {
  3289. name: 'some profile' + random,
  3290. active: true
  3291. },
  3292. )
  3293. =end
  3294. def report_profile_create(params = {})
  3295. switch_window_focus(params)
  3296. log('report_profile_create', params)
  3297. instance = params[:browser] || @browser
  3298. data = params[:data]
  3299. click(
  3300. browser: instance,
  3301. css: 'a[href="#manage"]',
  3302. mute_log: true,
  3303. )
  3304. click(
  3305. browser: instance,
  3306. css: '.content.active a[href="#manage/report_profiles"]',
  3307. mute_log: true,
  3308. )
  3309. click(
  3310. browser: instance,
  3311. css: '.content.active a.btn.primary[data-type="new"]',
  3312. mute_log: true,
  3313. )
  3314. set(
  3315. browser: instance,
  3316. css: '.modal input[name=name]',
  3317. value: data[:name],
  3318. mute_log: true,
  3319. )
  3320. if data[:active] == false
  3321. select(css: '.content.active .modal select[name="active"]', value: 'inactive')
  3322. end
  3323. sleep 0.5
  3324. click(
  3325. browser: instance,
  3326. css: '.content.active .modal .js-submit',
  3327. mute_log: true,
  3328. )
  3329. modal_disappear
  3330. end
  3331. =begin
  3332. object_manager_attribute_create(
  3333. browser: browser2,
  3334. data: {
  3335. object: 'Ticket', # optional, defaults to Ticket
  3336. name: 'field_name' + random,
  3337. display: 'Display Name of Field',
  3338. data_type: 'Select',
  3339. data_option: {
  3340. options: {
  3341. 'aa' => 'AA',
  3342. 'bb' => 'BB',
  3343. },
  3344. default: 'abc',
  3345. },
  3346. },
  3347. error: 'already exists'
  3348. )
  3349. object_manager_attribute_create(
  3350. browser: browser2,
  3351. data: {
  3352. object: 'Ticket', # optional, defaults to Ticket
  3353. name: 'field_name' + random,
  3354. display: 'Display Name of Field',
  3355. data_type: 'Text',
  3356. data_option: {
  3357. default: 'abc',
  3358. maxlength: 20,
  3359. },
  3360. },
  3361. error: 'already exists'
  3362. )
  3363. object_manager_attribute_create(
  3364. browser: browser2,
  3365. data: {
  3366. object: 'Ticket', # optional, defaults to Ticket
  3367. name: 'field_name' + random,
  3368. display: 'Display Name of Field',
  3369. data_type: 'Integer',
  3370. data_option: {
  3371. default: '15',
  3372. min: 1,
  3373. max: 999999,
  3374. },
  3375. },
  3376. error: 'already exists'
  3377. )
  3378. object_manager_attribute_create(
  3379. browser: browser2,
  3380. data: {
  3381. object: 'Ticket', # optional, defaults to Ticket
  3382. name: 'field_name' + random,
  3383. display: 'Display Name of Field',
  3384. data_type: 'Datetime',
  3385. data_option: {
  3386. future: true,
  3387. past: true,
  3388. diff: 24,
  3389. },
  3390. },
  3391. error: 'already exists'
  3392. )
  3393. object_manager_attribute_create(
  3394. browser: browser2,
  3395. data: {
  3396. object: 'Ticket', # optional, defaults to Ticket
  3397. name: 'field_name' + random,
  3398. display: 'Display Name of Field',
  3399. data_type: 'Date',
  3400. data_option: {
  3401. future: true,
  3402. past: true,
  3403. diff: 24,
  3404. },
  3405. },
  3406. error: 'already exists'
  3407. )
  3408. object_manager_attribute_create(
  3409. browser: browser2,
  3410. data: {
  3411. object: 'Ticket', # optional, defaults to Ticket
  3412. name: 'field_name' + random,
  3413. display: 'Display Name of Field',
  3414. data_type: 'Boolean',
  3415. data_option: {
  3416. options: {
  3417. true: 'YES',
  3418. false: 'NO',
  3419. }
  3420. default: undefined,
  3421. },
  3422. },
  3423. error: 'already exists'
  3424. )
  3425. =end
  3426. def object_manager_attribute_create(params = {})
  3427. switch_window_focus(params)
  3428. log('object_manager_attribute_create', params)
  3429. instance = params[:browser] || @browser
  3430. data = params[:data]
  3431. data[:object] = data[:object] || 'Ticket'
  3432. raise 'invalid object parameter in object_manager_attribute_create' if %w[Ticket User Organization Group].exclude? data[:object]
  3433. # make sure that required params are supplied
  3434. %i[name display data_type].each do |s|
  3435. next if data.key? s
  3436. raise "missing required param #{s} in object_manager_attribute_create()"
  3437. end
  3438. click(
  3439. browser: instance,
  3440. css: 'a[href="#manage"]',
  3441. mute_log: true,
  3442. )
  3443. click(
  3444. browser: instance,
  3445. css: '.content.active a[href="#system/object_manager"]',
  3446. mute_log: true,
  3447. )
  3448. watch_for(
  3449. browser: instance,
  3450. css: '.content.active .js-new',
  3451. )
  3452. click(
  3453. browser: instance,
  3454. css: ".content.active a[href='#c-#{data[:object]}']",
  3455. mute_log: true,
  3456. )
  3457. click(
  3458. browser: instance,
  3459. css: ".content.active #c-#{data[:object]} .js-new",
  3460. mute_log: true,
  3461. )
  3462. object_manager_attribute_perform('create', params)
  3463. end
  3464. =begin
  3465. object_manager_attribute_update(
  3466. browser: browser2,
  3467. data: {
  3468. object: 'Ticket', # optional, defaults to Ticket
  3469. name: 'field_name' + random,
  3470. display: 'Display Name of Field',
  3471. data_type: 'Select',
  3472. data_option: {
  3473. options: {
  3474. 'aa' => 'AA',
  3475. 'bb' => 'BB',
  3476. },
  3477. default: 'abc',
  3478. },
  3479. },
  3480. error: 'already exists'
  3481. )
  3482. =end
  3483. def object_manager_attribute_update(params = {})
  3484. switch_window_focus(params)
  3485. log('object_manager_attribute_update', params)
  3486. instance = params[:browser] || @browser
  3487. data = params[:data]
  3488. data[:object] = data[:object] || 'Ticket'
  3489. raise 'invalid object parameter in object_manager_attribute_update' if %w[Ticket User Organization Group].exclude? data[:object]
  3490. click(
  3491. browser: instance,
  3492. css: 'a[href="#manage"]',
  3493. mute_log: true,
  3494. )
  3495. click(
  3496. browser: instance,
  3497. css: '.content.active a[href="#system/object_manager"]',
  3498. mute_log: true,
  3499. )
  3500. watch_for(
  3501. browser: instance,
  3502. css: '.content.active .js-new',
  3503. )
  3504. click(
  3505. browser: instance,
  3506. css: ".content.active a[href='#c-#{data[:object]}']",
  3507. mute_log: true,
  3508. )
  3509. instance.execute_script("$(\".content.active #c-#{data[:object]} td:contains('#{data[:name]}')\").first().click()")
  3510. object_manager_attribute_perform('update', params)
  3511. end
  3512. =begin
  3513. object_manager_attribute_delete(
  3514. browser: browser2,
  3515. data: {
  3516. object: 'Ticket', # optional, defaults to Ticket
  3517. name: 'field_name' + random,
  3518. },
  3519. )
  3520. =end
  3521. def object_manager_attribute_delete(params = {})
  3522. switch_window_focus(params)
  3523. log('object_manager_attribute_delete', params)
  3524. instance = params[:browser] || @browser
  3525. data = params[:data]
  3526. data[:object] = data[:object] || 'Ticket'
  3527. raise 'invalid object parameter in object_manager_attribute_delete' if %w[Ticket User Organization Group].exclude? data[:object]
  3528. click(
  3529. browser: instance,
  3530. css: 'a[href="#manage"]',
  3531. mute_log: true,
  3532. )
  3533. click(
  3534. browser: instance,
  3535. css: '.content.active a[href="#system/object_manager"]',
  3536. mute_log: true,
  3537. )
  3538. watch_for(
  3539. browser: instance,
  3540. css: '.content.active .js-new',
  3541. )
  3542. click(
  3543. browser: instance,
  3544. css: ".content.active a[href='#c-#{data[:object]}']",
  3545. mute_log: true,
  3546. )
  3547. sleep 4
  3548. r = instance.execute_script("$(\".content.active #c-#{data[:object]} td:contains('#{data[:name]}')\").first().closest('tr').find('.js-delete').click()")
  3549. end
  3550. =begin
  3551. object_manager_attribute_discard_changes(
  3552. browser: browser2,
  3553. )
  3554. =end
  3555. def object_manager_attribute_discard_changes(params = {})
  3556. switch_window_focus(params)
  3557. log('object_manager_attribute_discard_changes', params)
  3558. instance = params[:browser] || @browser
  3559. click(
  3560. browser: instance,
  3561. css: 'a[href="#manage"]',
  3562. mute_log: true,
  3563. )
  3564. click(
  3565. browser: instance,
  3566. css: '.content.active a[href="#system/object_manager"]',
  3567. mute_log: true,
  3568. )
  3569. sleep 4
  3570. element = instance.find_elements(css: '.content.active .js-discard').first
  3571. element.click
  3572. watch_for_disappear(
  3573. browser: instance,
  3574. css: '.content.active .js-discard',
  3575. )
  3576. end
  3577. =begin
  3578. Execute any pending migrations in the object attribute manager
  3579. object_manager_attribute_migrate(
  3580. browser: browser2,
  3581. )
  3582. =end
  3583. def object_manager_attribute_migrate(params = {})
  3584. switch_window_focus(params)
  3585. log('object_manager_attribute_migrate', params)
  3586. instance = params[:browser] || @browser
  3587. watch_for(
  3588. browser: instance,
  3589. css: '.content.active',
  3590. value: 'Database Update required',
  3591. mute_log: true,
  3592. )
  3593. click(
  3594. browser: instance,
  3595. css: '.content.active .tab-pane.active div.js-execute',
  3596. mute_log: true,
  3597. )
  3598. modal_ready(
  3599. browser: instance,
  3600. )
  3601. title_text = instance.find_elements(css: '.modal .modal-title').first.text
  3602. if ['Zammad is restarting...', 'Zammad need a restart!'].include?(title_text)
  3603. # in the complex case, wait for server to restart
  3604. modal_disappear(
  3605. browser: instance,
  3606. timeout: 7.minutes,
  3607. )
  3608. elsif title_text == 'Config has changed'
  3609. # in the simple case, just click the submit button
  3610. click(
  3611. browser: instance,
  3612. css: '.modal .js-submit',
  3613. mute_log: true,
  3614. )
  3615. else
  3616. raise "Unknown title text \"#{title_text}\" found when trying to update database"
  3617. end
  3618. sleep 5
  3619. watch_for(
  3620. browser: instance,
  3621. css: '.content.active',
  3622. mute_log: true,
  3623. )
  3624. end
  3625. =begin
  3626. tags_verify(
  3627. browser: browser2,
  3628. tags: {
  3629. 'tag 1' => true,
  3630. 'tag 2' => true,
  3631. 'tag 3' => false,
  3632. },
  3633. )
  3634. =end
  3635. def tags_verify(params = {})
  3636. switch_window_focus(params)
  3637. log('tags_verify', params)
  3638. instance = params[:browser] || @browser
  3639. tags = instance.find_elements({ css: '.content.active .js-tag' })
  3640. assert(tags)
  3641. assert(tags[0])
  3642. tags_found = {}
  3643. params[:tags].each_key do |key|
  3644. tags_found[key] = false
  3645. end
  3646. tags.each do |element|
  3647. text = element.text
  3648. if tags_found.key?(text)
  3649. tags_found[text] = true
  3650. else
  3651. assert(false, "tag exists but is not in check to verify '#{text}'")
  3652. end
  3653. end
  3654. params[:tags].each do |key, value|
  3655. assert_equal(value, tags_found[key], "tag '#{key}'")
  3656. end
  3657. end
  3658. def quote(string)
  3659. string_quoted = string
  3660. string_quoted.gsub!(/&/, '&amp;')
  3661. string_quoted.gsub!(/</, '&lt;')
  3662. string_quoted.gsub!(/>/, '&gt;')
  3663. string_quoted
  3664. end
  3665. def switch_window_focus(params)
  3666. instance = params[:browser] || @browser
  3667. if instance != @last_used_browser
  3668. log('switch browser window focus', {})
  3669. instance.switch_to.window(instance.window_handles.first)
  3670. end
  3671. @last_used_browser = instance
  3672. end
  3673. def log(method, params = {})
  3674. begin
  3675. instance = params[:browser] || @browser
  3676. if instance
  3677. logs = instance.manage.logs.get(:browser)
  3678. logs.each do |log|
  3679. next if log.level == 'WARNING' && log.message =~ /Declaration\sdropped./ # ignore ff css warnings
  3680. time = Time.zone.parse(Time.zone.at(log.timestamp / 1000).to_datetime.to_s)
  3681. puts "#{time}/#{log.level}: #{log.message}"
  3682. end
  3683. end
  3684. rescue
  3685. # failed to get logs
  3686. end
  3687. return if !DEBUG
  3688. return if params[:mute_log]
  3689. puts "#{Time.zone.now}/#{method}: #{params.inspect}"
  3690. end
  3691. private
  3692. def add_tree_options(instance:, options:)
  3693. # first level entries have to get added in regular order
  3694. options.each_key.with_index do |option, index|
  3695. if index != 0
  3696. element = instance.find_elements(css: '.modal .js-treeTable .js-addRow')[index - 1]
  3697. element.click
  3698. end
  3699. element = instance.find_elements(css: '.modal .js-treeTable .js-key')[index]
  3700. element.clear
  3701. element.send_keys(option)
  3702. end
  3703. add_sub_tree_recursion(
  3704. instance: instance,
  3705. options: options,
  3706. )
  3707. end
  3708. def add_sub_tree_recursion(instance:, options:, offset: 0)
  3709. options.each_value.inject(offset) do |child_offset, children|
  3710. child_offset += 1
  3711. # put your recursion glasses on 8-)
  3712. add_sub_tree_options(
  3713. instance: instance,
  3714. options: children,
  3715. offset: child_offset,
  3716. )
  3717. end
  3718. end
  3719. def add_sub_tree_options(instance:, options:, offset:)
  3720. # sub level entries have to get added in reversed order
  3721. level_options = options.to_a.reverse.to_h.keys
  3722. level_options.each do |option|
  3723. # sub level entries have to get added via 'add child row' link
  3724. click_index = offset - 1
  3725. element = instance.find_elements(css: '.modal .js-treeTable .js-addChild')[click_index]
  3726. element.click
  3727. element = instance.find_elements(css: '.modal .js-treeTable .js-key')[offset]
  3728. element.clear
  3729. element.send_keys(option)
  3730. sleep 0.25
  3731. end
  3732. add_sub_tree_recursion(
  3733. instance: instance,
  3734. options: options,
  3735. offset: offset,
  3736. )
  3737. end
  3738. def token_verify(css, value)
  3739. original_element = @browser.find_element(:css, css)
  3740. elem = original_element.find_element(xpath: '../input[contains(@class, "token-input")]')
  3741. elem.send_keys value
  3742. elem.send_keys :enter
  3743. watch_for(
  3744. xpath: '../*/span[contains(@class,"token-label")]',
  3745. value: value,
  3746. container: original_element
  3747. )
  3748. end
  3749. def toggle_checkbox(scope, value)
  3750. checkbox = scope.find_element(css: "input[value=#{value}]")
  3751. @browser
  3752. .action
  3753. .move_to(checkbox)
  3754. .click
  3755. .perform
  3756. end
  3757. def checkbox_is_selected(scope, value)
  3758. scope.find_element(css: "input[value=#{value}]").property('checked')
  3759. end
  3760. =begin
  3761. Switch the current logged in user's profile language to a new language
  3762. switch_language(
  3763. browser: browser2,
  3764. data: {
  3765. language: 'Deutsch'
  3766. },
  3767. )
  3768. IMPORTANT REMINDER! At the end of tests, the caller must manually set the language back to English again:
  3769. switch_language(
  3770. browser: browser2,
  3771. data: {
  3772. language: 'English (United States)'
  3773. },
  3774. )
  3775. Failure to switch back to English will cause large amounts of subsequent tests to fail due to the UI language differences.
  3776. =end
  3777. def switch_language(params = {})
  3778. switch_window_focus(params)
  3779. log('switch_language', params)
  3780. instance = params[:browser] || @browser
  3781. data = params[:data]
  3782. click(browser: instance, css: '#navigation .user-menu .js-avatar')
  3783. click(browser: instance, css: '#navigation .user-menu a[href="#profile"]')
  3784. select(
  3785. browser: instance,
  3786. css: '.content.active .searchableSelect-shadow',
  3787. value: data[:language],
  3788. )
  3789. click(browser: instance, css: '.content.active .btn--primary')
  3790. watch_for(
  3791. browser: instance,
  3792. css: '#notify',
  3793. )
  3794. end
  3795. =begin
  3796. Retrieve a hash of all the avaiable Zammad settings and their current values.
  3797. settings = fetch_settings()
  3798. =end
  3799. def fetch_settings
  3800. url = URI.parse(browser_url)
  3801. req = Net::HTTP::Get.new(browser_url + '/api/v1/settings/')
  3802. req.basic_auth('master@example.com', 'test')
  3803. res = Net::HTTP.start(url.host, url.port) do |http|
  3804. http.request(req)
  3805. end
  3806. raise "HTTP error #{res.code} while fetching #{browser_url}/api/v1/settings/" if res.code != '200'
  3807. JSON.parse(res.body)
  3808. end
  3809. =begin
  3810. Enable or disable Zammad experiemental features remotely.
  3811. set_setting('ui_ticket_zoom_attachments_preview', true)
  3812. =end
  3813. def set_setting(name, value)
  3814. name_to_id = fetch_settings.map { |s| [s['name'], s['id']] }.to_h
  3815. id = name_to_id[name]
  3816. url = URI.parse(browser_url)
  3817. req = Net::HTTP::Put.new("#{browser_url}/api/v1/settings/#{id}")
  3818. req['Content-Type'] = 'application/json'
  3819. req.basic_auth('master@example.com', 'test')
  3820. req.body = { 'state_current' => { 'value' => value } }.to_json
  3821. res = Net::HTTP.start(url.host, url.port) do |http|
  3822. http.request(req)
  3823. end
  3824. raise "HTTP error #{res.code} while POSTing to #{browser_url}/api/v1/settings/" if res.code != '200'
  3825. end
  3826. =begin
  3827. Helper method for both object_manager_attribute_create and object_manager_attribute_update
  3828. =end
  3829. def object_manager_attribute_perform(action = 'create', params = {})
  3830. instance = params[:browser] || @browser
  3831. data = params[:data]
  3832. modal_ready(browser: instance)
  3833. if action == 'create'
  3834. set(
  3835. browser: instance,
  3836. css: '.modal input[name=name]',
  3837. value: data[:name],
  3838. mute_log: true,
  3839. )
  3840. end
  3841. if data[:display]
  3842. set(
  3843. browser: instance,
  3844. css: '.modal input[name=display]',
  3845. value: data[:display],
  3846. mute_log: true,
  3847. )
  3848. end
  3849. if data[:data_type]
  3850. select(
  3851. browser: instance,
  3852. css: '.modal select[name="data_type"]',
  3853. value: data[:data_type],
  3854. mute_log: true,
  3855. )
  3856. end
  3857. if data[:data_option]
  3858. if data[:data_option][:options]
  3859. if data[:data_type] == 'Boolean'
  3860. # rubocop:disable Lint/BooleanSymbol
  3861. element = instance.find_elements(css: '.modal .js-valueTrue').first
  3862. element.clear
  3863. element.send_keys(data[:data_option][:options][:true])
  3864. element = instance.find_elements(css: '.modal .js-valueFalse').first
  3865. element.clear
  3866. element.send_keys(data[:data_option][:options][:false])
  3867. # rubocop:enable Lint/BooleanSymbol
  3868. elsif data[:data_type] == 'Tree Select'
  3869. add_tree_options(
  3870. instance: instance,
  3871. options: data[:data_option][:options],
  3872. )
  3873. else
  3874. if action == 'update'
  3875. # first clear all existing entries
  3876. loop do
  3877. target = {
  3878. browser: instance,
  3879. css: '.modal .js-Table .js-remove',
  3880. mute_log: true,
  3881. }
  3882. break if !instance.find_elements(css: target[:css])[0]
  3883. click(target)
  3884. end
  3885. sleep 1
  3886. end
  3887. # then populate the table with the new values
  3888. data[:data_option][:options].each do |key, value|
  3889. element = instance.find_elements(css: '.modal .js-Table .js-key').last
  3890. element.clear
  3891. element.send_keys(key)
  3892. element = instance.find_elements(css: '.modal .js-Table .js-value').last
  3893. element.clear
  3894. element.send_keys(value)
  3895. element = instance.find_elements(css: '.modal .js-Table .js-add')[0]
  3896. element.click
  3897. end
  3898. end
  3899. end
  3900. %i[default min max diff].each do |key|
  3901. next if !data[:data_option].key?(key)
  3902. element = instance.find_elements(css: ".modal [name=\"data_option::#{key}\"]").first
  3903. element.clear
  3904. element.send_keys(data[:data_option][key])
  3905. end
  3906. %i[future past].each do |key|
  3907. next if !data[:data_option].key?(key)
  3908. select(
  3909. browser: instance,
  3910. css: ".modal select[name=\"data_option::#{key}\"]",
  3911. value: data[:data_option][key],
  3912. mute_log: true,
  3913. )
  3914. end
  3915. %i[maxlength].each do |key|
  3916. next if !data[:data_option].key?(key)
  3917. set(
  3918. browser: instance,
  3919. css: ".modal input[name=\"data_option::#{key}\"]",
  3920. value: data[:data_option][key],
  3921. mute_log: true,
  3922. )
  3923. end
  3924. end
  3925. if params[:do_not_submit]
  3926. assert(true, "attribute #{action}d without submit")
  3927. return true
  3928. end
  3929. instance.find_elements(css: '.modal button.js-submit')[0].click
  3930. if params[:error]
  3931. sleep 4
  3932. watch_for(
  3933. css: '.modal',
  3934. value: params[:error],
  3935. )
  3936. click(
  3937. browser: instance,
  3938. css: '.modal .js-close',
  3939. )
  3940. modal_disappear(browser: instance)
  3941. return
  3942. end
  3943. modal_disappear(browser: instance)
  3944. 11.times do
  3945. element = instance.find_elements(css: 'body')[0]
  3946. text = element.text
  3947. if text.match?(/#{Regexp.quote(data[:name])}/)
  3948. assert(true, 'object manager attribute updated')
  3949. sleep 1
  3950. return true
  3951. end
  3952. sleep 1
  3953. end
  3954. screenshot(browser: instance, comment: "object_manager_attribute_#{action}_failed")
  3955. raise "object_manager_attribute_#{action}_failed"
  3956. end
  3957. end