I'm writing a spec to test whether my Product model gets reindexed when I create an associated Image record.
The docs recommend calling Product.search_index.refresh
in tests to make sure that the index is up to date, but that defeats the purpose because I want to make sure that my after_create hooks on Image are causing Product to get reindexed.
sleep
in my testsI can call sleep
to wait until Searchkick has updated the index, but that slows down my tests and makes them brittle.
product = create(:product)
Product.search_index.refresh
image_name = 'a_lovely_book.png'
search_results = Product.search image_name, fields: [:image_names]
# This passes.
expect(search_results.count).to eq(0)
image = create(:product_image, name: image_name)
# This causes the test to pass because it gives Searchkick time to reindex Product.
sleep 5
# This succeeds if I have the sleep call above.
search_results = Product.search image_name, fields: [:image_names]
expect(search_results.count).to eq(1)
I've also considered doing something like this in my Image class so that reindexing happens immediately in tests. But I expect to write a good amount of these kinds of tests, and I don't want to repeat this code over and over again.
class Image
belongs_to :product
after_create :reindex_product
def reindex_product
if Rails.env.test?
product.search_index.refresh
else
product.reindex
end
end
end
Not sure how I could do this exactly, but maybe there's a way to use spies or mocks to make sure that the reindex
method gets called on Product?
I want to make sure that my after_create hooks on Image are causing Product to get reindexed.
You're not testing reindexing, just that reindexing is initiated at the appropriate time. So mocks are the way to go. Test the actual reindexing elsewhere, if you feel that's necessary.
Assuming Image looks something like this:
class Image < ApplicationRecord
belongs_to :product
# Note: the docs suggest after_commit so all saves will be reindexed.
after_commit :reindex_product
def reindex_product
product.reindex
end
end
The test, in RSpec, would look something like...
describe '.create' do
it 'reindexes the product' do
expect(product).to receive(:reindex)
Image.create( product: product, ... )
end
end
# This test illustrates why after_create might be insufficient.
describe '#save' do
it 'reindexes the product' do
expect(product).to receive(:reindex)
image = Image.new( product: product, ... )
image.save!
end
end
Or, if you're using asynchronous reindexing, you would check that a reindexing job was queued.