Don't create schemas in model tests unless needed

Creating a schema takes about 3-4 seconds on my machine, so omitting
the callbacks makes tests much faster.

To do so, we're using the `insert!` method added in Rails 6.0, which
inserts a record without executing callbacks or validations. To make the
tests look consistent, we're adding a FactoryBot strategy which uses
`insert!` instead of `create!`.

Note this strategy is useless in most cases because it doesn't work when
models have translatable attributes or associations. However, IMHO it's
worth it even if we only use it for tenants.

We could also use `Tenant.insert!` instead, but then we would have to
add all the mandatory attributes, and in this case the code is clearer
if we only add the attributes we need for the test.
This commit is contained in:
Javi Martín
2022-10-13 03:19:06 +02:00
parent 50076870eb
commit e9c2776252
5 changed files with 39 additions and 16 deletions

View File

@@ -0,0 +1,24 @@
module FactoryBot
module Strategy
class Insert
def initialize
@strategy = FactoryBot.strategy_by_name(:attributes_for).new
end
delegate :association, to: :@strategy
def result(evaluation)
build_class = evaluation.instance_variable_get(:@attribute_assigner)
.instance_variable_get(:@build_class)
timestamps = { created_at: Time.current, updated_at: Time.current }.select do |attribute, _|
build_class.has_attribute?(attribute)
end
build_class.insert!(timestamps.merge(@strategy.result(evaluation)))
end
end
FactoryBot.register_strategy(:insert, Insert)
end
end

View File

@@ -183,17 +183,16 @@ describe Abilities::Administrator do
it { should be_able_to :update, Tenant } it { should be_able_to :update, Tenant }
it { should_not be_able_to :destroy, Tenant } it { should_not be_able_to :destroy, Tenant }
it "does not allow administrators from other tenants to manage tenants " do context "administrators from other tenants" do
create(:tenant, schema: "subsidiary") before do
insert(:tenant, schema: "subsidiary")
Tenant.switch("subsidiary") do allow(Tenant).to receive(:current_schema).and_return("subsidiary")
admin = create(:administrator).user
expect(admin).not_to be_able_to :create, Tenant
expect(admin).not_to be_able_to :read, Tenant
expect(admin).not_to be_able_to :update, Tenant
expect(admin).not_to be_able_to :destroy, Tenant
end end
it { should_not be_able_to :create, Tenant }
it { should_not be_able_to :read, Tenant }
it { should_not be_able_to :update, Tenant }
it { should_not be_able_to :destroy, Tenant }
end end
end end
end end

View File

@@ -193,13 +193,12 @@ describe Setting do
end end
it "returns the tenant name for other tenants" do it "returns the tenant name for other tenants" do
create(:tenant, schema: "new", name: "New Institution") insert(:tenant, schema: "new", name: "New Institution")
allow(Tenant).to receive(:current_schema).and_return("new")
Tenant.switch("new") do
expect(Setting.default_org_name).to eq "New Institution" expect(Setting.default_org_name).to eq "New Institution"
end end
end end
end
describe ".default_mailer_from_address" do describe ".default_mailer_from_address" do
before { allow(Tenant).to receive(:default_host).and_return("consulproject.org") } before { allow(Tenant).to receive(:default_host).and_return("consulproject.org") }

View File

@@ -243,7 +243,7 @@ describe Tenant do
end end
it "is not valid with an already existing schema" do it "is not valid with an already existing schema" do
expect(create(:tenant, schema: "subdomainx")).to be_valid insert(:tenant, schema: "subdomainx")
expect(build(:tenant, schema: "subdomainx")).not_to be_valid expect(build(:tenant, schema: "subdomainx")).not_to be_valid
end end
@@ -270,7 +270,7 @@ describe Tenant do
end end
it "is not valid with an already existing name" do it "is not valid with an already existing name" do
expect(create(:tenant, name: "Name X")).to be_valid insert(:tenant, name: "Name X")
expect(build(:tenant, name: "Name X")).not_to be_valid expect(build(:tenant, name: "Name X")).not_to be_valid
end end
end end

View File

@@ -3,6 +3,7 @@ require "email_spec"
require "devise" require "devise"
require "knapsack_pro" require "knapsack_pro"
Dir["./spec/factory_bot/**/*.rb"].sort.each { |f| require f }
Dir["./spec/models/concerns/*.rb"].each { |f| require f } Dir["./spec/models/concerns/*.rb"].each { |f| require f }
Dir["./spec/support/**/*.rb"].sort.each { |f| require f } Dir["./spec/support/**/*.rb"].sort.each { |f| require f }
Dir["./spec/shared/**/*.rb"].sort.each { |f| require f } Dir["./spec/shared/**/*.rb"].sort.each { |f| require f }