From 3cea95fa69e108b51e0f97ed04ed7188a2b56e72 Mon Sep 17 00:00:00 2001 From: Robert Fletcher Date: Tue, 3 Mar 2026 17:52:39 -0800 Subject: [PATCH] yet more system tests --- spec/system/account_setup_spec.rb | 12 +++++-- spec/system/application_settings_spec.rb | 8 +++++ spec/system/feed_show_spec.rb | 28 +++++++++++++++ spec/system/feeds_index_spec.rb | 28 +++++++++++++++ spec/system/good_job_spec.rb | 8 +++++ spec/system/import_spec.rb | 9 +++++ spec/system/keyboard_shortcuts_spec.rb | 44 ++++++++++++++++++++++++ spec/system/login_spec.rb | 15 ++++++++ spec/system/profile_spec.rb | 27 +++++++++++++-- spec/system/starred_spec.rb | 20 +++++++++++ spec/system/stories_index_spec.rb | 22 ++++++++++++ 11 files changed, 217 insertions(+), 4 deletions(-) diff --git a/spec/system/account_setup_spec.rb b/spec/system/account_setup_spec.rb index 798874dc5..b3da84c87 100644 --- a/spec/system/account_setup_spec.rb +++ b/spec/system/account_setup_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true RSpec.describe "account setup" do - def fill_in_fields(username:) + def fill_in_fields(username:, confirm: "my-password") fill_in("Username", with: username) fill_in("Password", with: "my-password") - fill_in("Confirm", with: "my-password") + fill_in("Confirm", with: confirm) click_on("Next") end @@ -16,6 +16,14 @@ def fill_in_fields(username:) expect(page).to have_text("Logged in as my-username") end + it "shows an error when passwords do not match" do + visit "/" + + fill_in_fields(username: "my-username", confirm: "wrong-password") + + expect(page).to have_content("doesn't match") + end + it "allows a second user to sign up" do Setting::UserSignup.create!(enabled: true) create(:user) diff --git a/spec/system/application_settings_spec.rb b/spec/system/application_settings_spec.rb index c8ef8d096..23021d9eb 100644 --- a/spec/system/application_settings_spec.rb +++ b/spec/system/application_settings_spec.rb @@ -20,6 +20,14 @@ expect(page).to have_content("User signups are disabled") end + it "blocks non-admin users from settings" do + login_as(default_user) + + visit(settings_path) + + expect(page).to have_content("No route matches") + end + it "prevents signup when signups are disabled" do create(:user, admin: true) diff --git a/spec/system/feed_show_spec.rb b/spec/system/feed_show_spec.rb index 97bf31768..d78fdc97b 100644 --- a/spec/system/feed_show_spec.rb +++ b/spec/system/feed_show_spec.rb @@ -43,6 +43,34 @@ def create_and_visit_feed(story_title: nil) expect(page).to have_content("New Story") end + it "marks all stories as read with A hotkey" do + login_as(default_user) + create_and_visit_feed(story_title: "My Story") + + send_keys("A") + + expect(page).to have_content("You've reached RSS Zero") + end + + it "refreshes the feed with r hotkey" do + login_as(default_user) + feed = create_and_visit_feed + create(:story, feed:, title: "New Story") + + send_keys("r") + + expect(page).to have_content("New Story") + end + + it "navigates to add feed with a hotkey" do + login_as(default_user) + create_and_visit_feed + + send_keys("a") + + expect(page).to have_current_path(feeds_new_path) + end + it "only marks stories from the current feed as read" do login_as(default_user) other_feed = create(:feed) diff --git a/spec/system/feeds_index_spec.rb b/spec/system/feeds_index_spec.rb index 908ebe505..ace5f788c 100644 --- a/spec/system/feeds_index_spec.rb +++ b/spec/system/feeds_index_spec.rb @@ -50,6 +50,34 @@ expect(page).to have_field("Feed Name", with: feed.name) end + it "displays the unread count for a feed" do + login_as(default_user) + feed = create(:feed) + create_pair(:story, feed:) + + visit "/feeds" + + expect(page).to have_css(".feed-unread", text: "(2)") + end + + it "displays last fetched as Never for new feeds" do + login_as(default_user) + create(:feed) + + visit "/feeds" + + expect(page).to have_content("Never") + end + + it "displays the last fetched timestamp" do + login_as(default_user) + create(:feed, last_fetched: Time.zone.local(2024, 6, 15, 10, 30)) + + visit "/feeds" + + expect(page).to have_content("Jun 15, 10:30") + end + it "links to the feed" do login_as(default_user) feed = create(:feed) diff --git a/spec/system/good_job_spec.rb b/spec/system/good_job_spec.rb index e39fe10b5..940427c73 100644 --- a/spec/system/good_job_spec.rb +++ b/spec/system/good_job_spec.rb @@ -16,4 +16,12 @@ expect(page).to have_link("Scheduled").and have_link("Queued") end + + it "blocks non-admin users from the dashboard" do + login_as(default_user) + + visit(good_job_path) + + expect(page).to have_content("No route matches") + end end diff --git a/spec/system/import_spec.rb b/spec/system/import_spec.rb index ccd85e2a0..3d7f01d59 100644 --- a/spec/system/import_spec.rb +++ b/spec/system/import_spec.rb @@ -1,6 +1,15 @@ # frozen_string_literal: true RSpec.describe "importing feeds" do + it "allows skipping the import" do + login_as(default_user) + visit(feeds_import_path) + + click_on("Not now") + + expect(page).to have_content("We're getting you some stories to read") + end + it "allows importing feeds" do login_as(default_user) visit(feeds_import_path) diff --git a/spec/system/keyboard_shortcuts_spec.rb b/spec/system/keyboard_shortcuts_spec.rb index fe606589f..59430ab1d 100644 --- a/spec/system/keyboard_shortcuts_spec.rb +++ b/spec/system/keyboard_shortcuts_spec.rb @@ -56,6 +56,16 @@ def create_stories_and_visit expect(page).to have_no_css("li.story.open") end + it "toggles a story open and closed with enter" do + login_as(default_user) + create_stories_and_visit + send_keys(:enter) + + send_keys(:enter) + + expect(page).to have_no_css("li.story.open") + end + def create_story_and_visit(title:) create(:story, title:) visit(news_path) @@ -71,6 +81,31 @@ def create_story_and_visit(title:) expect(page).to have_content("My Story") end + def open_story_and_send(key) + send_keys("j") + find("li.story.cursor .story-keep-unread") + send_keys(key) + end + + it "toggles keep unread with m" do + login_as(default_user) + create_story_and_visit(title: "My Story") + open_story_and_send("m") + visit(news_path) + + expect(page).to have_content("My Story") + end + + it "refreshes the page with r" do + login_as(default_user) + visit(news_path) + create(:story, title: "My Story") + + send_keys("r") + + expect(page).to have_content("My Story") + end + it "marks all as read with A" do login_as(default_user) create_story_and_visit(title: "My Story") @@ -97,4 +132,13 @@ def create_story_and_visit(title:) expect(page).to have_current_path(feeds_new_path) end + + it "opens the shortcuts modal with ?" do + login_as(default_user) + create_story_and_visit(title: "My Story") + + send_keys("?") + + expect(page).to have_css("#shortcuts.in", visible: :visible) + end end diff --git a/spec/system/login_spec.rb b/spec/system/login_spec.rb index 01b3b38a5..7fafce1a0 100644 --- a/spec/system/login_spec.rb +++ b/spec/system/login_spec.rb @@ -24,6 +24,21 @@ def submit_login(username:, password:) expect(page).to have_content("That's the wrong password") end + def login_from_current_page(user) + fill_in("Username", with: user.username) + fill_in("Password", with: user.password) + click_on("Login") + end + + it "redirects to the original page after login" do + user = create(:user) + visit(starred_path) + + login_from_current_page(user) + + expect(page).to have_current_path(starred_path) + end + it "allows a user to log out" do login_as(default_user) diff --git a/spec/system/profile_spec.rb b/spec/system/profile_spec.rb index 8f1ee59fe..c3fcc85d4 100644 --- a/spec/system/profile_spec.rb +++ b/spec/system/profile_spec.rb @@ -13,9 +13,9 @@ expect(page).to have_text("Logged in as new_username") end - def fill_in_username_fields(existing_password) + def fill_in_username_fields(existing_password, username: "new_username") within_fieldset("Change Username") do - fill_in("Username", with: "new_username") + fill_in("Username", with: username) fill_in("Existing password", with: existing_password) end end @@ -49,6 +49,29 @@ def fill_in_password_fields(existing_password, new_password) expect(page).to have_text("Unable to update profile") end + def fill_in_mismatched_password_fields(existing_password) + within_fieldset("Change Password") do + fill_in("Existing password", with: existing_password) + fill_in("New password", with: "new_password") + fill_in("Password confirmation", with: "different_password") + end + end + + it "rejects password change with mismatched confirmation" do + fill_in_mismatched_password_fields(default_user.password) + click_on("Update password") + + expect(page).to have_text("Unable to update password") + end + + it "rejects username change when already taken" do + create(:user, username: "taken_name") + fill_in_username_fields(default_user.password, username: "taken_name") + click_on("Update username") + + expect(page).to have_text("Unable to update profile") + end + it "rejects password change with wrong existing password" do fill_in_password_fields("wrong_password", "new_password") click_on("Update password") diff --git a/spec/system/starred_spec.rb b/spec/system/starred_spec.rb index 3c2b1d8c7..abfafa236 100644 --- a/spec/system/starred_spec.rb +++ b/spec/system/starred_spec.rb @@ -78,4 +78,24 @@ def create_starred_stories(count) expect(page).to have_link("Next") end + + it "navigates to the next page" do + login_as(default_user) + create_starred_stories(21) + visit(starred_path) + + click_on("Next") + + expect(page).to have_content("2 of 2") + end + + it "navigates to the next page with arrow keys" do + login_as(default_user) + create_starred_stories(21) + visit(starred_path) + + send_keys(:arrow_right) + + expect(page).to have_content("2 of 2") + end end diff --git a/spec/system/stories_index_spec.rb b/spec/system/stories_index_spec.rb index 9611768be..7c0ff039d 100644 --- a/spec/system/stories_index_spec.rb +++ b/spec/system/stories_index_spec.rb @@ -114,6 +114,19 @@ def open_story_and_find_unread_icon(story_title) expect(icon[:class]).to include("fa-square-o") end + it "persists keep unread state across page reload" do + create(:story, title: "My Story") + login_as(default_user) + visit(news_path) + + find(".story-preview", text: "My Story").click + find(".story-actions .story-keep-unread").click + visit(news_path) + + icon = open_story_and_find_unread_icon("My Story") + expect(icon[:class]).to include("fa-check") + end + it "displays a download link for stories with enclosures" do create( :story, @@ -138,6 +151,15 @@ def open_story_and_find_unread_icon(story_title) expect(page).to have_no_css("a.story-enclosure") end + it "marks a story as read when opened" do + create(:story, title: "My Story") + login_as(default_user) + visit news_path + + find(".story-preview", text: "My Story").click + expect(page).to have_css(".story.read") + end + it "allows viewing a story with hot keys" do create(:story, title: "My Story", body: "My Body") login_as(default_user)