From 9392bd0f797c3fff845c37dda0d06f015a3f0232 Mon Sep 17 00:00:00 2001
From: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Date: Sun, 28 May 2023 15:35:55 +0200
Subject: [PATCH] DEV: fix tag synonyms flakey specs (#21787)

The fix use the SelectKit component in the spec and improves reliability of SelectKit component to ensure expanded/collapsed state effectively set/present.

Multiple lines have also been removed as they are not necessary, eg:

- check button is present
- click button

The check is un-necesssary as we won't find the button on click if not present. This kind of checks are only necessary when another element has to be present before the button is show, eg:

- check modal is displayed
- click button

FInally this commit changes the way the SelectKit component initializes component and now uses a css selector instead of a finder, it ensures we are always getting fresh object and allows to build complete selectors: ".context[data-id=1].foo:enabled"
---
 .../composer/default_to_subcategory_spec.rb   | 10 ++--
 .../page_objects/components/select_kit.rb     | 51 ++++++++++++++-----
 spec/system/page_objects/pages/discovery.rb   |  9 ++--
 spec/system/page_objects/pages/tag.rb         | 22 ++++----
 spec/system/tag_notification_level_spec.rb    |  4 +-
 spec/system/tag_synonyms_spec.rb              | 20 ++------
 6 files changed, 60 insertions(+), 56 deletions(-)

diff --git a/spec/system/composer/default_to_subcategory_spec.rb b/spec/system/composer/default_to_subcategory_spec.rb
index add412d8e83..38a1693f5da 100644
--- a/spec/system/composer/default_to_subcategory_spec.rb
+++ b/spec/system/composer/default_to_subcategory_spec.rb
@@ -19,7 +19,7 @@ describe "Default to Subcategory when parent Category doesn't allow posting",
   describe "anon user" do
     it "can visit the category" do
       category_page.visit(category_with_no_subcategory)
-      select_kit = PageObjects::Components::SelectKit.new(page.find(".navigation-container"))
+      select_kit = PageObjects::Components::SelectKit.new(".navigation-container")
       expect(select_kit).to have_selected_value(category_with_no_subcategory.id)
     end
   end
@@ -37,9 +37,7 @@ describe "Default to Subcategory when parent Category doesn't allow posting",
           expect(category_page).to have_button("New Topic", disabled: false)
           category_page.new_topic_button.click
           select_kit =
-            PageObjects::Components::SelectKit.new(
-              page.find("#reply-control.open .category-chooser"),
-            )
+            PageObjects::Components::SelectKit.new("#reply-control.open .category-chooser")
           expect(select_kit).to have_selected_value(subcategory.id)
         end
       end
@@ -49,9 +47,7 @@ describe "Default to Subcategory when parent Category doesn't allow posting",
           expect(category_page).to have_button("New Topic", disabled: false)
           category_page.new_topic_button.click
           select_kit =
-            PageObjects::Components::SelectKit.new(
-              page.find("#reply-control.open .category-chooser"),
-            )
+            PageObjects::Components::SelectKit.new("#reply-control.open .category-chooser")
           expect(select_kit).to have_selected_value(default_latest_category.id)
         end
       end
diff --git a/spec/system/page_objects/components/select_kit.rb b/spec/system/page_objects/components/select_kit.rb
index 05786ac44c4..6419552c1fa 100644
--- a/spec/system/page_objects/components/select_kit.rb
+++ b/spec/system/page_objects/components/select_kit.rb
@@ -3,44 +3,69 @@
 module PageObjects
   module Components
     class SelectKit < PageObjects::Components::Base
-      attr_reader :element
+      attr_reader :context
 
-      def initialize(element)
-        @element = element
+      def initialize(context)
+        @context = context
+      end
+
+      def component
+        find(@context)
+      end
+
+      def expanded_component
+        expand_if_needed
+        find(@context + ".is-expanded")
+      end
+
+      def collapsed_component
+        find(@context + ":not(.is-expanded)")
       end
 
       def is_expanded?
-        element.has_css?(".is-expanded")
+        has_css?(context + ".is-expanded")
       end
 
       def is_collapsed?
-        element.has_css?(":not(.is-expanded)")
+        has_css?(context + ":not(.is-expanded)")
       end
 
       def has_selected_value?(value)
-        element.find(".select-kit-header[data-value='#{value}']")
+        component.find(".select-kit-header[data-value='#{value}']")
       end
 
       def has_selected_name?(value)
-        element.find(".select-kit-header[data-name='#{value}']")
+        component.find(".select-kit-header[data-name='#{value}']")
       end
 
       def expand
-        element.find(":not(.is-expanded) .select-kit-header").click
+        collapsed_component.find(":not(.is-expanded) .select-kit-header").click
+        expanded_component
       end
 
       def collapse
-        element.find(".is-expanded .select-kit-header").click
+        expanded_component.find(".is-expanded .select-kit-header").click
+        collapsed_component
+      end
+
+      def search(value = nil)
+        expanded_component.find(".select-kit-filter .filter-input").fill_in(with: value)
       end
 
       def select_row_by_value(value)
-        expand
-        element.find(".select-kit-row[data-value='#{value}']").click
+        expanded_component.find(".select-kit-row[data-value='#{value}']").click
       end
 
       def select_row_by_name(name)
-        expand
-        element.find(".select-kit-row[data-name='#{name}']").click
+        expanded_component.find(".select-kit-row[data-name='#{name}']").click
+      end
+
+      def select_row_by_index(index)
+        expanded_component.find(".select-kit-row[data-index='#{index}']").click
+      end
+
+      def expand_if_needed
+        expand if is_collapsed?
       end
     end
   end
diff --git a/spec/system/page_objects/pages/discovery.rb b/spec/system/page_objects/pages/discovery.rb
index 6ad5e911289..e0715e52947 100644
--- a/spec/system/page_objects/pages/discovery.rb
+++ b/spec/system/page_objects/pages/discovery.rb
@@ -8,18 +8,15 @@ module PageObjects
       end
 
       def category_drop
-        element = page.find(".category-breadcrumb li:first-of-type .category-drop")
-        Components::SelectKit.new(element)
+        Components::SelectKit.new(".category-breadcrumb li:first-of-type .category-drop")
       end
 
       def subcategory_drop
-        element = page.find(".category-breadcrumb li:nth-of-type(2) .category-drop")
-        Components::SelectKit.new(element)
+        Components::SelectKit.new(".category-breadcrumb li:nth-of-type(2) .category-drop")
       end
 
       def tag_drop
-        element = page.find(".category-breadcrumb .tag-drop")
-        Components::SelectKit.new(element)
+        Components::SelectKit.new(".category-breadcrumb .tag-drop")
       end
     end
   end
diff --git a/spec/system/page_objects/pages/tag.rb b/spec/system/page_objects/pages/tag.rb
index c8fa0208972..101a8d42e2a 100644
--- a/spec/system/page_objects/pages/tag.rb
+++ b/spec/system/page_objects/pages/tag.rb
@@ -24,20 +24,22 @@ module PageObjects
         find(".dialog-footer .btn-primary")
       end
 
-      def add_synonyms_select_field
-        find("#add-synonyms")
+      def add_synonyms_dropdown
+        PageObjects::Components::SelectKit.new("#add-synonyms")
       end
 
-      def search_tags(search)
-        find("#add-synonyms-filter input").fill_in(with: search)
+      def search_tags(query)
+        add_synonyms_dropdown.search(query)
       end
 
-      def has_search_result?(tag)
-        page.has_selector?(".select-kit-row[data-name='#{tag}']")
-      end
-
-      def search_result(index)
-        find(".select-kit-collection li:nth-child(#{index})")
+      def select_tag(value: nil, index: nil, name: nil)
+        if value
+          add_synonyms_dropdown.select_row_by_value(value)
+        elsif name
+          add_synonyms_dropdown.select_row_by_name(name)
+        elsif index
+          add_synonyms_dropdown.select_row_by_index(index)
+        end
       end
 
       def tag_box(tag)
diff --git a/spec/system/tag_notification_level_spec.rb b/spec/system/tag_notification_level_spec.rb
index 7ec02905ff0..16577d62989 100644
--- a/spec/system/tag_notification_level_spec.rb
+++ b/spec/system/tag_notification_level_spec.rb
@@ -2,9 +2,7 @@
 
 describe "Tag notification level", type: :system, js: true do
   let(:tags_page) { PageObjects::Pages::Tag.new }
-  let(:select_kit) do
-    PageObjects::Components::SelectKit.new(page.find(".tag-notifications-button"))
-  end
+  let(:select_kit) { PageObjects::Components::SelectKit.new(".tag-notifications-button") }
 
   fab!(:tag_1) { Fabricate(:tag) }
   fab!(:current_user) { Fabricate(:admin) }
diff --git a/spec/system/tag_synonyms_spec.rb b/spec/system/tag_synonyms_spec.rb
index 483c318b11d..7eea218327a 100644
--- a/spec/system/tag_synonyms_spec.rb
+++ b/spec/system/tag_synonyms_spec.rb
@@ -11,23 +11,13 @@ describe "Tag synonyms", type: :system, js: true do
   describe "when visiting edit tag page" do
     it "allows an admin to add existing tag as a synonym" do
       tags_page.visit_tag(tag_1)
-
-      expect(tags_page.tag_info_btn).to be_visible
       tags_page.tag_info_btn.click
-
-      expect(tags_page.edit_synonyms_btn).to be_visible
       tags_page.edit_synonyms_btn.click
-
-      expect(tags_page.add_synonyms_select_field).to be_visible
-      tags_page.add_synonyms_select_field.click
-
-      expect(tags_page.has_search_result?(tag_2.name)).to be_truthy
-      tags_page.search_result(1).click
-
-      expect(tags_page.add_synonym_btn).to be_visible
+      tags_page.select_tag(index: 0)
       tags_page.add_synonym_btn.click
 
       expect(tags_page.confirm_synonym_btn).to be_visible
+
       tags_page.confirm_synonym_btn.click
 
       expect(tags_page.tag_box(tag_2.name)).to be_visible
@@ -37,13 +27,9 @@ describe "Tag synonyms", type: :system, js: true do
       tags_page.visit_tag(tag_1)
       tags_page.tag_info_btn.click
       tags_page.edit_synonyms_btn.click
-      tags_page.add_synonyms_select_field.click
-
       # searched tag doesnt exist but will show option to create tag
       tags_page.search_tags("graphics")
-      expect(tags_page.has_search_result?("graphics")).to be_truthy
-
-      tags_page.search_result(1).click
+      tags_page.select_tag(value: "graphics")
       tags_page.add_synonym_btn.click
       tags_page.confirm_synonym_btn.click