otwarchive-symphonyarchive/spec/controllers/chapters_controller_spec.rb
2026-03-11 22:22:11 +00:00

1266 lines
53 KiB
Ruby

require 'spec_helper'
describe ChaptersController do
include LoginMacros
include RedirectExpectationHelper
let(:user) { create(:user) }
let!(:work) { create(:work, authors: [user.pseuds.first]) }
let(:unposted_work) { create(:draft, authors: [user.pseuds.first]) }
let(:co_creator) { create(:user) }
let(:banned_user) { create(:user, banned: true) }
let(:banned_users_work) do
banned_user.update!(banned: false)
work = create(:work, authors: [banned_user.pseuds.first, co_creator.pseuds.first])
banned_user.update!(banned: true)
work
end
let(:banned_users_work_chapter2) do
banned_user.update!(banned: false)
chapter = create(:chapter, work: banned_users_work, position: 2, authors: [banned_user.pseuds.first, co_creator.pseuds.first])
banned_user.update!(banned: true)
chapter
end
let(:suspended_user) { create(:user, suspended: true, suspended_until: 1.week.from_now) }
let(:suspended_users_work) do
suspended_user.update!(suspended: false, suspended_until: nil)
work = create(:work, authors: [suspended_user.pseuds.first, co_creator.pseuds.first])
suspended_user.update!(suspended: true, suspended_until: 1.week.from_now)
work
end
let(:suspended_users_work_chapter2) do
suspended_user.update!(suspended: false, suspended_until: nil)
chapter = create(:chapter, work: suspended_users_work, position: 2, authors: [suspended_user.pseuds.first, co_creator.pseuds.first])
suspended_user.update!(suspended: true, suspended_until: 1.week.from_now)
chapter
end
describe "index" do
it "redirects to work" do
get :index, params: { work_id: work.id }
it_redirects_to work_path(work.id)
end
end
describe "manage" do
context "when user is logged out" do
it "errors and redirects to login" do
get :manage, params: { work_id: work.id }
it_redirects_to_with_error(new_user_session_path, "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when work owner is logged in" do
before do
fake_login_known_user(user)
end
it "errors and redirects to root path if work does not exist" do
get :manage, params: { work_id: 0 }
it_redirects_to_with_error(root_path, "Sorry, we couldn't find the work you were looking for.")
end
it "renders manage template" do
get :manage, params: { work_id: work.id }
expect(response).to render_template(:manage)
end
it "assigns @chapters to include draft chapters" do
chapter = create(:chapter, :draft, work: work, position: 2)
get :manage, params: { work_id: work.id }
expect(assigns[:chapters]).to eq([work.chapters.first, chapter])
end
it "assigns @chapters to chapters in order" do
chapter = create(:chapter, work: work, position: 2)
get :manage, params: { work_id: work.id }
expect(assigns[:chapters]).to eq([work.chapters.first, chapter])
end
end
context "when other user is logged in" do
it "errors and redirects to work" do
fake_login
get :manage, params: { work_id: work.id }
it_redirects_to_with_error(work_path(work.id), "Sorry, you don't have permission to access the page you were trying to reach.")
end
end
end
describe "show" do
context "when user is logged out" do
it "renders show template" do
get :show, params: { work_id: work.id, id: work.chapters.first }
expect(response).to render_template(:show)
end
it "errors and redirects to login when work is restricted" do
restricted_work = create(:work, restricted: true)
get :show, params: { work_id: restricted_work.id, id: restricted_work.chapters.first }
it_redirects_to(new_user_session_path(restricted: true))
end
it "assigns @chapters to only posted chapters" do
chapter = create(:chapter, :draft, work: work)
get :show, params: { work_id: work.id, id: chapter.id }
expect(assigns[:chapters]).to eq([work.chapters.first])
end
it "errors and redirects to login when trying to view unposted chapter" do
chapter = create(:chapter, :draft, work: work)
get :show, params: { work_id: work.id, id: chapter.id }
it_redirects_to_with_error(new_user_session_path, "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when work is adult" do
render_views
before do
allow_any_instance_of(Work).to receive(:adult?).and_return true
end
it "stores adult preference in sessions when given" do
get :show, params: { work_id: work.id, id: work.chapters.first, view_adult: true }
expect(cookies[:view_adult]).to eq "true"
end
it "renders _adults template if work is adult and adult permission has not been given" do
get :show, params: { work_id: work.id, id: work.chapters.first }
expect(response).to render_template("works/_adult")
end
it "does not render _adults template if work is adult and adult permission has been given" do
get :show, params: { work_id: work.id, id: work.chapters.first, view_adult: true }
expect(response).not_to render_template("works/_adult")
end
end
context "when work is not adult" do
render_views
it "does not render _adults template if work is not adult" do
get :show, params: { work_id: work.id, id: work.chapters.first }
expect(response).not_to render_template("works/_adult")
end
end
it "redirects to chapter with selected_id" do
chapter = create(:chapter, work: work, position: 2)
get :show, params: { work_id: work.id, id: work.chapters.first, selected_id: chapter.id }
it_redirects_to work_chapter_path(work_id: work.id, id: chapter.id)
end
it "errors and redirects to work if chapter is not found" do
chapter = create(:chapter)
get :show, params: { work_id: work.id, id: chapter.id }
it_redirects_to_with_error(work_path(work), "Sorry, we couldn't find the chapter you were looking for.")
end
it "assigns @chapters to chapters in order" do
chapter = create(:chapter, work: work, position: 2)
get :show, params: { work_id: work.id, id: chapter.id }
expect(assigns[:chapters]).to eq([work.chapters.first, chapter])
end
it "assigns @previous_chapter when not on first chapter" do
chapter = create(:chapter, work: work, position: 2)
get :show, params: { work_id: work.id, id: chapter.id }
expect(assigns[:previous_chapter]).to eq(work.chapters.first)
end
it "does not assign @previous_chapter when on first chapter" do
create(:chapter, work: work, position: 2)
get :show, params: { work_id: work.id, id: work.chapters.first.id }
expect(assigns[:previous_chapter]).to be_nil
end
it "assigns @next_chapter when not on last chapter" do
chapter = create(:chapter, work: work, position: 2)
get :show, params: { work_id: work.id, id: work.chapters.first.id }
expect(assigns[:next_chapter]).to eq(chapter)
end
it "does not assign @next_chapter when on last chapter" do
chapter = create(:chapter, work: work, position: 2)
get :show, params: { work_id: work.id, id: chapter.id }
expect(assigns[:next_chapter]).to be_nil
end
it "assigns @page_title with fandom, author name, work title, and chapter" do
expect_any_instance_of(ChaptersController).to receive(:get_page_title).with("Testing", user.pseuds.first.name, "My title is long enough - Chapter 1").and_return("page title")
get :show, params: { work_id: work.id, id: work.chapters.first.id }
expect(assigns[:page_title]).to eq("page title")
end
it "assigns @page_title with unrevealed work" do
allow_any_instance_of(Work).to receive(:unrevealed?).and_return(true)
get :show, params: { work_id: work.id, id: work.chapters.first.id }
expect(assigns[:page_title]).to eq("Mystery Work - Chapter 1")
end
it "assigns @page_title with anonymous work" do
allow_any_instance_of(Work).to receive(:anonymous?).and_return(true)
expect_any_instance_of(ChaptersController).to receive(:get_page_title).with("Testing", "Anonymous", "My title is long enough - Chapter 1").and_return("page title")
get :show, params: { work_id: work.id, id: work.chapters.first.id }
expect(assigns[:page_title]).to eq("page title")
end
context "when work has no fandom" do
it "assigns @page_title with a placeholder for the fandom" do
allow_any_instance_of(Work).to receive(:tag_groups).and_return("Fandom" => [])
expect_any_instance_of(ChaptersController).to receive(:get_page_title).with("No fandom specified", user.pseuds.first.name, "#{work.title} - Chapter 1").and_return("page title")
get :show, params: { work_id: work.id, id: work.chapters.first.id }
expect(response).to have_http_status(:ok)
expect(assigns[:page_title]).to eq("page title")
end
end
it "assigns @kudos to non-anonymous kudos" do
kudo = create(:kudo, commentable: work, user: create(:user))
create(:kudo, commentable: work)
get :show, params: { work_id: work.id, id: work.chapters.first.id }
expect(assigns[:kudos]).to eq [kudo]
end
it "assigns instance variables correctly" do
second_chapter = create(:chapter, work: work, position: 2)
third_chapter = create(:chapter, work: work, position: 3)
kudo = create(:kudo, commentable: work, user: create(:user))
tag = create(:fandom)
expect_any_instance_of(Work).to receive(:tag_groups).and_return("Fandom" => [tag])
expect_any_instance_of(ChaptersController).to receive(:get_page_title).with(tag.name, user.pseuds.first.name, "My title is long enough - Chapter 2").and_return("page title")
get :show, params: { work_id: work.id, id: second_chapter.id }
expect(assigns[:work]).to eq work
expect(assigns[:tag_groups]).to eq "Fandom" => [tag]
expect(assigns[:chapter]).to eq second_chapter
expect(assigns[:chapters]).to eq [work.chapters.first, second_chapter, third_chapter]
expect(assigns[:previous_chapter]).to eq work.chapters.first
expect(assigns[:next_chapter]).to eq third_chapter
expect(assigns[:page_title]).to eq "page title"
expect(assigns[:kudos]).to eq [kudo]
expect(assigns[:subscription]).to be_nil
end
context "when work owner is logged in" do
before do
fake_login_known_user(user)
end
it "assigns @chapters to all chapters" do
chapter = create(:chapter, :draft, work: work, position: 2)
get :show, params: { work_id: work.id, id: chapter.id }
expect(assigns[:chapters]).to eq([work.chapters.first, chapter])
end
end
context "when other user is logged in" do
before do
fake_login
end
it "assigns @chapters to only posted chapters" do
chapter = create(:chapter, :draft, work: work)
get :show, params: { work_id: work.id, id: chapter.id }
expect(assigns[:chapters]).to eq([work.chapters.first])
end
it "assigns @subscription to user's subscription when user is subscribed to work" do
subscription = create(:subscription, subscribable: work, user: controller.current_user)
get :show, params: { work_id: work, id: work.chapters.first.id }
expect(assigns[:subscription]).to eq(subscription)
end
it "assigns @subscription to unsaved subscription when user is not subscribed to work" do
get :show, params: { work_id: work, id: work.chapters.first.id }
expect(assigns[:subscription]).to be_new_record
end
it "updates the reading history" do
expect(Reading).to receive(:update_or_create).with(work, controller.current_user)
get :show, params: { work_id: work.id, id: work.chapters.first.id }
end
end
end
describe "new" do
context "when user is logged out" do
it "errors and redirects to login" do
get :new, params: { work_id: work.id }
it_redirects_to_with_error(new_user_session_path, "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when work owner is logged in" do
before do
fake_login_known_user(user)
end
it "renders new template" do
get :new, params: { work_id: work.id }
expect(response).to render_template(:new)
end
it "errors and redirects to user page when user is suspended" do
fake_login_known_user(suspended_user)
get :new, params: { work_id: suspended_users_work.id }
it_redirects_to_simple(user_path(suspended_user))
expect(flash[:error]).to include("Your account has been suspended")
end
it "errors and redirects to user page when user is banned" do
fake_login_known_user(banned_user)
get :new, params: { work_id: banned_users_work.id }
it_redirects_to_simple(user_path(banned_user))
expect(flash[:error]).to include("Your account has been banned.")
end
end
context "when other user is logged in" do
before do
fake_login
end
it "errors and redirects to work" do
get :new, params: { work_id: work.id }
it_redirects_to_with_error(work_path(work), "Sorry, you don't have permission to access the page you were trying to reach.")
end
end
end
describe "edit" do
context "when user is logged out" do
it "errors and redirects to login" do
get :edit, params: { work_id: work.id, id: work.chapters.first.id }
it_redirects_to_with_error(new_user_session_path, "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when logged in user owns the chapter" do
before do
fake_login_known_user(user)
end
it "renders edit template" do
get :edit, params: { work_id: work.id, id: work.chapters.first.id }
expect(response).to render_template(:edit)
end
it "errors and redirects to user page when user is suspended" do
fake_login_known_user(suspended_user)
get :edit, params: { work_id: suspended_users_work.id, id: suspended_users_work.chapters.first.id }
it_redirects_to_simple(user_path(suspended_user))
expect(flash[:error]).to include("Your account has been suspended")
end
it "renders edit template when user is banned" do
fake_login_known_user(banned_user)
get :edit, params: { work_id: banned_users_work.id, id: banned_users_work.chapters.first.id }
expect(response).to render_template(:edit)
end
end
context "when logged in user does not own the chapter" do
before do
fake_login
end
it "errors and redirects to work" do
get :edit, params: { work_id: work.id, id: work.chapters.first.id }
it_redirects_to_with_error(work_path(work), "Sorry, you don't have permission to access the page you were trying to reach.")
end
end
context "with valid remove params" do
context "when work is multichaptered and co-created" do
let!(:co_created_chapter) { create(:chapter, work: work, authors: [user.pseuds.first, co_creator.pseuds.first]) }
context "when logged in user also owns other chapters" do
before do
fake_login_known_user(user)
end
it "removes user from chapter, gives notice, and redirects to work" do
get :edit, params: { work_id: work.id, id: co_created_chapter.id, remove: "me" }
expect(co_created_chapter.reload.pseuds).to eq [co_creator.pseuds.first]
expect(work.reload.pseuds).to eq [user.pseuds.first, co_creator.pseuds.first]
it_redirects_to_with_notice(work_path(work), "You have been removed as a creator from the chapter.")
end
end
context "when logged in user only owns this chapter" do
before do
fake_login_known_user(co_creator)
end
it "removes user from chapter and delegates removal of the user from the work to the work controller" do
get :edit, params: { work_id: work.id, id: co_created_chapter.id, remove: "me" }
expect(co_created_chapter.reload.pseuds).to eq [user.pseuds.first]
expect(work.reload.pseuds).to eq [user.pseuds.first, co_creator.pseuds.first]
it_redirects_to(edit_work_path(work, remove: "me"))
end
end
context "when the logged in user is suspended" do
before do
fake_login_known_user(suspended_user)
end
it "errors and redirects to user page" do
get :edit, params: { work_id: suspended_users_work.id, id: suspended_users_work_chapter2.id, remove: "me" }
expect(flash[:error]).to include("Your account has been suspended")
end
end
context "when the logged in user is banned" do
before do
fake_login_known_user(banned_user)
end
it "removes user from chapter, gives notice, and redirects to work" do
get :edit, params: { work_id: banned_users_work.id, id: banned_users_work_chapter2.id, remove: "me" }
expect(banned_users_work_chapter2.reload.pseuds).to eq [co_creator.pseuds.first]
expect(banned_users_work.reload.pseuds).to eq [co_creator.pseuds.first, banned_user.pseuds.first]
it_redirects_to_with_notice(work_path(banned_users_work), "You have been removed as a creator from the chapter.")
end
end
end
end
end
describe "create" do
let(:chapter_attributes) { { content: "This doesn't matter" } }
context "when user is logged out" do
it "errors and redirects to login" do
post :create, params: { work_id: work.id, chapter: chapter_attributes }
it_redirects_to_with_error(new_user_session_path, "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when work owner is logged in" do
before do
fake_login_known_user(user)
chapter_attributes[:author_attributes] = { ids: [user.pseuds.first.id] }
end
it "errors and redirects to user page when user is suspended" do
fake_login_known_user(suspended_user)
post :create, params: { work_id: suspended_users_work.id, chapter: chapter_attributes }
it_redirects_to_simple(user_path(suspended_user))
expect(flash[:error]).to include("Your account has been suspended")
end
it "errors and redirects to user page when user is banned" do
fake_login_known_user(banned_user)
post :create, params: { work_id: banned_users_work.id, chapter: chapter_attributes }
it_redirects_to_simple(user_path(banned_user))
expect(flash[:error]).to include("Your account has been banned.")
end
it "does not allow a user to submit only a pseud that is not theirs" do
user2 = create(:user)
chapter_attributes[:author_attributes] = { ids: [user2.pseuds.first.id] }
expect { post :create, params: { work_id: work.id, chapter: chapter_attributes } }.not_to change { Chapter.count }
expect(response).to render_template("new")
expect(assigns[:chapter].errors.full_messages).to \
include "You're not allowed to use that pseud."
end
it "adds a new chapter" do
expect { post :create, params: { work_id: work.id, chapter: chapter_attributes } }.to change { Chapter.count }
expect(work.chapters.count).to eq 2
end
it "updates the works wip length when given" do
chapter_attributes[:wip_length] = 3
expect(work.wip_length).to eq 1
post :create, params: { work_id: work.id, chapter: chapter_attributes }
expect(assigns[:work].wip_length).to eq 3
end
it "renders new if chapter has invalid pseuds" do
chapter_attributes[:author_attributes] = { byline: "*impossible*" }
post :create, params: { work_id: work.id, chapter: chapter_attributes }
expect(response).to render_template(:new)
expect(assigns[:chapter].errors.full_messages).to \
include("Invalid creator: Could not find a pseud *impossible*.")
end
it "renders new if chapter has ambiguous pseuds" do
create(:pseud, name: "ambiguous")
create(:pseud, name: "ambiguous")
chapter_attributes[:author_attributes] = { byline: "ambiguous" }
post :create, params: { work_id: work.id, chapter: chapter_attributes }
expect(response).to render_template(:new)
expect(assigns[:chapter].errors.full_messages).to \
include("Invalid creator: The pseud ambiguous is ambiguous.")
end
it "renders new if the edit button has been clicked" do
post :create, params: { work_id: work.id, chapter: chapter_attributes, edit_button: true }
expect(response).to render_template(:new)
end
it "redirects if the cancel button has been clicked" do
post :create, params: { work_id: work.id, chapter: chapter_attributes, cancel_button: true }
expect(response).to have_http_status :redirect
end
context "when neither posting nor previewing is explicitly specified" do
it "does not update the work's version" do
expect do
post :create, params: { work_id: work.id, chapter: chapter_attributes }
end.to avoid_changing { work.reload.major_version }
.and avoid_changing { work.reload.minor_version }
end
end
context "when the post button is clicked" do
context "when the chapter and work are valid" do
it "posts the chapter" do
post :create, params: { work_id: work.id, chapter: chapter_attributes, post_without_preview_button: true }
expect(assigns[:chapter].posted).to be true
end
it "updates cached chapter counts" do
expect do
post :create, params: { work_id: work.id, chapter: chapter_attributes, post_without_preview_button: true }
end.to change { work.number_of_chapters }
.from(1).to(2)
.and change { work.number_of_posted_chapters }
.from(1).to(2)
end
it "updates the work's major version" do
expect do
post :create, params: { work_id: work.id, chapter: chapter_attributes, post_without_preview_button: true }
end.to change { work.reload.major_version }
.from(1).to(2)
.and avoid_changing { work.reload.minor_version }
end
it "posts the work if the work was not posted before" do
post :create, params: { work_id: unposted_work.id, chapter: chapter_attributes, post_without_preview_button: true }
expect(assigns[:work].posted).to be true
end
it "gives a notice and redirects to the posted chapter" do
post :create, params: { work_id: work.id, chapter: chapter_attributes, post_without_preview_button: true }
it_redirects_to_with_notice(work_chapter_path(work_id: work.id, id: assigns[:chapter].id), "Chapter has been posted!")
end
end
context "when the chapter or work is not valid" do
it "does not add a chapter" do
expect { post :create, params: { work_id: work.id, chapter: { content: "" }, post_without_preview_button: true } }.to_not change(Chapter, :count)
end
it "renders new" do
post :create, params: { work_id: work.id, chapter: { content: "" }, post_without_preview_button: true }
expect(response).to render_template(:new)
end
end
it "updates the work's revision date" do
travel_to(1.day.ago) do
work.touch
end
old_updated_at = work.updated_at
post :create, params: { work_id: work.id, chapter: chapter_attributes, post_without_preview_button: true }
expect(assigns[:work].updated_at).not_to eq(old_updated_at)
end
end
context "when the preview button is clicked" do
context "when the chapter and work are valid" do
it "does not post the chapter" do
post :create, params: { work_id: work.id, chapter: chapter_attributes, preview_button: true }
expect(assigns[:chapter].posted).to be false
end
it "updates cached chapter counts" do
expect do
post :create, params: { work_id: work.id, chapter: chapter_attributes, preview_button: true }
end.to change { work.number_of_chapters }
.from(1).to(2)
.and avoid_changing { work.number_of_posted_chapters }
end
it "does not update the work's version" do
expect do
post :create, params: { work_id: work.id, chapter: chapter_attributes, preview_button: true }
end.to avoid_changing { work.reload.major_version }
.and avoid_changing { work.reload.minor_version }
end
it "gives a notice that the chapter is a draft and redirects to the chapter preview" do
post :create, params: { work_id: work.id, chapter: chapter_attributes, preview_button: true }
it_redirects_to_with_notice(preview_work_chapter_path(work_id: work.id, id: assigns[:chapter].id), "This is a draft chapter in a posted work. It will be kept unless the work is deleted.")
end
it "gives a notice that the work and chapter are drafts and redirects to the chapter preview" do
post :create, params: { work_id: unposted_work.id, chapter: chapter_attributes, preview_button: true }
it_redirects_to_simple(preview_work_chapter_path(work_id: unposted_work.id, id: assigns[:chapter].id))
expect(flash[:notice]).to include("This is a draft chapter in an unposted work")
end
end
context "when the chapter or work is not valid" do
it "does not add a chapter" do
expect { post :create, params: { work_id: work.id, chapter: { content: "" }, preview_button: true } }.to_not change(Chapter, :count)
end
it "renders new" do
post :create, params: { work_id: work.id, chapter: { content: "" }, preview_button: true }
expect(response).to render_template(:new)
end
end
end
end
context "when other user is logged in" do
before do
fake_login
end
context "when the user tries to add themselves as a coauthor" do
before do
chapter_attributes[:author_attributes] = { ids: [user.pseuds.first.id, controller.current_user.pseuds.first.id] }
end
it "errors and redirects to work" do
post :create, params: { work_id: work.id, chapter: chapter_attributes }
it_redirects_to_with_error(work_path(work), "Sorry, you don't have permission to access the page you were trying to reach.")
end
end
end
end
describe "update" do
let(:chapter_attributes) { { content: "This doesn't matter" } }
context "when user is logged out" do
it "errors and redirects to login" do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes }
it_redirects_to_with_error(new_user_session_path, "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when work owner is logged in" do
before do
fake_login_known_user(user)
end
it "errors and redirects to user page when user is suspended" do
fake_login_known_user(suspended_user)
put :update, params: { work_id: suspended_users_work.id, id: suspended_users_work.chapters.first.id, chapter: chapter_attributes }
it_redirects_to_simple(user_path(suspended_user))
expect(flash[:error]).to include("Your account has been suspended")
end
it "errors and redirects to user page when user is banned" do
fake_login_known_user(banned_user)
put :update, params: { work_id: banned_users_work.id, id: banned_users_work.chapters.first.id, chapter: chapter_attributes }
it_redirects_to_simple(user_path(banned_user))
expect(flash[:error]).to include("Your account has been banned.")
end
it "does not allow a user to submit only a pseud that is not theirs" do
user2 = create(:user)
chapter_attributes[:author_attributes] = { ids: [user2.pseuds.first.id] }
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes }
expect(response).to render_template("edit")
expect(assigns[:chapter].errors.full_messages).to \
include "You're not allowed to use that pseud."
end
it "updates the work's wip length when given" do
chapter_attributes[:wip_length] = 3
expect(work.wip_length).to eq 1
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes }
expect(assigns[:work].wip_length).to eq 3
end
it "renders edit if chapter has invalid pseuds" do
chapter_attributes[:author_attributes] = { byline: "*impossible*" }
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes }
expect(response).to render_template(:edit)
expect(assigns[:chapter].errors.full_messages).to \
include("Invalid creator: Could not find a pseud *impossible*.")
end
it "renders edit if chapter has ambiguous pseuds" do
create(:pseud, name: "ambiguous")
create(:pseud, name: "ambiguous")
chapter_attributes[:author_attributes] = { byline: "ambiguous" }
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes }
expect(response).to render_template(:edit)
expect(assigns[:chapter].errors.full_messages).to \
include("Invalid creator: The pseud ambiguous is ambiguous.")
end
context "when the preview button is clicked" do
it "assigns preview_mode to true" do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes, preview_button: true }
expect(assigns[:preview_mode]).to be true
end
it "gives a notice if the chapter has been posted and renders preview" do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes, preview_button: true }
expect(response).to render_template(:preview)
expect(flash[:notice]).to include "This is a preview of what this chapter will look like after your changes have been applied."
end
it "gives a notice if the chapter has not been posted and renders preview" do
unposted_chapter = create(:chapter, :draft, work: work, authors: [user.pseuds.first])
put :update, params: { work_id: work.id, id: unposted_chapter.id, chapter: chapter_attributes, preview_button: true }
expect(response).to render_template(:preview)
expect(flash[:notice]).to include "This is a draft chapter in a posted work."
end
end
it "redirects if the cancel button has been clicked" do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes, cancel_button: true }
expect(response).to have_http_status :redirect
end
it "renders edit if the edit button has been clicked" do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes, edit_button: true }
expect(response).to render_template(:edit)
end
it "updates the work's minor version" do
expect do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes }
end.to change { work.reload.minor_version }
.from(0).to(1)
.and avoid_changing { work.reload.major_version }
end
context "when the post button is clicked" do
context "when the chapter and work are valid" do
it "posts the chapter" do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes, post_button: true }
expect(assigns[:chapter].posted).to be true
end
it "posts the work if the work was not posted before" do
pending "multi-chapter works should post when chapter is posted"
put :update, params: { work_id: unposted_work.id, id: unposted_work.chapters.first.id, chapter: chapter_attributes, post_button: true }
expect(assigns[:work].posted).to be true
end
it "gives a notice if the chapter was already posted and redirects to the posted chapter" do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes, post_button: true }
it_redirects_to_with_notice(work_chapter_path(work_id: work.id, id: work.chapters.first.id), "Chapter was successfully updated.")
end
it "gives a notice if the chapter was not already posted and redirects to the posted chapter" do
unposted_chapter = create(:chapter, :draft, work: work, authors: [user.pseuds.first])
put :update, params: { work_id: work.id, id: unposted_chapter.id, chapter: chapter_attributes, post_button: true }
it_redirects_to_with_notice(work_chapter_path(work_id: work.id, id: unposted_chapter.id), "Chapter was successfully posted.")
end
it "updates the work's minor version if the chapter was already posted" do
expect do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes, post_button: true }
end.to change { work.reload.minor_version }
.from(0).to(1)
.and avoid_changing { work.reload.major_version }
end
it "updates the work's major version if the chapter was not already posted" do
unposted_chapter = create(:chapter, :draft, work: work, authors: [user.pseuds.first])
expect do
put :update, params: { work_id: work.id, id: unposted_chapter.id, chapter: chapter_attributes, post_button: true }
end.to change { work.reload.major_version }
.from(1).to(2)
.and avoid_changing { work.reload.minor_version }
end
end
context "when the chapter or work is not valid" do
it "does not update the chapter" do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: { content: "" }, post_button: true }
expect(assigns[:chapter]).to eq work.chapters.first
end
it "renders edit" do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: { content: "" }, post_button: true }
expect(response).to render_template(:edit)
end
end
it "updates the work's revision date" do
travel_to(1.day.ago) do
work.touch
end
old_updated_at = work.updated_at
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes, post_button: true }
expect(assigns[:work].updated_at).not_to eq(old_updated_at)
end
end
context "when the post button is clicked" do
it "posts the chapter" do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes, post_without_preview_button: true }
expect(assigns[:chapter].posted).to be true
end
end
end
context "when other user is logged in" do
before do
fake_login
end
context "when the user tries to add themselves as a coauthor" do
before do
chapter_attributes[:author_attributes] = { ids: [user.pseuds.first.id, controller.current_user.pseuds.first.id] }
end
it "errors and redirects to work" do
put :update, params: { work_id: work.id, id: work.chapters.first.id, chapter: chapter_attributes }
it_redirects_to_with_error(work_path(work), "Sorry, you don't have permission to access the page you were trying to reach.")
end
end
end
end
describe "update_positions" do
let(:chapter1) { work.chapters.first }
let!(:chapter2) { create(:chapter, :draft, work: work, position: 2, authors: [user.pseuds.first]) }
let!(:chapter3) { create(:chapter, work: work, position: 3, authors: [user.pseuds.first]) }
let!(:chapter4) { create(:chapter, work: work, position: 4, authors: [user.pseuds.first]) }
context "when user is logged out" do
it "errors and redirects to login" do
post :update_positions, params: { work_id: work.id, chapter: [chapter1, chapter3, chapter2, chapter4] }
it_redirects_to_with_error(new_user_session_path, "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when work owner is logged in" do
before do
fake_login_known_user(user)
end
context "when passing params[:chapters]" do
it "updates the positions of the chapters" do
post :update_positions, params: { work_id: work.id, chapters: [1, 3, 2, 4] }
expect(chapter1.reload.position).to eq(1)
expect(chapter2.reload.position).to eq(3)
expect(chapter3.reload.position).to eq(2)
expect(chapter4.reload.position).to eq(4)
end
it "preserves ordering if order values are all empty" do
post :update_positions, params: { work_id: work.id, chapters: ["", "", "", ""] }
expect(chapter1.reload.position).to eq(1)
expect(chapter2.reload.position).to eq(2)
expect(chapter3.reload.position).to eq(3)
expect(chapter4.reload.position).to eq(4)
end
it "preserves ordering for empty values" do
post :update_positions, params: { work_id: work.id, chapters: ["", "", "", 1] }
expect(chapter1.reload.position).to eq(2)
expect(chapter2.reload.position).to eq(3)
expect(chapter3.reload.position).to eq(4)
expect(chapter4.reload.position).to eq(1)
end
it "gives a notice and redirects to work" do
post :update_positions, params: { work_id: work.id, chapters: [1, 3, 2, 4] }
it_redirects_to_with_notice(work, "Chapter order has been successfully updated.")
end
end
context "when passing params[:chapter]" do
it "updates the positions of the chapters" do
post :update_positions, params: { work_id: work.id, chapter: [chapter1, chapter3, chapter2, chapter4], format: :js }
expect(chapter1.reload.position).to eq(1)
expect(chapter2.reload.position).to eq(3)
expect(chapter3.reload.position).to eq(2)
expect(chapter4.reload.position).to eq(4)
end
end
context "when the logged in user is suspended" do
before do
fake_login_known_user(suspended_user)
end
it "errors and redirects to user page" do
post :update_positions, params: { work_id: suspended_users_work.id, chapter: [suspended_users_work_chapter2, suspended_users_work.chapters.first] }
expect(flash[:error]).to include("Your account has been suspended")
end
end
context "when the logged in user is banned" do
before do
fake_login_known_user(banned_user)
end
it "errors and redirects to user page" do
post :update_positions, params: { work_id: banned_users_work.id, chapter: [banned_users_work_chapter2, banned_users_work.chapters.first] }
expect(flash[:error]).to include("Your account has been banned")
end
end
end
end
describe "preview" do
context "when user is logged out" do
it "errors and redirects to login" do
get :preview, params: { work_id: work.id, id: work.chapters.first.id }
it_redirects_to_with_error(new_user_session_path, "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when work owner is logged in" do
before do
fake_login_known_user(user)
end
it "renders preview template" do
get :preview, params: { work_id: work.id, id: work.chapters.first.id }
expect(response).to render_template(:preview)
end
it "assigns instance variables correctly" do
get :preview, params: { work_id: work.id, id: work.chapters.first.id }
expect(assigns[:work]).to eq work
expect(assigns[:chapter]).to eq work.chapters.first
expect(assigns[:preview_mode]).to be true
end
end
context "when other user is logged in" do
before do
fake_login
end
it "errors and redirects to work" do
get :preview, params: { work_id: work.id, id: work.chapters.first.id }
it_redirects_to_with_error(work_path(work), "Sorry, you don't have permission to access the page you were trying to reach.")
end
end
end
describe "post" do
before do
@chapter_to_post = create(:chapter, :draft, work: work, authors: [user.pseuds.first], position: 2)
end
context "when user is logged out" do
it "errors and redirects to login" do
post :post, params: { work_id: work.id, id: @chapter_to_post.id }
it_redirects_to_with_error(new_user_session_path, "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when work owner is logged in" do
before do
fake_login_known_user(user)
end
it "redirects to work when cancel button is clicked" do
post :post, params: { work_id: work.id, id: @chapter_to_post.id, cancel_button: true }
it_redirects_to(work)
end
it "redirects to edit when edit button is clicked" do
post :post, params: { work_id: work.id, id: @chapter_to_post.id, edit_button: true }
it_redirects_to(edit_work_chapter_path(work_id: work.id, id: @chapter_to_post.id))
end
context "when the chapter and work are valid" do
it "posts the chapter and redirects to work" do
post :post, params: { work_id: work.id, id: @chapter_to_post.id }
expect(assigns[:chapter].posted).to be true
it_redirects_to_with_notice(work, "Chapter has been posted!")
end
it "updates the work's major version when posted" do
expect do
post :post, params: { work_id: work.id, id: @chapter_to_post.id }
end.to change { work.reload.major_version }
.from(1).to(2)
.and avoid_changing { work.reload.minor_version }
end
it "posts the work if the work was not posted before" do
post :post, params: { work_id: unposted_work.id, id: unposted_work.chapters.first.id }
expect(assigns[:work].posted).to be true
end
end
context "when the chapter or work is not valid" do
before do
allow_any_instance_of(Chapter).to receive(:save).and_return(false)
end
it "does not update the chapter" do
post :post, params: { work_id: work.id, id: @chapter_to_post.id }
expect(assigns[:chapter]).to eq @chapter_to_post
end
it "renders preview" do
post :post, params: { work_id: work.id, id: @chapter_to_post.id }
expect(response).to render_template(:preview)
end
end
it "updates the work's revision date" do
travel_to(1.day.ago) do
work.touch
end
old_updated_at = work.updated_at
post :post, params: { work_id: work.id, id: @chapter_to_post.id }
expect(assigns[:work].updated_at).not_to eq(old_updated_at)
end
end
context "when other user is logged in" do
before do
fake_login
end
it "errors and redirects to work" do
post :post, params: { work_id: work.id, id: @chapter_to_post.id }
it_redirects_to_with_error(work_path(work), "Sorry, you don't have permission to access the page you were trying to reach.")
end
end
end
describe "confirm_delete" do
context "when user is logged out" do
it "errors and redirects to work" do
get :confirm_delete, params: { work_id: work.id, id: work.chapters.first.id }
it_redirects_to_with_error(work_path(work), "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when work owner is logged in" do
before do
fake_login_known_user(user)
end
it "renders confirm delete template" do
get :confirm_delete, params: { work_id: work.id, id: work.chapters.first.id }
expect(response).to render_template(:confirm_delete)
end
it "assigns instance variables correctly" do
get :confirm_delete, params: { work_id: work.id, id: work.chapters.first.id }
expect(assigns[:work]).to eq work
expect(assigns[:chapter]).to eq work.chapters.first
end
end
context "when other user is logged in" do
before do
fake_login
end
it "errors and redirects to work" do
get :confirm_delete, params: { work_id: work.id, id: work.chapters.first.id }
it_redirects_to_with_error(work_path(work), "Sorry, you don't have permission to access the page you were trying to reach.")
end
end
end
describe "destroy" do
context "when user is logged out" do
it "errors and redirects to login" do
pending "clean up chapter filters"
delete :destroy, params: { work_id: work.id, id: work.chapters.first.id }
it_redirects_to_with_error(new_user_session_path, "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when work owner is logged in" do
before do
fake_login_known_user(user)
end
context "when work has one chapter" do
it "redirects to edit work" do
delete :destroy, params: { work_id: work.id, id: work.chapters.first.id }
it_redirects_to_with_error(edit_work_path(work), "You can't delete the only chapter in your work. If you want to delete the work, choose \"Delete Work\".")
end
end
context "when work has more than one chapter" do
let!(:chapter2) { create(:chapter, work: work, position: 2, authors: [user.pseuds.first]) }
it "updates the work's minor version" do
expect do
delete :destroy, params: { work_id: work.id, id: chapter2.id }
end.to change { work.reload.minor_version }
.from(0).to(1)
.and avoid_changing { work.reload.major_version }
end
it "updates the work's revision date" do
travel_to(1.day.ago) do
work.touch
end
old_updated_at = work.updated_at
delete :destroy, params: { work_id: work.id, id: chapter2.id }
expect(assigns[:work].updated_at).not_to eq(old_updated_at)
end
it "updates cached chapter counts" do
expect do
delete :destroy, params: { work_id: work.id, id: chapter2.id }
end.to change { work.number_of_chapters }
.from(2).to(1)
.and change { work.number_of_posted_chapters }
.from(2).to(1)
end
it "gives a notice that the chapter was deleted and redirects to work" do
delete :destroy, params: { work_id: work.id, id: chapter2.id }
it_redirects_to_with_notice(work, "The chapter was successfully deleted.")
end
it "gives a notice that the draft chapter was deleted if the chapter was a draft and redirects to work" do
chapter2.posted = false
chapter2.save
delete :destroy, params: { work_id: work.id, id: chapter2.id }
it_redirects_to_with_notice(work, "The chapter draft was successfully deleted.")
end
it "errors and redirects to work when chapter is not deleted" do
allow_any_instance_of(Chapter).to receive(:destroy).and_return(false)
delete :destroy, params: { work_id: work.id, id: chapter2.id }
it_redirects_to_with_error(work, "Something went wrong. Please try again.")
end
it "does not reorder chapters when deleting the last chapter" do
chapter1 = work.chapters.first
delete :destroy, params: { work_id: work.id, id: chapter2.id }
expect(work.reload.chapters_in_order).to eq([chapter1])
expect(work.reload.chapters_in_order.first.position).to eq(1)
end
it "updates chapter positions when deleting the first chapter of a two chapter work" do
delete :destroy, params: { work_id: work.id, id: work.chapters.first.id }
expect(work.reload.chapters_in_order).to eq([chapter2])
expect(work.reload.chapters_in_order.first.position).to eq(1)
end
it "maintains chapter order when deleting the first chapter of a >3 chapter work" do
chapter3 = create(:chapter, work: work, position: 3, authors: [user.pseuds.first])
chapter4 = create(:chapter, :draft, work: work, position: 4, authors: [user.pseuds.first])
chapter5 = create(:chapter, work: work, position: 5, authors: [user.pseuds.first])
delete :destroy, params: { work_id: work.id, id: work.chapters.first.id }
work.reload
posted_chapters = work.chapters_in_order
expect(posted_chapters).to eq([chapter2, chapter3, chapter5])
expect(posted_chapters.map(&:position)).to eq([1, 2, 4])
all_chapters = work.chapters_in_order(include_drafts: true)
expect(all_chapters).to eq([chapter2, chapter3, chapter4, chapter5])
expect(all_chapters.map(&:position)).to eq([1, 2, 3, 4])
end
it "reorders chapters properly when deleting a mid-work chapter" do
chapter1 = work.chapters.first
chapter3 = create(:chapter, :draft, work: work, position: 3, authors: [user.pseuds.first])
chapter4 = create(:chapter, work: work, position: 4, authors: [user.pseuds.first])
delete :destroy, params: { work_id: work.id, id: chapter2.id }
work.reload
posted_chapters = work.chapters_in_order
expect(posted_chapters).to eq([chapter1, chapter4])
expect(posted_chapters.map(&:position)).to eq([1, 3])
all_chapters = work.chapters_in_order(include_drafts: true)
expect(all_chapters).to eq([chapter1, chapter3, chapter4])
expect(all_chapters.map(&:position)).to eq([1, 2, 3])
end
end
context "when work has more than one chapter and one is a draft" do
let!(:chapter2) { create(:chapter, work: work, posted: false, position: 2, authors: [user.pseuds.first]) }
it "updates cached chapter counts" do
expect do
delete :destroy, params: { work_id: work.id, id: chapter2.id }
end.to change { work.number_of_chapters }
.from(2).to(1)
.and avoid_changing { work.number_of_posted_chapters }
end
it "does not update the work's version" do
expect do
delete :destroy, params: { work_id: work.id, id: chapter2.id }
end.to avoid_changing { work.reload.major_version }
.and avoid_changing { work.reload.minor_version }
end
end
context "when work has more than one chapter and all but one are drafts" do
let!(:chapter2) { create(:chapter, work: work, posted: false, position: 2, authors: [user.pseuds.first]) }
it "cannot delete the posted chapter" do
delete :destroy, params: { work_id: work.id, id: work.chapters.first.id }
it_redirects_to_with_error(edit_work_path(work), "You can't delete the only chapter in your work. If you want to delete the work, choose \"Delete Work\".")
end
end
context "when the logged in user is suspended" do
before do
fake_login_known_user(suspended_user)
end
it "errors and redirects to user page" do
delete :destroy, params: { work_id: suspended_users_work.id, id: suspended_users_work_chapter2.id }
expect(flash[:error]).to include("Your account has been suspended")
end
end
context "when the logged in user is banned" do
before do
fake_login_known_user(banned_user)
end
it "gives a notice that the chapter was deleted and redirects to work" do
delete :destroy, params: { work_id: banned_users_work.id, id: banned_users_work_chapter2.id }
it_redirects_to_with_notice(banned_users_work, "The chapter was successfully deleted.")
end
end
end
context "when other user is logged in" do
before do
fake_login
end
it "errors and redirects to work" do
delete :destroy, params: { work_id: work.id, id: work.chapters.first.id }
it_redirects_to_with_error(work_path(work), "Sorry, you don't have permission to access the page you were trying to reach.")
end
end
end
end