1
0
Fork 0
mirror of https://github.com/thoughtbot/shoulda-matchers.git synced 2022-11-09 12:01:38 -05:00

Fix habtm matcher to support symbols for join_table (#1323)

The fix is simple but required slightly rewriting the tests, as it turns
out the existing tests weren't exercising all of the possible checks
that join_table makes.
This commit is contained in:
Elliot Winkler 2020-07-25 17:28:19 -06:00 committed by GitHub
parent 97810e6154
commit 39f1dd7c93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 338 additions and 75 deletions

View file

@ -920,21 +920,21 @@ module Shoulda
# asserts that the table you're referring to actually exists. # asserts that the table you're referring to actually exists.
# #
# class Person < ActiveRecord::Base # class Person < ActiveRecord::Base
# has_and_belongs_to_many :issues, join_table: 'people_tickets' # has_and_belongs_to_many :issues, join_table: :people_tickets
# end # end
# #
# # RSpec # # RSpec
# RSpec.describe Person, type: :model do # RSpec.describe Person, type: :model do
# it do # it do
# should have_and_belong_to_many(:issues). # should have_and_belong_to_many(:issues).
# join_table('people_tickets') # join_table(:people_tickets)
# end # end
# end # end
# #
# # Minitest (Shoulda) # # Minitest (Shoulda)
# class PersonTest < ActiveSupport::TestCase # class PersonTest < ActiveSupport::TestCase
# should have_and_belong_to_many(:issues). # should have_and_belong_to_many(:issues).
# join_table('people_tickets') # join_table(:people_tickets)
# end # end
# #
# ##### validate # ##### validate

View file

@ -29,7 +29,7 @@ module Shoulda
if option_verifier.correct_for_string?(:join_table, options[:join_table_name]) if option_verifier.correct_for_string?(:join_table, options[:join_table_name])
true true
else else
@failure_message = "#{name} should use '#{options[:join_table_name]}' for :join_table option" @failure_message = "#{name} should use #{options[:join_table_name].inspect} for :join_table option"
false false
end end
else else
@ -38,7 +38,7 @@ module Shoulda
end end
def join_table_exists? def join_table_exists?
if RailsShim.tables_and_views(connection).include?(join_table_name) if RailsShim.tables_and_views(connection).include?(join_table_name.to_s)
true true
else else
@failure_message = missing_table_message @failure_message = missing_table_message

View file

@ -1570,96 +1570,359 @@ Expected Parent to have a has_many association called children through conceptio
end.to fail_with_message_including('missing columns: person_id, relative_id') end.to fail_with_message_including('missing columns: person_id, relative_id')
end end
context 'when the association is declared with a :join_table option' do context 'when qualified with join_table' do
it 'accepts when testing with the same :join_table option' do context 'and it is a symbol' do
join_table_name = 'people_and_their_families' context 'and the association has been declared with a :join_table option' do
context 'which is the same as the matcher' do
context 'and the join table exists' do
context 'and the join table has the appropriate foreign key columns' do
it 'matches' do
define_model :relative
define_model :relative define_model :person do
has_and_belongs_to_many(
:relatives,
join_table: :people_and_their_families
)
end
define_model :person do create_table(:people_and_their_families, id: false) do |t|
has_and_belongs_to_many(:relatives, join_table: join_table_name) t.references :person
t.references :relative
end
build_matcher = -> do
have_and_belong_to_many(:relatives).
join_table(:people_and_their_families)
end
expect(&build_matcher).
to match_against(Person.new).
or_fail_with(<<-MESSAGE)
Did not expect Person to have a has_and_belongs_to_many association called relatives
MESSAGE
end
end
context 'and the join table is missing columns' do
it 'does not match, producing an appropriate failure message' do
define_model :relative
define_model :person do
has_and_belongs_to_many(
:relatives,
join_table: :people_and_their_families
)
end
create_table(:people_and_their_families)
build_matcher = -> do
have_and_belong_to_many(:relatives).
join_table(:people_and_their_families)
end
expect(&build_matcher).
not_to match_against(Person.new).
and_fail_with(<<-MESSAGE)
Expected Person to have a has_and_belongs_to_many association called relatives (join table people_and_their_families missing columns: person_id, relative_id)
MESSAGE
end
end
end
context 'and the join table does not exist' do
it 'does not match, producing an appropriate failure message' do
define_model :relative
define_model :person do
has_and_belongs_to_many(
:relatives,
join_table: :people_and_their_families
)
end
build_matcher = -> do
have_and_belong_to_many(:relatives).
join_table(:family_tree)
end
expect(&build_matcher).
not_to match_against(Person.new).
and_fail_with(<<-MESSAGE)
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use :family_tree for :join_table option)
MESSAGE
end
end
end
context 'which is the not the same as the matcher' do
it 'does not match, producing an appropriate failure message' do
define_model :relative
define_model :person do
has_and_belongs_to_many(
:relatives,
join_table: :people_and_their_families
)
end
create_table(:people_and_their_families, id: false) do |t|
t.references :person
t.references :relative
end
build_matcher = -> do
have_and_belong_to_many(:relatives).join_table(:family_tree)
end
expect(&build_matcher).
not_to match_against(Person.new).
and_fail_with(<<-MESSAGE)
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use :family_tree for :join_table option)
MESSAGE
end
end
end end
create_table(join_table_name, id: false) do |t| context 'and the association has not been declared with a :join_table option' do
t.references :person it 'does not match, producing an appropriate failure message' do
t.references :relative define_model :relative
end
expect(Person.new). define_model :person do
to have_and_belong_to_many(:relatives). has_and_belongs_to_many(:relatives)
join_table(join_table_name) end
create_table(:people_relatives, id: false) do |t|
t.references :person
t.references :relative
end
build_matcher = -> do
have_and_belong_to_many(:relatives).join_table(:family_tree)
end
expect(&build_matcher).
not_to match_against(Person.new).
and_fail_with(<<-MESSAGE)
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use :family_tree for :join_table option)
MESSAGE
end
end
end end
it 'accepts even when not explicitly testing with a :join_table option' do context 'and it is a string' do
join_table_name = 'people_and_their_families' context 'and the association has been declared with a :join_table option' do
context 'which is the same as the matcher' do
context 'and the join table exists' do
context 'and the join table has the appropriate foreign key columns' do
it 'matches' do
define_model :relative
define_model :relative define_model :person do
has_and_belongs_to_many(
:relatives,
join_table: 'people_and_their_families'
)
end
define_model :person do create_table(:people_and_their_families, id: false) do |t|
has_and_belongs_to_many(:relatives, t.references :person
join_table: join_table_name t.references :relative
) end
build_matcher = -> do
have_and_belong_to_many(:relatives).
join_table('people_and_their_families')
end
expect(&build_matcher).
to match_against(Person.new).
or_fail_with(<<-MESSAGE)
Did not expect Person to have a has_and_belongs_to_many association called relatives
MESSAGE
end
end
context 'and the join table is missing columns' do
it 'does not match, producing an appropriate failure message' do
define_model :relative
define_model :person do
has_and_belongs_to_many(
:relatives,
join_table: 'people_and_their_families'
)
end
create_table(:people_and_their_families)
build_matcher = -> do
have_and_belong_to_many(:relatives).
join_table('people_and_their_families')
end
expect(&build_matcher).
not_to match_against(Person.new).
and_fail_with(<<-MESSAGE)
Expected Person to have a has_and_belongs_to_many association called relatives (join table people_and_their_families missing columns: person_id, relative_id)
MESSAGE
end
end
end
context 'and the join table does not exist' do
it 'does not match, producing an appropriate failure message' do
define_model :relative
define_model :person do
has_and_belongs_to_many(
:relatives,
join_table: 'people_and_their_families'
)
end
build_matcher = -> do
have_and_belong_to_many(:relatives).
join_table('family_tree')
end
expect(&build_matcher).
not_to match_against(Person.new).
and_fail_with(<<-MESSAGE)
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use "family_tree" for :join_table option)
MESSAGE
end
end
end
context 'which is the not the same as the matcher' do
it 'does not match, producing an appropriate failure message' do
define_model :relative
define_model :person do
has_and_belongs_to_many(
:relatives,
join_table: 'people_and_their_families'
)
end
create_table(:people_and_their_families, id: false) do |t|
t.references :person
t.references :relative
end
build_matcher = -> do
have_and_belong_to_many(:relatives).join_table('family_tree')
end
expect(&build_matcher).
not_to match_against(Person.new).
and_fail_with(<<-MESSAGE)
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use "family_tree" for :join_table option)
MESSAGE
end
end
end end
create_table(join_table_name, id: false) do |t| context 'and the association has not been declared with a :join_table option' do
t.references :person it 'does not match, producing an appropriate failure message' do
t.references :relative define_model :relative
define_model :person do
has_and_belongs_to_many(:relatives)
end
create_table(:people_relatives, id: false) do |t|
t.references :person
t.references :relative
end
build_matcher = -> do
have_and_belong_to_many(:relatives).join_table('family_tree')
end
expect(&build_matcher).
not_to match_against(Person.new).
and_fail_with(<<-MESSAGE)
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use "family_tree" for :join_table option)
MESSAGE
end
end end
expect(Person.new).to have_and_belong_to_many(:relatives)
end
it 'rejects when testing with a different :join_table option' do
join_table_name = 'people_and_their_families'
define_model :relative
define_model :person do
has_and_belongs_to_many(
:relatives,
join_table: join_table_name
)
end
create_table(join_table_name, id: false) do |t|
t.references :person
t.references :relative
end
assertion = lambda do
expect(Person.new).
to have_and_belong_to_many(:relatives).
join_table('family_tree')
end
expect(&assertion).to fail_with_message_including(
"relatives should use 'family_tree' for :join_table option"
)
end end
end end
context 'when the association is not declared with a :join_table option' do context 'when the matcher is not qualified with join_table but the association has still been declared with a :join_table option' do
it 'rejects when testing with a :join_table option' do context 'and the join table exists' do
define_model :relative context 'and the join table has the appropriate foreign key columns' do
it 'matches' do
define_model :relative
define_model :person do define_model :person do
has_and_belongs_to_many(:relatives) has_and_belongs_to_many(
:relatives,
join_table: :people_and_their_families
)
end
create_table(:people_and_their_families, id: false) do |t|
t.references :person
t.references :relative
end
build_matcher = -> { have_and_belong_to_many(:relatives) }
expect(&build_matcher).
to match_against(Person.new).
or_fail_with(<<-MESSAGE)
Did not expect Person to have a has_and_belongs_to_many association called relatives
MESSAGE
end
end end
create_table('people_relatives', id: false) do |t| context 'and the join table is missing columns' do
t.references :person it 'does not match, producing an appropriate failure message' do
t.references :relative define_model :relative
end
assertion = lambda do define_model :person do
expect(Person.new). has_and_belongs_to_many(
to have_and_belong_to_many(:relatives). :relatives,
join_table('family_tree') join_table: :people_and_their_families
end )
end
expect(&assertion).to fail_with_message_including( create_table(:people_and_their_families)
"relatives should use 'family_tree' for :join_table option"
) build_matcher = -> { have_and_belong_to_many(:relatives) }
expect(&build_matcher).
not_to match_against(Person.new).
and_fail_with(<<-MESSAGE)
Expected Person to have a has_and_belongs_to_many association called relatives (join table people_and_their_families missing columns: person_id, relative_id)
MESSAGE
end
end
end
context 'and the join table does not exist' do
it 'does not match, producing an appropriate failure message' do
define_model :relative
define_model :person do
has_and_belongs_to_many(
:relatives,
join_table: :people_and_their_families
)
end
build_matcher = -> { have_and_belong_to_many(:relatives) }
expect(&build_matcher).
not_to match_against(Person.new).
and_fail_with(<<-MESSAGE)
Expected Person to have a has_and_belongs_to_many association called relatives (join table people_and_their_families doesn't exist)
MESSAGE
end
end end
end end