Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions spec/requests/faqs_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
expect(response.body).to include("Unpublished FAQ")
end

it "shows the New FAQ admin control" do
get faqs_path
expect(response.body).to include("New FAQ")
end
Comment on lines +73 to +76

it "filters by unpublished param" do
get faqs_path, params: { published: "false" } # needs to be string param
expect(response.body).to include("Unpublished FAQ")
Expand Down Expand Up @@ -109,6 +114,12 @@
expect(response.body).to include("Published FAQ")
expect(response.body).not_to include("Unpublished FAQ")
end

it "hides admin controls" do
get faqs_path
expect(response.body).not_to include("New FAQ")
expect(response.body).not_to include(edit_faq_path(published_faq))
end
Comment on lines +118 to +122
end

context "as a guest" do
Expand All @@ -124,6 +135,12 @@
expect(response.body).not_to include("Published FAQ")
expect(response.body).not_to include("Unpublished FAQ")
end

it "hides admin controls" do
get faqs_path
expect(response.body).not_to include("New FAQ")
expect(response.body).not_to include(edit_faq_path(public_faq))
end
Comment on lines +139 to +143
end
end

Expand Down
14 changes: 14 additions & 0 deletions spec/requests/home_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@
end
end

describe "GET / (signed in)" do
it "shows the Upcoming Events and Community News sections" do
user = create(:user)
create(:person, user: user)
sign_in user

get root_path

expect(response).to have_http_status(:ok)
expect(response.body).to include("Upcoming Events")
expect(response.body).to include("Community News")
end
end

describe "GET /home/* (turbo frame lazy loading)" do
%w[workshops resources events community_news stories video_recordings].each do |section|
it "#{section} returns 200 for visitors" do
Expand Down
45 changes: 45 additions & 0 deletions spec/requests/login_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require "rails_helper"

RSpec.describe "User login", type: :request do
let(:password) { "MyString" }
let(:generic_error) { "Invalid email or password. Please email us or fill out our Contact Us form for assistance." }

def log_in(email, password)
post user_session_path, params: { user: { email: email, password: password } }
end

context "when user is inactive" do
let(:user) { create(:user, password: password, inactive: true) }

it "does not allow login and shows the generic error" do
log_in(user.email, password)

expect(response).to redirect_to(new_user_session_path)
follow_redirect!
expect(response.body).to include(generic_error)
end
end

context "when credentials are wrong" do
let(:user) { create(:user, password: password) }

it "shows the generic error" do
log_in(user.email, "wrong_password")

expect(response).to have_http_status(:unprocessable_content)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Devise re-renders the form with 422 on bad credentials (it does not redirect), unlike the inactive-user path above which redirects. Mirrors actual app behavior.

expect(response.body).to include(generic_error)
end
end

context "when user is active and unlocked" do
let(:user) { create(:user, password: password) }

it "logs in successfully" do
log_in(user.email, password)

expect(response).to redirect_to(root_path)
follow_redirect!
expect(response.body).not_to include(generic_error)
end
end
end
51 changes: 51 additions & 0 deletions spec/requests/organizations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,57 @@
end
end

describe "sector displays" do
let!(:organization_with_sectors) do
affiliated_sector_1 = create(:sector, name: "Affiliated Sector 1")
affiliated_sector_2 = create(:sector, name: "Affiliated Sector 2")
person_1 = create(:person)
person_2 = create(:person)
create(:sectorable_item, sector: affiliated_sector_1, sectorable: person_1)
create(:sectorable_item, sector: affiliated_sector_2, sectorable: person_2)

org = create(:organization, organization_status: organization_status)
create(:sectorable_item, sector: create(:sector, name: "Direct Sector 1"), sectorable: org)
create(:sectorable_item, sector: create(:sector, name: "Direct Sector 2"), sectorable: org)
create(:affiliation, organization: org, person: person_1, position: :default)
create(:affiliation, organization: org, person: person_2, position: :default)
org
end

it "truncates sectors to the first 3 with a 'more' indicator on the show page" do
get organization_url(organization_with_sectors)

page = Capybara.string(response.body)
all_sector_names = organization_with_sectors.all_sectors.map(&:name).sort
expect(all_sector_names.length).to be > 3
all_sector_names.first(3).each { |name| expect(page).to have_content(name) }
expect(page).not_to have_content(all_sector_names[3])
expect(page).to have_content(/\+?[0-9]+ more|\.\.\./i)
end

it "lists all sectors with per-sector people counts on the populations served page" do
get populations_served_organization_url(organization_with_sectors)

page = Capybara.string(response.body)
expect(page).to have_content("Sector Distribution")
expect(page).to have_content(organization_with_sectors.name)

organization_with_sectors.all_sectors.map(&:name).each do |name|
expect(page).to have_content(name)
end

people = organization_with_sectors.users.includes(person: :sectors).map(&:person).compact
expected_counts = Hash.new(0)
people.each do |person|
primary_sector = person.sectors.first
expected_counts[primary_sector.name] += 1 if primary_sector
end
expected_counts.each do |_sector_name, count|
expect(page).to have_content("#{count} #{count == 1 ? 'person' : 'people'}")
end
Comment on lines +115 to +117
end
end

describe "GET /new" do
it "renders a successful response" do
get new_organization_url
Expand Down
38 changes: 38 additions & 0 deletions spec/requests/sectors_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,44 @@
get sectors_url
expect(response).to be_successful
end

context "filtering" do

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: These filter tests are new coverage, not just a port — the request spec previously only asserted 200 OK, so the published/name filtering logic had no fast-layer test.

let!(:sectors) do
[
create(:sector, name: "Sector1", published: true),
create(:sector, name: "Sector2", published: true),
create(:sector, name: "Sector3", published: false),
create(:sector, name: "Sector4", published: false)
]
end

it "returns all sectors without filters" do
get sectors_url
sectors.each { |sector| expect(response.body).to include(sector.name) }
end

it "returns only published sectors when published=true" do
get sectors_url, params: { published: "true" }
expect(response.body).to include("Sector1", "Sector2")
expect(response.body).not_to include("Sector3")
expect(response.body).not_to include("Sector4")
end

it "returns only unpublished sectors when published=false" do
get sectors_url, params: { published: "false" }
expect(response.body).to include("Sector3", "Sector4")
expect(response.body).not_to include("Sector1")
expect(response.body).not_to include("Sector2")
end

it "filters by name" do
get sectors_url, params: { sector_name: "Sector1" }
expect(response.body).to include("Sector1")
expect(response.body).not_to include("Sector2")
expect(response.body).not_to include("Sector3")
expect(response.body).not_to include("Sector4")
end
end
end

describe "GET /show" do
Expand Down
17 changes: 17 additions & 0 deletions spec/requests/stories_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,23 @@
expect(response.body).not_to include(story_in_other_org.title)
end

it "shows the empty-state message when no stories match" do

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: The stories index is turbo-frame lazy-loaded, so these hit it with the Turbo-Frame header to get the story list into the body — empty state and body-query search were not covered before.

get stories_url(title: "no-such-story-zzz"), headers: { "Turbo-Frame" => "story_results" }
expect(response.body).to include("No stories found")
end

it "filters by title and body query together" do
match = Story.create!(base_attributes.merge(title: "Best Story Match", rhino_body: "healing through art", published: true))
title_only = Story.create!(base_attributes.merge(title: "Best Story Other", rhino_body: "something else", published: true))
body_only = Story.create!(base_attributes.merge(title: "Unrelated Tale", rhino_body: "healing through art", published: true))

get stories_url(title: "Best Story", query: "healing"), headers: { "Turbo-Frame" => "story_results" }

expect(response.body).to include(match.title)
expect(response.body).not_to include(title_only.title)
expect(response.body).not_to include(body_only.title)
end

describe "external link handling" do
let(:turbo_headers) { { "Turbo-Frame" => "story_results" } }

Expand Down
36 changes: 36 additions & 0 deletions spec/requests/story_ideas_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@
get story_idea_url(create(:story_idea))
expect(response).to be_successful
end

it "renders the organization and creator as links" do
creator = create(:user)
creator_person = create(:person, user: creator)
org = create(:organization, name: "Community Arts Project")
story_idea = create(:story_idea, created_by: creator, organization: org)

get story_idea_url(story_idea)

page = Capybara.string(response.body)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Capybara.string(response.body) lets request specs keep the system spec's have_link/have_text assertions (link vs. plain text by role) without booting a browser. This is the pattern that made the conversions faithful.

expect(page).to have_link(org.name, href: organization_path(org))
expect(page).to have_link(creator.name, href: person_path(creator_person))
end
end

describe "GET /new" do
Expand Down Expand Up @@ -228,6 +241,29 @@
get story_idea_url(story_idea)
expect(response).to be_successful
end

it "renders the organization as plain text and the creator as a link" do
person = create(:person, user: regular_user)
org = create(:organization, name: "Community Arts Project")
story_idea = create(:story_idea, created_by: regular_user, organization: org)

get story_idea_url(story_idea)

page = Capybara.string(response.body)
expect(page).to have_text(org.name)
expect(page).not_to have_link(org.name)
expect(page).to have_link(regular_user.name, href: person_path(person))
end

it "renders the creator as plain text when they have no person record" do
story_idea = create(:story_idea, created_by: regular_user)

get story_idea_url(story_idea)

page = Capybara.string(response.body)
expect(page).to have_text(regular_user.name)
expect(page).not_to have_link(regular_user.name)
end
end
end

Expand Down
73 changes: 73 additions & 0 deletions spec/requests/workshop_logs_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,79 @@
clear_enqueued_jobs
end

describe "GET /show" do

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: There was no GET /show context here before; the deleted system spec was the only place workshop-log show rendering (org/creator links, external title, workshop chip) was tested.

it "renders the organization as plain text and the creator as a link (non-admin)" do
person = create(:person, user: user)
create(:affiliation, person: person, organization: organization)
workshop_log = create(:workshop_log, created_by: user, organization: organization,
workshop: workshop, windows_type: windows_type, workshop_held_on: 1.day.ago)

get workshop_log_path(workshop_log)

page = Capybara.string(response.body)
expect(page).to have_text(organization.name)
expect(page).not_to have_link(organization.name)
expect(page).to have_link(user.name, href: person_path(person))
end

it "renders the creator as plain text when they have no person record" do
workshop_log = create(:workshop_log, created_by: user, organization: organization,
workshop: workshop, windows_type: windows_type, workshop_held_on: 1.day.ago)

get workshop_log_path(workshop_log)

page = Capybara.string(response.body)
expect(page).to have_text(user.name)
expect(page).not_to have_link(user.name)
end

it "shows the external title in the heading and beside the Workshop label when there is no workshop" do
workshop_log = create(:workshop_log, created_by: user, organization: organization,
workshop: nil, windows_type: windows_type,
external_workshop_title: "Community Mural Project", workshop_held_on: 1.day.ago)

get workshop_log_path(workshop_log)

page = Capybara.string(response.body)
expect(page).to have_css("h1", text: "Community Mural Project")
workshop_div = page.find("span", text: "Workshop:").ancestor("div", match: :first)
expect(workshop_div).to have_text("Community Mural Project")
end

it "shows the workshop name in the heading and both the workshop and external title when both are present" do
titled_workshop = create(:workshop, :published, title: "Healing Through Art", windows_type: windows_type)
workshop_log = create(:workshop_log, created_by: user, organization: organization,
workshop: titled_workshop, windows_type: windows_type,
external_workshop_title: "Guest-led Session", workshop_held_on: 1.day.ago)

get workshop_log_path(workshop_log)

page = Capybara.string(response.body)
expect(page).to have_css("h1", text: "Healing Through Art")
workshop_div = page.find("span", text: "Workshop:").ancestor("div", match: :first)
expect(workshop_div).to have_text("Healing Through Art")
expect(workshop_div).to have_text("Guest-led Session")
end

context "as an admin" do
let(:admin) { create(:user, :admin) }
before { sign_in admin }

it "renders the organization and creator as links" do
person = create(:person, user: user)
create(:affiliation, person: person, organization: organization)
workshop_log = create(:workshop_log, created_by: user, organization: organization,
workshop: workshop, windows_type: windows_type, workshop_held_on: 1.day.ago)

get workshop_log_path(workshop_log)

page = Capybara.string(response.body)
expect(page).to have_link(organization.name, href: organization_path(organization))
expect(page).to have_link(user.name, href: person_path(person))
end
end
end

describe "GET /index" do
it "loads the index page successfully" do
get workshop_logs_path
Expand Down
Loading
Loading