jekyll-algolia/spec/jekyll/algolia/indexer_spec.rb

275 lines
7.2 KiB
Ruby

# rubocop:disable Metrics/BlockLength
# frozen_string_literal: true
require 'spec_helper'
describe(Jekyll::Algolia::Indexer) do
let(:current) { Jekyll::Algolia::Indexer }
let(:configurator) { Jekyll::Algolia::Configurator }
let(:logger) { Jekyll::Algolia::Logger }
let(:dry_run) { false }
before { allow(configurator).to receive(:dry_run?).and_return(dry_run) }
before { allow(logger).to receive(:log) }
describe '.init' do
before do
allow(configurator).to receive(:application_id).and_return('app_id')
allow(configurator).to receive(:api_key).and_return('api_key')
allow(::Algolia).to receive(:init)
allow(current).to receive(:set_user_agent)
end
before { current.init }
it 'should instanciate Algolia search with application id and api_key' do
expect(::Algolia)
.to have_received(:init)
.with(hash_including(
application_id: 'app_id',
api_key: 'api_key'
))
end
it 'should set the user agent' do
expect(current).to have_received(:set_user_agent)
end
end
describe '.set_user_agent' do
let(:user_agent) do
'Jekyll Integration (vIntegration); '\
'Algolia for Ruby (vAlgolia); '\
'Jekyll (vJekyll); '\
'Ruby (vRuby)'
end
before do
stub_const('Jekyll::Algolia::VERSION', 'vIntegration')
stub_const('::Algolia::VERSION', 'vAlgolia')
stub_const('::Jekyll::VERSION', 'vJekyll')
stub_const('RUBY_VERSION', 'vRuby')
allow(::Algolia).to receive(:set_extra_header)
end
before { current.set_user_agent }
it do
expect(::Algolia)
.to have_received(:set_extra_header)
.with('User-Agent', user_agent)
end
end
describe '.index' do
subject { current.index(input) }
let(:input) { 'index_name' }
before do
expect(::Algolia::Index)
.to receive(:new)
.with('index_name')
.and_return('custom_index')
end
it { should eq 'custom_index' }
end
describe '.remote_object_ids' do
subject { current.remote_object_ids(index) }
let(:index) { double('Algolia::Index').as_null_object }
before do
expect(index)
.to receive(:browse)
.with(attributesToRetrieve: 'objectID')
.and_yield('objectID' => 'foo')
.and_yield('objectID' => 'bar')
end
it { should include('foo') }
it { should include('bar') }
# Should be ordered
it { should eq %w[bar foo] }
end
describe '.local_object_ids' do
subject { current.local_object_ids(records) }
let(:records) { [{ objectID: 'foo' }, { objectID: 'bar' }] }
it { should include('foo') }
it { should include('bar') }
# Should be ordered
it { should eq %w[bar foo] }
context 'with records missing their objectID' do
let(:records) do
[
{ objectID: 'foo' },
{ foo: 'foo' },
{ objectID: 'bar' },
{ bar: 'bar' }
]
end
it { should eq %w[bar foo] }
end
end
describe '.update_settings' do
let(:index) { double('Algolia::Index', set_settings!: nil) }
let(:settings) { { 'foo' => 'bar' } }
before { current.update_settings(index, settings) }
it do
expect(index).to have_received(:set_settings!).with(settings)
end
context 'when running a dry run' do
let(:dry_run) { true }
it do
expect(index)
.to_not have_received(:set_settings!)
end
end
end
describe '.update_records' do
let(:index_name) { 'my_index' }
let(:old_records_ids) { %w[abc] }
let(:new_records) { [{ 'objectID' => 'def' }] }
let(:indexing_batch_size) { 1000 }
before { allow(::Algolia).to receive(:batch!) }
before do
allow(configurator)
.to receive(:algolia)
.with('indexing_batch_size')
.and_return(indexing_batch_size)
end
before { current.update_records(index_name, old_records_ids, new_records) }
context 'when running a dry run' do
let(:dry_run) { true }
it do
expect(::Algolia)
.to_not have_received(:batch!)
end
end
context 'when nothing to update' do
let(:old_records_ids) { [] }
let(:new_records) { [] }
it do
expect(::Algolia)
.to_not have_received(:batch!)
end
end
it 'should batch all operations' do
expect(::Algolia)
.to have_received(:batch!)
.with([
{
action: 'addObject',
indexName: 'my_index',
body: { 'objectID' => 'def' }
},
{
action: 'deleteObject',
indexName: 'my_index',
body: { objectID: 'abc' }
}
])
end
context 'split in smaller batches if too many operations' do
let(:indexing_batch_size) { 1 }
it do
expect(::Algolia)
.to have_received(:batch!)
.ordered
.with([
{
action: 'addObject',
indexName: 'my_index',
body: { 'objectID' => 'def' }
}
])
expect(::Algolia)
.to have_received(:batch!)
.ordered
.with([
{
action: 'deleteObject',
indexName: 'my_index',
body: { objectID: 'abc' }
}
])
end
end
end
describe '.run' do
let(:records) { [{ objectID: 'foo' }, { objectID: 'bar' }] }
let(:remote_ids) { %w[foo baz] }
let(:settings) { 'settings' }
let(:index_name) { 'my_index' }
before do
allow(configurator).to receive(:settings).and_return(settings)
allow(configurator).to receive(:index_name).and_return(index_name)
allow(current).to receive(:init)
allow(current).to receive(:index).and_return('my_index')
allow(current).to receive(:update_settings)
allow(current).to receive(:remote_object_ids).and_return(remote_ids)
allow(current).to receive(:update_records)
end
context 'with records' do
before { current.run(records) }
it { expect(current).to have_received(:init) }
it do
expect(current)
.to have_received(:update_settings)
.with('my_index', settings)
end
it do
expect(current)
.to have_received(:update_records)
.with(index_name, ['baz'], [{ objectID: 'bar' }])
end
end
context 'with empty results' do
subject { -> { current.run(records) } }
let(:records) { [] }
before do
expect(configurator)
.to receive(:algolia)
.with('files_to_exclude')
.and_return(%w[foo.html bar.md])
expect(configurator)
.to receive(:algolia)
.with('nodes_to_index')
.and_return('p,li')
expect(logger)
.to receive(:known_message)
.with(
'no_records_found',
hash_including(
'files_to_exclude' => 'foo.html, bar.md',
'nodes_to_index' => 'p,li'
)
)
end
it { is_expected.to raise_error SystemExit }
end
end
end
# rubocop:enable Metrics/BlockLength