RSpec.shared_examples 'mongo connector' do |options| model_name = options.fetch(:model_name) factory_name = options[:factory_name] || model_name commands = options.fetch(:only) if commands.include?(:insert) insert_method_name = "#{model_name}_insert" describe "##{insert_method_name}" do let(:model) { build(factory_name) } subject { @connector.send(insert_method_name, model) } before { allow(model).to receive(:validate!).and_return(true) } after { @tester_connector.cleanup } it 'inserts new record' do expect {subject}.to change {@tester_connector.list.size}.from(0).to(1) end it 'validates inserted record' do expect(model).to receive(:validate!) subject end it "doesn't insert nonvalid records" do allow(model).to receive(:validate!) { raise InvalidRecord.new('') } expect {subject}.to raise_error(InvalidRecord) end it 'sets created_at of record' do expect(model.created_at).to be nil subject expect(@tester_connector.list.first['created_at']).not_to be nil end it 'raises error if record with such id already exists' do @tester_connector.create(id: model.id) expect {subject}.to raise_error(InvalidRecord) end end end if commands.include?(:list) list_method_name = "#{model_name.to_s.pluralize}" describe "##{list_method_name}" do subject { @connector.send(list_method_name) } it 'should be empty if collection is empty' do expect(subject).to eq [] end it "returns array of #{model_name.to_s.pluralize} if collection isn't empty" do @tester_connector.create_list(2) do expect(subject).to be_an_array_of(model_class).and have_size(2) end end end end if commands.include?(:show) show_method_name = model_name describe "##{show_method_name}" do subject { @connector.send(show_method_name, 'foo') } it 'raises RecordNotFound when there is no such record' do expect { subject }.to raise_error(RecordNotFound) end it 'returns record if was found' do @tester_connector.create(build(factory_name, id: 'foo').to_mongo_hash) do expect(subject).to be_an_instance_of(model_class) end end end end if commands.include?(:update) update_method_name = "#{model_name}_update" field_to_update = options.fetch(:field_to_update).to_s describe "##{update_method_name}" do let(:model) { build(model_name, field_to_update => 'new_value') } let(:insert_model_to_update) { @tester_connector.create(attributes_for(factory_name)) } subject { @connector.send(update_method_name, model) } before { allow(model).to receive(:validate!).and_return(true) } after { @tester_connector.cleanup } it 'validates updated record' do insert_model_to_update expect(model).to receive(:validate!) subject end it 'updates record' do insert_model_to_update subject updated_value = @tester_connector.list.first[field_to_update] expect(updated_value).to eq 'new_value' end it 'raises RecordNotFound if there is no such record' do expect{ subject }.to raise_error(RecordNotFound) end end end if commands.include?(:delete) delete_method_name = "#{model_name}_delete" describe "##{delete_method_name}" do let(:model) { build(factory_name) } let(:insert_model_to_delete) { @tester_connector.create(model.to_mongo_hash) } subject { @connector.send(delete_method_name, model.id) } it 'deletes record' do insert_model_to_delete expect {subject}.to change {@tester_connector.list.empty?}.to(true) @tester_connector.cleanup end it 'raises RecordNotFound if there is no such record' do expect { subject }.to raise_error(RecordNotFound) end end end end