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.
This commit is contained in:
parent
f705e6d367
commit
e323628d8a
|
@ -43,7 +43,7 @@ describe "Bookmarking posts and topics", type: :system, js: true do
|
|||
bookmark_modal.fill_name("something important")
|
||||
bookmark_modal.cancel
|
||||
|
||||
expect(topic_page).not_to have_post_bookmarked(post)
|
||||
expect(topic_page).to have_no_post_bookmarked(post)
|
||||
expect(Bookmark.exists?(bookmarkable: post, user: user)).to eq(false)
|
||||
end
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ describe "Edit Category", type: :system, js: true do
|
|||
it "should allow you to select and save a form template" do
|
||||
category_page.visit_edit_template(category)
|
||||
category_page.toggle_form_templates
|
||||
expect(category_page).not_to have_d_editor
|
||||
expect(category_page).to have_no_d_editor
|
||||
category_page.select_form_template(form_template.name)
|
||||
expect(category_page).to have_selected_template(form_template.name)
|
||||
category_page.save_settings
|
||||
|
@ -57,7 +57,7 @@ describe "Edit Category", type: :system, js: true do
|
|||
it "should have form templates enabled and showing the selected templates" do
|
||||
category_page.visit_edit_template(category)
|
||||
expect(category_page).to have_form_template_enabled
|
||||
expect(category_page).not_to have_d_editor
|
||||
expect(category_page).to have_no_d_editor
|
||||
selected_templates = "#{form_template.name},#{form_template_2.name}"
|
||||
expect(category_page).to have_selected_template(selected_templates)
|
||||
end
|
||||
|
|
|
@ -91,7 +91,7 @@ describe "Custom sidebar sections", type: :system, js: true do
|
|||
expect(sidebar).to have_section("Edited section")
|
||||
expect(sidebar).to have_section_link("Edited Tag")
|
||||
|
||||
expect(sidebar).not_to have_section_link("Sidebar Categories")
|
||||
expect(sidebar).to have_no_section_link("Sidebar Categories")
|
||||
end
|
||||
|
||||
it "allows the user to reorder links in custom section" do
|
||||
|
@ -161,7 +161,7 @@ describe "Custom sidebar sections", type: :system, js: true do
|
|||
section_modal.delete
|
||||
section_modal.confirm_delete
|
||||
|
||||
expect(sidebar).not_to have_section("My section")
|
||||
expect(sidebar).to have_no_section("My section")
|
||||
end
|
||||
|
||||
it "allows admin to create, edit and delete public section" do
|
||||
|
@ -188,7 +188,7 @@ describe "Custom sidebar sections", type: :system, js: true do
|
|||
section_modal.delete
|
||||
section_modal.confirm_delete
|
||||
|
||||
expect(sidebar).not_to have_section("Edited public section")
|
||||
expect(sidebar).to have_no_section("Edited public section")
|
||||
end
|
||||
|
||||
it "shows anonymous public sections" do
|
||||
|
|
|
@ -54,19 +54,19 @@ describe "Emoji deny list", type: :system, js: true do
|
|||
composer.click_toolbar_button("insert-emoji")
|
||||
expect(composer.emoji_picker).to be_visible
|
||||
|
||||
expect(emoji_picker).not_to have_emoji("fu")
|
||||
expect(emoji_picker).to have_no_emoji("fu")
|
||||
end
|
||||
|
||||
it "should not show denied emojis and aliases in emoji autocomplete" do
|
||||
topic_page.visit_topic_and_open_composer(topic)
|
||||
|
||||
composer.type_content(":poop") # shows no results
|
||||
expect(composer).not_to have_emoji_autocomplete
|
||||
expect(composer).to have_no_emoji_autocomplete
|
||||
|
||||
composer.clear_content
|
||||
|
||||
composer.type_content(":middle") # middle_finger is alias
|
||||
expect(composer).not_to have_emoji_suggestion("fu")
|
||||
expect(composer).to have_no_emoji_suggestion("fu")
|
||||
end
|
||||
|
||||
it "should not show denied emoji in preview" do
|
||||
|
@ -78,7 +78,7 @@ describe "Emoji deny list", type: :system, js: true do
|
|||
composer.clear_content
|
||||
|
||||
composer.fill_content(":fu:")
|
||||
expect(composer).not_to have_emoji_preview("fu")
|
||||
expect(composer).to have_no_emoji_preview("fu")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -76,12 +76,26 @@ module PageObjects
|
|||
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?("#{AUTOCOMPLETE_MENU} .emoji-shortname", text: 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?(".d-editor-preview .emoji[title=':#{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
|
||||
|
@ -91,6 +105,12 @@ module PageObjects
|
|||
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
|
||||
|
|
|
@ -18,6 +18,10 @@ module PageObjects
|
|||
def has_emoji?(emoji_name)
|
||||
page.has_css?(emoji_button_selector(emoji_name))
|
||||
end
|
||||
|
||||
def has_no_emoji?(emoji_name)
|
||||
page.has_no_css?(emoji_button_selector(emoji_name))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -38,19 +38,35 @@ module PageObjects
|
|||
end
|
||||
|
||||
def has_section_link?(name, href: nil, active: false)
|
||||
attributes = {}
|
||||
attributes[:href] = href if href
|
||||
attributes[:class] = SIDEBAR_SECTION_LINK_SELECTOR
|
||||
attributes[:class] += "--active" if active
|
||||
has_link?(name, **attributes)
|
||||
section_link_present?(name, href: href, active: active, present: true)
|
||||
end
|
||||
|
||||
def has_no_section_link?(name, href: nil, active: false)
|
||||
section_link_present?(name, href: href, active: active, present: false)
|
||||
end
|
||||
|
||||
def custom_section_modal_title
|
||||
find("#discourse-modal-title")
|
||||
end
|
||||
|
||||
SIDEBAR_WRAPPER_SELECTOR = ".sidebar-wrapper"
|
||||
|
||||
def has_section?(name)
|
||||
find(".sidebar-wrapper").has_button?(name)
|
||||
find(SIDEBAR_WRAPPER_SELECTOR).has_button?(name)
|
||||
end
|
||||
|
||||
def has_no_section?(name)
|
||||
find(SIDEBAR_WRAPPER_SELECTOR).has_no_button?(name)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def section_link_present?(name, href: nil, active: false, present:)
|
||||
attributes = {}
|
||||
attributes[:href] = href if href
|
||||
attributes[:class] = SIDEBAR_SECTION_LINK_SELECTOR
|
||||
attributes[:class] += "--active" if active
|
||||
page.public_send(present ? :has_link? : :has_no_link?, name, **attributes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,8 +40,14 @@ module PageObjects
|
|||
find(".d-toggle-switch .toggle-template-type", visible: false)["aria-checked"] == "true"
|
||||
end
|
||||
|
||||
D_EDITOR_SELECTOR = ".d-editor"
|
||||
|
||||
def has_d_editor?
|
||||
page.has_selector?(".d-editor")
|
||||
page.has_selector?(D_EDITOR_SELECTOR)
|
||||
end
|
||||
|
||||
def has_no_d_editor?
|
||||
page.has_no_selector?(D_EDITOR_SELECTOR)
|
||||
end
|
||||
|
||||
def has_selected_template?(template_name)
|
||||
|
|
|
@ -29,16 +29,28 @@ module PageObjects
|
|||
find(".d-header #search-button").click
|
||||
end
|
||||
|
||||
SEARCH_RESULT_SELECTOR = ".search-results .fps-result"
|
||||
|
||||
def has_search_result?
|
||||
page.has_selector?(".search-results .fps-result")
|
||||
page.has_selector?(SEARCH_RESULT_SELECTOR)
|
||||
end
|
||||
|
||||
def has_no_search_result?
|
||||
page.has_no_selector?(SEARCH_RESULT_SELECTOR)
|
||||
end
|
||||
|
||||
def has_warning_message?
|
||||
page.has_selector?(".search-results .warning")
|
||||
end
|
||||
|
||||
def is_search_page
|
||||
has_css?("body.search-page")
|
||||
SEARCH_PAGE_SELECTOR = "body.search-page"
|
||||
|
||||
def active?
|
||||
has_css?(SEARCH_PAGE_SELECTOR)
|
||||
end
|
||||
|
||||
def not_active?
|
||||
has_no_css?(SEARCH_PAGE_SELECTOR)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,9 +58,11 @@ module PageObjects
|
|||
end
|
||||
|
||||
def has_post_bookmarked?(post)
|
||||
within post_by_number(post) do
|
||||
has_css?(".bookmark.with-reminder.bookmarked")
|
||||
end
|
||||
is_post_bookmarked(post, bookmarked: true)
|
||||
end
|
||||
|
||||
def has_no_post_bookmarked?(post)
|
||||
is_post_bookmarked(post, bookmarked: false)
|
||||
end
|
||||
|
||||
def expand_post_actions(post)
|
||||
|
@ -142,6 +144,15 @@ module PageObjects
|
|||
def topic_footer_button_id(button)
|
||||
"#topic-footer-button-#{button}"
|
||||
end
|
||||
|
||||
def is_post_bookmarked(post, bookmarked:)
|
||||
within post_by_number(post) do
|
||||
page.public_send(
|
||||
bookmarked ? :has_css? : :has_no_css?,
|
||||
".bookmark.with-reminder.bookmarked",
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,7 +23,7 @@ describe "Search", type: :system, js: true do
|
|||
expect(search_page.heading_text).not_to eq("Search")
|
||||
|
||||
search_page.click_home_logo
|
||||
expect(search_page.is_search_page).to be_falsey
|
||||
expect(search_page).to be_not_active
|
||||
|
||||
page.go_back
|
||||
# ensure results are still there when using browser's history
|
||||
|
@ -32,7 +32,7 @@ describe "Search", type: :system, js: true do
|
|||
search_page.click_home_logo
|
||||
search_page.click_search_icon
|
||||
|
||||
expect(search_page).not_to have_search_result
|
||||
expect(search_page).to have_no_search_result
|
||||
expect(search_page.heading_text).to eq("Search")
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue