discourse/spec/system/page_objects/components/composer.rb
Alan Guo Xiang Tan e323628d8a
DEV: Speed up core system tests (#21394)
What is the problem?

We are relying on RSpec custom matchers in system tests by defining
predicates in page objects. The problem is that this can result in a
system test unnecessarily waiting up till the full duration of
Capybara's default wait time when the RSpec custom matcher is used with
`not_to`. Considering this topic page object where we have a `has_post?`
predicate defined.

```
class Topic < PageObject
  def has_post?
    has_css?('something')
  end
end
```

The assertion `expect(Topic.new).not_to have_post` will end up waiting
the full Capybara's default wait time since the RSpec custom matcher is
calling Capybara's `has_css?` method which will wait until the selector
appear. If the selector has already disappeared by the time the
assertion is called, we end up waiting for something that will never
exists.

This commit fixes such cases by introducing new predicates that uses
the `has_no_*` versions of Capybara's node matchers.

For future reference, `to have_css` and `not_to have_css` is safe to sue
because the RSpec matcher defined by Capbyara is smart enough to call
`has_css?` or `has_no_css?` based on the expectation of the assertion.
2023-05-05 07:45:53 +08:00

117 lines
2.5 KiB
Ruby

# frozen_string_literal: true
module PageObjects
module Components
class Composer < PageObjects::Components::Base
COMPOSER_ID = "#reply-control"
AUTOCOMPLETE_MENU = ".autocomplete.ac-emoji"
def opened?
page.has_css?("#{COMPOSER_ID}.open")
end
def open_composer_actions
find(".composer-action-title .btn").click
self
end
def click_toolbar_button(button_class)
find(".d-editor-button-bar button.#{button_class}").click
self
end
def fill_title(title)
find("#{COMPOSER_ID} #reply-title").fill_in(with: title)
self
end
def fill_content(content)
composer_input.fill_in(with: content)
self
end
def type_content(content)
composer_input.send_keys(content)
self
end
def clear_content
fill_content("")
end
def has_content?(content)
composer_input.value == content
end
def has_popup_content?(content)
composer_popup.has_content?(content)
end
def select_action(action)
find(action(action)).click
self
end
def create
find("#{COMPOSER_ID} .btn-primary").click
end
def action(action_title)
".composer-action-title .select-kit-collection li[title='#{action_title}']"
end
def button_label
find("#{COMPOSER_ID} .btn-primary .d-button-label")
end
def emoji_picker
find("#{COMPOSER_ID} .emoji-picker")
end
def emoji_autocomplete
find(AUTOCOMPLETE_MENU)
end
def has_emoji_autocomplete?
has_css?(AUTOCOMPLETE_MENU)
end
def has_no_emoji_autocomplete?
has_no_css?(AUTOCOMPLETE_MENU)
end
EMOJI_SUGGESTION_SELECTOR = "#{AUTOCOMPLETE_MENU} .emoji-shortname"
def has_emoji_suggestion?(emoji)
has_css?(EMOJI_SUGGESTION_SELECTOR, text: emoji)
end
def has_no_emoji_suggestion?(emoji)
has_no_css?(EMOJI_SUGGESTION_SELECTOR, text: emoji)
end
def has_emoji_preview?(emoji)
page.has_css?(emoji_preview_selector(emoji))
end
def has_no_emoji_preview?(emoji)
page.has_no_css?(emoji_preview_selector(emoji))
end
def composer_input
find("#{COMPOSER_ID} .d-editor .d-editor-input")
end
def composer_popup
find("#{COMPOSER_ID} .composer-popup")
end
private
def emoji_preview_selector(emoji)
".d-editor-preview .emoji[title=':#{emoji}:']"
end
end
end
end