diff --git a/Gemfile b/Gemfile index ff7471e77..bf6444978 100644 --- a/Gemfile +++ b/Gemfile @@ -46,6 +46,7 @@ gem 'request_store' gem 'builder' # gem 'did_you_mean' # github.com/yuki24/did_you_mean/issues/117 gem 'term-ansicolor', require: "term/ansicolor" +gem 'puma' # needed for looser jpeg header compat gem 'ruby-imagespec', :require => "image_spec", :git => "https://github.com/r888888888/ruby-imagespec.git", :branch => "exif-fixes" @@ -88,4 +89,6 @@ group :test do gem "webmock" gem "minitest-ci" gem "mock_redis" + gem "capybara" + gem "selenium-webdriver" end diff --git a/Gemfile.lock b/Gemfile.lock index 588c7f180..7e552d1cc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -121,6 +121,16 @@ GEM sshkit (~> 1.3) capistrano3-unicorn (0.2.1) capistrano (~> 3.1, >= 3.1.0) + capybara (3.29.0) + addressable + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (~> 1.5) + xpath (~> 3.2) + childprocess (2.0.0) + rake (< 13.0) chronic (0.10.2) cityhash (0.9.0) coderay (1.1.2) @@ -289,6 +299,8 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.1) + puma (4.1.1) + nio4r (~> 2.0) rack (2.0.7) rack-contrib (2.1.0) rack (~> 2.0) @@ -335,6 +347,7 @@ GEM recaptcha (5.1.0) json redis (4.1.2) + regexp_parser (1.6.0) representable (2.3.0) uber (~> 0.0.7) request_store (1.4.1) @@ -352,6 +365,9 @@ GEM crass (~> 1.0.2) nokogiri (>= 1.8.0) nokogumbo (~> 2.0) + selenium-webdriver (3.142.4) + childprocess (>= 0.5, < 3.0) + rubyzip (~> 1.2, >= 1.2.2) shoulda-context (1.2.2) shoulda-matchers (4.1.2) activesupport (>= 4.2.0) @@ -435,6 +451,8 @@ GEM websocket-extensions (0.1.4) whenever (1.0.0) chronic (>= 0.6.3) + xpath (3.2.0) + nokogiri (~> 1.8) zeitwerk (2.1.10) PLATFORMS @@ -455,6 +473,7 @@ DEPENDENCIES capistrano-rails capistrano-rbenv capistrano3-unicorn + capybara cityhash daemons delayed_job @@ -483,6 +502,7 @@ DEPENDENCIES pry-byebug pry-inline pry-rails + puma rack-mini-profiler rails (~> 6.0) rake @@ -496,6 +516,7 @@ DEPENDENCIES ruby-vips rubyzip sanitize + selenium-webdriver shoulda-context shoulda-matchers simple_form diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb new file mode 100644 index 000000000..6faf93767 --- /dev/null +++ b/test/application_system_test_case.rb @@ -0,0 +1,6 @@ +require "test_helper" + +class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + include SystemTestHelper + driven_by :selenium, using: :firefox, screen_size: [1400, 1400] +end diff --git a/test/system/autocomplete_test.rb b/test/system/autocomplete_test.rb new file mode 100644 index 000000000..4326a1176 --- /dev/null +++ b/test/system/autocomplete_test.rb @@ -0,0 +1,127 @@ +require "application_system_test_case" + +class AutocompleteTest < ApplicationSystemTestCase + def autocomplete(id, *keys) + fill_in id: id, with: "" + find_by_id(id).send_keys(keys) + end + + def assert_autocomplete_equals(expected_results, text, id:) + autocomplete(id, text) + + assert_selector 'ul.ui-autocomplete li', count: expected_results.size + expected_results.each do |result| + assert_selector "li[data-autocomplete-value='#{result}']", count: 1 + end + end + + def assert_search_autocomplete_equals(values, text) + visit posts_path unless current_path == posts_path + assert_autocomplete_equals(values, text, id: "tags") + end + + def assert_metatag_autocomplete_equals(values, metatag) + results = values.map { |value| "#{metatag.downcase}:#{value}" } + assert_search_autocomplete_equals(results, "#{metatag}:") + end + + def assert_mention_autocomplete_equals(values, text) + visit new_forum_post_path unless current_path == new_forum_post_path + assert_autocomplete_equals(values, text, id: "forum_post_body") + end + + context "Autocomplete" do + context "for post searches" do + should "work for static metatags" do + assert_metatag_autocomplete_equals(%w[any none], "child") + assert_metatag_autocomplete_equals(%w[any none], "parent") + assert_metatag_autocomplete_equals(%w[rating note status], "locked") + assert_metatag_autocomplete_equals(%w[safe questionable explicit], "rating") + assert_metatag_autocomplete_equals(%w[gif jpg mp4 png swf webm zip], "filetype") + assert_metatag_autocomplete_equals(%w[any none disinterest poor_quality breaks_rules], "disapproval") + assert_metatag_autocomplete_equals(%w[active any banned deleted flagged modqueue pending unmoderated], "status") + end + + should "work for username metatags" do + %w[user approver commenter comm noter noteupdater artcomm fav ordfav appealer flagger upvote downvote].each do |metatag| + assert_search_autocomplete_equals(["#{metatag}:DanbooruBot"], "#{metatag}:Danbo") + assert_search_autocomplete_equals(["#{metatag}:DanbooruBot"], "-#{metatag}:Danbo") + end + end + + should "work for pool metatags" do + @user = create(:user) + as(@user) { create(:pool, name: "Cute") } + as(@user) { create(:post, tag_string: "pool:Cute") } + + assert_search_autocomplete_equals(["pool:Cute"], "pool:c") + assert_search_autocomplete_equals(["pool:Cute"], "pool:cute") + assert_search_autocomplete_equals(["pool:Cute"], "pool:CUTE") + assert_search_autocomplete_equals(["pool:Cute"], "POOL:cute") + assert_search_autocomplete_equals(["pool:Cute"], "pool:*ute") + assert_search_autocomplete_equals(["pool:Cute"], "-pool:cute") + assert_search_autocomplete_equals(["pool:Cute"], "~pool:cute") + + assert_search_autocomplete_equals(["ordpool:Cute"], "ordpool:cute") + assert_search_autocomplete_equals(["ordpool:Cute"], "ORDPOOL:cute") + end + + should "work for regular tags" do + create(:tag, name: "bkub", post_count: 42) + + assert_search_autocomplete_equals(["bkub"], "b") + assert_search_autocomplete_equals(["bkub"], "bkub") + assert_search_autocomplete_equals(["bkub"], "BKUB") + assert_search_autocomplete_equals(["bkub"], " bkub") + assert_search_autocomplete_equals(["bkub"], "one two bkub") + + assert_search_autocomplete_equals(["bkub"], "-bkub") + assert_search_autocomplete_equals(["bkub"], "~bkub") + assert_search_autocomplete_equals(["bkub"], "-BKUB") + assert_search_autocomplete_equals(["bkub"], "~BKUB") + + assert_search_autocomplete_equals(["bkub"], "art:bkub") + assert_search_autocomplete_equals(["bkub"], "copy:bkub") + assert_search_autocomplete_equals(["bkub"], "char:bkub") + assert_search_autocomplete_equals(["bkub"], "gen:bkub") + assert_search_autocomplete_equals(["bkub"], "meta:bkub") + assert_search_autocomplete_equals(["bkub"], "-char:bkub") + assert_search_autocomplete_equals(["bkub"], "~char:bkub") + + assert_search_autocomplete_equals(["bkub"], "b*") + assert_search_autocomplete_equals(["bkub"], "B*") + assert_search_autocomplete_equals(["bkub"], "*b") + assert_search_autocomplete_equals(["bkub"], "*bkub*") + + assert_search_autocomplete_equals([], " ") + assert_search_autocomplete_equals([], "one") + assert_search_autocomplete_equals([], "one two") + end + + should "insert completions on click" do + visit posts_path + + autocomplete("tags", "rating:s") + first("ul.ui-autocomplete li").click + assert_equal("rating:safe ", find_field(id: "tags").value) + + autocomplete("tags", "one two rating:s") + first("ul.ui-autocomplete li").click + assert_equal("one two rating:safe ", find_field(id: "tags").value) + end + end + + context "for username mentions" do + should "work" do + signup "member" + + assert_mention_autocomplete_equals(["@member"], "@m") + assert_mention_autocomplete_equals(["@member"], "@member") + assert_mention_autocomplete_equals(["@member"], "@MEMBER") + assert_mention_autocomplete_equals(["@member"], "one two @member") + + # assert_mention_autocomplete_equals(["@member"], "<@member") + end + end + end +end diff --git a/test/test_helpers/system_test_helper.rb b/test/test_helpers/system_test_helper.rb new file mode 100644 index 000000000..eeefffec6 --- /dev/null +++ b/test/test_helpers/system_test_helper.rb @@ -0,0 +1,9 @@ +module SystemTestHelper + def signup(name, password: "password") + visit new_user_path + fill_in "Name", with: name + fill_in "Password", with: password + fill_in "Password confirmation", with: password + click_button "Sign up" + end +end