From cb17e839dc6ad18bfa1082448a0093ed2792bfb9 Mon Sep 17 00:00:00 2001 From: Tal Hayon Date: Mon, 13 Nov 2017 07:38:28 +0200 Subject: [PATCH 1/5] AO3-4862 Extended work controller test coverage --- features/works/work_edit_multiple.feature | 4 +- features/works/work_edit_tags.feature | 17 +++ .../works/default_rails_actions_spec.rb | 123 +++++++++++++++++- spec/controllers/works/miscellaneous_spec.rb | 69 ++++++++++ .../works/multiple_actions_spec.rb | 20 ++- 5 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 spec/controllers/works/miscellaneous_spec.rb diff --git a/features/works/work_edit_multiple.feature b/features/works/work_edit_multiple.feature index 1c6f75f83e0..83f7035054d 100644 --- a/features/works/work_edit_multiple.feature +++ b/features/works/work_edit_multiple.feature @@ -39,6 +39,8 @@ Feature: Edit Multiple Works And I should see "Edit Multiple Works" And I should see "All" And I should see "None" + And I should not see "Pristine" + And I should not see "Naruto" When I select "Glorious" for editing And I select "Excellent" for editing And I press "Edit" @@ -46,7 +48,7 @@ Feature: Edit Multiple Works And I should see "Glorious" And I should see "Excellent" When I set the fandom to "Random" - And I press "Update All Works" + And I press "Update All Works" Then I should see "Your edits were put through" And I should see "Random" And I should not see "SGA" diff --git a/features/works/work_edit_tags.feature b/features/works/work_edit_tags.feature index 3d0bfc1c468..61fadd443f7 100644 --- a/features/works/work_edit_tags.feature +++ b/features/works/work_edit_tags.feature @@ -103,3 +103,20 @@ Feature: Edit tags on a work And I press "Preview" Then I should see the page title "Preview Work Tags" And I should see "Fandom: exclusive fandom" + + Scenario: User can preview a work's tags and return to edit them + Given I have loaded the "tags" fixture + And I am logged in as a random user + And I post the work "Work 1" + And I view the work "Work 1" + And I follow "Edit Tags" + And I fill in "Additional Tags" with "classic" + When I press "Preview" + Then I should see "Preview Tags" + And I should not see the default work content + When "AO3-3455" is fixed + # And I should see "classic" + When I press "Edit" + Then I should see "Edit Work Tags" + When "AO3-3455" is fixed + # And I should see "classic" diff --git a/spec/controllers/works/default_rails_actions_spec.rb b/spec/controllers/works/default_rails_actions_spec.rb index 894093c86a9..74b21c05cb8 100644 --- a/spec/controllers/works/default_rails_actions_spec.rb +++ b/spec/controllers/works/default_rails_actions_spec.rb @@ -251,6 +251,42 @@ def call_with_params(params) end end + describe "edit" do + let(:user) { create(:user) } + let(:work) { + create(:work, authors: [user.default_pseud], posted: true) + } + + before do + fake_login_known_user(user) + end + + it "redirects to orphan work page if only author is being removed" do + get :edit, params: { id: work.id, remove: "me" } + expect(response).to redirect_to controller: 'orphans', action: 'new', work_id: work.id + end + end + + context "destroy" do + let(:user) { create(:user) } + let!(:work) { + create(:work, authors: [user.default_pseud], posted: true) + } + + before do + fake_login_known_user(user) + end + + it "sets flash message in case of error" do + allow_any_instance_of(Work).to receive(:destroy).and_raise("Cannot save") + + delete :destroy, params: { id: work } + expect(flash[:error]).to eq("We couldn't delete that right now, sorry! Please try again later.") + + allow_any_instance_of(Work).to receive(:destroy).and_call_original + end + end + describe "create" do let(:user) { create(:user) } @@ -290,6 +326,32 @@ def call_with_params(params) include "Invalid creator: Could not find a pseud *impossible*." end + xit "renders new if edit is pressed" do + work_attributes = attributes_for(:work) + post :create, params: { work: work_attributes, edit_button: true } + expect(response).to render_template("new") + end + + context "cancel button is pressed" do + before do + work_attributes = attributes_for(:work) + post :create, params: { work: work_attributes, cancel_button: true } + end + + it "redirects to user page with notice" do + it_redirects_to_with_notice(@user, "New work posting canceled.") + end + end + + it "renders the co-author view if a work has invalid pseuds" do + allow_any_instance_of(Work).to receive(:invalid_pseuds).and_return(@user.pseuds.first) + work_attributes = attributes_for(:work) + post :create, params: { work: work_attributes } + expect(response).to render_template("new") + expect(assigns[:work].errors.full_messages).to \ + include "Invalid creator: Could not find a pseud *impossible*." + end + it "renders new if the work has ambiguous pseuds" do create(:pseud, name: "ambiguous") create(:pseud, name: "ambiguous") @@ -446,6 +508,10 @@ def call_with_params(params) AdminSetting.first.update_attribute(:enable_test_caching, false) end + after do + allow(controller).to receive(:use_caching?).and_call_original + end + it "returns the result with different works the second time" do get :index expect(assigns(:works)).to include(@work) @@ -460,6 +526,10 @@ def call_with_params(params) AdminSetting.first.update_attribute(:enable_test_caching, true) end + after do + allow(controller).to receive(:use_caching?).and_call_original + end + context "with NO owner tag" do it "returns the same result the second time when a new work is created within the expiration time" do get :index @@ -489,6 +559,23 @@ def call_with_params(params) expect(assigns(:works).items).not_to include(@work) end + context "when disabling filtering" do + before do + allow(controller).to receive(:fetch_admin_settings).and_return(true) + admin_settings = AdminSetting.new(disable_filtering: true) + controller.instance_variable_set("@admin_settings", admin_settings) + end + + it "should show results when filters are disabled" do + get :index, params: { tag_id: @fandom.name } + expect(assigns(:works)).to include(@work) + end + + after do + allow(controller).to receive(:fetch_admin_settings).and_call_original + end + end + context "with restricted works" do before do @work2 = create(:work, fandom_string: @fandom.name, restricted: true) @@ -621,7 +708,7 @@ def call_with_params(params) describe "update" do let(:update_user) { create(:user) } let(:update_work) { - work = create(:work, authors: [update_user.default_pseud]) + work = create(:work, authors: [update_user.default_pseud], posted: true) create(:chapter, work: work) work } @@ -678,6 +765,40 @@ def call_with_params(params) end end + it "displays chapter errors if chapter is invalid" do + allow_any_instance_of(Chapter).to receive(:save).and_return(false) + chapter_error = ["Test Error"] + allow_any_instance_of(Chapter).to receive(:errors).and_return(chapter_error) + allow_any_instance_of(Chapter).to receive(:valid?).and_return(false) + + attrs = { title: "New Work Title" } + put :update, params: { id: update_work.id, work: attrs } + expect(assigns(:work).errors[:base]).to eq(chapter_error) + + allow_any_instance_of(Chapter).to receive(:valid?).and_call_original + allow_any_instance_of(Chapter).to receive(:errors).and_call_original + allow_any_instance_of(Chapter).to receive(:save).and_call_original + end + + context "where the coauthor is being updated" do + let(:new_coauthor) { create(:user) } + let(:params) do + { + work: { title: "New title" }, + pseud: { byline: new_coauthor.login }, + id: update_work.id + } + end + it "should update coauthors for each chapter when the work is updated" do + put :update, params: params + updated_work = Work.find(update_work.id) + expect(updated_work.pseuds).to include new_coauthor.default_pseud + updated_work.chapters.each do |c| + expect(c.pseuds).to include new_coauthor.default_pseud + end + end + end + it "allows the user to invite co-creators" do co_creator = create(:user) co_creator.preference.update!(allow_cocreator: true) diff --git a/spec/controllers/works/miscellaneous_spec.rb b/spec/controllers/works/miscellaneous_spec.rb new file mode 100644 index 00000000000..a1066f79b5f --- /dev/null +++ b/spec/controllers/works/miscellaneous_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true +require "spec_helper" + +describe WorksController do + include LoginMacros + include RedirectExpectationHelper + + let(:user) { create(:user) } + let!(:work) { create(:work, authors: [user.default_pseud], posted: true) } + + context "reindex" do + context "if the user is an admin or tag wrangler" do + let(:admin) { create(:admin) } + + before do + fake_login_admin(admin) + end + + it "should queue the work for reindex" do + expect(RedisSearchIndexQueue).to receive(:queue_works) + post :reindex, params: { id: work } + end + it "should redirect to the root path and display a success message" do + post :reindex, params: { id: work } + it_redirects_to_with_notice(root_path, "Work queued to be reindexed") + end + end + + context "if the user is not an admin" do + it "should redirect to the root path and display an error" do + fake_login + post :reindex, params: { id: work } + it_redirects_to_with_error(root_path, "Sorry, you don't have permission to perform this action.") + end + end + end + + context "update_tags" do + before do + fake_login_known_user(user) + end + + it "should render edit tags when there are invalid tags" do + allow_any_instance_of(Work).to receive(:invalid_tags).and_return([create(:unsorted_tag)]) + + patch :update_tags, params: { id: work } + expect(response).to render_template "edit_tags" + + allow_any_instance_of(Work).to receive(:invalid_tags).and_call_original + end + + it "should throw error when there are invalid tags and trying to preview" do + allow_any_instance_of(Work).to receive(:invalid_tags).and_return([create(:unsorted_tag)]) + + expect {patch :update_tags, params: { id: work, preview_button: true } }.to raise_error UncaughtThrowError + + allow_any_instance_of(Work).to receive(:invalid_tags).and_call_original + end + end + + context "preview_tags" do + it "should render preview tags" do + fake_login_known_user(user) + + get :preview_tags, params: { id: work } + expect(response).to render_template "preview_tags" + end + end +end diff --git a/spec/controllers/works/multiple_actions_spec.rb b/spec/controllers/works/multiple_actions_spec.rb index eaa7951fb26..597d9391da7 100644 --- a/spec/controllers/works/multiple_actions_spec.rb +++ b/spec/controllers/works/multiple_actions_spec.rb @@ -243,6 +243,25 @@ end end + context "when work parameters are invalid" do + let(:work_params) { + { + work: { + summary: "a" * (ArchiveConfig.SUMMARY_MAX + 1), + } + } + } + + before do + put :update_multiple, params: params + end + + xit "redirects to the user multiple work path with an error" do + it_redirects_to_with_error(edit_multiple_user_works_path(multiple_works_user), + flash[:error]).to match("The work Work 1 could not be edited: Summary must be less than") + end + end + context "updating creators" do let(:pseud_to_invite) do user = FactoryBot.create(:user) @@ -251,7 +270,6 @@ end let(:other_editor_pseud) { create(:pseud, user: multiple_works_user) } - let(:work_params) { { work: { From 29abeca6f48f1bd9adc6d30cc92badb6e17c33db Mon Sep 17 00:00:00 2001 From: Cesy Date: Sat, 25 Jul 2020 09:56:05 +0100 Subject: [PATCH 2/5] AO3-4862 Fixing test failures --- features/works/work_edit_multiple.feature | 2 - features/works/work_edit_tags.feature | 5 +- .../works/default_rails_actions_spec.rb | 159 +++++++----------- spec/controllers/works/miscellaneous_spec.rb | 69 -------- .../works/multiple_actions_spec.rb | 19 --- spec/controllers/works/tags_spec.rb | 20 +++ 6 files changed, 84 insertions(+), 190 deletions(-) delete mode 100644 spec/controllers/works/miscellaneous_spec.rb create mode 100644 spec/controllers/works/tags_spec.rb diff --git a/features/works/work_edit_multiple.feature b/features/works/work_edit_multiple.feature index 83f7035054d..b054b97fb53 100644 --- a/features/works/work_edit_multiple.feature +++ b/features/works/work_edit_multiple.feature @@ -39,8 +39,6 @@ Feature: Edit Multiple Works And I should see "Edit Multiple Works" And I should see "All" And I should see "None" - And I should not see "Pristine" - And I should not see "Naruto" When I select "Glorious" for editing And I select "Excellent" for editing And I press "Edit" diff --git a/features/works/work_edit_tags.feature b/features/works/work_edit_tags.feature index 61fadd443f7..84d76478ce3 100644 --- a/features/works/work_edit_tags.feature +++ b/features/works/work_edit_tags.feature @@ -115,8 +115,7 @@ Feature: Edit tags on a work Then I should see "Preview Tags" And I should not see the default work content When "AO3-3455" is fixed - # And I should see "classic" + And I should see "classic" within "Additional Tags" When I press "Edit" Then I should see "Edit Work Tags" - When "AO3-3455" is fixed - # And I should see "classic" + And I should see "classic" within "Additional Tags" diff --git a/spec/controllers/works/default_rails_actions_spec.rb b/spec/controllers/works/default_rails_actions_spec.rb index 74b21c05cb8..abe39c4cb51 100644 --- a/spec/controllers/works/default_rails_actions_spec.rb +++ b/spec/controllers/works/default_rails_actions_spec.rb @@ -253,9 +253,7 @@ def call_with_params(params) describe "edit" do let(:user) { create(:user) } - let(:work) { - create(:work, authors: [user.default_pseud], posted: true) - } + let!(:work) { create(:work, authors: [user.default_pseud]) } before do fake_login_known_user(user) @@ -263,15 +261,13 @@ def call_with_params(params) it "redirects to orphan work page if only author is being removed" do get :edit, params: { id: work.id, remove: "me" } - expect(response).to redirect_to controller: 'orphans', action: 'new', work_id: work.id + expect(response).to redirect_to controller: "orphans", action: "new", work_id: work.id end end - context "destroy" do + describe "destroy" do let(:user) { create(:user) } - let!(:work) { - create(:work, authors: [user.default_pseud], posted: true) - } + let!(:work) { create(:work, authors: [user.default_pseud]) } before do fake_login_known_user(user) @@ -282,8 +278,6 @@ def call_with_params(params) delete :destroy, params: { id: work } expect(flash[:error]).to eq("We couldn't delete that right now, sorry! Please try again later.") - - allow_any_instance_of(Work).to receive(:destroy).and_call_original end end @@ -326,32 +320,23 @@ def call_with_params(params) include "Invalid creator: Could not find a pseud *impossible*." end - xit "renders new if edit is pressed" do - work_attributes = attributes_for(:work) + it "renders new if edit_button params set" do + work_attributes = attributes_for(:work).except(:posted) post :create, params: { work: work_attributes, edit_button: true } expect(response).to render_template("new") end - context "cancel button is pressed" do + context "with cancel_button params" do before do work_attributes = attributes_for(:work) post :create, params: { work: work_attributes, cancel_button: true } end it "redirects to user page with notice" do - it_redirects_to_with_notice(@user, "New work posting canceled.") + it_redirects_to_with_notice(user, "New work posting canceled.") end end - it "renders the co-author view if a work has invalid pseuds" do - allow_any_instance_of(Work).to receive(:invalid_pseuds).and_return(@user.pseuds.first) - work_attributes = attributes_for(:work) - post :create, params: { work: work_attributes } - expect(response).to render_template("new") - expect(assigns[:work].errors.full_messages).to \ - include "Invalid creator: Could not find a pseud *impossible*." - end - it "renders new if the work has ambiguous pseuds" do create(:pseud, name: "ambiguous") create(:pseud, name: "ambiguous") @@ -471,18 +456,16 @@ def call_with_params(params) end describe "index" do - before do - @fandom = create(:canonical_fandom) - @work = create(:work, fandom_string: @fandom.name) - end + let(:fandom) { create(:canonical_fandom) } + let!(:work) { create(:work, fandom_string: fandom.name) } it "returns the work" do get :index - expect(assigns(:works)).to include(@work) + expect(assigns(:works)).to include(work) end it "sets the fandom when given a fandom id" do - params = { fandom_id: @fandom.id } + params = { fandom_id: fandom.id } get :index, params: params expect(assigns(:fandom)).to eq(@fandom) end @@ -514,14 +497,27 @@ def call_with_params(params) it "returns the result with different works the second time" do get :index - expect(assigns(:works)).to include(@work) + expect(assigns(:works)).to include(work) work2 = create(:work) get :index expect(assigns(:works)).to include(work2) end + + it "when tag is a synonym redirects to the merger's work index" do + noncanonical_fandom = create(:fandom, merger: fandom) + get :index, params: { id: work, tag_id: noncanonical_fandom.name } + expect(response).to redirect_to(tag_works_path(fandom)) + end + + it "when tag is a synonym when collection is specified redirects to the merger's collection works index" do + noncanonical_fandom = create(:fandom, canonical: false, merger: fandom) + collection = create(:collection) + get :index, params: { id: work, tag_id: noncanonical_fandom.name, collection_id: collection } + expect(response).to redirect_to(collection_tag_works_path(collection, fandom)) + end end - describe "with caching" do + context "with caching" do before do AdminSetting.first.update_attribute(:enable_test_caching, true) end @@ -533,7 +529,7 @@ def call_with_params(params) context "with NO owner tag" do it "returns the same result the second time when a new work is created within the expiration time" do get :index - expect(assigns(:works)).to include(@work) + expect(assigns(:works)).to include(work) work2 = create(:work) run_all_indexing_jobs get :index @@ -542,61 +538,64 @@ def call_with_params(params) end context "with a valid owner tag" do + let!(:fandom2) { create(:canonical_fandom) } + let!(:work2) { create(:work, fandom_string: fandom2.name) } + before do - @fandom2 = create(:canonical_fandom) - @work2 = create(:work, fandom_string: @fandom2.name) run_all_indexing_jobs end it "only gets works under that tag" do - get :index, params: { tag_id: @fandom.name } - expect(assigns(:works).items).to include(@work) - expect(assigns(:works).items).not_to include(@work2) + get :index, params: { tag_id: fandom.name } + expect(assigns(:works).items).to include(work) + expect(assigns(:works).items).not_to include(work2) end it "shows different results on second page" do - get :index, params: { tag_id: @fandom.name, page: 2 } - expect(assigns(:works).items).not_to include(@work) + get :index, params: { tag_id: fandom.name, page: 2 } + expect(assigns(:works).items).not_to include(work) end - context "when disabling filtering" do + context "when suspend_filter_counts is on" do before do allow(controller).to receive(:fetch_admin_settings).and_return(true) - admin_settings = AdminSetting.new(disable_filtering: true) + AdminSetting.first.update_attribute(:suspend_filter_counts, true) + admin_settings = AdminSetting.first controller.instance_variable_set("@admin_settings", admin_settings) end - it "should show results when filters are disabled" do - get :index, params: { tag_id: @fandom.name } - expect(assigns(:works)).to include(@work) - end - after do allow(controller).to receive(:fetch_admin_settings).and_call_original end + + it "shows the work in the index" do + get :index, params: { tag_id: fandom.name } + expect(assigns(:works)).to include(work) + end end context "with restricted works" do + let!(:work2) { create(:work, fandom_string: fandom.name, restricted: true) } + before do - @work2 = create(:work, fandom_string: @fandom.name, restricted: true) run_all_indexing_jobs end - it "shows restricted works to guests" do - get :index, params: { tag_id: @fandom.name } - expect(assigns(:works).items).to include(@work) - expect(assigns(:works).items).not_to include(@work2) + it "hides them from guests, showing only unrestricted works" do + get :index, params: { tag_id: fandom.name } + expect(assigns(:works).items).to include(work) + expect(assigns(:works).items).not_to include(work2) end end context "when tag is a synonym" do - let(:fandom_synonym) { create(:fandom, merger: @fandom) } + let(:fandom_synonym) { create(:fandom, merger: fandom) } it "redirects to the merger's work index" do params = { tag_id: fandom_synonym.name } get :index, params: params - it_redirects_to tag_works_path(@fandom) + it_redirects_to tag_works_path(fandom) end context "when collection is specified" do @@ -605,7 +604,7 @@ def call_with_params(params) it "redirects to the merger's collection works index" do params = { tag_id: fandom_synonym.name, collection_id: collection.name } get :index, params: params - it_redirects_to collection_tag_works_path(collection, @fandom) + it_redirects_to collection_tag_works_path(collection, fandom) end end end @@ -652,7 +651,7 @@ def call_with_params(params) params = { user_id: user.login } get :index, params: params expect(assigns(:works).items).to include(user_work, pseud_work) - expect(assigns(:works).items).not_to include(@work) + expect(assigns(:works).items).not_to include(work) end context "with a valid pseud" do @@ -660,7 +659,7 @@ def call_with_params(params) params = { user_id: user.login, pseud_id: pseud.name } get :index, params: params expect(assigns(:works).items).to include(pseud_work) - expect(assigns(:works).items).not_to include(user_work, @work) + expect(assigns(:works).items).not_to include(user_work, work) end end @@ -669,7 +668,7 @@ def call_with_params(params) params = { user_id: user.login, pseud_id: "nonexistent_pseud" } get :index, params: params expect(assigns(:works).items).to include(user_work, pseud_work) - expect(assigns(:works).items).not_to include(@work) + expect(assigns(:works).items).not_to include(work) end end end @@ -707,11 +706,11 @@ def call_with_params(params) describe "update" do let(:update_user) { create(:user) } - let(:update_work) { - work = create(:work, authors: [update_user.default_pseud], posted: true) + let!(:update_work) do + work = create(:work, authors: [update_user.default_pseud]) create(:chapter, work: work) work - } + end context "when logged in as admin", work_search: false do let(:work) { create(:work) } @@ -737,11 +736,11 @@ def call_with_params(params) end it "doesn't allow the user to add a series that they don't own" do - @series = create(:series) - attrs = { series_attributes: { id: @series.id } } + series = create(:series) + attrs = { series_attributes: { id: series.id } } expect { put :update, params: { id: update_work.id, work: attrs } - }.not_to change { @series.works.all.count } + }.not_to change { series.works.all.count } expect(response).to render_template :edit expect(assigns[:work].errors.full_messages).to \ include("You can't add a work to that series.") @@ -765,40 +764,6 @@ def call_with_params(params) end end - it "displays chapter errors if chapter is invalid" do - allow_any_instance_of(Chapter).to receive(:save).and_return(false) - chapter_error = ["Test Error"] - allow_any_instance_of(Chapter).to receive(:errors).and_return(chapter_error) - allow_any_instance_of(Chapter).to receive(:valid?).and_return(false) - - attrs = { title: "New Work Title" } - put :update, params: { id: update_work.id, work: attrs } - expect(assigns(:work).errors[:base]).to eq(chapter_error) - - allow_any_instance_of(Chapter).to receive(:valid?).and_call_original - allow_any_instance_of(Chapter).to receive(:errors).and_call_original - allow_any_instance_of(Chapter).to receive(:save).and_call_original - end - - context "where the coauthor is being updated" do - let(:new_coauthor) { create(:user) } - let(:params) do - { - work: { title: "New title" }, - pseud: { byline: new_coauthor.login }, - id: update_work.id - } - end - it "should update coauthors for each chapter when the work is updated" do - put :update, params: params - updated_work = Work.find(update_work.id) - expect(updated_work.pseuds).to include new_coauthor.default_pseud - updated_work.chapters.each do |c| - expect(c.pseuds).to include new_coauthor.default_pseud - end - end - end - it "allows the user to invite co-creators" do co_creator = create(:user) co_creator.preference.update!(allow_cocreator: true) diff --git a/spec/controllers/works/miscellaneous_spec.rb b/spec/controllers/works/miscellaneous_spec.rb deleted file mode 100644 index a1066f79b5f..00000000000 --- a/spec/controllers/works/miscellaneous_spec.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true -require "spec_helper" - -describe WorksController do - include LoginMacros - include RedirectExpectationHelper - - let(:user) { create(:user) } - let!(:work) { create(:work, authors: [user.default_pseud], posted: true) } - - context "reindex" do - context "if the user is an admin or tag wrangler" do - let(:admin) { create(:admin) } - - before do - fake_login_admin(admin) - end - - it "should queue the work for reindex" do - expect(RedisSearchIndexQueue).to receive(:queue_works) - post :reindex, params: { id: work } - end - it "should redirect to the root path and display a success message" do - post :reindex, params: { id: work } - it_redirects_to_with_notice(root_path, "Work queued to be reindexed") - end - end - - context "if the user is not an admin" do - it "should redirect to the root path and display an error" do - fake_login - post :reindex, params: { id: work } - it_redirects_to_with_error(root_path, "Sorry, you don't have permission to perform this action.") - end - end - end - - context "update_tags" do - before do - fake_login_known_user(user) - end - - it "should render edit tags when there are invalid tags" do - allow_any_instance_of(Work).to receive(:invalid_tags).and_return([create(:unsorted_tag)]) - - patch :update_tags, params: { id: work } - expect(response).to render_template "edit_tags" - - allow_any_instance_of(Work).to receive(:invalid_tags).and_call_original - end - - it "should throw error when there are invalid tags and trying to preview" do - allow_any_instance_of(Work).to receive(:invalid_tags).and_return([create(:unsorted_tag)]) - - expect {patch :update_tags, params: { id: work, preview_button: true } }.to raise_error UncaughtThrowError - - allow_any_instance_of(Work).to receive(:invalid_tags).and_call_original - end - end - - context "preview_tags" do - it "should render preview tags" do - fake_login_known_user(user) - - get :preview_tags, params: { id: work } - expect(response).to render_template "preview_tags" - end - end -end diff --git a/spec/controllers/works/multiple_actions_spec.rb b/spec/controllers/works/multiple_actions_spec.rb index 597d9391da7..34ef361926f 100644 --- a/spec/controllers/works/multiple_actions_spec.rb +++ b/spec/controllers/works/multiple_actions_spec.rb @@ -243,25 +243,6 @@ end end - context "when work parameters are invalid" do - let(:work_params) { - { - work: { - summary: "a" * (ArchiveConfig.SUMMARY_MAX + 1), - } - } - } - - before do - put :update_multiple, params: params - end - - xit "redirects to the user multiple work path with an error" do - it_redirects_to_with_error(edit_multiple_user_works_path(multiple_works_user), - flash[:error]).to match("The work Work 1 could not be edited: Summary must be less than") - end - end - context "updating creators" do let(:pseud_to_invite) do user = FactoryBot.create(:user) diff --git a/spec/controllers/works/tags_spec.rb b/spec/controllers/works/tags_spec.rb new file mode 100644 index 00000000000..2c11d26c5fe --- /dev/null +++ b/spec/controllers/works/tags_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe WorksController do + include LoginMacros + include RedirectExpectationHelper + + let(:user) { create(:user) } + let(:work) { create(:work, authors: [user.default_pseud]) } + + describe "preview_tags" do + it "renders preview tags" do + fake_login_known_user(user) + + get :preview_tags, params: { id: work } + expect(response).to render_template "preview_tags" + end + end +end From 91a0c8dc6bbf2d2771acbdb3fd837d11ffc5faab Mon Sep 17 00:00:00 2001 From: Bilka Date: Sat, 1 Aug 2026 14:41:58 +0200 Subject: [PATCH 3/5] AO3-4862 Clean up preview tags tests --- features/step_definitions/work_steps.rb | 8 ----- features/works/work_edit_tags.feature | 22 ++++---------- spec/controllers/works/tags_spec.rb | 31 ++++++++++++++++---- spec/controllers/works/updating_tags_spec.rb | 28 ------------------ 4 files changed, 30 insertions(+), 59 deletions(-) delete mode 100644 spec/controllers/works/updating_tags_spec.rb diff --git a/features/step_definitions/work_steps.rb b/features/step_definitions/work_steps.rb index ca2dea38284..e98e7724420 100644 --- a/features/step_definitions/work_steps.rb +++ b/features/step_definitions/work_steps.rb @@ -392,14 +392,6 @@ step "the periodic tag count task is run" end -Then /^I should see the default work content$/ do - page.should have_content(DEFAULT_CONTENT) -end - -Then /^I should not see the default work content$/ do - page.should_not have_content(DEFAULT_CONTENT) -end - When /^I fill in basic work tags$/ do select(DEFAULT_RATING, from: "Rating") fill_in("Fandoms", with: DEFAULT_FANDOM) diff --git a/features/works/work_edit_tags.feature b/features/works/work_edit_tags.feature index 84d76478ce3..b4ba998782f 100644 --- a/features/works/work_edit_tags.feature +++ b/features/works/work_edit_tags.feature @@ -95,7 +95,7 @@ Feature: Edit tags on a work Then I should see the page title "Work 1 -" And I should see "Fandom: testing" - Scenario: Preview edit tags + Scenario: Preview edit tags and return to edit them Given I am logged in as "regularuser" And I post the work "Some Work" And I follow "Edit Tags" @@ -103,19 +103,7 @@ Feature: Edit tags on a work And I press "Preview" Then I should see the page title "Preview Work Tags" And I should see "Fandom: exclusive fandom" - - Scenario: User can preview a work's tags and return to edit them - Given I have loaded the "tags" fixture - And I am logged in as a random user - And I post the work "Work 1" - And I view the work "Work 1" - And I follow "Edit Tags" - And I fill in "Additional Tags" with "classic" - When I press "Preview" - Then I should see "Preview Tags" - And I should not see the default work content - When "AO3-3455" is fixed - And I should see "classic" within "Additional Tags" - When I press "Edit" - Then I should see "Edit Work Tags" - And I should see "classic" within "Additional Tags" + And I should see "Preview Tags" + When I press "Edit" + Then I should see "Edit Work Tags" + And the "Fandoms" field should contain "exclusive fandom" diff --git a/spec/controllers/works/tags_spec.rb b/spec/controllers/works/tags_spec.rb index 2c11d26c5fe..6530042c373 100644 --- a/spec/controllers/works/tags_spec.rb +++ b/spec/controllers/works/tags_spec.rb @@ -1,17 +1,36 @@ -# frozen_string_literal: true - require "spec_helper" describe WorksController do include LoginMacros include RedirectExpectationHelper - let(:user) { create(:user) } - let(:work) { create(:work, authors: [user.default_pseud]) } + describe "POST #update_tags" do + let(:work) { create(:work) } + let!(:language) { create(:language) } + + shared_examples "can update work tags and language" do + it "updates the work and redirects with notice" do + post :update_tags, params: { + id: work, work: { relationship_string: "kronfaumei", language_id: language.id } + } + it_redirects_to_with_notice(work_path(work), "Work was successfully updated.") + expect(work.reload.relationship_string).to eq("kronfaumei") + expect(work.language).to eq(language) + end + end + + context "when logged in as the work creator" do + before { fake_login_known_user(work.users.first) } + + it_behaves_like "can update work tags and language" + end + end + + describe "GET #preview_tags" do + let(:work) { create(:work) } - describe "preview_tags" do it "renders preview tags" do - fake_login_known_user(user) + fake_login_known_user(work.users.first) get :preview_tags, params: { id: work } expect(response).to render_template "preview_tags" diff --git a/spec/controllers/works/updating_tags_spec.rb b/spec/controllers/works/updating_tags_spec.rb deleted file mode 100644 index 16a2f631dc6..00000000000 --- a/spec/controllers/works/updating_tags_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require "spec_helper" - -describe WorksController do - include LoginMacros - include RedirectExpectationHelper - - describe "POST #update_tags" do - let(:work) { create(:work) } - let!(:language) { create(:language) } - - shared_examples "can update work tags and language" do - it "updates the work and redirects with notice" do - post :update_tags, params: { - id: work, work: { relationship_string: "kronfaumei", language_id: language.id } - } - it_redirects_to_with_notice(work_path(work), "Work was successfully updated.") - expect(work.reload.relationship_string).to eq("kronfaumei") - expect(work.language).to eq(language) - end - end - - context "when logged in as the work creator" do - before { fake_login_known_user(work.users.first) } - - it_behaves_like "can update work tags and language" - end - end -end From a63105586053af4f94829891f229decb9cccdf30 Mon Sep 17 00:00:00 2001 From: Bilka Date: Sat, 1 Aug 2026 15:07:23 +0200 Subject: [PATCH 4/5] AO3-4862 Remove redundant tests --- .../works/default_rails_actions_spec.rb | 126 ++++-------------- .../works/multiple_actions_spec.rb | 1 + 2 files changed, 26 insertions(+), 101 deletions(-) diff --git a/spec/controllers/works/default_rails_actions_spec.rb b/spec/controllers/works/default_rails_actions_spec.rb index abe39c4cb51..070c4b37848 100644 --- a/spec/controllers/works/default_rails_actions_spec.rb +++ b/spec/controllers/works/default_rails_actions_spec.rb @@ -251,51 +251,20 @@ def call_with_params(params) end end - describe "edit" do - let(:user) { create(:user) } - let!(:work) { create(:work, authors: [user.default_pseud]) } - - before do - fake_login_known_user(user) - end - - it "redirects to orphan work page if only author is being removed" do - get :edit, params: { id: work.id, remove: "me" } - expect(response).to redirect_to controller: "orphans", action: "new", work_id: work.id - end - end - - describe "destroy" do - let(:user) { create(:user) } - let!(:work) { create(:work, authors: [user.default_pseud]) } - - before do - fake_login_known_user(user) - end - - it "sets flash message in case of error" do - allow_any_instance_of(Work).to receive(:destroy).and_raise("Cannot save") - - delete :destroy, params: { id: work } - expect(flash[:error]).to eq("We couldn't delete that right now, sorry! Please try again later.") - end - end - describe "create" do let(:user) { create(:user) } before { fake_login_known_user(user) } it "doesn't allow a user to create a work in a series that they don't own" do - @series = create(:series) + series = create(:series) work_attributes = attributes_for(:work).except(:posted) - work_attributes[:series_attributes] = { id: @series.id } - expect { + work_attributes[:series_attributes] = { id: series.id } + expect do post :create, params: { work: work_attributes } - }.not_to change { @series.works.all.count } + end.not_to change { series.works.all.count } expect(response).to render_template :new - expect(assigns[:work].errors.full_messages).to \ - include("You can't add a work to that series.") + expect(assigns[:work].errors.full_messages).to include("You can't add a work to that series.") end it "doesn't allow a user to submit only a pseud that is not theirs" do @@ -320,23 +289,6 @@ def call_with_params(params) include "Invalid creator: Could not find a pseud *impossible*." end - it "renders new if edit_button params set" do - work_attributes = attributes_for(:work).except(:posted) - post :create, params: { work: work_attributes, edit_button: true } - expect(response).to render_template("new") - end - - context "with cancel_button params" do - before do - work_attributes = attributes_for(:work) - post :create, params: { work: work_attributes, cancel_button: true } - end - - it "redirects to user page with notice" do - it_redirects_to_with_notice(user, "New work posting canceled.") - end - end - it "renders new if the work has ambiguous pseuds" do create(:pseud, name: "ambiguous") create(:pseud, name: "ambiguous") @@ -467,7 +419,7 @@ def call_with_params(params) it "sets the fandom when given a fandom id" do params = { fandom_id: fandom.id } get :index, params: params - expect(assigns(:fandom)).to eq(@fandom) + expect(assigns(:fandom)).to eq(fandom) end describe "when the fandom id is invalid" do @@ -482,19 +434,15 @@ def call_with_params(params) it "returns the work" do params = { fandom_id: nil } get :index, params: params - expect(assigns(:works)).to include(@work) + expect(assigns(:works)).to include(work) end end - describe "without caching" do + context "without caching" do before do AdminSetting.first.update_attribute(:enable_test_caching, false) end - after do - allow(controller).to receive(:use_caching?).and_call_original - end - it "returns the result with different works the second time" do get :index expect(assigns(:works)).to include(work) @@ -502,19 +450,6 @@ def call_with_params(params) get :index expect(assigns(:works)).to include(work2) end - - it "when tag is a synonym redirects to the merger's work index" do - noncanonical_fandom = create(:fandom, merger: fandom) - get :index, params: { id: work, tag_id: noncanonical_fandom.name } - expect(response).to redirect_to(tag_works_path(fandom)) - end - - it "when tag is a synonym when collection is specified redirects to the merger's collection works index" do - noncanonical_fandom = create(:fandom, canonical: false, merger: fandom) - collection = create(:collection) - get :index, params: { id: work, tag_id: noncanonical_fandom.name, collection_id: collection } - expect(response).to redirect_to(collection_tag_works_path(collection, fandom)) - end end context "with caching" do @@ -522,10 +457,6 @@ def call_with_params(params) AdminSetting.first.update_attribute(:enable_test_caching, true) end - after do - allow(controller).to receive(:use_caching?).and_call_original - end - context "with NO owner tag" do it "returns the same result the second time when a new work is created within the expiration time" do get :index @@ -556,24 +487,6 @@ def call_with_params(params) expect(assigns(:works).items).not_to include(work) end - context "when suspend_filter_counts is on" do - before do - allow(controller).to receive(:fetch_admin_settings).and_return(true) - AdminSetting.first.update_attribute(:suspend_filter_counts, true) - admin_settings = AdminSetting.first - controller.instance_variable_set("@admin_settings", admin_settings) - end - - after do - allow(controller).to receive(:fetch_admin_settings).and_call_original - end - - it "shows the work in the index" do - get :index, params: { tag_id: fandom.name } - expect(assigns(:works)).to include(work) - end - end - context "with restricted works" do let!(:work2) { create(:work, fandom_string: fandom.name, restricted: true) } @@ -586,7 +499,6 @@ def call_with_params(params) expect(assigns(:works).items).to include(work) expect(assigns(:works).items).not_to include(work2) end - end context "when tag is a synonym" do @@ -706,7 +618,7 @@ def call_with_params(params) describe "update" do let(:update_user) { create(:user) } - let!(:update_work) do + let(:update_work) do work = create(:work, authors: [update_user.default_pseud]) create(:chapter, work: work) work @@ -738,12 +650,11 @@ def call_with_params(params) it "doesn't allow the user to add a series that they don't own" do series = create(:series) attrs = { series_attributes: { id: series.id } } - expect { + expect do put :update, params: { id: update_work.id, work: attrs } - }.not_to change { series.works.all.count } + end.not_to change { series.works.all.count } expect(response).to render_template :edit - expect(assigns[:work].errors.full_messages).to \ - include("You can't add a work to that series.") + expect(assigns(:work).errors.full_messages).to include("You can't add a work to that series.") end it "redirects to the edit page if the work could not be saved" do @@ -1143,5 +1054,18 @@ def call_with_params(params) .to raise_exception(ActiveRecord::RecordNotFound) end end + + context "when the work deletion errors out" do + before do + allow_any_instance_of(Work).to receive(:destroy) { raise ActiveRecord::RecordNotDestroyed } + + fake_login_known_user(work.users.first) + end + + it "sets flash message" do + delete :destroy, params: { id: work } + expect(flash[:error]).to eq("We couldn't delete that right now, sorry! Please try again later.") + end + end end end diff --git a/spec/controllers/works/multiple_actions_spec.rb b/spec/controllers/works/multiple_actions_spec.rb index 34ef361926f..eaa7951fb26 100644 --- a/spec/controllers/works/multiple_actions_spec.rb +++ b/spec/controllers/works/multiple_actions_spec.rb @@ -251,6 +251,7 @@ end let(:other_editor_pseud) { create(:pseud, user: multiple_works_user) } + let(:work_params) { { work: { From 73ba27a548f43f65268b8502427dba3e5bc09a88 Mon Sep 17 00:00:00 2001 From: Bilka Date: Sat, 1 Aug 2026 15:39:30 +0200 Subject: [PATCH 5/5] AO3-4862 Add missing tests --- app/controllers/works_controller.rb | 5 ----- features/admins/admin_works.feature | 14 ++++++++++++++ .../works/default_rails_actions_spec.rb | 14 ++++++++++++++ spec/controllers/works/drafts_spec.rb | 2 -- spec/controllers/works/importing_spec.rb | 14 ++++++++++++++ 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/app/controllers/works_controller.rb b/app/controllers/works_controller.rb index b70cdcb3c89..901479ef37c 100755 --- a/app/controllers/works_controller.rb +++ b/app/controllers/works_controller.rb @@ -601,11 +601,6 @@ def post_draft @user = current_user @work = Work.find(params[:id]) - unless @user.is_author_of?(@work) - flash[:error] = ts('You can only post your own works.') - redirect_to(current_user) && return - end - if @work.posted flash[:error] = ts('That work is already posted. Do you want to edit it instead?') redirect_to(edit_user_work_path(@user, @work)) && return diff --git a/features/admins/admin_works.feature b/features/admins/admin_works.feature index 4b97a160970..cd3d88c1ed3 100644 --- a/features/admins/admin_works.feature +++ b/features/admins/admin_works.feature @@ -400,6 +400,20 @@ Feature: Admin Actions for Works, Comments, Series, Bookmarks Then I should see "Deutsch" And I should not see "English" + Scenario: Admin can edit language on drafts + Given basic languages + And I am logged in + And the draft "Wrong Language" + When I am logged in as a "policy_and_abuse" admin + And I view the work "Wrong Language" + And I follow "Edit Work" + When I select "Deutsch" from "Choose a language" + And I press "Save Draft" + Then I should see "Tags were successfully updated." + And I should see "This work is a draft" + And I should see "Deutsch" + But I should not see "English" + Scenario: When admin edits tags and language on works at the same time, both Activities entries are added Given basic languages And the work "Wrong Tags and Language" diff --git a/spec/controllers/works/default_rails_actions_spec.rb b/spec/controllers/works/default_rails_actions_spec.rb index 070c4b37848..fe69e8e2149 100644 --- a/spec/controllers/works/default_rails_actions_spec.rb +++ b/spec/controllers/works/default_rails_actions_spec.rb @@ -387,6 +387,20 @@ def call_with_params(params) end.to raise_error ActiveRecord::RecordNotFound end end + + context "when collection is given but the work is not in the collection" do + let(:unrelated_collection) { create(:collection) } + + before do + work.update!(collections: [create(:collection)]) + end + + it "redirects to the work" do + get :show, params: { id: work.id, collection_id: unrelated_collection.name } + + it_redirects_to work_path(work) + end + end end describe "share" do diff --git a/spec/controllers/works/drafts_spec.rb b/spec/controllers/works/drafts_spec.rb index 81a9a514735..9a91279ffea 100644 --- a/spec/controllers/works/drafts_spec.rb +++ b/spec/controllers/works/drafts_spec.rb @@ -86,8 +86,6 @@ it "should display an error if the current user is not the owner of the specified work" do random_work = create(:draft) put :post_draft, params: { id: random_work.id } - # There is code to return a different message in the action, but it is unreachable using a web request - # as the application_controller redirects the user first it_redirects_to_with_error(work_path(random_work), "Sorry, you don't have permission to access the page you were trying to reach.") end diff --git a/spec/controllers/works/importing_spec.rb b/spec/controllers/works/importing_spec.rb index e6bb82db344..36c9e80dc73 100644 --- a/spec/controllers/works/importing_spec.rb +++ b/spec/controllers/works/importing_spec.rb @@ -18,6 +18,20 @@ expect(flash[:error]).to eq "Did you want to enter a URL?" end + context "when the work doesn't save" do + before do + WebMock.stub_request(:get, /import-site-without-tags/) + .to_return(status: 200, + body: "stubbed response", + headers: {}) + end + + it "shows an error message" do + get :import, params: { urls: "http://import-site-without-tags.net", language_id: "en", work: { fandom_string: "Testing" } } + expect(flash[:error]).to eq "We were only partially able to import this work and couldn't save it. Please review below!" + end + end + it "there is an external author name but importing_for_others is NOT turned on" do params = { urls: "url1, url2",