Module: Avo::TestHelpers

Includes:
WaitForLoaded
Included in:
PrefixedTestHelpers
Defined in:
lib/avo/test_helpers.rb

Instance Method Summary collapse

Methods included from WaitForLoaded

#wait_for_action_dialog_to_disappear, #wait_for_body_class_missing, #wait_for_element_missing, #wait_for_element_present, #wait_for_loaded, #wait_for_path_to_be, #wait_for_route_loaded, #wait_for_route_loading, #wait_for_search_loaded, #wait_for_search_to_dissapear, #wait_for_tag_suggestions_to_appear, #wait_for_tag_to_appear, #wait_for_tag_to_disappear, #wait_for_turbo_frame_id, #wait_for_turbo_frame_src, #wait_for_turbo_loaded

Instance Method Details

#accept_custom_alert(&block) ⇒ Object



341
342
343
344
# File 'lib/avo/test_helpers.rb', line 341

def accept_custom_alert(&block)
  block.call
  find('#turbo-confirm button[value="confirm"]').click
end

#add_tag(field:, tag:) ⇒ Object

Example usage:

expect(add_tag(field: :tags, tag: "one")).to eq ["one"]
add_tag(field: :tags, tag: "two")


274
275
276
277
278
279
280
281
282
283
284
# File 'lib/avo/test_helpers.rb', line 274

def add_tag(field:, tag:)
  # Find the input field for the specified field and click it
  find("[data-field-id='#{field}'] [data-slot='value'] [role='textbox']").click

  # Enter the specified tag into the input field
  type tag, :return
  wait_for_tag_to_appear(tag)

  # Return an array of the current tags
  tags(field: field)
end

#check_select_allObject



263
264
265
# File 'lib/avo/test_helpers.rb', line 263

def check_select_all
  find("input[type='checkbox'][name='Select all'][data-action='input->item-select-all#toggle']").set(true)
end

#click_global_search_inputObject



96
97
98
# File 'lib/avo/test_helpers.rb', line 96

def click_global_search_input
  page.find("[data-global-search-target='input']").click
end

#click_on_sidebar_item(label) ⇒ Object



178
179
180
181
182
# File 'lib/avo/test_helpers.rb', line 178

def click_on_sidebar_item(label)
  within main_sidebar do
    click_on label
  end
end

#click_row_action(record, control:) ⇒ Object

Clicks a row control action (destroy, detach, edit, etc.) for a given record. Works for both grid view (actions behind a popover trigger) and table view (flat inline actions).



348
349
350
351
352
353
354
355
356
# File 'lib/avo/test_helpers.rb', line 348

def click_row_action(record, control:)
  row = find("[data-record-id='#{record.to_param}']")

  if row.has_css?(".grid-card__action", wait: 0)
    row.find(".grid-card__action").click
  end

  find("a[data-control='#{control}'][data-resource-id='#{record.to_param}']").click
end

#click_tab(tab_name = "", within_target: nil, **args) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/avo/test_helpers.rb', line 145

def click_tab(tab_name = "", within_target: nil, **args)
  tab_container_selector = '[data-controller="tabs"] [role="tablist"]'

  if within_target.present?
    within within_target do
      within find(tab_container_selector) do
        find_link(tab_name).trigger("click")
      end
    end
  else
    within find(tab_container_selector) do
      find_link(tab_name).trigger("click")
    end
  end
  wait_for_loaded
end

#close_pickerObject



227
228
229
230
# File 'lib/avo/test_helpers.rb', line 227

def close_picker
  all(".header__title").first.trigger("click")
  sleep 0.3
end

#empty_dashObject



92
93
94
# File 'lib/avo/test_helpers.rb', line 92

def empty_dash
  ""
end

#first_tab_groupObject



166
167
168
# File 'lib/avo/test_helpers.rb', line 166

def first_tab_group
  tab_group 0
end

#grid_field_wrapper(record_id:) ⇒ Object

Finds the wrapper element on the index grid view type for the given record id Example usage:

grid_field_wrapper(record_id: 5)


22
23
24
# File 'lib/avo/test_helpers.rb', line 22

def grid_field_wrapper(record_id:)
  find("[data-component-name='avo/index/grid_item_component'][data-resource-id='#{record_id}']")
end

#has_and_belongs_to_many_field_wrapper(id:, view: :show) ⇒ Object

Finds the table on the show view for the given has_and_belongs_to_many field id and view Example usage:

has_and_belongs_to_many_field_wrapper(id: :users)
has_and_belongs_to_many_field_wrapper(id: :users, view: :edit)


52
53
54
# File 'lib/avo/test_helpers.rb', line 52

def has_and_belongs_to_many_field_wrapper(id:, view: :show)
  related_field_context(id: id, relation: :has_and_belongs_to_many, view: view)
end

#has_many_field_wrapper(id:, view: :show) ⇒ Object

Finds the table on the show view for the given has_many field id and view Example usage:

has_many_field_wrapper(id: :users)
has_many_field_wrapper(id: :users, view: :edit)


44
45
46
# File 'lib/avo/test_helpers.rb', line 44

def has_many_field_wrapper(id:, view: :show)
  related_field_context(id: id, relation: :has_many, view: view)
end

#has_one_field_wrapper(id:, view: :show) ⇒ Object

Finds the table on the show view for the given has_one field id and view Example usage:

has_one_field_wrapper(id: :users)
has_one_field_wrapper(id: :users, view: :edit)


60
61
62
# File 'lib/avo/test_helpers.rb', line 60

def has_one_field_wrapper(id:, view: :show)
  related_field_context(id: id, relation: :has_one, view: view)
end

#index_field_label(id:) ⇒ Object

Finds the label element on the index view for the given field id Example usage:

index_field_label(id: "name")


67
68
69
# File 'lib/avo/test_helpers.rb', line 67

def index_field_label(id:)
  find("[data-component-name='avo/partials/table_header'] [data-table-header-field-id='#{id}']").text
end

#index_field_value(id:, record_id:, type: nil) ⇒ Object

Finds the value element on the index view for the given field id Example usage:

index_field_value(id: "name", record_id: 2)


81
82
83
# File 'lib/avo/test_helpers.rb', line 81

def index_field_value(id:, record_id:, type: nil)
  index_field_wrapper(id: id, record_id: record_id, type: type).text
end

#index_field_wrapper(id:, record_id:, type: nil) ⇒ Object

Finds the wrapper element on the index view for the given field id and type, and associated with the given record id Example usage:

index_field_wrapper(id: "name", type: "text", record_id: 2)
index_field_wrapper(id: "name", record_id: 2)


9
10
11
12
13
14
15
16
17
# File 'lib/avo/test_helpers.rb', line 9

def index_field_wrapper(id:, record_id:, type: nil)
  base_data = "#{row(record_id)} [data-field-id='#{id}']"

  if type.present?
    find("#{base_data}[data-resource-index-target='#{wrapper_name_for(id: id, type: type)}']")
  else
    find(base_data)
  end
end

#open_panel_action(action_name:, list: "Actions") ⇒ Object

Click on the action from the panel (index and show above the table) Pass list: nil to run an action outside of the list Pass list: “List name” if list is not the default “Actions” Example usage:

open_panel_action(action_name: "Dummy action")
open_panel_action(list: nil, action_name: "Release fish")
open_panel_action(list: "Runnables", action_name: "Release fish")


239
240
241
# File 'lib/avo/test_helpers.rb', line 239

def open_panel_action(action_name:, list: "Actions")
  open_action(action_name: action_name, list: list, context: first(".header__controls"))
end

#open_pickerObject



223
224
225
# File 'lib/avo/test_helpers.rb', line 223

def open_picker
  text_input.click
end

#open_row_action(record_id:, action_name:, list: "Actions") ⇒ Object

Open the action from the record_id row Pass list: nil to run an action outside of the list Pass list: “List name” if list is not the default “Actions” Example usage:

open_row_action(action_name: "Dummy action")
open_row_action(list: nil, action_name: "Release fish")
open_row_action(list: "Runnables", action_name: "Release fish")


250
251
252
# File 'lib/avo/test_helpers.rb', line 250

def open_row_action(record_id:, action_name:, list: "Actions")
  open_action(action_name: action_name, list: list, context: row(record_id))
end

#remove_tag(field:, tag:) ⇒ Object

Example usage:

expect(remove_tag(field: :tags, tag: "one")).to eq ["three"]
remove_tag(field: :tags, tag: "one")


289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/avo/test_helpers.rb', line 289

def remove_tag(field:, tag:)
  # Within the specified field
  within("[data-field-id='#{field}'] [data-slot='value']") do
    # Find the tag with the specified text and click the remove button for the tag
    page.find(".tagify__tag", text: tag).find(".tagify__tag__removeBtn").click

    wait_for_tag_to_disappear(tag)
  end

  # Return an array of the current tags
  tags(field: field)
end

#run_actionObject

Click on submit action button if dialog is open



255
256
257
258
259
260
261
# File 'lib/avo/test_helpers.rb', line 255

def run_action
  within(find("[role='dialog']")) do
    find("[data-target='submit_action']").click
  end

  wait_for_action_dialog_to_disappear
end

#saveObject

Save a record and wait for the page to load For most cases ‘.click` works Sometimes other element may be overlapping the button so the `.trigger(“click”)` solves the issue Trigger can’t be used by default because it breaks on some feature specs



136
137
138
139
140
141
142
143
# File 'lib/avo/test_helpers.rb', line 136

def save
  button = find("button.button", text: "Save")
  button.click
rescue Capybara::Cuprite::MouseEventFailed
  button.trigger("click")
ensure
  wait_for_loaded
end

#second_tab_groupObject



170
171
172
# File 'lib/avo/test_helpers.rb', line 170

def second_tab_group
  tab_group 1
end

#select_first_result_in_searchObject

TODO: this will make sense only on global search Should use the click_global_search_input or click_resource_search_input method to open the search box first and optionaly write_in_search. Example usage:

open_search_box(:users) # opens the search box for the "users" resource
write_in_search("John Doe")
select_first_result_in_search


123
124
125
126
127
128
129
130
# File 'lib/avo/test_helpers.rb', line 123

def select_first_result_in_search
  type :down, :enter
rescue
  find(".aa-Input").send_keys :arrow_down
  find(".aa-Input").send_keys :enter
ensure
  wait_for_search_loaded
end

#set_picker_dates(input, *dates) ⇒ Object



189
190
191
192
193
194
195
# File 'lib/avo/test_helpers.rb', line 189

def set_picker_dates(input, *dates)
  page.execute_script(
    "arguments[0]._flatpickr.setDate(arguments[1], true)",
    input.native,
    (dates.length == 1) ? dates.first : dates
  )
end

#set_picker_day(date) ⇒ Object



184
185
186
187
# File 'lib/avo/test_helpers.rb', line 184

def set_picker_day(date)
  find(".flatpickr-day[aria-label=\"#{date}\"]").click
  sleep 0.2
end

#set_picker_hour(value) ⇒ Object



205
206
207
# File 'lib/avo/test_helpers.rb', line 205

def set_picker_hour(value)
  find(".flatpickr-hour").set(value)
end

#set_picker_minute(value) ⇒ Object



209
210
211
# File 'lib/avo/test_helpers.rb', line 209

def set_picker_minute(value)
  find(".flatpickr-minute").set(value)
end

#set_picker_second(value) ⇒ Object



213
214
215
# File 'lib/avo/test_helpers.rb', line 213

def set_picker_second(value)
  find(".flatpickr-second").set(value)
end

#set_picker_text_input(value) ⇒ Object



217
218
219
220
221
# File 'lib/avo/test_helpers.rb', line 217

def set_picker_text_input(value)
  element = find("input.form-control[type='text']")
  # Set value without firing input/change events
  page.execute_script("arguments[0].value = arguments[1]", element.native, value)
end

#set_picker_time(input, hour:, minute: 0, second: 0) ⇒ Object



197
198
199
200
201
202
203
# File 'lib/avo/test_helpers.rb', line 197

def set_picker_time(input, hour:, minute: 0, second: 0)
  page.execute_script(
    "arguments[0]._flatpickr.setDate(arguments[1], true)",
    input.native,
    "#{hour}:#{minute}:#{second}"
  )
end

#show_field_label(id:) ⇒ Object

Finds the label element on the show view for the given field id Example usage:

show_field_label(id: "name")


74
75
76
# File 'lib/avo/test_helpers.rb', line 74

def show_field_label(id:)
  within(show_field_wrapper(id: id)) { find("[data-slot='label']").text }
end

#show_field_value(id:, type: nil) ⇒ Object

Finds the value element on the show view for the given field id Example usage:

show_field_value(id: "name")


88
89
90
# File 'lib/avo/test_helpers.rb', line 88

def show_field_value(id:, type: nil)
  within(show_field_wrapper(id: id, type: type)) { find("[data-slot='value']").text }
end

#show_field_wrapper(id:, type: nil) ⇒ Object

Finds the wrapper element on the show view for the given field id and type Example usage:

show_field_wrapper(id: "name", type: "text")
show_field_wrapper(id: "name")


30
31
32
33
34
35
36
37
38
# File 'lib/avo/test_helpers.rb', line 30

def show_field_wrapper(id:, type: nil)
  base_data = "[data-field-id='#{id}']"

  if type.present?
    find("#{base_data}[data-resource-show-target='#{wrapper_name_for(id: id, type: type)}']")
  else
    find(base_data)
  end
end

#tab_group(index = 0) ⇒ Object



162
163
164
# File 'lib/avo/test_helpers.rb', line 162

def tab_group(index = 0)
  find_all('[data-controller="tabs"]')[index]
end

#tag_suggestions(field:, input:) ⇒ Object

Example usage:

expect(tag_suggestions(field: :tags, input: "")).to eq ["one", "two", "three"]
expect(tag_suggestions(field: :tags, input: "t")).to eq ["two", "three"]


314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/avo/test_helpers.rb', line 314

def tag_suggestions(field:, input:)
  # Find the input field for the specified tag field
  input_area = find("[data-field-id='#{field}'] [data-slot='value'] [role='textbox']")

  # If the input argument is present, enter it into the input field
  # Else, set input to "open" than to " " to trigger dropdown
  if input.present?
    input_area.set(input)
  else
    input_area.set("open")
    input_area.set(" ")
  end
  wait_for_tag_suggestions_to_appear

  # Find all elements with class 'tagify_dropdown_item' within the dropdown
  # Map the elements to their 'label' attribute values and return the array of labels
  page.all(".tagify__dropdown__item").map { |element| element[:label] }
end

#tags(field:) ⇒ Object

Example usage:

expect(tags(field: :tags)).to eq ["one", "two", "three"]
expect(tags(field: :tags)).to eq []


305
306
307
308
309
# File 'lib/avo/test_helpers.rb', line 305

def tags(field:)
  # Find all elements with class 'tagify__tag'
  # Map the elements to text and return the array of texts
  page.all(".tagify__tag").map(&:text)
end

#third_tab_groupObject



174
175
176
# File 'lib/avo/test_helpers.rb', line 174

def third_tab_group
  tab_group 3
end

#toggle_collapsable(section) ⇒ Object



267
268
269
# File 'lib/avo/test_helpers.rb', line 267

def toggle_collapsable(section)
  find("[data-action='click->menu#triggerCollapse'][data-menu-key-param*='main_menu.#{section.underscore}'] svg").click
end

#typeObject



333
334
335
336
337
338
339
# File 'lib/avo/test_helpers.rb', line 333

def type(...)
  if page.driver.browser.respond_to?(:keyboard)
    page.driver.browser.keyboard.type(...)
  else
    page.send_keys(...)
  end
end

#write_in_global_search(input) ⇒ Object



113
114
115
# File 'lib/avo/test_helpers.rb', line 113

def write_in_global_search(input)
  page.find("[data-global-search-target='input']").set(input)
end

#write_in_search(input) ⇒ Object

Should use the click_global_search_input or click_resource_search_input method to open the search box first. Example usage:

open_search_box(:users)
within(has_and_belongs_to_many_field_wrapper(id: :users)) {
  click_resource_search_input # opens the search box for the "users" resource
  write_in_search("Bob")
}


107
108
109
110
111
# File 'lib/avo/test_helpers.rb', line 107

def write_in_search(input)
  # Use xpath to find outside of within context if any
  find('[data-resource-search-target="input"]').set(input)
  wait_for_search_loaded
end