* Add dual booting logic to Gemfile This might be helpful for the Rails 6.0 upgrade project. * Add more than one gemfile to Travis' configuration We want to see how the application behaves with more than one Rails versions: - Gemfile -> Rails 5.2 - Gemfile.next -> Rails 6.0 This will help us figure out what needs to be addressed before migrating to Rails 6.0. If you want to read more about this technique (dual booting) you can check out this page: https://www.fastruby.io/blog/upgrade-rails/dual-boot/dual-boot-with-rails-6-0-beta.html * Fix joins * Upgrade Gemfile.next.lock * Make sure we're installing the correct versions of gems * Add Rails 6 notes * Update rubocop in Gemfile.next.lock * Fix organization spec * Fix page_views_spec * Add Rails 6 and run rails app:update * Remove some tricks * Remove Gemfile.next for now * Fix .content_type deprecation * Fix deprecation of .where.not NAND/NOR behavior * Fix deprecation of parameterized emails * Fix specs * Remove next flag for now * Fix spec (hopefully) * Add wait_for_javascript * Fix spec, thanks @maestromac! * Try without wait for javascript hack * Remove unnecessary bin/update * Remove file that snuck in the rebase * Update the vendored gems * Replace migrate+db:setup with db:prepare * Update vendored gems * Fix Gemfile.lock and update vendored stuff * Fix Gemfile.lock to be the same as master's minus the changes Co-authored-by: rhymes <rhymesete@gmail.com>
295 lines
11 KiB
Ruby
295 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(:api_secrets).through(:users) }
|
|
it { is_expected.to have_many(:articles) }
|
|
it { is_expected.to have_many(:listings) }
|
|
it { is_expected.to have_many(:collections) }
|
|
it { is_expected.to have_many(:credits) }
|
|
it { is_expected.to have_many(:display_ads) }
|
|
it { is_expected.to have_many(:notifications) }
|
|
it { is_expected.to have_many(:organization_memberships).dependent(:delete_all) }
|
|
it { is_expected.to have_many(:profile_pins) }
|
|
it { is_expected.to have_many(:sponsorships) }
|
|
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_presence_of(:name) }
|
|
it { is_expected.to validate_presence_of(:summary) }
|
|
it { is_expected.to validate_presence_of(:url) }
|
|
it { is_expected.to validate_presence_of(:profile_image) }
|
|
it { is_expected.to validate_presence_of(:slug) }
|
|
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(:secret).is_equal_to(100) }
|
|
it { is_expected.to validate_length_of(:name).is_at_most(50) }
|
|
it { is_expected.to validate_length_of(:slug).is_at_least(2).is_at_most(18) }
|
|
it { is_expected.to validate_length_of(:twitter_username).is_at_most(15) }
|
|
it { is_expected.to validate_length_of(:github_username).is_at_most(50) }
|
|
it { is_expected.to validate_length_of(:url).is_at_most(200) }
|
|
it { is_expected.to validate_length_of(:tag_line).is_at_most(60) }
|
|
it { is_expected.to validate_length_of(:proof).is_at_most(1500) }
|
|
it { is_expected.to validate_length_of(:location).is_at_most(64) }
|
|
it { is_expected.to validate_length_of(:email).is_at_most(64) }
|
|
it { is_expected.to validate_length_of(:company_size).is_at_most(7) }
|
|
it { is_expected.to validate_length_of(:story).is_at_most(640) }
|
|
it { is_expected.to validate_length_of(:tech_stack).is_at_most(640) }
|
|
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
|
|
|
|
it "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
|