docbrown/spec/models/user_spec.rb
Michael Kohl 6b2160f307
Theming cleanup (#15237)
* Theming cleanup

* Fix specs

* Use correct method

* Update storybook theme switcher
2021-11-09 10:11:55 -05:00

853 lines
31 KiB
Ruby

require "rails_helper"
RSpec.describe User, type: :model do
def user_from_authorization_service(service_name, signed_in_resource = nil, cta_variant = "navbar_basic")
auth = OmniAuth.config.mock_auth[service_name]
Authentication::Authenticator.call(
auth,
current_user: signed_in_resource,
cta_variant: cta_variant,
)
end
def mock_username(provider_name, username)
case provider_name
when :apple
OmniAuth.config.mock_auth[provider_name].info.first_name = username
when :forem
OmniAuth.config.mock_auth[provider_name].info.user_nickname = username
else
OmniAuth.config.mock_auth[provider_name].info.nickname = username
end
end
def provider_username(service_name)
auth_payload = OmniAuth.config.mock_auth[service_name]
provider_class = Authentication::Providers.get!(auth_payload.provider)
provider_class.new(auth_payload).user_nickname
end
let(:user) { create(:user) }
let(:other_user) { create(:user) }
let(:org) { create(:organization) }
before do
omniauth_mock_providers_payload
allow(Settings::Authentication).to receive(:providers).and_return(Authentication::Providers.available)
end
describe "validations" do
describe "builtin validations" do
subject { user }
it { is_expected.to have_one(:profile).dependent(:destroy) }
it { is_expected.to have_one(:notification_setting).dependent(:destroy) }
it { is_expected.to have_one(:setting).dependent(:destroy) }
it { is_expected.to have_many(:access_grants).class_name("Doorkeeper::AccessGrant").dependent(:delete_all) }
it { is_expected.to have_many(:access_tokens).class_name("Doorkeeper::AccessToken").dependent(:delete_all) }
it { is_expected.to have_many(:ahoy_events).class_name("Ahoy::Event").dependent(:destroy) }
it { is_expected.to have_many(:ahoy_visits).class_name("Ahoy::Visit").dependent(:destroy) }
it { is_expected.to have_many(:api_secrets).dependent(:destroy) }
it { is_expected.to have_many(:articles).dependent(:destroy) }
it { is_expected.to have_many(:audit_logs).dependent(:nullify) }
it { is_expected.to have_many(:badge_achievements).dependent(:destroy) }
it { is_expected.to have_many(:badges).through(:badge_achievements) }
it { is_expected.to have_many(:chat_channel_memberships).dependent(:destroy) }
it { is_expected.to have_many(:chat_channels).through(:chat_channel_memberships) }
it { is_expected.to have_many(:collections).dependent(:destroy) }
it { is_expected.to have_many(:comments).dependent(:destroy) }
it { is_expected.to have_many(:credits).dependent(:destroy) }
it { is_expected.to have_many(:discussion_locks).dependent(:destroy) }
it { is_expected.to have_many(:display_ad_events).dependent(:destroy) }
it { is_expected.to have_many(:email_authorizations).dependent(:delete_all) }
it { is_expected.to have_many(:email_messages).class_name("Ahoy::Message").dependent(:destroy) }
it { is_expected.to have_many(:field_test_memberships).class_name("FieldTest::Membership").dependent(:destroy) }
it { is_expected.to have_many(:github_repos).dependent(:destroy) }
it { is_expected.to have_many(:html_variants).dependent(:destroy) }
it { is_expected.to have_many(:identities).dependent(:destroy) }
it { is_expected.to have_many(:identities_enabled) }
it { is_expected.to have_many(:listings).dependent(:destroy) }
it { is_expected.to have_many(:mentions).dependent(:destroy) }
it { is_expected.to have_many(:messages).dependent(:destroy) }
it { is_expected.to have_many(:notes).dependent(:destroy) }
it { is_expected.to have_many(:notification_subscriptions).dependent(:destroy) }
it { is_expected.to have_many(:notifications).dependent(:destroy) }
it { is_expected.to have_many(:organization_memberships).dependent(:destroy) }
it { is_expected.to have_many(:organizations).through(:organization_memberships) }
it { is_expected.to have_many(:page_views).dependent(:nullify) }
it { is_expected.to have_many(:podcast_episode_appearances).dependent(:destroy) }
it { is_expected.to have_many(:podcast_episodes).through(:podcast_episode_appearances).source(:podcast_episode) }
it { is_expected.to have_many(:podcast_ownerships).dependent(:destroy) }
it { is_expected.to have_many(:podcasts_owned).through(:podcast_ownerships).source(:podcast) }
it { is_expected.to have_many(:poll_skips).dependent(:destroy) }
it { is_expected.to have_many(:poll_votes).dependent(:destroy) }
it { is_expected.to have_many(:profile_pins).dependent(:delete_all) }
it { is_expected.to have_many(:rating_votes).dependent(:nullify) }
it { is_expected.to have_many(:reactions).dependent(:destroy) }
it { is_expected.to have_many(:response_templates).dependent(:destroy) }
it { is_expected.to have_many(:source_authored_user_subscriptions).dependent(:destroy) }
it { is_expected.to have_many(:subscribed_to_user_subscriptions).dependent(:destroy) }
it { is_expected.to have_many(:subscribers).dependent(:destroy) }
it { is_expected.to have_many(:tweets).dependent(:nullify) }
it { is_expected.to have_many(:webhook_endpoints).class_name("Webhook::Endpoint").dependent(:delete_all) }
# rubocop:disable RSpec/NamedSubject
it do
expect(subject).to have_many(:access_grants)
.class_name("Doorkeeper::AccessGrant")
.with_foreign_key("resource_owner_id")
.dependent(:delete_all)
end
it do
expect(subject).to have_many(:access_tokens)
.class_name("Doorkeeper::AccessToken")
.with_foreign_key("resource_owner_id")
.dependent(:delete_all)
end
it do
expect(subject).to have_many(:affected_feedback_messages)
.class_name("FeedbackMessage")
.with_foreign_key("affected_id")
.dependent(:nullify)
end
it do
expect(subject).to have_many(:authored_notes)
.class_name("Note")
.with_foreign_key("author_id")
.dependent(:delete_all)
end
it do
expect(subject).to have_many(:badge_achievements_rewarded)
.class_name("BadgeAchievement")
.with_foreign_key("rewarder_id")
.inverse_of(:rewarder)
.dependent(:nullify)
end
it do
expect(subject).to have_many(:banished_users)
.class_name("BanishedUser")
.with_foreign_key("banished_by_id")
.inverse_of(:banished_by)
.dependent(:nullify)
end
it do
expect(subject).to have_many(:blocked_blocks)
.class_name("UserBlock")
.with_foreign_key("blocked_id")
.dependent(:delete_all)
end
it do
expect(subject).to have_many(:blocker_blocks)
.class_name("UserBlock")
.with_foreign_key("blocker_id")
.dependent(:delete_all)
end
it do
expect(subject).to have_many(:created_podcasts)
.class_name("Podcast")
.with_foreign_key(:creator_id)
.dependent(:nullify)
end
it do
expect(subject).to have_many(:offender_feedback_messages)
.class_name("FeedbackMessage")
.with_foreign_key(:offender_id)
.dependent(:nullify)
end
it do
expect(subject).to have_many(:reporter_feedback_messages)
.class_name("FeedbackMessage")
.with_foreign_key(:reporter_id)
.dependent(:nullify)
end
# rubocop:enable RSpec/NamedSubject
it { is_expected.not_to allow_value("AcMe_1%").for(:username) }
it { is_expected.to allow_value("AcMe_1").for(:username) }
it { is_expected.not_to allow_value("$example.com/value\x1F").for(:payment_pointer) }
it { is_expected.not_to allow_value("example.com/value").for(:payment_pointer) }
it { is_expected.to allow_value(" $example.com/value ").for(:payment_pointer) }
it { is_expected.to allow_value(nil).for(:payment_pointer) }
it { is_expected.to allow_value("").for(:payment_pointer) }
it { is_expected.to validate_length_of(:email).is_at_most(50).allow_nil }
it { is_expected.to validate_length_of(:name).is_at_most(100).is_at_least(1) }
it { is_expected.to validate_length_of(:password).is_at_most(100).is_at_least(8) }
it { is_expected.to validate_length_of(:username).is_at_most(30).is_at_least(2) }
it { is_expected.to validate_presence_of(:articles_count) }
it { is_expected.to validate_presence_of(:badge_achievements_count) }
it { is_expected.to validate_presence_of(:blocked_by_count) }
it { is_expected.to validate_presence_of(:blocking_others_count) }
it { is_expected.to validate_presence_of(:comments_count) }
it { is_expected.to validate_presence_of(:credits_count) }
it { is_expected.to validate_presence_of(:following_orgs_count) }
it { is_expected.to validate_presence_of(:following_tags_count) }
it { is_expected.to validate_presence_of(:following_users_count) }
it { is_expected.to validate_presence_of(:rating_votes_count) }
it { is_expected.to validate_presence_of(:reactions_count) }
it { is_expected.to validate_presence_of(:sign_in_count) }
it { is_expected.to validate_presence_of(:spent_credits_count) }
it { is_expected.to validate_presence_of(:subscribed_to_user_subscriptions_count) }
# rubocop:disable RSpec/NestedGroups
context "when evaluating the custom error message for username uniqueness" do
subject { create(:user, username: "test_user_123") }
it { is_expected.to validate_uniqueness_of(:username).with_message("test_user_123 is taken.").case_insensitive }
end
# rubocop:enable RSpec/NestedGroups
Authentication::Providers.username_fields.each do |username_field|
it { is_expected.to validate_uniqueness_of(username_field).allow_nil }
end
end
it "renders custom error message with value of taken username" do
create(:user, username: "test_user_123")
same_username = build(:user, username: "test_user_123")
expect(same_username).not_to be_valid
expect(same_username.errors[:username].to_s).to include("test_user_123 is taken.")
end
it "validates username against reserved words" do
user = build(:user, username: "readinglist")
expect(user).not_to be_valid
expect(user.errors[:username].to_s).to include("reserved")
end
it "takes organization slug into account" do
create(:organization, slug: "lightalloy")
user = build(:user, username: "lightalloy")
expect(user).not_to be_valid
expect(user.errors[:username].to_s).to include("taken")
end
it "takes podcast slug into account" do
create(:podcast, slug: "lightpodcast")
user = build(:user, username: "lightpodcast")
expect(user).not_to be_valid
expect(user.errors[:username].to_s).to include("taken")
end
it "takes page slug into account" do
create(:page, slug: "page_yo")
user = build(:user, username: "page_yo")
expect(user).not_to be_valid
expect(user.errors[:username].to_s).to include("taken")
end
it "validates can_send_confirmation_email for existing user" do
user = create(:user)
limiter = RateLimitChecker.new(user)
allow(user).to receive(:rate_limiter).and_return(limiter)
allow(limiter).to receive(:limit_by_action).and_return(true)
allow(limiter).to receive(:track_limit_by_action)
user.update(email: "new_email@yo.com")
expect(user).not_to be_valid
expect(user.errors[:email].to_s).to include("confirmation could not be sent. Rate limit reached")
expect(limiter).to have_received(:track_limit_by_action).with(:send_email_confirmation).twice
end
it "validates update_rate_limit for existing user" do
user = create(:user)
limiter = RateLimitChecker.new(user)
allow(user).to receive(:rate_limiter).and_return(limiter)
allow(limiter).to receive(:limit_by_action).and_return(true)
allow(limiter).to receive(:track_limit_by_action)
user.update(articles_count: 5)
expect(user).not_to be_valid
expect(user.errors[:base].to_s).to include("could not be saved. Rate limit reached")
expect(limiter).to have_received(:track_limit_by_action).with(:user_update).twice
end
end
context "when callbacks are triggered before validation" do
let(:user) { build(:user) }
Authentication::Providers.username_fields.each do |username_field|
describe username_field do
it "sets #{username_field} to nil if empty" do
user.assign_attributes(username_field => "")
user.validate!
expect(user.attributes[username_field.to_s]).to be_nil
end
it "does not change a valid name" do
user.assign_attributes(username_field => "hello")
user.validate!
expect(user.attributes[username_field.to_s]).to eq("hello")
end
end
end
describe "#email" do
it "sets email to nil if empty" do
user.email = ""
user.validate!
expect(user.email).to eq(nil)
end
it "does not change a valid name" do
user.email = "anna@example.com"
user.validate!
expect(user.email).to eq("anna@example.com")
end
end
describe "#username" do
it "receives a temporary username if none is given" do
user.username = ""
user.validate!
expect(user.username).not_to be_blank
end
it "does not allow to change to a username that is taken" do
user.username = other_user.username
expect(user).not_to be_valid
end
it "does not allow to change to a username that is taken by an organization" do
user.username = create(:organization).slug
expect(user).not_to be_valid
end
end
context "when the past value is relevant" do
let(:user) { create(:user) }
it "changes old_username and old_old_username properly if username changes" do
old_username = user.username
random_new_username = "username_#{rand(100_000_000)}"
user.update(username: random_new_username)
expect(user.username).to eq(random_new_username)
expect(user.old_username).to eq(old_username)
new_username = user.username
user.update(username: "username_#{rand(100_000_000)}")
expect(user.old_username).to eq(new_username)
expect(user.old_old_username).to eq(old_username)
end
end
end
context "when callbacks are triggered before and after create" do
let(:user) { create(:user, email: nil) }
describe "#send_welcome_notification" do
let(:mascot_account) { create(:user) }
let!(:set_up_profile_broadcast) { create(:set_up_profile_broadcast) }
before do
allow(described_class).to receive(:mascot_account).and_return(mascot_account)
end
it "sends a setup welcome notification when an active broadcast exists" do
new_user = nil
sidekiq_perform_enqueued_jobs do
new_user = create(:user)
end
expect(new_user.reload.notifications.count).to eq(1)
expect(new_user.reload.notifications.first.notifiable).to eq(set_up_profile_broadcast)
end
it "does not send a setup welcome notification without an active broadcast" do
set_up_profile_broadcast.update!(active: false)
new_user = nil
sidekiq_perform_enqueued_jobs do
new_user = create(:user)
end
expect(new_user.reload.notifications.count).to eq(0)
end
end
end
context "when callbacks are triggered after commit" do
describe "subscribing to mailchimp newsletter" do
let(:user) { build(:user) }
it "enqueues SubscribeToMailchimpNewsletterWorker" do
sidekiq_assert_enqueued_with(job: Users::SubscribeToMailchimpNewsletterWorker, args: user.id) do
user.save
end
end
it "does not enqueue without an email" do
sidekiq_assert_no_enqueued_jobs(only: Users::SubscribeToMailchimpNewsletterWorker) do
user.update(email: "")
end
end
it "does not enqueue with an unconfirmed email" do
sidekiq_assert_no_enqueued_jobs(only: Users::SubscribeToMailchimpNewsletterWorker) do
user.update(unconfirmed_email: "bob@bob.com", confirmation_sent_at: Time.current)
end
end
it "does not enqueue with a non-registered user" do
sidekiq_assert_no_enqueued_jobs(only: Users::SubscribeToMailchimpNewsletterWorker) do
user.update(registered: false)
end
end
it "does not enqueue if Mailchimp is not enabled" do
allow(Settings::General).to receive(:mailchimp_api_key).and_return(nil)
sidekiq_assert_no_enqueued_jobs(only: Users::SubscribeToMailchimpNewsletterWorker) do
user.update(email: "something@real.com")
end
end
it "does not enqueue when the email address or subscription status has not changed" do
# The trait replaces the method with a dummy, but we need the actual method for this test.
user = described_class.find(create(:user, :ignore_mailchimp_subscribe_callback).id)
sidekiq_assert_no_enqueued_jobs(only: Users::SubscribeToMailchimpNewsletterWorker) do
user.update(credits_count: 100)
end
end
end
end
describe "user registration", vcr: { cassette_name: "fastly_sloan" } do
let(:user) { create(:user) }
before do
allow(FeatureFlag).to receive(:enabled?).with(:forem_passport).and_return(true)
omniauth_mock_providers_payload
end
Authentication::Providers.available.each do |provider_name|
it "finds user by email and assigns identity to that if exists for #{provider_name}" do
OmniAuth.config.mock_auth[provider_name].info.email = user.email
new_user = user_from_authorization_service(provider_name)
expect(new_user.id).to eq(user.id)
end
it "assigns random username if username is taken on registration for #{provider_name}" do
OmniAuth.config.mock_auth[provider_name].info.nickname = user.username
OmniAuth.config.mock_auth[provider_name].info.first_name = user.username
new_user = user_from_authorization_service(provider_name)
expect(new_user.persisted?).to be(true)
expect(new_user.username).not_to eq(user.username)
end
it "assigns signup_cta_variant to state param if new user for #{provider_name}" do
new_user = user_from_authorization_service(provider_name, nil, "hey-hey-hey")
expect(new_user.signup_cta_variant).to eq("hey-hey-hey")
end
it "does not assign signup_cta_variant to non-new users for #{provider_name}" do
returning_user = create(:user, signup_cta_variant: nil)
new_user = user_from_authorization_service(provider_name, returning_user, "hey-hey-hey")
expect(new_user.signup_cta_variant).to be(nil)
end
it "assigns proper social username based on authentication for #{provider_name}" do
mock_username(provider_name, "valid_username")
new_user = user_from_authorization_service(provider_name)
case provider_name
when :apple
expect(new_user.username).to match(/valid_username_\w+/)
when :facebook
expect(new_user.username).to match(/fname_lname_\S*\z/)
else
expect(new_user.username).to eq("valid_username")
end
end
it "marks registered_at for newly registered user" do
new_user = user_from_authorization_service(provider_name, nil, "navbar_basic")
expect(new_user.registered_at).not_to be nil
end
it "assigns modified username if the username is invalid for #{provider_name}" do
mock_username(provider_name, "invalid.username")
new_user = user_from_authorization_service(provider_name)
case provider_name
when :apple
expect(new_user.username).to match(/invalidusername_\w+/)
when :facebook
expect(new_user.username).to match(/fname_lname_\S*\z/)
else
expect(new_user.username).to eq("invalidusername")
end
end
it "serializes the authentication payload for #{provider_name}" do
new_user = user_from_authorization_service(provider_name)
identity = new_user.identities.last
expect(identity.auth_data_dump.provider).to eq(identity.provider)
end
it "does not allow previously banished users to sign up again for #{provider_name}" do
banished_name = "SpammyMcSpamface"
mock_username(provider_name, banished_name)
create(:banished_user, username: provider_username(provider_name))
expect do
user_from_authorization_service(provider_name, nil, "navbar_basic")
end.to raise_error(ActiveRecord::RecordInvalid, /Username has been banished./)
end
end
it "assigns multiple identities to the same user", :aggregate_failures, vcr: { cassette_name: "fastly_sloan" } do
providers = Authentication::Providers.available
users = []
Authentication::Providers.available.each do |provider_name|
OmniAuth.config.mock_auth[provider_name].info.email = "person1@example.com"
users.append(user_from_authorization_service(provider_name))
end
expect(users.uniq.first.identities.count).to eq(providers.length)
end
end
it "does not allow an existing user to change their name to a banished one" do
banished_name = "SpammyMcSpamface"
create(:banished_user, username: banished_name)
user = create(:user)
user.update(username: banished_name)
expect(user.errors.full_messages).to include("Username has been banished.")
end
describe "#follow and #all_follows" do
it "follows users" do
expect do
user.follow(create(:user))
end.to change(user.all_follows, :size).by(1)
end
end
describe "spam" do
before do
allow(Settings::General).to receive(:mascot_user_id).and_return(user.id)
allow(Settings::RateLimit).to receive(:spam_trigger_terms).and_return(
["yahoomagoo gogo", "testtestetest", "magoo.+magee"],
)
end
it "creates vomit reaction if possible spam" do
user.name = "Hi my name is Yahoomagoo gogo"
user.save
expect(Reaction.last.category).to eq("vomit")
expect(Reaction.last.reactable_id).to eq(user.id)
end
it "creates vomit reaction if possible spam based on pattern" do
user.name = "Hi my name is magoo to the magee"
user.save
expect(Reaction.last.category).to eq("vomit")
expect(Reaction.last.reactable_id).to eq(user.id)
end
it "does not create vomit reaction if does not have matching title" do
user.save
expect(Reaction.last).to be nil
end
it "does not create vomit reaction if does not have pattern match" do
user.name = "Hi my name is magoo to"
user.save
expect(Reaction.last).to be nil
end
end
describe "#suspended?" do
subject { user.suspended? }
context "with suspended role" do
before do
user.add_role(:suspended)
end
it { is_expected.to be true }
end
it { is_expected.to be false }
end
describe "#comment_suspended?" do
subject { user.comment_suspended? }
context "with comment_suspended role" do
before do
user.add_role(:comment_suspended)
end
it { is_expected.to be true }
end
it { is_expected.to be false }
end
describe "#moderator_for_tags" do
let(:tags) { create_list(:tag, 2) }
it "lists tags user moderates" do
user.add_role(:tag_moderator, tags.first)
expect(user.moderator_for_tags).to include(tags.first.name)
expect(user.moderator_for_tags).not_to include(tags.last.name)
end
it "returns empty array if no tags moderated" do
expect(user.moderator_for_tags).to be_empty
end
end
describe "#followed_articles" do
let!(:another_user) { create(:user) }
let!(:articles) { create_list(:article, 2, user: another_user) }
before do
user.follow(another_user)
end
it "returns all articles following" do
expect(user.followed_articles.size).to eq(articles.size)
end
it "returns segment of articles if limit is passed" do
expect(user.followed_articles.limit(1).size).to eq(articles.size - 1)
end
end
describe "theming properties" do
before do
allow(Settings::UserExperience).to receive(:default_font).and_return("sans-serif")
end
it "creates proper body class with defaults" do
# rubocop:disable Layout/LineLength
classes = "light-theme sans-serif-article-body trusted-status-#{user.trusted} #{user.setting.config_navbar}-header"
# rubocop:enable Layout/LineLength
expect(user.decorate.config_body_class).to eq(classes)
end
it "creates proper body class with sans serif config" do
user.setting.config_font = "sans_serif"
# rubocop:disable Layout/LineLength
classes = "light-theme sans-serif-article-body trusted-status-#{user.trusted} #{user.setting.config_navbar}-header"
# rubocop:enable Layout/LineLength
expect(user.decorate.config_body_class).to eq(classes)
end
it "creates proper body class with open dyslexic config" do
user.setting.config_font = "open_dyslexic"
# rubocop:disable Layout/LineLength
classes = "light-theme open-dyslexic-article-body trusted-status-#{user.trusted} #{user.setting.config_navbar}-header"
# rubocop:enable Layout/LineLength
expect(user.decorate.config_body_class).to eq(classes)
end
it "creates proper body class with dark theme" do
user.setting.config_theme = "dark_theme"
classes = "dark-theme sans-serif-article-body trusted-status-#{user.trusted} #{user.setting.config_navbar}-header"
expect(user.decorate.config_body_class).to eq(classes)
end
end
describe "#calculate_score" do
it "calculates a score" do
user.update_column(:badge_achievements_count, 3)
user.calculate_score
expect(user.score).to eq(30)
end
end
describe "cache counts" do
it "has an accurate tag follow count" do
tag = create(:tag)
user.follow(tag)
expect(user.reload.following_tags_count).to eq(1)
end
it "has an accurate user follow count" do
user.follow(other_user)
expect(user.reload.following_users_count).to eq(1)
end
it "has an accurate organization follow count" do
user.follow(org)
expect(user.reload.following_orgs_count).to eq(1)
end
it "returns cached ids of articles that have been saved to their readinglist" do
article = create(:article)
article2 = create(:article)
create(:reading_reaction, user: user, reactable: article)
create(:reading_reaction, user: user, reactable: article2)
expect(user.cached_reading_list_article_ids).to eq([article2.id, article.id])
end
end
describe "#org_admin?" do
it "recognizes an org admin" do
create(:organization_membership, user: user, organization: org, type_of_user: "admin")
expect(user.org_admin?(org)).to be(true)
end
it "forbids an incorrect org admin" do
other_org = create(:organization)
create(:organization_membership, user: user, organization: org, type_of_user: "admin")
expect(user.org_admin?(other_org)).to be(false)
expect(other_user.org_admin?(org)).to be(false)
end
it "returns false if nil is given" do
expect(user.org_admin?(nil)).to be(false)
end
end
describe "#enough_credits?" do
it "returns false if the user has less unspent credits than neeed" do
expect(user.enough_credits?(1)).to be(false)
end
it "returns true if the user has the exact amount of unspent credits" do
create(:credit, user: user, spent: false)
expect(user.enough_credits?(1)).to be(true)
end
it "returns true if the user has more unspent credits than needed" do
create_list(:credit, 2, user: user, spent: false)
expect(user.enough_credits?(1)).to be(true)
end
end
describe "#receives_follower_email_notifications?" do
it "returns false if user has no email" do
user.assign_attributes(email: nil)
expect(user.receives_follower_email_notifications?).to be(false)
end
it "returns false if user opted out from follower notifications" do
user.notification_setting.update(email_follower_notifications: false)
expect(user.receives_follower_email_notifications?).to be(false)
end
it "returns true if user opted in from follower notifications and has an email" do
user.notification_setting.update(email_follower_notifications: true)
expect(user.receives_follower_email_notifications?).to be(true)
end
end
describe ".staff_account" do
it "returns nil if the account does not exist" do
expect(described_class.staff_account).to be_nil
end
it "returns the user if the account exists" do
allow(Settings::Community).to receive(:staff_user_id).and_return(user.id)
expect(described_class.staff_account).to eq(user)
end
end
describe ".mascot_account" do
it "returns nil if the account does not exist" do
expect(described_class.mascot_account).to be_nil
end
it "returns the user if the account exists" do
allow(Settings::General).to receive(:mascot_user_id).and_return(user.id)
expect(described_class.mascot_account).to eq(user)
end
end
describe "#authenticated_through?" do
let(:provider) { Authentication::Providers.available.first }
it "returns false if provider is not known" do
expect(user.authenticated_through?(:unknown)).to be(false)
end
it "returns false if provider is not enabled" do
providers = Authentication::Providers.available - [provider]
allow(Authentication::Providers).to receive(:enabled).and_return(providers)
expect(user.authenticated_through?(provider)).to be(false)
end
it "returns false if the user has no related identity" do
expect(user.authenticated_through?(provider)).to be(false)
end
it "returns true if the user has related identity" do
user = create(:user, :with_identity, identities: [provider])
expect(user.authenticated_through?(provider)).to be(true)
end
end
describe "#authenticated_with_all_providers?" do
let(:provider) { (Authentication::Providers.available - [:apple]).first }
it "returns false if the user has no related identity" do
expect(user.authenticated_with_all_providers?).to be(false)
end
it "returns false if the user is missing any of the identities" do
providers = Authentication::Providers.available - [provider]
user = create(:user, :with_identity, identities: providers)
expect(user.authenticated_with_all_providers?).to be(false)
end
it "returns true if the user has all the enabled providers" do
allow(Settings::Authentication).to receive(:providers).and_return(Authentication::Providers.available)
user = create(:user, :with_identity)
expect(user.authenticated_with_all_providers?).to be(true)
end
end
describe "#trusted" do
it "memoizes the result from rolify" do
allow(Rails.cache)
.to receive(:fetch)
.with("user-#{user.id}/has_trusted_role", expires_in: 200.hours)
.and_return(false)
.once
2.times { user.trusted }
end
end
describe "profiles" do
it "automatically creates a profile for new users", :aggregate_failures do
user = create(:user)
expect(user.profile).to be_present
expect(user.profile).to respond_to(:location)
end
end
end