docbrown/spec/models/organization_spec.rb
Michael Kohl 8f5cfa2c0f
Drop profile columns from user (#10707)
* Prepare to drop profile columns from user

* Update code and factory

* Also remove unused constant

* Move validation from user to profile

* Remove Profiles::ExtractData service object

* Add more comments

* Simplify sameAs attribute generation

* Obey me machine, I am your master

* Fix condition order in guard clause

* Temporarily disable callback

* Fix specs

* Reduce usage of Profile#refresh_attributes!

* Remove leftover comment

* Handle social media links differently

* More spec fixes

* Fix specs for admin profile fields controller

* Fix specs after merge

* Fix remaining specs

* Update user show request spec

* Add comment for follow_hiring_tag

* Only save profile when user is valid

* Fix seeds.rb for profile fields

* Switch from before_save to after_save

* Undo unrelated formattin change

* Update spec/fixtures/files/profile_fields.csv

Co-authored-by: Molly Struve <mollylbs@gmail.com>

* Remove data update script and spec

* Fix spec

* Fix typo in comment

* Fix typo in comment

* Move article resave logic to service object

* Move profile field creation to before(:suite)

* Refactor error handling in Profiles::Update

* Fix Profiles::Update specs and refactor

* Temporarily disable spec

* Add ProfileValidator

* Clean up

* Move DB ready check into app/lib

* Refresh attributes after importing from CSV

* Fix specs

* Remove unused file

* A girl has no name. A profile neither.

* Fix specs

* Add responds_to? check

* Spec fix

* Add name to user fields in profile settings page

Co-authored-by: Molly Struve <mollylbs@gmail.com>
2020-12-03 08:14:38 +07:00

300 lines
11 KiB
Ruby

require "rails_helper"
RSpec.describe Organization, type: :model do
let(:organization) { create(:organization) }
describe "validations" do
describe "builtin validations" do
subject { organization }
it { is_expected.to have_many(:articles).dependent(:nullify) }
it { is_expected.to have_many(:collections).dependent(:nullify) }
it { is_expected.to have_many(:credits).dependent(:restrict_with_error) }
it { is_expected.to have_many(:display_ads).dependent(:destroy) }
it { is_expected.to have_many(:listings).dependent(:destroy) }
it { is_expected.to have_many(:notifications).dependent(:destroy) }
it { is_expected.to have_many(:organization_memberships).dependent(:delete_all) }
it { is_expected.to have_many(:profile_pins).dependent(:destroy) }
it { is_expected.to have_many(:sponsorships).dependent(:destroy) }
it { is_expected.to have_many(:unspent_credits).class_name("Credit") }
it { is_expected.to have_many(:users).through(:organization_memberships) }
it { is_expected.to validate_length_of(:company_size).is_at_most(7) }
it { is_expected.to validate_length_of(:cta_body_markdown).is_at_most(256) }
it { is_expected.to validate_length_of(:cta_button_text).is_at_most(20) }
it { is_expected.to validate_length_of(:email).is_at_most(64) }
it { is_expected.to validate_length_of(:github_username).is_at_most(50) }
it { is_expected.to validate_length_of(:location).is_at_most(64) }
it { is_expected.to validate_length_of(:name).is_at_most(50) }
it { is_expected.to validate_length_of(:proof).is_at_most(1500) }
it { is_expected.to validate_length_of(:secret).is_equal_to(100) }
it { is_expected.to validate_length_of(:slug).is_at_least(2).is_at_most(18) }
it { is_expected.to validate_length_of(:story).is_at_most(640) }
it { is_expected.to validate_length_of(:tag_line).is_at_most(60) }
it { is_expected.to validate_length_of(:tech_stack).is_at_most(640) }
it { is_expected.to validate_length_of(:twitter_username).is_at_most(15) }
it { is_expected.to validate_length_of(:url).is_at_most(200) }
it { is_expected.to validate_presence_of(:articles_count) }
it { is_expected.to validate_presence_of(:credits_count) }
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_presence_of(:profile_image) }
it { is_expected.to validate_presence_of(:slug) }
it { is_expected.to validate_presence_of(:spent_credits_count) }
it { is_expected.to validate_presence_of(:summary) }
it { is_expected.to validate_presence_of(:unspent_credits_count) }
it { is_expected.to validate_presence_of(:url) }
it { is_expected.to validate_uniqueness_of(:secret).allow_nil }
it { is_expected.to validate_uniqueness_of(:slug).case_insensitive }
it { is_expected.not_to allow_value("#xyz").for(:bg_color_hex) }
it { is_expected.not_to allow_value("#xyz").for(:text_color_hex) }
it { is_expected.to allow_value("#aabbcc").for(:bg_color_hex) }
it { is_expected.to allow_value("#aabbcc").for(:text_color_hex) }
it { is_expected.to allow_value("#abc").for(:bg_color_hex) }
it { is_expected.to allow_value("#abc").for(:text_color_hex) }
it { is_expected.not_to allow_value("3.0").for(:company_size) }
it { is_expected.to allow_value("3").for(:company_size) }
end
end
context "when callbacks are triggered before save" do
it "generates a secret if set to empty string" do
organization.secret = ""
organization.save
expect(organization.reload.secret).not_to eq("")
end
it "generates a secret if set to nil" do
organization.secret = nil
organization.save
expect(organization.reload.secret).not_to be(nil)
end
end
context "when callbacks are triggered after commit" do
it "on update syncs elasticsearch data" do
article = create(:article, organization: organization)
sidekiq_perform_enqueued_jobs
new_org_name = "#{organization.name}+NEW"
organization.update(name: new_org_name)
sidekiq_perform_enqueued_jobs
expect(article.elasticsearch_doc.dig("_source", "organization", "name")).to eq(new_org_name)
end
# TODO: This will be fixed by @mstruve
# https://github.com/forem/forem/pull/10707#pullrequestreview-538071192
xit "on destroy removes data from elasticsearch" do
article = create(:article, organization: organization)
sidekiq_perform_enqueued_jobs
expect(article.elasticsearch_doc.dig("_source", "organization", "id")).to eq(organization.id)
organization.destroy
sidekiq_perform_enqueued_jobs
expect(article.elasticsearch_doc.dig("_source", "organization")).to be_nil
end
end
describe "#name" do
it "rejects names with over 50 characters" do
organization.name = "x" * 51
expect(organization).not_to be_valid
end
it "accepts names with 50 or less characters" do
organization.name = "x" * 50
expect(organization).to be_valid
end
end
describe "#summary" do
it "rejects summaries with over 250 characters" do
organization.summary = "x" * 251
expect(organization).not_to be_valid
end
it "accepts summaries with 250 or less characters" do
organization.summary = "x" * 250
expect(organization).to be_valid
end
end
describe "#text_color_hex" do
it "accepts hex color codes" do
organization.text_color_hex = Faker::Color.hex_color
expect(organization).to be_valid
end
it "rejects color names" do
organization.text_color_hex = Faker::Color.color_name
expect(organization).not_to be_valid
end
it "rejects RGB colors" do
organization.text_color_hex = Faker::Color.rgb_color
expect(organization).not_to be_valid
end
it "rejects wrong color format" do
organization.text_color_hex = "#FOOBAR"
expect(organization).not_to be_valid
end
end
describe "#slug" do
it "accepts properly formatted slug" do
organization.slug = "heyho"
expect(organization).to be_valid
end
it "accepts properly formatted slug with numbers" do
organization.slug = "HeyHo2"
expect(organization).to be_valid
end
it "rejects slug with spaces" do
organization.slug = "hey ho"
expect(organization).not_to be_valid
end
it "rejects slug with unacceptable character" do
organization.slug = "Hey&Ho"
expect(organization).not_to be_valid
end
it "downcases slug" do
organization.slug = "HaHaHa"
organization.save
expect(organization.slug).to eq("hahaha")
end
it "rejects reserved slug" do
organization = build(:organization, slug: "settings")
expect(organization).not_to be_valid
expect(organization.errors[:slug].to_s.include?("reserved")).to be true
end
it "takes organization slug into account " do
create(:user, username: "lightalloy")
organization = build(:organization, slug: "lightalloy")
expect(organization).not_to be_valid
expect(organization.errors[:slug].to_s.include?("taken")).to be true
end
it "takes podcast slug into account" do
create(:podcast, slug: "devpodcast")
organization = build(:organization, slug: "devpodcast")
expect(organization).not_to be_valid
expect(organization.errors[:slug].to_s.include?("taken")).to be true
end
it "takes page slug into account" do
create(:page, slug: "needed_info_for_site")
organization = build(:organization, slug: "needed_info_for_site")
expect(organization).not_to be_valid
expect(organization.errors[:slug].to_s.include?("taken")).to be true
end
it "takes sitemap into account" do
organization = build(:organization, slug: "sitemap-yo")
expect(organization).not_to be_valid
expect(organization.errors[:slug].to_s.include?("taken")).to be true
end
context "when callbacks are triggered after save" do
let(:organization) { build(:organization) }
before do
allow(Organizations::BustCacheWorker).to receive(:perform_async)
end
it "triggers cache busting on save" do
organization.save
expect(Organizations::BustCacheWorker).to have_received(:perform_async).with(organization.id, organization.slug)
end
end
end
describe "#url" do
it "accepts valid http url" do
organization.url = "http://ben.com"
expect(organization).to be_valid
end
it "accepts valid secure http url" do
organization.url = "https://ben.com"
expect(organization).to be_valid
end
it "rejects invalid http url" do
organization.url = "ben.com"
expect(organization).not_to be_valid
end
end
describe "#check_for_slug_change" do
let(:user) { create(:user) }
it "properly updates the slug/username" do
random_new_slug = "slug_#{rand(10_000)}"
organization.update(slug: random_new_slug)
expect(organization.slug).to eq(random_new_slug)
end
it "updates old_slug to original slug if slug was changed" do
original_slug = organization.slug
organization.update(slug: "slug_#{rand(10_000)}")
expect(organization.old_slug).to eq(original_slug)
end
it "updates old_old_slug properly if slug was changed and there was an old_slug" do
original_slug = organization.slug
organization.update(slug: "something_else")
organization.update(slug: "another_slug")
expect(organization.old_old_slug).to eq(original_slug)
end
context "when dealing with organization articles" do
before do
create(:organization_membership, user: user, organization: organization, type_of_user: "admin")
create(:article, organization: organization, user: user)
end
it "updates the paths of the organization's articles" do
new_slug = "slug_#{rand(10_000)}"
sidekiq_perform_enqueued_jobs(only: Organizations::UpdateOrganizationArticlesPathsWorker) do
organization.update(slug: new_slug)
end
article = Article.find_by(organization_id: organization.id)
expect(article.path).to include(new_slug)
end
it "updates article cached_organizations" do
new_slug = "slug_#{rand(10_000)}"
sidekiq_perform_enqueued_jobs(only: Organizations::UpdateOrganizationArticlesPathsWorker) do
organization.update(slug: new_slug)
end
article = Article.find_by(organization_id: organization.id)
expect(article.cached_organization.slug).to eq(new_slug)
end
end
end
describe "#enough_credits?" do
it "returns false if the user has less unspent credits than neeed" do
expect(organization.enough_credits?(1)).to be(false)
end
it "returns true if the user has the exact amount of unspent credits" do
create(:credit, organization: organization, spent: false)
expect(organization.enough_credits?(1)).to be(true)
end
it "returns true if the user has more unspent credits than needed" do
create_list(:credit, 2, organization: organization, spent: false)
expect(organization.enough_credits?(1)).to be(true)
end
end
end