custom_extensions.rb 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class Capybara::Node::Element
  3. # This is an extension to each node to check if the element
  4. # is moving or in a fixed position. This is especially helpful
  5. # for animated elements that cause flanky tests.
  6. # NOTE: In CI env a special sleep is performed between checks
  7. # because animations can be slow.
  8. #
  9. # @param [Integer] checks the number of performed movement checks
  10. #
  11. # @example
  12. # find('.clues-close').in_fixed_position.click
  13. # => waits till clues moved to final position and performs click afterwards
  14. #
  15. # @raise [RuntimeError] raised in case the element is
  16. # still moving after max number of checks was passed
  17. #
  18. # @return [Capybara::Node::Element] the element/node
  19. def in_fixed_position(checks: 100, wait: 0.2)
  20. previous = native.location
  21. (checks + 1).times do
  22. sleep wait
  23. current = native.location
  24. return self if previous == current
  25. previous = current
  26. end
  27. raise "Element still moving after #{checks} checks"
  28. end
  29. end
  30. module ZammadCapybarActionDelegator
  31. def select(...)
  32. super.tap do
  33. await_empty_ajax_queue
  34. end
  35. end
  36. def unselect(...)
  37. super.tap do
  38. await_empty_ajax_queue
  39. end
  40. end
  41. def click(...)
  42. super.tap do
  43. await_empty_ajax_queue
  44. end
  45. end
  46. def click_on(...)
  47. super.tap do
  48. await_empty_ajax_queue
  49. end
  50. end
  51. def click_link(...)
  52. super.tap do
  53. await_empty_ajax_queue
  54. end
  55. end
  56. def click_link_or_button(...)
  57. super.tap do
  58. await_empty_ajax_queue
  59. end
  60. end
  61. def click_button(...)
  62. super.tap do
  63. await_empty_ajax_queue
  64. end
  65. end
  66. def select_option(...)
  67. super.tap do
  68. await_empty_ajax_queue
  69. end
  70. end
  71. def send_keys(...)
  72. super.tap do
  73. await_empty_ajax_queue
  74. end
  75. end
  76. def fill_in(...)
  77. super.tap do
  78. await_empty_ajax_queue
  79. end
  80. end
  81. def hot_keys
  82. mac_platform? ? %i[control alt] : %i[shift control]
  83. end
  84. def magic_key
  85. mac_platform? ? :command : :control
  86. end
  87. def mac_platform?
  88. Gem::Platform.local.os.eql? 'darwin'
  89. end
  90. def check(...)
  91. super.tap do
  92. await_empty_ajax_queue
  93. end
  94. end
  95. end
  96. module ZammadCapybarSelectorDelegator
  97. def find_field(...)
  98. ZammadCapybaraElementDelegator.new(element: super, context: self)
  99. end
  100. def find_button(...)
  101. ZammadCapybaraElementDelegator.new(element: super, context: self)
  102. end
  103. def find_by_id(...)
  104. ZammadCapybaraElementDelegator.new(element: super, context: self)
  105. end
  106. def find_link(...)
  107. ZammadCapybaraElementDelegator.new(element: super, context: self)
  108. end
  109. def find(...)
  110. ZammadCapybaraElementDelegator.new(element: super, context: self)
  111. end
  112. def first(...)
  113. ZammadCapybaraElementDelegator.new(element: super, context: self)
  114. end
  115. def all(...)
  116. super.map { |element| ZammadCapybaraElementDelegator.new(element: element, context: self) }
  117. end
  118. end
  119. class ZammadCapybaraSessionDelegator < SimpleDelegator
  120. extend Forwardable
  121. def_delegator :@context, :await_empty_ajax_queue
  122. attr_reader :element
  123. include ZammadCapybarSelectorDelegator
  124. def initialize(context:, element:)
  125. @context = context
  126. @element = element
  127. super(element)
  128. end
  129. end
  130. class ZammadCapybaraElementDelegator < ZammadCapybaraSessionDelegator
  131. include ZammadCapybarActionDelegator
  132. end
  133. module CapybaraCustomExtensions
  134. include ZammadCapybarActionDelegator
  135. include ZammadCapybarSelectorDelegator
  136. def page(...)
  137. ZammadCapybaraSessionDelegator.new(element: super, context: self)
  138. end
  139. end
  140. RSpec.configure do |config|
  141. config.include CapybaraCustomExtensions, type: :system
  142. end