otwarchive-symphonyarchive/spec/models/search/bookmark_search_form_spec.rb
2026-03-11 22:22:11 +00:00

510 lines
18 KiB
Ruby

# frozen_string_literal: true
require "spec_helper"
describe BookmarkSearchForm, bookmark_search: true do
describe "options" do
it "includes flags set to false" do
bsf = BookmarkSearchForm.new(show_restricted: false, show_private: false)
expect(bsf.options).to include(show_restricted: false)
expect(bsf.options).to include(show_private: false)
end
end
describe "bookmarkable_search_results" do
describe "sorting" do
context "when everything is created at a different time" do
let(:tag) { create(:canonical_fandom) }
let!(:work1) do
travel_to(40.minutes.ago) do
create(:work, title: "One", fandom_string: tag.name)
end
end
let!(:work2) do
travel_to(60.minutes.ago) do
create(:work, title: "Two", fandom_string: tag.name)
end
end
let!(:work3) do
travel_to(50.minutes.ago) do
create(:work, title: "Three", fandom_string: tag.name)
end
end
let!(:bookmark1) do
travel_to(30.minutes.ago) do
create(:bookmark, bookmarkable: work1)
end
end
let!(:bookmark2) do
travel_to(10.minutes.ago) do
create(:bookmark, bookmarkable: work2)
end
end
let!(:bookmark3) do
travel_to(20.minutes.ago) do
create(:bookmark, bookmarkable: work3)
end
end
before { run_all_indexing_jobs }
context "by Date Updated" do
it "returns bookmarkables in the correct order" do
results = BookmarkSearchForm.new(
parent: tag, sort_column: "bookmarkable_date"
).bookmarkable_search_results
expect(results.map(&:title)).to eq %w[One Three Two]
end
it "changes when the work is updated" do
work2.update_attribute(:revised_at, Time.current)
run_all_indexing_jobs
results = BookmarkSearchForm.new(
parent: tag, sort_column: "bookmarkable_date"
).bookmarkable_search_results
expect(results.map(&:title)).to eq %w[Two One Three]
end
end
context "by Date Bookmarked" do
it "returns bookmarkables in the correct order" do
results = BookmarkSearchForm.new(
parent: tag, sort_column: "created_at"
).bookmarkable_search_results
expect(results.map(&:title)).to eq %w[Two Three One]
end
it "changes when a new bookmark is created" do
create(:bookmark, bookmarkable: work1)
run_all_indexing_jobs
results = BookmarkSearchForm.new(
parent: tag, sort_column: "created_at"
).bookmarkable_search_results
expect(results.map(&:title)).to eq %w[One Two Three]
end
end
end
context "when everything is created and updated at the same time" do
before { freeze_time }
let(:tag) { create(:canonical_fandom) }
let!(:work1) { create(:work, fandom_string: tag.name) }
let!(:work2) { create(:work, fandom_string: tag.name) }
let!(:bookmark1) { create(:bookmark, bookmarkable: work1) }
let!(:bookmark2) { create(:bookmark, bookmarkable: work2) }
context "doesn't change tied bookmarkables order on work update" do
it "when sorted by Date Updated" do
search = BookmarkSearchForm.new(
parent: tag, sort_column: "bookmarkable_date"
)
run_all_indexing_jobs
res = search.bookmarkable_search_results.map(&:id)
[work1, work2].each do |work|
work.update!(summary: "Updated")
run_all_indexing_jobs
expect(search.bookmarkable_search_results.map(&:id)).to eq(res)
end
end
it "when sorted by Date Bookmarked" do
run_all_indexing_jobs
search = BookmarkSearchForm.new(
parent: tag, sort_column: "created_at"
)
run_all_indexing_jobs
res = search.bookmarkable_search_results.map(&:id)
[work1, work2].each do |work|
work.update!(summary: "Updated")
run_all_indexing_jobs
expect(search.bookmarkable_search_results.map(&:id)).to eq(res)
end
end
end
end
end
describe "searching" do
context "by work language" do
let(:language) { create(:language, short: "ptBR") }
let(:work1) { create(:work) }
let(:work2) { create(:work, language_id: language.id) }
let!(:bookmark1) { create(:bookmark, bookmarkable: work1) }
let!(:bookmark2) { create(:bookmark, bookmarkable: work2) }
let(:unused_language) { create(:language, name: "unused", short: "tlh") }
before { run_all_indexing_jobs }
it "returns work bookmarkables with specified language" do
# "Work language" dropdown, with short names
results = BookmarkSearchForm.new(language_id: "ptBR").bookmarkable_search_results
expect(results).not_to include work1
expect(results).to include work2
# "Work language" dropdown, with IDs (backward compatibility)
bsf = BookmarkSearchForm.new(language_id: language.id)
expect(bsf.language_id).to eq("ptBR")
results = bsf.bookmarkable_search_results
expect(results).not_to include work1
expect(results).to include work2
# "Any field on work" or "Search within results", with short names
results = BookmarkSearchForm.new(bookmarkable_query: "language_id: ptBR").bookmarkable_search_results
expect(results).not_to include work1
expect(results).to include work2
# "Any field on work" or "Search within results", with IDs (backward compatibility)
bsf = BookmarkSearchForm.new(bookmarkable_query: "language_id: #{language.id} OR language_id: #{unused_language.id}")
expect(bsf.bookmarkable_query).to eq("language_id: ptBR OR language_id: tlh")
results = bsf.bookmarkable_search_results
expect(results).not_to include work1
expect(results).to include work2
end
end
context "using pseud_ids in the bookmarkable query" do
let(:pseud) { create(:pseud) }
let(:collection) { create(:collection) }
let(:work) { create(:work, authors: [pseud], collections: [collection]) }
let(:series) { create(:series, authors: [pseud], works: [work]) }
let!(:bookmark1) { create(:bookmark, bookmarkable: work) }
let!(:bookmark2) { create(:bookmark, bookmarkable: series) }
before { run_all_indexing_jobs }
context "when a work & series are anonymous" do
let(:collection) { create(:anonymous_collection) }
it "doesn't include the work or the series" do
results = BookmarkSearchForm.new(bookmarkable_query: "pseud_ids: #{pseud.id}").bookmarkable_search_results
expect(results).not_to include work
expect(results).not_to include series
end
end
context "when a work & series are unrevealed" do
let(:collection) { create(:unrevealed_collection) }
it "doesn't include the work or the series" do
results = BookmarkSearchForm.new(bookmarkable_query: "pseud_ids: #{pseud.id}").bookmarkable_search_results
expect(results).not_to include work
expect(results).not_to include series
end
end
context "when a work & series are neither unrevealed nor anonymous" do
it "includes the work and the series" do
results = BookmarkSearchForm.new(bookmarkable_query: "pseud_ids: #{pseud.id}").bookmarkable_search_results
expect(results).to include work
expect(results).to include series
end
end
end
context "using user_ids in the bookmarkable query" do
let(:user) { create(:user) }
let(:collection) { create(:collection) }
let(:work) { create(:work, authors: [user.default_pseud], collections: [collection]) }
let(:series) { create(:series, authors: [user.default_pseud], works: [work]) }
let!(:bookmark1) { create(:bookmark, bookmarkable: work) }
let!(:bookmark2) { create(:bookmark, bookmarkable: series) }
before { run_all_indexing_jobs }
context "when a work & series are anonymous" do
let(:collection) { create(:anonymous_collection) }
it "doesn't include the work or the series" do
results = BookmarkSearchForm.new(bookmarkable_query: "user_ids: #{user.id}").bookmarkable_search_results
expect(results).not_to include work
expect(results).not_to include series
end
end
context "when a work & series are unrevealed" do
let(:collection) { create(:unrevealed_collection) }
it "doesn't include the work or the series" do
results = BookmarkSearchForm.new(bookmarkable_query: "user_ids: #{user.id}").bookmarkable_search_results
expect(results).not_to include work
expect(results).not_to include series
end
end
context "when a work & series are neither unrevealed nor anonymous" do
it "includes the work and the series" do
results = BookmarkSearchForm.new(bookmarkable_query: "user_ids: #{user.id}").bookmarkable_search_results
expect(results).to include work
expect(results).to include series
end
end
end
end
end
describe "search_results" do
describe "sorting" do
before { freeze_time }
let!(:work1) { create(:work) }
let!(:work2) { create(:work) }
let(:bookmarker) { create(:user) }
let!(:bookmark1) { create(:bookmark, bookmarkable: work1, pseud: bookmarker.default_pseud) }
let!(:bookmark2) { create(:bookmark, bookmarkable: work2, pseud: bookmarker.default_pseud) }
context "doesn't change tied bookmark order on work/bookmark update" do
%w[created_at bookmarkable_date].each do |sort_column|
it "when sorted by #{sort_column}" do
search = BookmarkSearchForm.new(
bookmarker: bookmarker.default_pseud.name, sort_column: sort_column
)
run_all_indexing_jobs
res = search.search_results.map(&:id)
[work1, work2].each do |work|
work.update!(summary: "Updated")
run_all_indexing_jobs
expect(search.search_results.map(&:id)).to eq(res)
end
[bookmark1, bookmark2].each do |bookmark|
bookmark.update!(bookmarker_notes: "Updated")
run_all_indexing_jobs
expect(search.search_results.map(&:id)).to eq(res)
end
end
end
end
end
end
describe "when searching by bookmarker" do
let(:bookmarker) { create(:user, login: "yabalchoath") }
{
Work: :work,
Series: :series_with_a_work,
ExternalWork: :external_work
}.each_pair do |type, factory|
it "returns the correct bookmarked #{type.to_s.pluralize} when bookmarker changes username" do
bookmarkable = create(factory)
bookmark = create(:bookmark,
bookmarkable_id: bookmarkable.id,
bookmarkable_type: type,
pseud: bookmarker.default_pseud)
run_all_indexing_jobs
result = BookmarkSearchForm.new(bookmarker: "yabalchoath").search_results.first
expect(result).to eq bookmark
bookmarker.login = "cioelle"
bookmarker.save!
run_all_indexing_jobs
result = BookmarkSearchForm.new(bookmarker: "yabalchoath").search_results.first
expect(result).to be_nil
result = BookmarkSearchForm.new(bookmarker: "cioelle").search_results.first
expect(result).to eq bookmark
end
end
end
describe "when searching any bookmarkable field for author of bookmarkable" do
let(:author) { create(:user, login: "yabalchoath") }
{
Work: :work,
Series: :series_with_a_work
}.each_pair do |type, factory|
it "returns the correct bookmarked #{type.to_s.pluralize} when author changes username" do
bookmarkable = create(factory, authors: [author.default_pseud])
bookmark = create(:bookmark, bookmarkable_id: bookmarkable.id, bookmarkable_type: type)
run_all_indexing_jobs
result = BookmarkSearchForm.new(bookmarkable_query: "yabalchoath").search_results.first
expect(result).to eq bookmark
author.login = "cioelle"
author.save!
run_all_indexing_jobs
result = BookmarkSearchForm.new(bookmarkable_query: "yabalchoath").search_results.first
expect(result).to be_nil
result = BookmarkSearchForm.new(bookmarkable_query: "cioelle").search_results.first
expect(result).to eq bookmark
end
end
end
describe "#processed_options" do
it "removes blank options" do
options = { foo: nil, bar: false }
searcher = BookmarkSearchForm.new(options)
expect(searcher.options).to have_key(:bar)
expect(searcher.options).not_to have_key(:foo)
end
it "renames the notes field" do
options = { bookmark_notes: "Mordor" }
searcher = BookmarkSearchForm.new(options)
expect(searcher.options[:notes]).to eq("Mordor")
end
it "unescapes angle brackets for date fields" do
options = {
date: "<1 week ago",
bookmarkable_date: ">1 year ago",
title: "escaped >.< field"
}
searcher = BookmarkSearchForm.new(options)
expect(searcher.options[:date]).to eq("<1 week ago")
expect(searcher.options[:bookmarkable_date]).to eq(">1 year ago")
expect(searcher.options[:title]).to eq("escaped &gt;.&lt; field")
end
it "renames old warning_ids fields" do
options = { warning_ids: [13] }
searcher = BookmarkSearchForm.new(options)
expect(searcher.options[:archive_warning_ids]).to eq([13])
end
end
describe "facets" do
let(:author) { create(:user).default_pseud }
let(:bookmarker) { create(:user).default_pseud }
let(:fandom1) { create(:canonical_fandom) }
let(:fandom2) { create(:canonical_fandom) }
let(:fandom3) { create(:fandom, merger: fandom1) }
let(:character1) { create(:canonical_character) }
let(:character2) { create(:canonical_character) }
let(:character3) { create(:canonical_character) }
let(:freeform1) { create(:canonical_freeform) }
let(:freeform2) { create(:freeform, merger: freeform1) }
let(:work1) do
create(:work,
fandom_string: fandom1.name,
character_string: [character1.name, character2.name].join(","),
authors: [author])
end
let(:work2) do
create(:work,
fandom_string: fandom2.name,
character_string: [character1.name, character2.name].join(","),
authors: [author])
end
let(:work3) do
create(:work,
fandom_string: fandom3.name,
character_string: [character1.name, character3.name].join(","),
authors: [author])
end
let!(:bookmark1) { create(:bookmark, pseud: bookmarker, bookmarkable: work1, tag_string: freeform1.name) }
let!(:bookmark2) { create(:bookmark, pseud: bookmarker, bookmarkable: work2, tag_string: freeform1.name) }
let!(:bookmark3) { create(:bookmark, pseud: bookmarker, bookmarkable: work3, tag_string: freeform2.name) }
before { run_all_indexing_jobs }
let(:form) { BookmarkSearchForm.new(faceted: true) }
let(:facets) { results.facets }
def facet_hash(facets)
facets.to_h { |facet| [facet.name, facet.count] }
end
shared_examples "it calculates the correct counts" do
it "lists the canonical fandoms with their counts" do
expect(facet_hash(facets["fandom"])).to eq(
{
fandom1.name => 2,
fandom2.name => 1
}
)
end
it "lists the canonical characters with their counts" do
expect(facet_hash(facets["character"])).to eq(
{
character1.name => 3,
character2.name => 2,
character3.name => 1
}
)
end
it "lists all bookmark tags with their counts" do
expect(facet_hash(facets["tag"])).to eq(
{
freeform1.name => 2,
freeform2.name => 1
}
)
end
context "when excluding tags" do
let(:form) { BookmarkSearchForm.new(faceted: true, excluded_tag_ids: [fandom2.id]) }
it "lists the canonical fandoms with their counts" do
expect(facet_hash(facets["fandom"])).to eq(
{
fandom1.name => 2
}
)
end
it "lists the canonical characters with their counts" do
expect(facet_hash(facets["character"])).to eq(
{
character1.name => 2,
character2.name => 1,
character3.name => 1
}
)
end
it "lists all bookmark tags with their counts" do
expect(facet_hash(facets["tag"])).to eq(
{
freeform1.name => 1,
freeform2.name => 1
}
)
end
end
end
context "for search_results" do
let(:results) { form.search_results }
it_behaves_like "it calculates the correct counts"
end
context "for bookmarkable_search_results" do
let(:results) { form.bookmarkable_search_results }
it_behaves_like "it calculates the correct counts"
end
end
end