DEV: Enable RSpec/InstanceVariable rule for models

This commit is contained in:
Loïc Guitaut 2025-02-14 14:53:30 +01:00 committed by Loïc Guitaut
parent 566c772980
commit 140775d505
29 changed files with 692 additions and 745 deletions

View File

@ -35,3 +35,8 @@ Discourse/Plugins/NoMonkeyPatching:
Lint/Debugger:
Exclude:
- script/**/*
RSpec/InstanceVariable:
Enabled: true
Include:
- spec/models/**/*

View File

@ -3,14 +3,12 @@
RSpec.describe CategoryGroup do
describe "#permission_types" do
context "when verifying enum sequence" do
before { @permission_types = CategoryGroup.permission_types }
it "'full' should be at 1st position" do
expect(@permission_types[:full]).to eq(1)
expect(described_class.permission_types[:full]).to eq(1)
end
it "'readonly' should be at 3rd position" do
expect(@permission_types[:readonly]).to eq(3)
expect(described_class.permission_types[:readonly]).to eq(3)
end
end
end

View File

@ -291,54 +291,40 @@ RSpec.describe Category do
end
describe "non-english characters" do
let(:category) { Fabricate(:category_with_definition, name: "测试") }
context "when using ascii slug generator" do
before do
SiteSetting.slug_generation_method = "ascii"
@category = Fabricate(:category_with_definition, name: "测试")
end
after { @category.destroy }
before { SiteSetting.slug_generation_method = "ascii" }
it "creates a blank slug" do
expect(@category.slug).to be_blank
expect(@category.slug_for_url).to eq("#{@category.id}-category")
expect(category.slug).to be_blank
expect(category.slug_for_url).to eq("#{category.id}-category")
end
end
context "when using none slug generator" do
before do
SiteSetting.slug_generation_method = "none"
@category = Fabricate(:category_with_definition, name: "测试")
end
after do
SiteSetting.slug_generation_method = "ascii"
@category.destroy
end
before { SiteSetting.slug_generation_method = "none" }
after { SiteSetting.slug_generation_method = "ascii" }
it "creates a blank slug" do
expect(@category.slug).to be_blank
expect(@category.slug_for_url).to eq("#{@category.id}-category")
expect(category.slug).to be_blank
expect(category.slug_for_url).to eq("#{category.id}-category")
end
end
context "when using encoded slug generator" do
before do
SiteSetting.slug_generation_method = "encoded"
@category = Fabricate(:category_with_definition, name: "测试")
end
after do
SiteSetting.slug_generation_method = "ascii"
@category.destroy
end
before { SiteSetting.slug_generation_method = "encoded" }
after { SiteSetting.slug_generation_method = "ascii" }
it "creates a slug" do
expect(@category.slug).to eq("%E6%B5%8B%E8%AF%95")
expect(@category.slug_for_url).to eq("%E6%B5%8B%E8%AF%95")
expect(category.slug).to eq("%E6%B5%8B%E8%AF%95")
expect(category.slug_for_url).to eq("%E6%B5%8B%E8%AF%95")
end
it "keeps the encoded slug after saving" do
@category.save
expect(@category.slug).to eq("%E6%B5%8B%E8%AF%95")
expect(@category.slug_for_url).to eq("%E6%B5%8B%E8%AF%95")
category.save
expect(category.slug).to eq("%E6%B5%8B%E8%AF%95")
expect(category.slug_for_url).to eq("%E6%B5%8B%E8%AF%95")
end
end
end
@ -353,25 +339,25 @@ RSpec.describe Category do
end
describe "custom slug can be provided" do
it "can be sanitized" do
@c = Fabricate(:category_with_definition, name: "Fun Cats", slug: "fun-cats")
@cat = Fabricate(:category_with_definition, name: "love cats", slug: "love-cats")
let(:category_1) { Fabricate(:category_with_definition, name: "Fun Cats", slug: "fun-cats") }
let!(:category_2) { Fabricate(:category_with_definition, name: "love cats", slug: "love-cats") }
@c.slug = " invalid slug"
@c.save
expect(@c.slug).to eq("invalid-slug")
it "can be sanitized" do
category_1.slug = " invalid slug"
category_1.save
expect(category_1.slug).to eq("invalid-slug")
c = Fabricate.build(:category, name: "More Fun Cats", slug: "love-cats")
expect(c).not_to be_valid
expect(c.errors[:slug]).to be_present
@cat.slug = "#{@c.id}-category"
expect(@cat).not_to be_valid
expect(@cat.errors[:slug]).to be_present
category_2.slug = "#{category_1.id}-category"
expect(category_2).not_to be_valid
expect(category_2.errors[:slug]).to be_present
@cat.slug = "#{@cat.id}-category"
expect(@cat).to be_valid
expect(@cat.errors[:slug]).not_to be_present
category_2.slug = "#{category_2.id}-category"
expect(category_2).to be_valid
expect(category_2.errors[:slug]).not_to be_present
end
context "if SiteSettings.slug_generation_method = ascii" do
@ -396,40 +382,38 @@ RSpec.describe Category do
end
describe "after create" do
before do
@category = Fabricate(:category_with_definition, name: "Amazing Category")
@topic = @category.topic
end
fab!(:category) { Fabricate(:category_with_definition, name: "Amazing Category") }
let(:topic) { category.topic }
it "is created correctly" do
expect(@category.slug).to eq("amazing-category")
expect(@category.slug_for_url).to eq(@category.slug)
expect(category.slug).to eq("amazing-category")
expect(category.slug_for_url).to eq(category.slug)
expect(@category.description).to be_blank
expect(category.description).to be_blank
expect(Topic.where(category_id: @category).count).to eq(1)
expect(Topic.where(category_id: category).count).to eq(1)
expect(@topic).to be_present
expect(topic).to be_present
expect(@topic.category).to eq(@category)
expect(topic.category).to eq(category)
expect(@topic).to be_visible
expect(topic).to be_visible
expect(@topic.pinned_at).to be_present
expect(topic.pinned_at).to be_present
expect(Guardian.new(@category.user).can_delete?(@topic)).to be false
expect(Guardian.new(category.user).can_delete?(topic)).to be false
expect(@topic.posts.count).to eq(1)
expect(topic.posts.count).to eq(1)
expect(@category.topic_url).to be_present
expect(category.topic_url).to be_present
expect(@category.posts_week).to eq(0)
expect(@category.posts_month).to eq(0)
expect(@category.posts_year).to eq(0)
expect(category.posts_week).to eq(0)
expect(category.posts_month).to eq(0)
expect(category.posts_year).to eq(0)
expect(@category.topics_week).to eq(0)
expect(@category.topics_month).to eq(0)
expect(@category.topics_year).to eq(0)
expect(category.topics_week).to eq(0)
expect(category.topics_month).to eq(0)
expect(category.topics_year).to eq(0)
end
it "cooks the definition" do
@ -444,31 +428,31 @@ RSpec.describe Category do
end
it "renames the definition when renamed" do
@category.update(name: "Troutfishing")
@topic.reload
expect(@topic.title).to match(/Troutfishing/)
expect(@topic.fancy_title).to match(/Troutfishing/)
category.update(name: "Troutfishing")
topic.reload
expect(topic.title).to match(/Troutfishing/)
expect(topic.fancy_title).to match(/Troutfishing/)
end
it "doesn't raise an error if there is no definition topic to rename (uncategorized)" do
expect { @category.update(name: "Troutfishing", topic_id: nil) }.to_not raise_error
expect { category.update(name: "Troutfishing", topic_id: nil) }.to_not raise_error
end
it "creates permalink when category slug is changed" do
@category.update(slug: "new-category")
category.update(slug: "new-category")
expect(Permalink.count).to eq(1)
end
it "reuses existing permalink when category slug is changed" do
permalink = Permalink.create!(url: "c/#{@category.slug}/#{@category.id}", category_id: 42)
permalink = Permalink.create!(url: "c/#{category.slug}/#{category.id}", category_id: 42)
expect { @category.update(slug: "new-slug") }.to_not change { Permalink.count }
expect(permalink.reload.category_id).to eq(@category.id)
expect { category.update(slug: "new-slug") }.to_not change { Permalink.count }
expect(permalink.reload.category_id).to eq(category.id)
end
it "creates permalink when sub category slug is changed" do
sub_category =
Fabricate(:category_with_definition, slug: "sub-category", parent_category_id: @category.id)
Fabricate(:category_with_definition, slug: "sub-category", parent_category_id: category.id)
sub_category.update(slug: "new-sub-category")
expect(Permalink.count).to eq(1)
end
@ -492,8 +476,8 @@ RSpec.describe Category do
it "correctly creates permalink when category slug is changed in subfolder install" do
set_subfolder "/forum"
old_url = @category.url
@category.update(slug: "new-category")
old_url = category.url
category.update(slug: "new-category")
permalink = Permalink.last
expect(permalink.url).to eq(old_url[1..-1])
end
@ -524,17 +508,19 @@ RSpec.describe Category do
end
describe "trying to change the category topic's category" do
let(:new_category) do
Fabricate(:category_with_definition, name: "2nd Category", user: category.user)
end
before do
@new_cat = Fabricate(:category_with_definition, name: "2nd Category", user: @category.user)
@topic.change_category_to_id(@new_cat.id)
@topic.reload
@category.reload
topic.change_category_to_id(new_category.id)
topic.reload
category.reload
end
it "does not cause changes" do
expect(@category.topic_count).to eq(0)
expect(@topic.category).to eq(@category)
expect(@category.topic).to eq(@topic)
expect(category.topic_count).to eq(0)
expect(topic.category).to eq(category)
expect(category.topic).to eq(topic)
end
end
end
@ -561,31 +547,30 @@ RSpec.describe Category do
end
describe "destroy" do
before do
@category = Fabricate(:category_with_definition)
@category_id = @category.id
@topic_id = @category.topic_id
SiteSetting.shared_drafts_category = @category.id.to_s
end
let(:category) { Fabricate(:category_with_definition) }
let(:category_id) { category.id }
let(:topic_id) { category.topic_id }
before { SiteSetting.shared_drafts_category = category.id.to_s }
it "is deleted correctly" do
@category.destroy
expect(Category.exists?(id: @category_id)).to be false
expect(Topic.with_deleted.where.not(deleted_at: nil).exists?(id: @topic_id)).to be true
category.destroy
expect(Category.exists?(id: category_id)).to be false
expect(Topic.with_deleted.where.not(deleted_at: nil).exists?(id: topic_id)).to be true
expect(SiteSetting.shared_drafts_category).to be_blank
end
it "deletes related embeddable host" do
embeddable_host = Fabricate(:embeddable_host, category: @category)
@category.destroy!
embeddable_host = Fabricate(:embeddable_host, category:)
category.destroy!
expect { embeddable_host.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
it "triggers a extensibility event" do
event = DiscourseEvent.track(:category_destroyed) { @category.destroy }
event = DiscourseEvent.track(:category_destroyed) { category.destroy }
expect(event[:event_name]).to eq(:category_destroyed)
expect(event[:params].first).to eq(@category)
expect(event[:params].first).to eq(category)
end
end
@ -616,101 +601,101 @@ RSpec.describe Category do
end
describe "update_stats" do
before do
@category =
Fabricate(:category_with_definition, user: Fabricate(:user, refresh_auto_groups: true))
let(:category) do
Fabricate(:category_with_definition, user: Fabricate(:user, refresh_auto_groups: true))
end
context "with regular topics" do
before do
create_post(user: @category.user, category: @category.id)
create_post(user: category.user, category:)
Category.update_stats
@category.reload
category.reload
end
it "updates topic stats" do
expect(@category.topics_week).to eq(1)
expect(@category.topics_month).to eq(1)
expect(@category.topics_year).to eq(1)
expect(@category.topic_count).to eq(1)
expect(@category.post_count).to eq(1)
expect(@category.posts_year).to eq(1)
expect(@category.posts_month).to eq(1)
expect(@category.posts_week).to eq(1)
expect(category.topics_week).to eq(1)
expect(category.topics_month).to eq(1)
expect(category.topics_year).to eq(1)
expect(category.topic_count).to eq(1)
expect(category.post_count).to eq(1)
expect(category.posts_year).to eq(1)
expect(category.posts_month).to eq(1)
expect(category.posts_week).to eq(1)
end
end
context "with deleted topics" do
before do
@category.topics << Fabricate(:deleted_topic, user: @category.user)
category.topics << Fabricate(:deleted_topic, user: category.user)
Category.update_stats
@category.reload
category.reload
end
it "does not count deleted topics" do
expect(@category.topics_week).to eq(0)
expect(@category.topic_count).to eq(0)
expect(@category.topics_month).to eq(0)
expect(@category.topics_year).to eq(0)
expect(@category.post_count).to eq(0)
expect(@category.posts_year).to eq(0)
expect(@category.posts_month).to eq(0)
expect(@category.posts_week).to eq(0)
expect(category.topics_week).to eq(0)
expect(category.topic_count).to eq(0)
expect(category.topics_month).to eq(0)
expect(category.topics_year).to eq(0)
expect(category.post_count).to eq(0)
expect(category.posts_year).to eq(0)
expect(category.posts_month).to eq(0)
expect(category.posts_week).to eq(0)
end
end
context "with revised post" do
before do
post = create_post(user: @category.user, category: @category.id)
post = create_post(user: category.user, category:)
SiteSetting.editing_grace_period = 1.minute
post.revise(post.user, { raw: "updated body" }, revised_at: post.updated_at + 2.minutes)
Category.update_stats
@category.reload
category.reload
end
it "doesn't count each version of a post" do
expect(@category.post_count).to eq(1)
expect(@category.posts_year).to eq(1)
expect(@category.posts_month).to eq(1)
expect(@category.posts_week).to eq(1)
expect(category.post_count).to eq(1)
expect(category.posts_year).to eq(1)
expect(category.posts_month).to eq(1)
expect(category.posts_week).to eq(1)
end
end
context "for uncategorized category" do
let(:uncategorized) { Category.find(SiteSetting.uncategorized_category_id) }
before do
@uncategorized = Category.find(SiteSetting.uncategorized_category_id)
create_post(user: Fabricate(:user, refresh_auto_groups: true), category: @uncategorized.id)
create_post(user: Fabricate(:user, refresh_auto_groups: true), category: uncategorized)
Category.update_stats
@uncategorized.reload
uncategorized.reload
end
it "updates topic stats" do
expect(@uncategorized.topics_week).to eq(1)
expect(@uncategorized.topics_month).to eq(1)
expect(@uncategorized.topics_year).to eq(1)
expect(@uncategorized.topic_count).to eq(1)
expect(@uncategorized.post_count).to eq(1)
expect(@uncategorized.posts_year).to eq(1)
expect(@uncategorized.posts_month).to eq(1)
expect(@uncategorized.posts_week).to eq(1)
expect(uncategorized.topics_week).to eq(1)
expect(uncategorized.topics_month).to eq(1)
expect(uncategorized.topics_year).to eq(1)
expect(uncategorized.topic_count).to eq(1)
expect(uncategorized.post_count).to eq(1)
expect(uncategorized.posts_year).to eq(1)
expect(uncategorized.posts_month).to eq(1)
expect(uncategorized.posts_week).to eq(1)
end
end
context "when there are no topics left" do
let!(:topic) { create_post(user: @category.user, category: @category.id).reload.topic }
let!(:topic) { create_post(user: category.user, category:).reload.topic }
it "can update the topic count to zero" do
@category.reload
expect(@category.topic_count).to eq(1)
expect(@category.topics.count).to eq(2)
category.reload
expect(category.topic_count).to eq(1)
expect(category.topics.count).to eq(2)
topic.delete # Delete so the post trash/destroy hook doesn't fire
Category.update_stats
@category.reload
expect(@category.topics.count).to eq(1)
expect(@category.topic_count).to eq(0)
category.reload
expect(category.topics.count).to eq(1)
expect(category.topic_count).to eq(0)
end
end
end

View File

@ -3,14 +3,12 @@
RSpec.describe DirectoryItem do
describe "#period_types" do
context "when verifying enum sequence" do
before { @period_types = DirectoryItem.period_types }
it "'all' should be at 1st position" do
expect(@period_types[:all]).to eq(1)
expect(described_class.period_types[:all]).to eq(1)
end
it "'quarterly' should be at 6th position" do
expect(@period_types[:quarterly]).to eq(6)
expect(described_class.period_types[:quarterly]).to eq(6)
end
end
end

View File

@ -1,13 +1,13 @@
# frozen_string_literal: true
RSpec.describe DiscourseConnect do
before do
@discourse_connect_url = "http://example.com/discourse_sso"
@discourse_connect_secret = "shjkfdhsfkjh"
let(:discourse_connect_url) { "http://example.com/discourse_sso" }
let(:discourse_connect_secret) { "shjkfdhsfkjh" }
SiteSetting.discourse_connect_url = @discourse_connect_url
before do
SiteSetting.discourse_connect_url = discourse_connect_url
SiteSetting.enable_discourse_connect = true
SiteSetting.discourse_connect_secret = @discourse_connect_secret
SiteSetting.discourse_connect_secret = discourse_connect_secret
SiteSetting.reserved_usernames = ""
Jobs.run_immediately!
end
@ -788,7 +788,7 @@ RSpec.describe DiscourseConnect do
it "generates a correct sso url" do
url, payload = DiscourseConnect.generate_url(secure_session: secure_session).split("?")
expect(url).to eq @discourse_connect_url
expect(url).to eq discourse_connect_url
sso = DiscourseConnect.parse(payload, secure_session: secure_session)
expect(sso.nonce).to_not be_nil

View File

@ -66,8 +66,8 @@ RSpec.describe EmailToken do
context "with taken email address" do
before do
@other_user = Fabricate(:coding_horror)
email_token.update_attribute :email, @other_user.email
other_user = Fabricate(:coding_horror)
email_token.update_attribute :email, other_user.email
end
it "returns nil when the email has been taken since the token has been generated" do

View File

@ -1,15 +1,16 @@
# frozen_string_literal: true
RSpec.describe GroupAssociatedGroup do
let(:user) { Fabricate(:user) }
let(:group) { Fabricate(:group) }
let(:group2) { Fabricate(:group) }
let(:associated_group) { Fabricate(:associated_group) }
let(:associated_group2) { Fabricate(:associated_group) }
before do
fab!(:user)
fab!(:group)
fab!(:group2) { Fabricate(:group) }
fab!(:associated_group)
fab!(:associated_group2) { Fabricate(:associated_group) }
fab!(:uag) do
UserAssociatedGroup.create(user_id: user.id, associated_group_id: associated_group.id)
@gag = described_class.create(group_id: group.id, associated_group_id: associated_group.id)
end
fab!(:gag) do
described_class.create(group_id: group.id, associated_group_id: associated_group.id)
end
it "adds users to group when created" do
@ -17,7 +18,7 @@ RSpec.describe GroupAssociatedGroup do
end
it "removes users from group when destroyed" do
@gag.destroy!
gag.destroy!
expect(group.users.include?(user)).to eq(false)
end
@ -25,7 +26,7 @@ RSpec.describe GroupAssociatedGroup do
UserAssociatedGroup.create(user_id: user.id, associated_group_id: associated_group2.id)
described_class.create(group_id: group.id, associated_group_id: associated_group2.id)
@gag.destroy!
gag.destroy!
expect(group.users.include?(user)).to eq(true)
end
@ -33,7 +34,7 @@ RSpec.describe GroupAssociatedGroup do
UserAssociatedGroup.create(user_id: user.id, associated_group_id: associated_group2.id)
described_class.create(group_id: group2.id, associated_group_id: associated_group2.id)
@gag.destroy!
gag.destroy!
expect(group.users.include?(user)).to eq(false)
end
end

View File

@ -121,14 +121,12 @@ RSpec.describe Group do
describe "#builtin" do
context "when verifying enum sequence" do
before { @builtin = Group.builtin }
it "'moderators' should be at 1st position" do
expect(@builtin[:moderators]).to eq(1)
expect(described_class.builtin[:moderators]).to eq(1)
end
it "'trust_level_2' should be at 4th position" do
expect(@builtin[:trust_level_2]).to eq(4)
expect(described_class.builtin[:trust_level_2]).to eq(4)
end
end
end
@ -1189,17 +1187,18 @@ RSpec.describe Group do
describe "IMAP" do
let(:group) { Fabricate(:group) }
let(:mocked_imap_provider) do
MockedImapProvider.new(
group.imap_server,
port: group.imap_port,
ssl: group.imap_ssl,
username: group.email_username,
password: group.email_password,
)
end
def mock_imap
@mocked_imap_provider =
MockedImapProvider.new(
group.imap_server,
port: group.imap_port,
ssl: group.imap_ssl,
username: group.email_username,
password: group.email_password,
)
Imap::Providers::Detector.stubs(:init_with_detected_provider).returns(@mocked_imap_provider)
Imap::Providers::Detector.stubs(:init_with_detected_provider).returns(mocked_imap_provider)
end
def configure_imap
@ -1215,12 +1214,12 @@ RSpec.describe Group do
def enable_imap
SiteSetting.enable_imap = true
@mocked_imap_provider.stubs(:connect!)
@mocked_imap_provider.stubs(:list_mailboxes_with_attributes).returns(
mocked_imap_provider.stubs(:connect!)
mocked_imap_provider.stubs(:list_mailboxes_with_attributes).returns(
[stub(attr: [], name: "Inbox")],
)
@mocked_imap_provider.stubs(:list_mailboxes).returns(["Inbox"])
@mocked_imap_provider.stubs(:disconnect!)
mocked_imap_provider.stubs(:list_mailboxes).returns(["Inbox"])
mocked_imap_provider.stubs(:disconnect!)
end
before { Discourse.redis.del("group_imap_mailboxes_#{group.id}") }
@ -1240,7 +1239,7 @@ RSpec.describe Group do
configure_imap
mock_imap
SiteSetting.enable_imap = true
@mocked_imap_provider.stubs(:connect!).raises(Net::IMAP::NoResponseError)
mocked_imap_provider.stubs(:connect!).raises(Net::IMAP::NoResponseError)
group.imap_mailboxes
expect(group.reload.imap_last_error).not_to eq(nil)
end

View File

@ -13,41 +13,41 @@ RSpec.describe Notification do
it { is_expected.to belong_to :topic }
describe "#types" do
context "when verifying enum sequence" do
before { @types = Notification.types }
subject(:types) { Notification.types }
context "when verifying enum sequence" do
it "has a correct position for each type" do
expect(@types[:mentioned]).to eq(1)
expect(@types[:replied]).to eq(2)
expect(@types[:quoted]).to eq(3)
expect(@types[:edited]).to eq(4)
expect(@types[:liked]).to eq(5)
expect(@types[:private_message]).to eq(6)
expect(@types[:invited_to_private_message]).to eq(7)
expect(@types[:invitee_accepted]).to eq(8)
expect(@types[:posted]).to eq(9)
expect(@types[:moved_post]).to eq(10)
expect(@types[:linked]).to eq(11)
expect(@types[:granted_badge]).to eq(12)
expect(@types[:invited_to_topic]).to eq(13)
expect(@types[:custom]).to eq(14)
expect(@types[:group_mentioned]).to eq(15)
expect(@types[:group_message_summary]).to eq(16)
expect(@types[:watching_first_post]).to eq(17)
expect(@types[:topic_reminder]).to eq(18)
expect(@types[:liked_consolidated]).to eq(19)
expect(@types[:post_approved]).to eq(20)
expect(@types[:code_review_commit_approved]).to eq(21)
expect(@types[:membership_request_accepted]).to eq(22)
expect(@types[:membership_request_consolidated]).to eq(23)
expect(@types[:bookmark_reminder]).to eq(24)
expect(@types[:reaction]).to eq(25)
expect(@types[:votes_released]).to eq(26)
expect(@types[:event_reminder]).to eq(27)
expect(@types[:event_invitation]).to eq(28)
expect(@types[:chat_mention]).to eq(29)
expect(@types[:chat_message]).to eq(30)
expect(@types[:assigned]).to eq(34)
expect(types[:mentioned]).to eq(1)
expect(types[:replied]).to eq(2)
expect(types[:quoted]).to eq(3)
expect(types[:edited]).to eq(4)
expect(types[:liked]).to eq(5)
expect(types[:private_message]).to eq(6)
expect(types[:invited_to_private_message]).to eq(7)
expect(types[:invitee_accepted]).to eq(8)
expect(types[:posted]).to eq(9)
expect(types[:moved_post]).to eq(10)
expect(types[:linked]).to eq(11)
expect(types[:granted_badge]).to eq(12)
expect(types[:invited_to_topic]).to eq(13)
expect(types[:custom]).to eq(14)
expect(types[:group_mentioned]).to eq(15)
expect(types[:group_message_summary]).to eq(16)
expect(types[:watching_first_post]).to eq(17)
expect(types[:topic_reminder]).to eq(18)
expect(types[:liked_consolidated]).to eq(19)
expect(types[:post_approved]).to eq(20)
expect(types[:code_review_commit_approved]).to eq(21)
expect(types[:membership_request_accepted]).to eq(22)
expect(types[:membership_request_consolidated]).to eq(23)
expect(types[:bookmark_reminder]).to eq(24)
expect(types[:reaction]).to eq(25)
expect(types[:votes_released]).to eq(26)
expect(types[:event_reminder]).to eq(27)
expect(types[:event_invitation]).to eq(28)
expect(types[:chat_mention]).to eq(29)
expect(types[:chat_message]).to eq(30)
expect(types[:assigned]).to eq(34)
end
end
end
@ -256,31 +256,31 @@ RSpec.describe Notification do
end
describe "private message" do
before do
@topic = Fabricate(:private_message_topic)
@post = Fabricate(:post, topic: @topic, user: @topic.user)
@target = @post.topic.topic_allowed_users.reject { |a| a.user_id == @post.user_id }[0].user
let(:topic) { Fabricate(:private_message_topic) }
let(:post) { Fabricate(:post, topic:, user: topic.user) }
let(:target) { post.topic.topic_allowed_users.reject { |a| a.user_id == post.user_id }[0].user }
before do
TopicUser.change(
@target.id,
@topic.id,
target.id,
topic.id,
notification_level: TopicUser.notification_levels[:watching],
)
PostAlerter.post_created(@post)
PostAlerter.post_created(post)
end
it "should create and roll up private message notifications" do
expect(@target.notifications.first.notification_type).to eq(
expect(target.notifications.first.notification_type).to eq(
Notification.types[:private_message],
)
expect(@post.user.unread_notifications).to eq(0)
expect(@post.user.total_unread_notifications).to eq(0)
expect(@target.unread_high_priority_notifications).to eq(1)
expect(post.user.unread_notifications).to eq(0)
expect(post.user.total_unread_notifications).to eq(0)
expect(target.unread_high_priority_notifications).to eq(1)
Fabricate(:post, topic: @topic, user: @topic.user)
@target.reload
expect(@target.unread_high_priority_notifications).to eq(1)
Fabricate(:post, topic:, user: topic.user)
target.reload
expect(target.unread_high_priority_notifications).to eq(1)
end
end
@ -623,10 +623,10 @@ RSpec.describe Notification do
describe "#recent_report" do
let(:post) { Fabricate(:post) }
let(:vars) { { i: 0 } }
def fab(type, read)
@i ||= 0
@i += 1
vars[:i] += 1
Notification.create!(
read: read,
user_id: user.id,
@ -634,7 +634,7 @@ RSpec.describe Notification do
post_number: post.post_number,
data: "[]",
notification_type: type,
created_at: @i.days.from_now,
created_at: vars[:i].days.from_now,
)
end

View File

@ -19,10 +19,8 @@ RSpec.describe PostActionType do
describe "#types" do
context "when verifying enum sequence" do
before { @types = PostActionType.types }
it "'spam' should be at 8th position" do
expect(@types[:spam]).to eq(8)
expect(described_class.types[:spam]).to eq(8)
end
end
end

View File

@ -6,14 +6,12 @@ RSpec.describe PostMover do
describe "#move_types" do
context "when verifying enum sequence" do
before { @move_types = PostMover.move_types }
it "'new_topic' should be at 1st position" do
expect(@move_types[:new_topic]).to eq(1)
expect(described_class.move_types[:new_topic]).to eq(1)
end
it "'existing_topic' should be at 2nd position" do
expect(@move_types[:existing_topic]).to eq(2)
expect(described_class.move_types[:existing_topic]).to eq(2)
end
end
end

View File

@ -13,42 +13,36 @@ RSpec.describe Post do
describe "#hidden_reasons" do
context "when verifying enum sequence" do
before { @hidden_reasons = Post.hidden_reasons }
it "'flag_threshold_reached' should be at 1st position" do
expect(@hidden_reasons[:flag_threshold_reached]).to eq(1)
expect(described_class.hidden_reasons[:flag_threshold_reached]).to eq(1)
end
it "'flagged_by_tl3_user' should be at 4th position" do
expect(@hidden_reasons[:flagged_by_tl3_user]).to eq(4)
expect(described_class.hidden_reasons[:flagged_by_tl3_user]).to eq(4)
end
end
end
describe "#types" do
context "when verifying enum sequence" do
before { @types = Post.types }
it "'regular' should be at 1st position" do
expect(@types[:regular]).to eq(1)
expect(described_class.types[:regular]).to eq(1)
end
it "'whisper' should be at 4th position" do
expect(@types[:whisper]).to eq(4)
expect(described_class.types[:whisper]).to eq(4)
end
end
end
describe "#cook_methods" do
context "when verifying enum sequence" do
before { @cook_methods = Post.cook_methods }
it "'regular' should be at 1st position" do
expect(@cook_methods[:regular]).to eq(1)
expect(described_class.cook_methods[:regular]).to eq(1)
end
it "'email' should be at 3rd position" do
expect(@cook_methods[:email]).to eq(3)
expect(described_class.cook_methods[:email]).to eq(3)
end
end
end

View File

@ -126,48 +126,47 @@ RSpec.describe PostTiming do
end
describe "recording" do
before do
@topic = post.topic
@coding_horror = Fabricate(:coding_horror)
@timing_attrs = {
let(:topic) { post.topic }
let(:coding_horror) { Fabricate(:coding_horror) }
let(:timing_attrs) do
{
msecs: 1234,
topic_id: post.topic_id,
user_id: @coding_horror.id,
user_id: coding_horror.id,
post_number: post.post_number,
}
end
it "adds a view to the post" do
expect {
PostTiming.record_timing(@timing_attrs)
PostTiming.record_timing(timing_attrs)
post.reload
}.to change(post, :reads).by(1)
end
it "doesn't update the posts read count if the topic is a PM" do
pm = Fabricate(:private_message_post).topic
@timing_attrs = @timing_attrs.merge(topic_id: pm.id)
PostTiming.record_timing(@timing_attrs)
PostTiming.record_timing(timing_attrs.merge(topic_id: pm.id))
expect(@coding_horror.user_stat.posts_read_count).to eq(0)
expect(coding_horror.user_stat.posts_read_count).to eq(0)
end
describe "multiple calls" do
it "correctly works" do
PostTiming.record_timing(@timing_attrs)
PostTiming.record_timing(@timing_attrs)
PostTiming.record_timing(timing_attrs)
PostTiming.record_timing(timing_attrs)
timing =
PostTiming.find_by(
topic_id: post.topic_id,
user_id: @coding_horror.id,
user_id: coding_horror.id,
post_number: post.post_number,
)
expect(timing).to be_present
expect(timing.msecs).to eq(2468)
expect(@coding_horror.user_stat.posts_read_count).to eq(1)
expect(coding_horror.user_stat.posts_read_count).to eq(1)
end
end
end

View File

@ -224,16 +224,18 @@ RSpec.describe Reviewable, type: :model do
end
describe "Including pending queued posts even if they don't pass the minimum priority threshold" do
let(:queued_post) do
Fabricate(:reviewable_queued_post, score: 0, target: post, force_review: true)
end
let(:queued_user) { Fabricate(:reviewable_user, score: 0, force_review: true) }
before do
SiteSetting.reviewable_default_visibility = :high
Reviewable.set_priorities(high: 10)
@queued_post =
Fabricate(:reviewable_queued_post, score: 0, target: post, force_review: true)
@queued_user = Fabricate(:reviewable_user, score: 0, force_review: true)
end
it "includes queued posts when searching for pending reviewables" do
expect(Reviewable.list_for(user)).to contain_exactly(@queued_post, @queued_user)
expect(Reviewable.list_for(user)).to contain_exactly(queued_post, queued_user)
end
it "excludes pending queued posts when applying a different status filter" do

View File

@ -202,21 +202,22 @@ RSpec.describe ReviewableUser, type: :model do
end
describe "when must_approve_users is true" do
before do
let!(:reviewable) do
SiteSetting.must_approve_users = true
Jobs.run_immediately!
@reviewable = ReviewableUser.find_by(target: user)
Jobs.run_later!
ReviewableUser.find_by(target: user)
end
before { Jobs.run_later! }
it "creates the ReviewableUser for a user, with moderator access" do
expect(@reviewable.reviewable_by_moderator).to eq(true)
expect(reviewable.reviewable_by_moderator).to eq(true)
end
context "with email jobs" do
it "enqueues a 'signup after approval' email if must_approve_users is true" do
expect_enqueued_with(job: :critical_user_email, args: { type: :signup_after_approval }) do
@reviewable.perform(admin, :approve_user)
reviewable.perform(admin, :approve_user)
end
end
@ -228,7 +229,7 @@ RSpec.describe ReviewableUser, type: :model do
args: {
type: :signup_after_approval,
},
) { @reviewable.perform(admin, :approve_user) }
) { reviewable.perform(admin, :approve_user) }
end
end

View File

@ -408,11 +408,12 @@ RSpec.describe ScreenedIpAddress do
end
context "when allow_admin record exists" do
let(:permitted_ip_address) { "111.234.23.11" }
before do
@permitted_ip_address = "111.234.23.11"
Fabricate(
:screened_ip_address,
ip_address: @permitted_ip_address,
ip_address: permitted_ip_address,
action_type: described_class.actions[:allow_admin],
)
end
@ -427,12 +428,12 @@ RSpec.describe ScreenedIpAddress do
before { SiteSetting.use_admin_ip_allowlist = true }
it "returns false when user is nil" do
expect(described_class.block_admin_login?(nil, @permitted_ip_address)).to eq(false)
expect(described_class.block_admin_login?(nil, permitted_ip_address)).to eq(false)
end
it "returns false for an admin user at the allowed ip address" do
expect(
described_class.block_admin_login?(Fabricate.build(:admin), @permitted_ip_address),
described_class.block_admin_login?(Fabricate.build(:admin), permitted_ip_address),
).to eq(false)
end
@ -444,7 +445,7 @@ RSpec.describe ScreenedIpAddress do
it "returns false for regular user at allowed ip address" do
expect(
described_class.block_admin_login?(Fabricate.build(:user), @permitted_ip_address),
described_class.block_admin_login?(Fabricate.build(:user), permitted_ip_address),
).to eq(false)
end

View File

@ -25,28 +25,34 @@ RSpec.describe ScreenedUrl do
end
describe "normalize" do
subject(:normalized) do
record.normalize
record
end
subject(:normalized) { record.tap(&:normalize) }
let(:record) { described_class.new(@params) }
let(:record) { described_class.new(params) }
%w[http:// HTTP:// https:// HTTPS://].each do |prefix|
it "strips #{prefix}" do
@params = valid_params.merge(url: url.gsub("http://", prefix))
expect(normalized.url).to eq(url.gsub("http://", ""))
context "with #{prefix} prefix" do
let(:params) { valid_params.merge(url: url.gsub("http://", prefix)) }
it "strips it" do
expect(normalized.url).to eq(url.gsub("http://", ""))
end
end
end
it "strips trailing slash" do
@params = valid_params.merge(url: "silverbullet.in/")
expect(normalized.url).to eq("silverbullet.in")
context "with a trailing slash" do
let(:params) { valid_params.merge(url: "silverbullet.in/") }
it "strips it" do
expect(normalized.url).to eq("silverbullet.in")
end
end
it "strips trailing slashes" do
@params = valid_params.merge(url: "silverbullet.in/buy///")
expect(normalized.url).to eq("silverbullet.in/buy")
context "with trailing slashes" do
let(:params) { valid_params.merge(url: "silverbullet.in/buy///") }
it "strips them" do
expect(normalized.url).to eq("silverbullet.in/buy")
end
end
it "downcases domains" do

View File

@ -2,11 +2,10 @@
RSpec.describe Tag do
def make_some_tags(count: 3, tag_a_topic: false)
@tags = []
if tag_a_topic
count.times { |i| @tags << Fabricate(:tag, topics: [Fabricate(:topic)]) }
Fabricate.times(count, :tag, topics: [Fabricate(:topic)])
else
count.times { |i| @tags << Fabricate(:tag) }
Fabricate.times(count, :tag)
end
end
@ -84,68 +83,79 @@ RSpec.describe Tag do
end
describe "#top_tags" do
it "returns nothing if nothing has been tagged" do
make_some_tags(tag_a_topic: false)
expect(Tag.top_tags.sort).to be_empty
context "when nothing has been tagged" do
let!(:tags) { make_some_tags(tag_a_topic: false) }
it "returns nothing" do
expect(Tag.top_tags.sort).to be_empty
end
end
it "can return all tags" do
make_some_tags(tag_a_topic: true)
expect(Tag.top_tags.sort).to eq(@tags.map(&:name).sort)
context "when something has been tagged" do
let!(:tags) { make_some_tags(tag_a_topic: true) }
it "returns all tags" do
expect(Tag.top_tags.sort).to eq(tags.map(&:name).sort)
end
end
context "with categories" do
let(:tags) { make_some_tags(count: 4) }
let(:category1) { Fabricate(:category) }
let(:private_category) { Fabricate(:category) }
let!(:topics) do
[
Fabricate(:topic, category: category1, tags: [tags[0]]),
Fabricate(:topic, tags: [tags[1]]),
Fabricate(:topic, category: private_category, tags: [tags[2]]),
]
end
before do
make_some_tags(count: 4) # one tag that isn't used
@category1 = Fabricate(:category)
@private_category = Fabricate(:category)
@private_category.set_permissions(admins: :full)
@private_category.save!
@topics = []
@topics << Fabricate(:topic, category: @category1, tags: [@tags[0]])
@topics << Fabricate(:topic, tags: [@tags[1]])
@topics << Fabricate(:topic, category: @private_category, tags: [@tags[2]])
private_category.set_permissions(admins: :full)
private_category.save!
end
it "works correctly" do
expect(Tag.top_tags(category: @category1).sort).to eq([@tags[0].name].sort)
expect(Tag.top_tags(category: category1).sort).to eq([tags[0].name].sort)
expect(Tag.top_tags(guardian: Guardian.new(Fabricate(:admin))).sort).to eq(
[@tags[0].name, @tags[1].name, @tags[2].name].sort,
[tags[0].name, tags[1].name, tags[2].name].sort,
)
expect(
Tag.top_tags(category: @private_category, guardian: Guardian.new(Fabricate(:admin))).sort,
).to eq([@tags[2].name].sort)
Tag.top_tags(category: private_category, guardian: Guardian.new(Fabricate(:admin))).sort,
).to eq([tags[2].name].sort)
expect(Tag.top_tags.sort).to eq([@tags[0].name, @tags[1].name].sort)
expect(Tag.top_tags(category: @private_category)).to be_empty
expect(Tag.top_tags.sort).to eq([tags[0].name, tags[1].name].sort)
expect(Tag.top_tags(category: private_category)).to be_empty
sub_category = Fabricate(:category, parent_category_id: @category1.id)
Fabricate(:topic, category: sub_category, tags: [@tags[1]])
expect(Tag.top_tags(category: @category1).sort).to eq([@tags[0].name, @tags[1].name].sort)
sub_category = Fabricate(:category, parent_category_id: category1.id)
Fabricate(:topic, category: sub_category, tags: [tags[1]])
expect(Tag.top_tags(category: category1).sort).to eq([tags[0].name, tags[1].name].sort)
end
end
context "with category-specific tags" do
before do
make_some_tags(count: 3)
@category1 = Fabricate(:category, tags: [@tags[0]]) # only one tag allowed in this category
@category2 = Fabricate(:category)
@topics = []
@topics << Fabricate(:topic, category: @category1, tags: [@tags[0]])
@topics << Fabricate(:topic, category: @category2, tags: [@tags[1], @tags[2]])
@topics << Fabricate(:topic, tags: [@tags[2]]) # uncategorized
let(:tags) { make_some_tags(count: 3) }
let(:category1) { Fabricate(:category, tags: [tags[0]]) } # only one tag allowed in this category
let(:category2) { Fabricate(:category) }
let!(:topics) do
[
Fabricate(:topic, category: category1, tags: [tags[0]]),
Fabricate(:topic, category: category2, tags: [tags[1], tags[2]]),
Fabricate(:topic, tags: [tags[2]]), # uncategorized
]
end
it "for category with restricted tags, lists those tags" do
expect(Tag.top_tags(category: @category1)).to eq([@tags[0].name])
expect(Tag.top_tags(category: category1)).to eq([tags[0].name])
end
it "for category without tags, lists allowed tags" do
expect(Tag.top_tags(category: @category2).sort).to eq([@tags[1].name, @tags[2].name].sort)
expect(Tag.top_tags(category: category2).sort).to eq([tags[1].name, tags[2].name].sort)
end
it "for no category arg, lists all tags" do
expect(Tag.top_tags.sort).to eq([@tags[0].name, @tags[1].name, @tags[2].name].sort)
expect(Tag.top_tags.sort).to eq([tags[0].name, tags[1].name, tags[2].name].sort)
end
end

View File

@ -3,14 +3,12 @@
RSpec.describe TopTopic do
describe "#sorted_periods" do
context "when verifying enum sequence" do
before { @sorted_periods = TopTopic.sorted_periods }
it "'daily' should be at 1st position" do
expect(@sorted_periods[:daily]).to eq(1)
expect(described_class.sorted_periods[:daily]).to eq(1)
end
it "'all' should be at 6th position" do
expect(@sorted_periods[:all]).to eq(6)
expect(described_class.sorted_periods[:all]).to eq(6)
end
end
end

View File

@ -235,16 +235,17 @@ RSpec.describe TopicConverter do
end
context "when topic has replies" do
let(:replied_user) { Fabricate(:coding_horror) }
before do
@replied_user = Fabricate(:coding_horror)
create_post(topic: topic, user: @replied_user)
create_post(topic: topic, user: replied_user)
topic.reload
end
it "adds users who replied to topic in Private Message" do
topic.convert_to_private_message(admin)
expect(topic.reload.topic_allowed_users.where(user_id: @replied_user.id).count).to eq(1)
expect(topic.reload.topic_allowed_users.where(user_id: replied_user.id).count).to eq(1)
expect(topic.reload.user.user_stat.post_count).to eq(0)
end
end

View File

@ -89,23 +89,9 @@ RSpec.describe TopicEmbed do
HTML
parsed = TopicEmbed.parse_html(html, "https://blog.discourse.com/somepost.html")
expected = "<div><div> article content cats cats </div></div>"
expected = <<-HTML
<div><div>
article content
cats
cats
</div></div>
HTML
expect(parsed.body.strip).to eq(expected.strip)
expect(parsed.body.squish).to eq(expected.squish)
end
context "when creating a post" do
@ -559,31 +545,31 @@ RSpec.describe TopicEmbed do
let(:contents) do
"my normal size emoji <p class='foo'>Hi</p> <img class='emoji other foo' src='/images/smiley.jpg'>"
end
let(:response) { TopicEmbed.find_remote(url) }
before do
SiteSetting.allowed_embed_classnames = "emoji, foo"
stub_request(:get, url).to_return(status: 200, body: contents)
@response = TopicEmbed.find_remote(url)
end
it "has no author tag" do
expect(@response.author).to be_blank
expect(response.author).to be_blank
end
it "img node has emoji class" do
expect(@response.body).to have_tag("img", with: { class: "emoji" })
expect(response.body).to have_tag("img", with: { class: "emoji" })
end
it "img node has foo class" do
expect(@response.body).to have_tag("img", with: { class: "foo" })
expect(response.body).to have_tag("img", with: { class: "foo" })
end
it "p node has foo class" do
expect(@response.body).to have_tag("p", with: { class: "foo" })
expect(response.body).to have_tag("p", with: { class: "foo" })
end
it "nodes removes classes other than emoji" do
expect(@response.body).to have_tag("img", without: { class: "other" })
expect(response.body).to have_tag("img", without: { class: "other" })
end
end
@ -609,27 +595,27 @@ RSpec.describe TopicEmbed do
let(:contents) do
"my normal size emoji <p class='foo'>Hi</p> <img class='emoji other foo' src='/images/smiley.jpg'>"
end
let(:response) { TopicEmbed.find_remote(url) }
before(:each) do
SiteSetting.allowed_embed_classnames = ""
stub_request(:get, url).to_return(status: 200, body: contents)
@response = TopicEmbed.find_remote(url)
end
it 'img node doesn\'t have emoji class' do
expect(@response.body).to have_tag("img", without: { class: "emoji" })
expect(response.body).to have_tag("img", without: { class: "emoji" })
end
it 'img node doesn\'t have foo class' do
expect(@response.body).to have_tag("img", without: { class: "foo" })
expect(response.body).to have_tag("img", without: { class: "foo" })
end
it 'p node doesn\'t foo class' do
expect(@response.body).to have_tag("p", without: { class: "foo" })
expect(response.body).to have_tag("p", without: { class: "foo" })
end
it 'img node doesn\'t have other class' do
expect(@response.body).to have_tag("img", without: { class: "other" })
expect(response.body).to have_tag("img", without: { class: "other" })
end
end

View File

@ -4,60 +4,50 @@ RSpec.describe TopicGroup do
describe "#update_last_read" do
fab!(:group)
fab!(:user)
fab!(:topic) { Fabricate(:private_message_topic, allowed_groups: [group]) }
before do
@topic = Fabricate(:private_message_topic, allowed_groups: [group])
group.add(user)
end
before { group.add(user) }
it "does nothing if the user is not a member of an allowed group" do
another_user = Fabricate(:user)
described_class.update_last_read(another_user, @topic.id, @topic.highest_post_number)
created_topic_group = described_class.where(topic: @topic, group: group).exists?
described_class.update_last_read(another_user, topic.id, topic.highest_post_number)
created_topic_group = described_class.where(topic:, group:).exists?
expect(created_topic_group).to eq(false)
end
it "creates a new record if the user is a member of an allowed group" do
described_class.update_last_read(user, @topic.id, @topic.highest_post_number)
created_topic_group = described_class.find_by(topic: @topic, group: group)
described_class.update_last_read(user, topic.id, topic.highest_post_number)
created_topic_group = described_class.find_by(topic:, group:)
expect(created_topic_group.last_read_post_number).to eq @topic.highest_post_number
expect(created_topic_group.last_read_post_number).to eq topic.highest_post_number
end
it "does nothing if the topic does not have allowed groups" do
@topic.update!(allowed_groups: [])
topic.update!(allowed_groups: [])
described_class.update_last_read(user, @topic.id, @topic.highest_post_number)
created_topic_group = described_class.where(topic: @topic, group: group).exists?
described_class.update_last_read(user, topic.id, topic.highest_post_number)
created_topic_group = described_class.where(topic:, group:).exists?
expect(created_topic_group).to eq(false)
end
it "updates an existing record with a higher post number" do
described_class.create!(
topic: @topic,
group: group,
last_read_post_number: @topic.highest_post_number - 1,
)
described_class.create!(topic:, group:, last_read_post_number: topic.highest_post_number - 1)
described_class.update_last_read(user, @topic.id, @topic.highest_post_number)
created_topic_group = described_class.find_by(topic: @topic, group: group)
described_class.update_last_read(user, topic.id, topic.highest_post_number)
created_topic_group = described_class.find_by(topic:, group:)
expect(created_topic_group.last_read_post_number).to eq @topic.highest_post_number
expect(created_topic_group.last_read_post_number).to eq topic.highest_post_number
end
it "does nothing if the user read post number is lower than the current one" do
highest_read_number = @topic.highest_post_number + 1
described_class.create!(
topic: @topic,
group: group,
last_read_post_number: highest_read_number,
)
highest_read_number = topic.highest_post_number + 1
described_class.create!(topic:, group:, last_read_post_number: highest_read_number)
described_class.update_last_read(user, @topic.id, @topic.highest_post_number)
created_topic_group = described_class.find_by(topic: @topic, group: group)
described_class.update_last_read(user, topic.id, topic.highest_post_number)
created_topic_group = described_class.find_by(topic:, group:)
expect(created_topic_group.last_read_post_number).to eq highest_read_number
end
@ -65,46 +55,38 @@ RSpec.describe TopicGroup do
it "creates a new record if the list of allowed groups has changed" do
another_allowed_group = Fabricate(:group)
another_allowed_group.add(user)
@topic.allowed_groups << another_allowed_group
described_class.create!(
topic: @topic,
group: group,
last_read_post_number: @topic.highest_post_number,
)
topic.allowed_groups << another_allowed_group
described_class.create!(topic:, group:, last_read_post_number: topic.highest_post_number)
described_class.update_last_read(user, @topic.id, @topic.highest_post_number)
created_topic_group = described_class.find_by(topic: @topic, group: another_allowed_group)
described_class.update_last_read(user, topic.id, topic.highest_post_number)
created_topic_group = described_class.find_by(topic:, group: another_allowed_group)
expect(created_topic_group.last_read_post_number).to eq @topic.highest_post_number
expect(created_topic_group.last_read_post_number).to eq topic.highest_post_number
end
it "Only updates the record that shares the same topic_id" do
new_post_number = 100
topic2 = Fabricate(:private_message_topic, allowed_groups: [group], topic_allowed_users: [])
described_class.create!(
topic: @topic,
group: group,
last_read_post_number: @topic.highest_post_number,
)
described_class.create!(topic:, group:, last_read_post_number: topic.highest_post_number)
described_class.create!(
topic: topic2,
group: group,
last_read_post_number: topic2.highest_post_number,
)
described_class.update_last_read(user, @topic.id, new_post_number)
created_topic_group = described_class.find_by(topic: @topic, group: group)
created_topic_group2 = described_class.find_by(topic: topic2, group: group)
described_class.update_last_read(user, topic.id, new_post_number)
created_topic_group = described_class.find_by(topic:, group:)
created_topic_group2 = described_class.find_by(topic: topic2, group:)
expect(created_topic_group.last_read_post_number).to eq new_post_number
expect(created_topic_group2.last_read_post_number).to eq topic2.highest_post_number
end
it "will not raise an error if a topic group already exists" do
TopicGroup.create_topic_group(user, @topic.id, 3, [])
expect(TopicGroup.find_by(group: group, topic: @topic).last_read_post_number).to eq(3)
TopicGroup.create_topic_group(user, @topic.id, 10, [])
expect(TopicGroup.find_by(group: group, topic: @topic).last_read_post_number).to eq(10)
TopicGroup.create_topic_group(user, topic.id, 3, [])
expect(TopicGroup.find_by(group: group, topic:).last_read_post_number).to eq(3)
TopicGroup.create_topic_group(user, topic.id, 10, [])
expect(TopicGroup.find_by(group:, topic:).last_read_post_number).to eq(10)
end
end
end

View File

@ -10,27 +10,27 @@ RSpec.describe TopicLinkClick do
end
describe "topic_links" do
before do
@topic = Fabricate(:topic, user: Fabricate(:user, refresh_auto_groups: true))
@post = Fabricate(:post_with_external_links, user: @topic.user, topic: @topic)
TopicLink.extract_from(@post)
@topic_link = @topic.topic_links.first
end
fab!(:topic) { Fabricate(:topic, user: Fabricate(:user, refresh_auto_groups: true)) }
fab!(:post) { Fabricate(:post_with_external_links, user: topic.user, topic:) }
let(:topic_link) { topic.topic_links.first }
before { TopicLink.extract_from(post) }
it "has 0 clicks at first" do
expect(@topic_link.clicks).to eq(0)
expect(topic_link.clicks).to eq(0)
end
describe ".create" do
before { TopicLinkClick.create(topic_link: @topic_link, ip_address: "192.168.1.1") }
before { described_class.create(topic_link:, ip_address: "192.168.1.1") }
it "creates the forum topic link click" do
expect(TopicLinkClick.count).to eq(1)
expect(described_class.count).to eq(1)
@topic_link.reload
expect(@topic_link.clicks).to eq(1)
topic_link.reload
expect(topic_link.clicks).to eq(1)
expect(TopicLinkClick.first.ip_address.to_s).to eq("192.168.1.1")
expect(described_class.first.ip_address.to_s).to eq("192.168.1.1")
end
end
@ -38,80 +38,79 @@ RSpec.describe TopicLinkClick do
it "works correctly" do
# returns nil to prevent exploits
click =
TopicLinkClick.create_from(
described_class.create_from(
url: "http://url-that-doesnt-exist.com",
post_id: @post.id,
post_id: post.id,
ip: "127.0.0.1",
)
expect(click).to eq(nil)
# redirects if allowlisted
click =
TopicLinkClick.create_from(
described_class.create_from(
url: "https://www.youtube.com/watch?v=jYd_5aggzd4",
post_id: @post.id,
post_id: post.id,
ip: "127.0.0.1",
)
expect(click).to eq("https://www.youtube.com/watch?v=jYd_5aggzd4")
# does not change own link
expect {
TopicLinkClick.create_from(
url: @topic_link.url,
post_id: @post.id,
described_class.create_from(
url: topic_link.url,
post_id: post.id,
ip: "127.0.0.0",
user_id: @post.user_id,
user_id: post.user_id,
)
}.not_to change(TopicLinkClick, :count)
}.not_to change(described_class, :count)
# can handle double # in a url
# NOTE: this is not compliant but exists in the wild
click =
TopicLinkClick.create_from(
described_class.create_from(
url: "http://discourse.org#a#b",
post_id: @post.id,
post_id: post.id,
ip: "127.0.0.1",
)
expect(click).to eq("http://discourse.org#a#b")
end
context "with a valid url and post_id" do
before do
@url =
TopicLinkClick.create_from(url: @topic_link.url, post_id: @post.id, ip: "127.0.0.1")
@click = TopicLinkClick.last
let!(:url) do
described_class.create_from(url: topic_link.url, post_id: post.id, ip: "127.0.0.1")
end
let(:click) { described_class.last }
it "creates a click" do
expect(@click).to be_present
expect(@click.topic_link).to eq(@topic_link)
expect(@url).to eq(@topic_link.url)
expect(click).to be_present
expect(click.topic_link).to eq(topic_link)
expect(url).to eq(topic_link.url)
# second click should not record
expect {
TopicLinkClick.create_from(url: @topic_link.url, post_id: @post.id, ip: "127.0.0.1")
}.not_to change(TopicLinkClick, :count)
described_class.create_from(url: topic_link.url, post_id: post.id, ip: "127.0.0.1")
}.not_to change(described_class, :count)
end
end
context "while logged in" do
fab!(:other_user) { Fabricate(:user) }
before do
@url =
TopicLinkClick.create_from(
url: @topic_link.url,
post_id: @post.id,
ip: "127.0.0.1",
user_id: other_user.id,
)
@click = TopicLinkClick.last
let!(:url) do
described_class.create_from(
url: topic_link.url,
post_id: post.id,
ip: "127.0.0.1",
user_id: other_user.id,
)
end
let(:click) { described_class.last }
it "creates a click without an IP" do
expect(@click).to be_present
expect(@click.topic_link).to eq(@topic_link)
expect(@click.user_id).to eq(other_user.id)
expect(@click.ip_address).to eq(nil)
expect(click).to be_present
expect(click.topic_link).to eq(topic_link)
expect(click.user_id).to eq(other_user.id)
expect(click.ip_address).to eq(nil)
end
end
@ -119,19 +118,19 @@ RSpec.describe TopicLinkClick do
let(:host) { URI.parse(Discourse.base_url).host }
it "returns the url" do
url = TopicLinkClick.create_from(url: "/relative-url", post_id: @post.id, ip: "127.0.0.1")
url = described_class.create_from(url: "/relative-url", post_id: post.id, ip: "127.0.0.1")
expect(url).to eq("/relative-url")
end
it "finds a protocol relative urls with a host" do
url = "//#{host}/relative-url"
redirect = TopicLinkClick.create_from(url: url)
redirect = described_class.create_from(url: url)
expect(redirect).to eq(url)
end
it "returns the url if it's on our host" do
url = "http://#{host}/relative-url"
redirect = TopicLinkClick.create_from(url: url)
redirect = described_class.create_from(url: url)
expect(redirect).to eq(url)
end
@ -144,9 +143,9 @@ RSpec.describe TopicLinkClick do
it "correctly handles cdn links" do
url =
TopicLinkClick.create_from(
described_class.create_from(
url: "https://cdn.discourse.org/stuff/my_link",
topic_id: @topic.id,
topic_id: topic.id,
ip: "127.0.0.3",
)
@ -154,9 +153,9 @@ RSpec.describe TopicLinkClick do
# cdn exploit
url =
TopicLinkClick.create_from(
described_class.create_from(
url: "https://cdn.discourse.org/bad/my_link",
topic_id: @topic.id,
topic_id: topic.id,
ip: "127.0.0.3",
)
@ -165,11 +164,11 @@ RSpec.describe TopicLinkClick do
# cdn better link track
path = "/uploads/site/29/5b585f848d8761d5.xls"
post = Fabricate(:post, topic: @topic, raw: "[test](#{path})")
post = Fabricate(:post, topic:, raw: "[test](#{path})")
TopicLink.extract_from(post)
url =
TopicLinkClick.create_from(
described_class.create_from(
url: "https://cdn.discourse.org/stuff#{path}",
topic_id: post.topic_id,
post_id: post.id,
@ -178,7 +177,7 @@ RSpec.describe TopicLinkClick do
expect(url).to eq("https://cdn.discourse.org/stuff#{path}")
click = TopicLinkClick.order("id desc").first
click = described_class.order("id desc").first
expect(click.topic_link_id).to eq(TopicLink.order("id desc").first.id)
end
@ -190,17 +189,13 @@ RSpec.describe TopicLinkClick do
SiteSetting.s3_cdn_url = "https://discourse-s3-cdn.global.ssl.fastly.net"
post =
Fabricate(
:post,
topic: @topic,
raw: "[test](//test.localhost/uploads/default/my-test-link)",
)
Fabricate(:post, topic:, raw: "[test](//test.localhost/uploads/default/my-test-link)")
TopicLink.extract_from(post)
url =
TopicLinkClick.create_from(
described_class.create_from(
url: "https://discourse-s3-cdn.global.ssl.fastly.net/my-test-link",
topic_id: @topic.id,
topic_id: topic.id,
ip: "127.0.0.3",
)
@ -210,66 +205,64 @@ RSpec.describe TopicLinkClick do
end
context "with a HTTPS version of the same URL" do
before do
@url =
TopicLinkClick.create_from(
url: "https://twitter.com",
topic_id: @topic.id,
ip: "127.0.0.3",
)
@click = TopicLinkClick.last
let!(:url) do
described_class.create_from(
url: "https://twitter.com",
topic_id: topic.id,
ip: "127.0.0.3",
)
end
let(:click) { described_class.last }
it "creates a click" do
expect(@click).to be_present
expect(@click.topic_link).to eq(@topic_link)
expect(@url).to eq("https://twitter.com")
expect(click).to be_present
expect(click.topic_link).to eq(topic_link)
expect(url).to eq("https://twitter.com")
end
end
context "with a google analytics tracking code" do
before do
@url =
TopicLinkClick.create_from(
url: "http://twitter.com?_ga=1.16846778.221554446.1071987018",
topic_id: @topic.id,
ip: "127.0.0.3",
)
@click = TopicLinkClick.last
let!(:url) do
described_class.create_from(
url: "http://twitter.com?_ga=1.16846778.221554446.1071987018",
topic_id: topic.id,
ip: "127.0.0.3",
)
end
let(:click) { described_class.last }
it "creates a click" do
expect(@click).to be_present
expect(@click.topic_link).to eq(@topic_link)
expect(@url).to eq("http://twitter.com?_ga=1.16846778.221554446.1071987018")
expect(click).to be_present
expect(click.topic_link).to eq(topic_link)
expect(url).to eq("http://twitter.com?_ga=1.16846778.221554446.1071987018")
end
end
context "with a query param and google analytics" do
before do
@topic = Fabricate(:topic, user: Fabricate(:user, refresh_auto_groups: true))
@post =
Fabricate(
:post,
topic: @topic,
user: @topic.user,
raw: "Here's a link to twitter: http://twitter.com?ref=forum",
)
TopicLink.extract_from(@post)
@topic_link = @topic.topic_links.first
let(:topic) { Fabricate(:topic, user: Fabricate(:user, refresh_auto_groups: true)) }
let!(:post) do
Fabricate(
:post,
topic:,
user: topic.user,
raw: "Here's a link to twitter: http://twitter.com?ref=forum",
)
end
let(:topic_link) { topic.topic_links.first }
before { TopicLink.extract_from(post) }
it "creates a click" do
url =
TopicLinkClick.create_from(
described_class.create_from(
url: "http://twitter.com?ref=forum&_ga=1.16846778.221554446.1071987018",
topic_id: @topic.id,
post_id: @post.id,
topic_id: topic.id,
post_id: post.id,
ip: "127.0.0.3",
)
click = TopicLinkClick.last
click = described_class.last
expect(click).to be_present
expect(click.topic_link).to eq(@topic_link)
expect(click.topic_link).to eq(topic_link)
expect(url).to eq("http://twitter.com?ref=forum&_ga=1.16846778.221554446.1071987018")
end
end
@ -284,25 +277,25 @@ RSpec.describe TopicLinkClick do
TopicLink.extract_from(post)
TopicLinkClick.create_from(
described_class.create_from(
url: "http://example.com/a",
post_id: post.id,
ip: "127.0.0.1",
user: Fabricate(:user),
)
TopicLinkClick.create_from(
described_class.create_from(
url: "http://example.com/a?b=c",
post_id: post.id,
ip: "127.0.0.2",
user: Fabricate(:user),
)
TopicLinkClick.create_from(
described_class.create_from(
url: "http://example.com/a?b=c&d=e",
post_id: post.id,
ip: "127.0.0.3",
user: Fabricate(:user),
)
TopicLinkClick.create_from(
described_class.create_from(
url: "http://example.com/a?b=c",
post_id: post.id,
ip: "127.0.0.4",
@ -320,33 +313,31 @@ RSpec.describe TopicLinkClick do
end
context "with a google analytics tracking code and a hash" do
before do
@url =
TopicLinkClick.create_from(
url: "http://discourse.org?_ga=1.16846778.221554446.1071987018#faq",
topic_id: @topic.id,
ip: "127.0.0.3",
)
@click = TopicLinkClick.last
let!(:url) do
described_class.create_from(
url: "http://discourse.org?_ga=1.16846778.221554446.1071987018#faq",
topic_id: topic.id,
ip: "127.0.0.3",
)
end
let(:click) { described_class.last }
it "creates a click" do
expect(@click).to be_present
expect(@url).to eq("http://discourse.org?_ga=1.16846778.221554446.1071987018#faq")
expect(click).to be_present
expect(url).to eq("http://discourse.org?_ga=1.16846778.221554446.1071987018#faq")
end
end
context "with a valid url and topic_id" do
before do
@url =
TopicLinkClick.create_from(url: @topic_link.url, topic_id: @topic.id, ip: "127.0.0.3")
@click = TopicLinkClick.last
let!(:url) do
described_class.create_from(url: topic_link.url, topic_id: topic.id, ip: "127.0.0.3")
end
let(:click) { described_class.last }
it "creates a click" do
expect(@click).to be_present
expect(@click.topic_link).to eq(@topic_link)
expect(@url).to eq(@topic_link.url)
expect(click).to be_present
expect(click.topic_link).to eq(topic_link)
expect(url).to eq(topic_link.url)
end
end
end

View File

@ -1333,7 +1333,7 @@ RSpec.describe Topic do
end
describe "bumping topics" do
let!(:topic) { Fabricate(:topic, bumped_at: 1.year.ago) }
fab!(:topic) { Fabricate(:topic, bumped_at: 1.year.ago) }
it "updates the bumped_at field when a new post is made" do
expect(topic.bumped_at).to be_present
@ -1344,19 +1344,18 @@ RSpec.describe Topic do
end
context "when editing posts" do
before do
@earlier_post = Fabricate(:post, topic: topic, user: topic.user)
@last_post = Fabricate(:post, topic: topic, user: topic.user)
topic.reload
end
fab!(:earlier_post) { Fabricate(:post, topic:, user: topic.user) }
fab!(:last_post) { Fabricate(:post, topic:, user: topic.user) }
before { topic.reload }
it "doesn't bump the topic on an edit to the last post that doesn't result in a new version" do
expect {
SiteSetting.editing_grace_period = 5.minutes
@last_post.revise(
@last_post.user,
{ raw: @last_post.raw + "a" },
revised_at: @last_post.created_at + 10.seconds,
last_post.revise(
last_post.user,
{ raw: last_post.raw + "a" },
revised_at: last_post.created_at + 10.seconds,
)
topic.reload
}.not_to change(topic, :bumped_at)
@ -1364,21 +1363,21 @@ RSpec.describe Topic do
it "bumps the topic when a new version is made of the last post" do
expect {
@last_post.revise(moderator, raw: "updated contents")
last_post.revise(moderator, raw: "updated contents")
topic.reload
}.to change(topic, :bumped_at)
end
it "doesn't bump the topic when a post that isn't the last post receives a new version" do
expect {
@earlier_post.revise(moderator, raw: "updated contents")
earlier_post.revise(moderator, raw: "updated contents")
topic.reload
}.not_to change(topic, :bumped_at)
end
it "doesn't bump the topic when a post have invalid topic title while edit" do
expect {
@last_post.revise(moderator, title: "invalid title")
last_post.revise(moderator, title: "invalid title")
topic.reload
}.not_to change(topic, :bumped_at)
end
@ -1419,38 +1418,36 @@ RSpec.describe Topic do
describe "update_status" do
fab!(:post) { Fabricate(:post).tap { |p| p.topic.update!(bumped_at: 1.hour.ago) } }
fab!(:topic) { post.topic }
before do
@original_bumped_at = topic.bumped_at
@user = topic.user
@user.admin = true
end
let(:user) { topic.user }
let!(:original_bumped_at) { topic.bumped_at }
before { user.admin = true }
context "with visibility" do
let(:category) { Fabricate(:category_with_definition) }
context "when disabled" do
it "should not be visible and have correct counts" do
topic.update_status("visible", false, @user)
topic.update_status("visible", false, user)
topic.reload
expect(topic).not_to be_visible
expect(topic.moderator_posts_count).to eq(1)
expect(topic.bumped_at).to eq_time(@original_bumped_at)
expect(topic.bumped_at).to eq_time(original_bumped_at)
end
it "decreases topic_count of topic category" do
topic.update!(category: category)
Category.update_stats
expect do 2.times { topic.update_status("visible", false, @user) } end.to change {
expect do 2.times { topic.update_status("visible", false, user) } end.to change {
category.reload.topic_count
}.by(-1)
end
it "decreases topic_count of user stat" do
expect do 2.times { topic.update_status("visible", false, @user) } end.to change {
expect do 2.times { topic.update_status("visible", false, user) } end.to change {
post.user.user_stat.reload.topic_count
}.from(1).to(0)
end
@ -1459,35 +1456,35 @@ RSpec.describe Topic do
user.user_profile.update(featured_topic_id: topic.id)
expect(user.user_profile.featured_topic).to eq(topic)
topic.update_status("visible", false, @user)
topic.update_status("visible", false, user)
expect(user.user_profile.reload.featured_topic).to eq(nil)
end
end
context "when enabled" do
before do
topic.update_status("visible", false, @user)
topic.update_status("visible", false, user)
topic.reload
end
it "should be visible with correct counts" do
topic.update_status("visible", true, @user)
topic.update_status("visible", true, user)
expect(topic).to be_visible
expect(topic.moderator_posts_count).to eq(2)
expect(topic.bumped_at).to eq_time(@original_bumped_at)
expect(topic.bumped_at).to eq_time(original_bumped_at)
end
it "increases topic_count of topic category" do
topic.update!(category: category)
expect do 2.times { topic.update_status("visible", true, @user) } end.to change {
expect do 2.times { topic.update_status("visible", true, user) } end.to change {
category.reload.topic_count
}.by(1)
end
it "increases topic_count of user stat" do
expect do 2.times { topic.update_status("visible", true, @user) } end.to change {
expect do 2.times { topic.update_status("visible", true, user) } end.to change {
post.user.user_stat.reload.topic_count
}.from(0).to(1)
end
@ -1497,27 +1494,27 @@ RSpec.describe Topic do
context "with pinned" do
context "when disabled" do
before do
topic.update_status("pinned", false, @user)
topic.update_status("pinned", false, user)
topic.reload
end
it "doesn't have a pinned_at but has correct dates" do
expect(topic.pinned_at).to be_blank
expect(topic.moderator_posts_count).to eq(1)
expect(topic.bumped_at).to eq_time(@original_bumped_at)
expect(topic.bumped_at).to eq_time(original_bumped_at)
end
end
context "when enabled" do
before do
topic.update_attribute :pinned_at, nil
topic.update_status("pinned", true, @user)
topic.update_status("pinned", true, user)
topic.reload
end
it "should enable correctly" do
expect(topic.pinned_at).to be_present
expect(topic.bumped_at).to eq_time(@original_bumped_at)
expect(topic.bumped_at).to eq_time(original_bumped_at)
expect(topic.moderator_posts_count).to eq(1)
end
end
@ -1525,67 +1522,69 @@ RSpec.describe Topic do
context "with archived" do
it "should create a staff action log entry" do
expect { topic.update_status("archived", true, @user) }.to change {
expect { topic.update_status("archived", true, user) }.to change {
UserHistory.where(action: UserHistory.actions[:topic_archived]).count
}.by(1)
end
context "when disabled" do
let(:archived_topic) { Fabricate(:topic, archived: true, bumped_at: 1.hour.ago) }
let!(:original_bumped_at) { archived_topic.bumped_at }
before do
@archived_topic = Fabricate(:topic, archived: true, bumped_at: 1.hour.ago)
@original_bumped_at = @archived_topic.bumped_at
@archived_topic.update_status("archived", false, @user)
@archived_topic.reload
archived_topic.update_status("archived", false, user)
archived_topic.reload
end
it "should archive correctly" do
expect(@archived_topic).not_to be_archived
expect(@archived_topic.bumped_at).to eq_time(@original_bumped_at)
expect(@archived_topic.moderator_posts_count).to eq(1)
expect(archived_topic).not_to be_archived
expect(archived_topic.bumped_at).to eq_time(original_bumped_at)
expect(archived_topic.moderator_posts_count).to eq(1)
end
end
context "when enabled" do
before do
topic.update_attribute :archived, false
topic.update_status("archived", true, @user)
topic.update_status("archived", true, user)
topic.reload
end
it "should be archived" do
expect(topic).to be_archived
expect(topic.moderator_posts_count).to eq(1)
expect(topic.bumped_at).to eq_time(@original_bumped_at)
expect(topic.bumped_at).to eq_time(original_bumped_at)
end
end
end
shared_examples_for "a status that closes a topic" do
context "when disabled" do
let(:closed_topic) { Fabricate(:topic, closed: true, bumped_at: 1.hour.ago) }
let!(:original_bumped_at) { closed_topic.bumped_at }
before do
@closed_topic = Fabricate(:topic, closed: true, bumped_at: 1.hour.ago)
@original_bumped_at = @closed_topic.bumped_at
@closed_topic.update_status(status, false, @user)
@closed_topic.reload
closed_topic.update_status(status, false, user)
closed_topic.reload
end
it "should not be pinned" do
expect(@closed_topic).not_to be_closed
expect(@closed_topic.moderator_posts_count).to eq(1)
expect(@closed_topic.bumped_at).not_to eq_time(@original_bumped_at)
expect(closed_topic).not_to be_closed
expect(closed_topic.moderator_posts_count).to eq(1)
expect(closed_topic.bumped_at).not_to eq_time(original_bumped_at)
end
end
context "when enabled" do
before do
topic.update_attribute :closed, false
topic.update_status(status, true, @user)
topic.update_status(status, true, user)
topic.reload
end
it "should be closed" do
expect(topic).to be_closed
expect(topic.bumped_at).to eq_time(@original_bumped_at)
expect(topic.bumped_at).to eq_time(original_bumped_at)
expect(topic.moderator_posts_count).to eq(1)
expect(topic.topic_timers.first).to eq(nil)
end
@ -1597,17 +1596,17 @@ RSpec.describe Topic do
it_behaves_like "a status that closes a topic"
it "should archive group message" do
group.add(@user)
group.add(user)
topic = Fabricate(:private_message_topic, allowed_groups: [group])
expect { topic.update_status(status, true, @user) }.to change(
expect { topic.update_status(status, true, user) }.to change(
topic.group_archived_messages,
:count,
).by(1)
end
it "should create a staff action log entry" do
expect { topic.update_status(status, true, @user) }.to change {
expect { topic.update_status(status, true, user) }.to change {
UserHistory.where(action: UserHistory.actions[:topic_closed]).count
}.by(1)
end
@ -1621,7 +1620,7 @@ RSpec.describe Topic do
it "includes the autoclose duration in the moderator post" do
freeze_time(Time.new(2000, 1, 1))
topic.created_at = 3.days.ago
topic.update_status(status, true, @user)
topic.update_status(status, true, user)
expect(topic.posts.last.raw).to include "closed after 3 days"
end
end
@ -1639,7 +1638,7 @@ RSpec.describe Topic do
freeze_time(2.days.from_now)
topic.update_status(status, true, @user)
topic.update_status(status, true, user)
expect(topic.posts.last.raw).to include "closed after 2 days"
end
end
@ -1713,47 +1712,44 @@ RSpec.describe Topic do
end
context "with last_poster info" do
before do
@post = create_post
@user = @post.user
@topic = @post.topic
end
let(:post) { create_post }
let!(:user) { post.user }
let!(:topic) { post.topic }
it "initially has the last_post_user_id of the OP" do
expect(@topic.last_post_user_id).to eq(@user.id)
expect(topic.last_post_user_id).to eq(user.id)
end
context "after a second post" do
before do
@second_user = coding_horror
@new_post = create_post(topic: @topic, user: @second_user)
@topic.reload
end
let(:second_user) { coding_horror }
let!(:new_post) { create_post(topic:, user: second_user) }
before { topic.reload }
it "updates the last_post_user_id to the second_user" do
expect(@topic.last_post_user_id).to eq(@second_user.id)
expect(@topic.last_posted_at.to_i).to eq(@new_post.created_at.to_i)
topic_user = @second_user.topic_users.find_by(topic_id: @topic.id)
expect(topic.last_post_user_id).to eq(second_user.id)
expect(topic.last_posted_at.to_i).to eq(new_post.created_at.to_i)
topic_user = second_user.topic_users.find_by(topic_id: topic.id)
expect(topic_user.posted?).to eq(true)
end
end
end
describe "with category" do
before { @category = Fabricate(:category_with_definition) }
fab!(:category) { Fabricate(:category_with_definition) }
it "should not increase the topic_count with no category" do
expect {
Fabricate(:topic, user: @category.user)
@category.reload
}.not_to change(@category, :topic_count)
Fabricate(:topic, user: category.user)
category.reload
}.not_to change(category, :topic_count)
end
it "should increase the category's topic_count" do
expect {
Fabricate(:topic, user: @category.user, category_id: @category.id)
@category.reload
}.to change(@category, :topic_count).by(1)
Fabricate(:topic, user: category.user, category_id: category.id)
category.reload
}.to change(category, :topic_count).by(1)
end
end
@ -2903,16 +2899,16 @@ RSpec.describe Topic do
topic = Fabricate(:topic)
user = topic.user
user.admin = true
@topic_status_event_triggered = false
topic_status_event = spy
blk = Proc.new { @topic_status_event_triggered = true }
blk = Proc.new { topic_status_event.triggered }
DiscourseEvent.on(:topic_status_updated, &blk)
topic.update_status("closed", true, user)
topic.reload
expect(@topic_status_event_triggered).to eq(true)
expect(topic_status_event).to have_received(:triggered)
ensure
DiscourseEvent.off(:topic_status_updated, &blk)
end
@ -3336,38 +3332,40 @@ RSpec.describe Topic do
end
describe "#auto_close_threshold_reached?" do
fab!(:post)
fab!(:reviewable) { Fabricate(:reviewable_flagged_post, target: post, topic: post.topic) }
let(:topic) { post.topic }
before do
Reviewable.set_priorities(low: 2.0, medium: 6.0, high: 9.0)
SiteSetting.num_flaggers_to_close_topic = 2
SiteSetting.reviewable_default_visibility = "medium"
SiteSetting.auto_close_topic_sensitivity = Reviewable.sensitivities[:high]
post = Fabricate(:post)
@topic = post.topic
@reviewable = Fabricate(:reviewable_flagged_post, target: post, topic: @topic)
end
it "ignores flags with a low score" do
5.times do
@reviewable.add_score(
reviewable.add_score(
Fabricate(:user, trust_level: TrustLevel[0]),
PostActionType.types[:spam],
created_at: 1.minute.ago,
)
end
expect(@topic.auto_close_threshold_reached?).to eq(false)
expect(topic.auto_close_threshold_reached?).to eq(false)
end
it "returns true when the flags have a high score" do
5.times do
@reviewable.add_score(
reviewable.add_score(
Fabricate(:user, admin: true),
PostActionType.types[:spam],
created_at: 1.minute.ago,
)
end
expect(@topic.auto_close_threshold_reached?).to eq(true)
expect(topic.auto_close_threshold_reached?).to eq(true)
end
end

View File

@ -43,28 +43,28 @@ RSpec.describe TopicUser do
describe "#notification_levels" do
context "when verifying enum sequence" do
before { @notification_levels = TopicUser.notification_levels }
let(:notification_levels) { TopicUser.notification_levels }
it "'muted' should be at 0 position" do
expect(@notification_levels[:muted]).to eq(0)
expect(notification_levels[:muted]).to eq(0)
end
it "'watching' should be at 3rd position" do
expect(@notification_levels[:watching]).to eq(3)
expect(notification_levels[:watching]).to eq(3)
end
end
end
describe "#notification_reasons" do
context "when verifying enum sequence" do
before { @notification_reasons = TopicUser.notification_reasons }
let(:notification_reasons) { TopicUser.notification_reasons }
it "'created_topic' should be at 1st position" do
expect(@notification_reasons[:created_topic]).to eq(1)
expect(notification_reasons[:created_topic]).to eq(1)
end
it "'plugin_changed' should be at 9th position" do
expect(@notification_reasons[:plugin_changed]).to eq(9)
expect(notification_reasons[:plugin_changed]).to eq(9)
end
end
end

View File

@ -188,31 +188,30 @@ RSpec.describe UserAction do
end
describe "when user likes" do
fab!(:post)
let(:likee) { post.user }
fab!(:liker) { coding_horror }
def likee_stream
UserAction.stream(user_id: likee.id, guardian: Guardian.new)
end
before { @old_count = likee_stream.count }
fab!(:post)
fab!(:liker) { coding_horror }
let(:likee) { post.user }
let!(:old_count) { likee_stream.count }
it "creates a new stream entry" do
PostActionCreator.like(liker, post)
expect(likee_stream.count).to eq(@old_count + 1)
expect(likee_stream.count).to eq(old_count + 1)
end
context "with successful like" do
before do
PostActionCreator.like(liker, post)
@liker_action = liker.user_actions.find_by(action_type: UserAction::LIKE)
@likee_action = likee.user_actions.find_by(action_type: UserAction::WAS_LIKED)
end
let(:liker_action) { liker.user_actions.find_by(action_type: UserAction::LIKE) }
let(:likee_action) { likee.user_actions.find_by(action_type: UserAction::WAS_LIKED) }
before { PostActionCreator.like(liker, post) }
it "should result in correct data assignment" do
expect(@liker_action).not_to eq(nil)
expect(@likee_action).not_to eq(nil)
expect(liker_action).not_to eq(nil)
expect(likee_action).not_to eq(nil)
expect(likee.user_stat.reload.likes_received).to eq(1)
expect(liker.user_stat.reload.likes_given).to eq(1)
@ -227,9 +226,9 @@ RSpec.describe UserAction do
let(:liker) { post.topic.topic_allowed_users.last.user }
it "should not increase user stats" do
expect(@liker_action).not_to eq(nil)
expect(liker_action).not_to eq(nil)
expect(liker.user_stat.reload.likes_given).to eq(0)
expect(@likee_action).not_to eq(nil)
expect(likee_action).not_to eq(nil)
expect(likee.user_stat.reload.likes_received).to eq(0)
PostActionDestroyer.destroy(liker, post, :like)
@ -244,61 +243,57 @@ RSpec.describe UserAction do
it "doesn't add the entry to the stream" do
PostActionCreator.like(liker, post)
expect(likee_stream.count).not_to eq(@old_count + 1)
expect(likee_stream.count).not_to eq(old_count + 1)
end
end
end
describe "when a user posts a new topic" do
before do
freeze_time(100.days.ago) do
@post = create_post
PostAlerter.post_created(@post)
end
end
let(:post) { Post.last }
before { freeze_time(100.days.ago) { PostAlerter.post_created(create_post) } }
describe "topic action" do
it "should exist" do
@action = @post.user.user_actions.find_by(action_type: UserAction::NEW_TOPIC)
let(:action) { post.user.user_actions.find_by(action_type: UserAction::NEW_TOPIC) }
expect(@action).not_to eq(nil)
expect(@action.created_at).to eq_time(@post.topic.created_at)
it "should exist" do
expect(action).not_to eq(nil)
expect(action.created_at).to eq_time(post.topic.created_at)
end
end
it "should not log a post user action" do
expect(@post.user.user_actions.find_by(action_type: UserAction::REPLY)).to eq(nil)
expect(post.user.user_actions.find_by(action_type: UserAction::REPLY)).to eq(nil)
end
describe "when another user posts on the topic" do
before do
@other_user = coding_horror
@mentioned = Fabricate(:admin)
fab!(:mentioned) { Fabricate(:admin) }
@response =
PostCreator.new(
@other_user,
reply_to_post_number: 1,
topic_id: @post.topic_id,
raw: "perhaps @#{@mentioned.username} knows how this works?",
).create
PostAlerter.post_created(@response)
let(:other_user) { coding_horror }
let(:response) do
PostCreator.new(
other_user,
reply_to_post_number: 1,
topic_id: post.topic_id,
raw: "perhaps @#{mentioned.username} knows how this works?",
).create
end
before { PostAlerter.post_created(response) }
it "should log user actions correctly" do
expect(@response.user.user_actions.find_by(action_type: UserAction::REPLY)).not_to eq(nil)
expect(@post.user.user_actions.find_by(action_type: UserAction::RESPONSE)).not_to eq(nil)
expect(@mentioned.user_actions.find_by(action_type: UserAction::MENTION)).not_to eq(nil)
expect(response.user.user_actions.find_by(action_type: UserAction::REPLY)).not_to eq(nil)
expect(post.user.user_actions.find_by(action_type: UserAction::RESPONSE)).not_to eq(nil)
expect(mentioned.user_actions.find_by(action_type: UserAction::MENTION)).not_to eq(nil)
expect(
@post.user.user_actions.joins(:target_post).where("posts.post_number = 2").count,
post.user.user_actions.joins(:target_post).where("posts.post_number = 2").count,
).to eq(1)
end
it "should not log a double notification for a post edit" do
@response.raw = "here it goes again"
@response.save!
expect(@response.user.user_actions.where(action_type: UserAction::REPLY).count).to eq(1)
response.raw = "here it goes again"
response.save!
expect(response.user.user_actions.where(action_type: UserAction::REPLY).count).to eq(1)
end
end
end

View File

@ -1,23 +1,23 @@
# frozen_string_literal: true
RSpec.describe UserAssociatedGroup do
let(:user) { Fabricate(:user) }
let(:group) { Fabricate(:group) }
let(:group2) { Fabricate(:group) }
let(:associated_group) { Fabricate(:associated_group) }
let(:associated_group2) { Fabricate(:associated_group) }
before do
fab!(:group)
fab!(:associated_group)
fab!(:user)
fab!(:gag) do
GroupAssociatedGroup.create(group_id: group.id, associated_group_id: associated_group.id)
@uag = described_class.create(user_id: user.id, associated_group_id: associated_group.id)
end
fab!(:uag) { described_class.create(user_id: user.id, associated_group_id: associated_group.id) }
let(:group2) { Fabricate(:group) }
let(:associated_group2) { Fabricate(:associated_group) }
it "adds user to group when created" do
expect(group.users.include?(user)).to eq(true)
end
it "removes user from group when destroyed" do
@uag.destroy!
uag.destroy!
expect(group.users.include?(user)).to eq(false)
end
@ -25,7 +25,7 @@ RSpec.describe UserAssociatedGroup do
GroupAssociatedGroup.create(group_id: group.id, associated_group_id: associated_group2.id)
described_class.create(user_id: user.id, associated_group_id: associated_group2.id)
@uag.destroy!
uag.destroy!
expect(group.users.include?(user)).to eq(true)
end
@ -33,7 +33,7 @@ RSpec.describe UserAssociatedGroup do
GroupAssociatedGroup.create(group_id: group2.id, associated_group_id: associated_group2.id)
described_class.create(user_id: user.id, associated_group_id: associated_group2.id)
@uag.destroy!
uag.destroy!
expect(group.users.include?(user)).to eq(false)
end
end

View File

@ -3,14 +3,14 @@
RSpec.describe UserHistory do
describe "#actions" do
context "when verifying enum sequence" do
before { @actions = UserHistory.actions }
let!(:actions) { described_class.actions }
it "'delete_user' should be at 1st position" do
expect(@actions[:delete_user]).to eq(1)
expect(actions[:delete_user]).to eq(1)
end
it "'change_site_text' should be at 29th position" do
expect(@actions[:change_site_text]).to eq(29)
expect(actions[:change_site_text]).to eq(29)
end
end
end
@ -18,23 +18,25 @@ RSpec.describe UserHistory do
describe "#staff_action_records" do
context "with some records" do
fab!(:admin)
let(:custom_type) { "confirmed_ham" }
before do
@change_site_setting =
UserHistory.create!(
action: UserHistory.actions[:change_site_setting],
subject: "title",
previous_value: "Old",
new_value: "New",
)
@change_trust_level =
UserHistory.create!(
action: UserHistory.actions[:change_trust_level],
target_user_id: Fabricate(:user).id,
details: "stuff happened",
)
@custom_history = StaffActionLogger.new(admin).log_custom("confirmed_ham", admin_only: true)
let(:custom_type) { "confirmed_ham" }
let!(:change_site_setting) do
UserHistory.create!(
action: UserHistory.actions[:change_site_setting],
subject: "title",
previous_value: "Old",
new_value: "New",
)
end
let!(:change_trust_level) do
UserHistory.create!(
action: UserHistory.actions[:change_trust_level],
target_user_id: Fabricate(:user).id,
details: "stuff happened",
)
end
let!(:custom_history) do
StaffActionLogger.new(admin).log_custom("confirmed_ham", admin_only: true)
end
it "returns all records for admins" do
@ -44,24 +46,24 @@ RSpec.describe UserHistory do
it "doesn't return records to moderators that only admins should see" do
records = described_class.staff_action_records(Fabricate(:moderator)).to_a
expect(records).not_to include([@change_site_setting])
expect(records).not_to include([change_site_setting])
end
it "filters by action" do
records =
described_class.staff_action_records(
admin,
action_id: @change_site_setting.action_before_type_cast,
action_id: change_site_setting.action_before_type_cast,
).to_a
expect(records.size).to eq(1)
expect(records.first).to eq(@change_site_setting)
expect(records.first).to eq(change_site_setting)
end
it "filters by action_name" do
records =
described_class.staff_action_records(admin, action_name: "change_site_setting").to_a
expect(records.size).to eq(1)
expect(records.first).to eq(@change_site_setting)
expect(records.first).to eq(change_site_setting)
end
it "Uses action_name as custom_type when searching for custom_staff logs" do
@ -73,7 +75,7 @@ RSpec.describe UserHistory do
).to_a
expect(records.size).to eq(1)
expect(records.first).to eq(@custom_history)
expect(records.first).to eq(custom_history)
end
end
end

View File

@ -793,32 +793,32 @@ RSpec.describe User do
end
describe "email_hash" do
before_all { @user = Fabricate(:user) }
fab!(:user)
fab!(:user2) { Fabricate(:user) }
it "should have a sane email hash" do
expect(@user.email_hash).to match(/^[0-9a-f]{32}$/)
expect(user.email_hash).to match(/^[0-9a-f]{32}$/)
end
it "should use downcase email" do
@user.email = "example@example.com"
@user2 = Fabricate(:user)
@user2.email = "ExAmPlE@eXaMpLe.com"
user.email = "example@example.com"
user2.email = "ExAmPlE@eXaMpLe.com"
expect(@user.email_hash).to eq(@user2.email_hash)
expect(user.email_hash).to eq(user2.email_hash)
end
it "should trim whitespace before hashing" do
@user.email = "example@example.com"
@user2 = Fabricate(:user)
@user2.email = " example@example.com "
user.email = "example@example.com"
user2.email = " example@example.com "
expect(@user.email_hash).to eq(@user2.email_hash)
expect(user.email_hash).to eq(user2.email_hash)
end
end
describe "associated_accounts" do
fab!(:user)
it "should correctly find social associations" do
user = Fabricate(:user)
expect(user.associated_accounts).to eq([])
UserAssociatedAccount.create(
@ -981,20 +981,18 @@ RSpec.describe User do
end
describe "username uniqueness" do
before_all do
@user = Fabricate.build(:user)
@user.save!
@codinghorror = Fabricate.build(:coding_horror)
end
fab!(:user)
let!(:codinghorror) { Fabricate.build(:coding_horror) }
it "should not allow saving if username is reused" do
@codinghorror.username = @user.username
expect(@codinghorror.save).to eq(false)
codinghorror.username = user.username
expect(codinghorror.save).to eq(false)
end
it "should not allow saving if username is reused in different casing" do
@codinghorror.username = @user.username.upcase
expect(@codinghorror.save).to eq(false)
codinghorror.username = user.username.upcase
expect(codinghorror.save).to eq(false)
end
end
@ -1200,23 +1198,24 @@ RSpec.describe User do
end
describe "passwords" do
let(:user) { Fabricate.build(:user, active: false) }
it "should not have an active account with a good password" do
@user = Fabricate.build(:user, active: false)
@user.password = "ilovepasta"
@user.save!
user.password = "ilovepasta"
user.save!
expect(@user.active).to eq(false)
expect(@user.confirm_password?("ilovepasta")).to eq(true)
expect(user.active).to eq(false)
expect(user.confirm_password?("ilovepasta")).to eq(true)
email_token = Fabricate(:email_token, user: @user, email: "pasta@delicious.com")
email_token = Fabricate(:email_token, user:, email: "pasta@delicious.com")
UserAuthToken.generate!(user_id: @user.id)
UserAuthToken.generate!(user_id: user.id)
@user.password = "passwordT0"
@user.save!
user.password = "passwordT0"
user.save!
# must expire old token on password change
expect(@user.user_auth_tokens.count).to eq(0)
expect(user.user_auth_tokens.count).to eq(0)
email_token.reload
expect(email_token.expired).to eq(true)