require "spec_helper" describe BookmarksController do include LoginMacros include RedirectExpectationHelper def it_redirects_to_user_login it_redirects_to_simple new_user_session_path end describe "new" do context "without javascript" do it "redirects logged out users" do get :new it_redirects_to_user_login end context "when logged in" do it "renders the new form template" do fake_login get :new expect(response).to render_template("new") end end end context "with javascript when logged in" do it "renders the bookmark_form_dynamic form" do fake_login get :new, params: { format: :js }, xhr: true expect(response).to render_template("bookmark_form_dynamic") end end context "denies access for work that isn't visible to user" do subject { get :new, params: { work_id: work } } let(:success) { expect(response).to render_template("new") } let(:success_admin) { 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.") } include_examples "denies access for work that isn't visible to user" end end describe "create" do let(:work) { create(:work) } context "when user is not logged in" do it "redirects to login" do post :create, params: { work_id: work.id } it_redirects_to_user_login end end context "when user is logged in" do let(:user) { create(:user) } let(:pseud) { user.default_pseud } before do fake_login_known_user(user) end context "when pseud doesn't belong to the user" do let(:other_user) { create(:user) } it "fails to bookmark the work" do post :create, params: { work_id: work.id, bookmark: { pseud_id: other_user.default_pseud.id } } it_redirects_to_with_error(root_path, "You can't bookmark with that pseud.") end end context "when user never bookmarked the work before" do shared_examples "all is correct" do it "bookmarks successfully" do post :create, params: { work_id: work.id, bookmark: { pseud_id: pseud.id } } bookmark = assigns(:bookmark) success_msg = "Bookmark was successfully created. It should appear in bookmark listings within the next few minutes." it_redirects_to_with_notice(bookmark_path(bookmark), success_msg) expect(bookmark.bookmarkable_id).to eq(work.id) expect(bookmark.bookmarkable_type).to eq("Work") expect(bookmark.pseud.id).to eq(pseud.id) end end context "when user bookmarks a work" do it_behaves_like "all is correct" end context "when user wants to bookmark a second work" do let(:other_work) { create(:work) } let!(:other_bookmark) { create(:bookmark, bookmarkable: other_work, pseud: pseud) } it_behaves_like "all is correct" end context "when two users want to bookmark the same work" do let(:other_user) { create(:user) } let!(:other_bookmark) { create(:bookmark, bookmarkable: work, pseud: other_user.default_pseud) } it_behaves_like "all is correct" end context "when user wants to bookmark a work with same id as bookmarked for other bookmarkable type" do # no series created yet, all IDs are free let(:series_with_same_id) { create(:series, id: work.id) } let!(:series_bookmark) { create(:bookmark, bookmarkable: series_with_same_id, pseud: pseud) } it_behaves_like "all is correct" end end context "when user bookmarked the work before" do shared_examples "work is already bookmarked by the user" do it "fails to bookmark the work" do post :create, params: { work_id: work.id, bookmark: { pseud_id: pseud.id } } expect(response).to render_template("new") expect(assigns(:bookmark).errors.full_messages).to include "You have already bookmarked that." end end context "when user uses same pseud" do let!(:old_bookmark) { create(:bookmark, bookmarkable: work, pseud: pseud) } it_behaves_like "work is already bookmarked by the user" end context "when user uses different pseud" do let(:other_pseud) { create(:pseud, user: user) } let!(:old_bookmark) { create(:bookmark, bookmarkable: work, pseud: other_pseud) } it_behaves_like "work is already bookmarked by the user" end end context "as a tag wrangler" do let(:user) { create(:tag_wrangler) } let(:pseud) { user.default_pseud } before { fake_login_known_user(user) } it "does not set last wrangling activity when the bookmark has a new tag" do bookmark_attributes = { pseud_id: pseud.id, tag_string: "My special new tag!" } post :create, params: { work_id: work.id, bookmark: bookmark_attributes } expect(user.last_wrangling_activity).to be_nil end end end end describe "edit" do context "with javascript" do let(:bookmark) { create(:bookmark) } it "renders the bookmark_form_dynamic form if logged in" do fake_login_known_user(bookmark.pseud.user) get :edit, params: { id: bookmark.id, format: :js }, xhr: true expect(response).to render_template("bookmark_form_dynamic") end end end describe "update" do context "when user updates old bookmarks created for the same bookmarkable (AO3-5565)" do before do # disable bookmarks validations to simulate previously created bookmarks allow_any_instance_of(Bookmark).to receive(:validate).and_return(true) allow_any_instance_of(Bookmark).to receive(:valid?).and_return(true) fake_login_known_user(bookmark.pseud.user) end let(:user) { create(:user) } let(:pseud) { user.default_pseud } let(:other_pseud) { create(:pseud, user: user) } let!(:bookmark) { create(:bookmark, pseud: pseud, bookmarker_notes: "My first Bookmark") } let!(:bookmark2) { create(:bookmark, bookmarkable_id: bookmark.bookmarkable_id, pseud: other_pseud, bookmarker_notes: "My second Bookmark") } it "first created bookmark can be updated" do put :update, params: { bookmark: { bookmarker_notes: "Updated first bookmark", pseud_id: other_pseud.id }, id: bookmark.id } it_redirects_to_with_notice(bookmark_path(bookmark), "Bookmark was successfully updated.") expect(assigns(:bookmark).bookmarker_notes).to include("Updated first bookmark") expect(assigns(:bookmark).pseud_id).to eq(other_pseud.id) end it "second created bookmark can be updated" do put :update, params: { bookmark: { bookmarker_notes: "Updated second bookmark", pseud_id: other_pseud.id }, id: bookmark2.id } it_redirects_to_with_notice(bookmark_path(bookmark2), "Bookmark was successfully updated.") expect(assigns(:bookmark).bookmarker_notes).to include("Updated second bookmark") expect(assigns(:bookmark).pseud_id).to eq(other_pseud.id) end end end describe "share" do it "returns correct response for bookmark to revealed work" do bookmark = create :bookmark # Assert this bookmark is of an revealed work expect(bookmark.bookmarkable.unrevealed?).to eq(false) fake_login_known_user(bookmark.pseud.user) get :share, params: { id: bookmark.id }, xhr: true expect(response.status).to eq(200) expect(response).to render_template("bookmarks/share") end it "returns a 404 response for bookmark to unrevealed work" do unrevealed_collection = create :unrevealed_collection unrevealed_work = create :work, collections: [unrevealed_collection] unrevealed_bookmark = create :bookmark, bookmarkable_id: unrevealed_work.id # Assert this bookmark is of an unrevealed work expect(unrevealed_bookmark.bookmarkable.unrevealed?).to eq(true) fake_login_known_user(unrevealed_bookmark.pseud.user) get :share, params: { id: unrevealed_bookmark.id }, xhr: true expect(response.status).to eq(404) end it "redirects to referer with an error for non-ajax warnings requests" do bookmark = create(:bookmark) fake_login_known_user(bookmark.pseud.user) get :share, params: { id: bookmark.id } it_redirects_to_with_error(root_path, "Sorry, you need to have JavaScript enabled for this.") end end describe "index" do let!(:external_work_bookmark) { create(:external_work_bookmark) } let!(:series_bookmark) { create(:series_bookmark) } let!(:work_bookmark) { create(:bookmark) } context "with external_work_id parameters" do it "loads the external work as the bookmarkable" do params = { external_work_id: external_work_bookmark.bookmarkable.id } get :index, params: params expect(assigns(:bookmarkable)).to eq(external_work_bookmark.bookmarkable) end end context "with user_id parameters" do context "when user_id does not exist" do it "raises a RecordNotFound error" do params = { user_id: "nobody" } expect { get :index, params: params }.to raise_error( ActiveRecord::RecordNotFound, "Couldn't find user named 'nobody'" ) end end context "when user_id exists" do context "when pseud_id does not exist" do it "raises a RecordNotFound error for the pseud" do params = { user_id: work_bookmark.pseud.user, pseud_id: "nobody" } expect { get :index, params: params }.to raise_error( ActiveRecord::RecordNotFound, "Couldn't find pseud named 'nobody'" ) end end end end context "with tag_id parameters" do let(:tag) { create(:fandom) } let(:merger) { create(:fandom, merger_id: canonical.id) } let(:canonical) { create(:canonical_fandom) } context "when tag_id does not exist" do it "raises a RecordNotFound error" do params = { tag_id: "nothingness" } expect { get :index, params: params }.to raise_error( ActiveRecord::RecordNotFound, "Couldn't find tag named 'nothingness'" ) end end context "when tag_id is not canonical" do context "when tag_id is a synonym" do it "redirects to the canonical's tag_bookmarks_path" do params = { tag_id: merger } get :index, params: params expect(response).to redirect_to(tag_bookmarks_path(canonical)) end end context "when tag_id is not a synonym" do it "redirects to tag_path" do params = { tag_id: tag } get :index, params: params expect(response).to redirect_to(tag_path(tag)) end end end end context "without caching" do before do AdminSetting.first.update_attribute(:enable_test_caching, false) end it "returns work bookmarks" do get :index expect(assigns(:bookmarks)).to include(work_bookmark) end it "does not return external work bookmarks" do get :index expect(assigns(:bookmarks)).not_to include(external_work_bookmark) end it "does not return series bookmarks" do get :index expect(assigns(:bookmarks)).not_to include(series_bookmark) end it "returns the result with new bookmarks the second time" do get :index expect(assigns(:bookmarks)).to include(work_bookmark) work_bookmark2 = create(:bookmark) get :index expect(assigns(:bookmarks)).to include(work_bookmark) expect(assigns(:bookmarks)).to include(work_bookmark2) end end context "with caching", bookmark_search: true do before do AdminSetting.first.update_attribute(:enable_test_caching, true) run_all_indexing_jobs end it "returns work bookmarks" do get :index expect(assigns(:bookmarks)).to include(work_bookmark) end it "returns external work bookmarks" do get :index expect(assigns(:bookmarks)).to include(external_work_bookmark) end it "returns series bookmarks" do get :index expect(assigns(:bookmarks)).to include(series_bookmark) end it "returns the same result the second time when a new bookmark is created within the expiration time" do get :index expect(assigns(:bookmarks)).to include(external_work_bookmark) expect(assigns(:bookmarks)).to include(series_bookmark) expect(assigns(:bookmarks)).to include(work_bookmark) work_bookmark2 = create(:bookmark) run_all_indexing_jobs get :index expect(assigns(:bookmarks)).to include(external_work_bookmark) expect(assigns(:bookmarks)).to include(series_bookmark) expect(assigns(:bookmarks)).to include(work_bookmark) expect(assigns(:bookmarks)).not_to include(work_bookmark2) end end context "denies access for work that isn't visible to user" do subject { get :index, params: { work_id: work } } let(:success) { expect(response).to render_template("index") } let(:success_admin) { success } include_examples "denies access for work that isn't visible to user" end context "denies access for restricted work to guest" do let(:work) { create(:work, restricted: true) } it "redirects with an error" do get :index, params: { work_id: work } it_redirects_to_with_error(root_path, "Sorry, you don't have permission to access the page you were trying to reach. Please log in.") end end end describe "show" do let(:chaptered_work) { create(:work, title: "Cool title") } let(:chapter2) { create(:chapter, work: chaptered_work, position: 2, title: "Second title") } let(:bookmark) { create(:bookmark, bookmarkable_id: chaptered_work.id) } context "when logged in" do it "returns a bookmark on a public multi-chapter work" do fake_login_known_user(bookmark.pseud.user) get :show, params: { id: bookmark } expect(response).to have_http_status(:success) expect(assigns(:bookmark)).to eq(bookmark) end end end end