Skip to content

Instantly share code, notes, and snippets.

@ericraio
Last active March 30, 2019 05:03
Show Gist options
  • Save ericraio/81f00c17ee274227952128bcb43d59f2 to your computer and use it in GitHub Desktop.
Save ericraio/81f00c17ee274227952128bcb43d59f2 to your computer and use it in GitHub Desktop.
# frozen_string_literal: true
require "rails_helper"
describe ImportService do
with_model :FakeModelImport do
table do |t|
end
model do
class FakeModelImport::Invalid
MISSING_CSV = "MISSING_CSV"
INVALID_FAKE_MODELS_THRESHOLD = 2
INVALID_FAKE_MODELS = "INVALID_FAKE_MODELS"
end
def invalid_fake_models
end
end
end
with_model :FakeModel do
table do |t|
t.string :email
t.integer :account_id
end
model do
def custom_fields
@custom_fields = {}
end
end
end
class FakeService < ImportService
def initialize
end
def record_class
FakeModel
end
end
class FakeService2 < ImportService
def initialize
end
end
let(:service) { FakeService.new }
let(:download_csv) { "header,header,header\nvalue,value,value\nvalue,value,value" }
let(:csv) { double("csv") }
let(:importer) { double("importer", csv: csv, update_attributes: nil, account_id: 123) }
before :each do
allow_any_instance_of(FakeModel).to receive(:custom_fields).and_return({})
allow(service).to receive(:importer).and_return(importer)
end
describe ImportService::Error do
it "inherits from StandardError" do
expect(ImportService::Error.superclass).to eql StandardError
end
end
describe ".new" do
context "when initialized directly" do
it "raises an error" do
expect do
ImportService.new
end.to raise_error(ImportService::Error)
end
end
end
describe "#importer" do
context "when called directly" do
it "raises an error" do
expect do
FakeService2.new.importer
end.to raise_error(ImportService::Error)
end
end
end
describe "#record_class" do
context "when called directly" do
it "raises an error" do
expect do
FakeService2.new.record_class
end.to raise_error(ImportService::Error)
end
end
end
describe "#process_import" do
context "when csv is attached and downloadable is available" do
let(:record) { double("record") }
before :each do
allow(csv).to receive(:attached?).and_return(true)
allow(csv).to receive(:download).and_return(download_csv)
allow(service).to receive(:build_record_from_row).and_return(record)
allow(service).to receive(:save_record_for_import)
end
context "when the importer sets the first row as headers" do
before :each do
allow(importer).to receive(:first_row_headers).and_return(true)
end
it "builds a record from the row" do
expect(service).to receive(:build_record_from_row).exactly(2).times
service.process_import
end
it "saves the record for the import" do
expect(service).to receive(:save_record_for_import).with(record).exactly(2).times
service.process_import
end
end
context "when the importer does not set the first row as headers" do
before :each do
allow(importer).to receive(:first_row_headers).and_return(false)
end
it "builds a record from the row" do
expect(service).to receive(:build_record_from_row).exactly(3).times
service.process_import
end
it "saves the record for the import" do
expect(service).to receive(:save_record_for_import).exactly(3).times
service.process_import
end
end
end
context "when csv is not attached" do
before :each do
allow(csv).to receive(:attached?).and_return(false)
allow(csv).to receive(:download).and_return(download_csv)
end
it "updates the attributes" do
expect(importer).to receive(:update_attributes).with(
status: "invalid",
invalid_reason: "MISSING_CSV"
)
service.process_import
end
it "does not build or save the records" do
expect(service).not_to receive(:build_record_from_row)
expect(service).not_to receive(:save_record_for_import)
service.process_import
end
end
context "when csv is not downloadable" do
before :each do
allow(csv).to receive(:attached?).and_return(true)
allow(csv).to receive(:download).and_return(false)
end
it "updates the attributes" do
expect(importer).to receive(:update_attributes).with(
status: "invalid",
invalid_reason: "MISSING_CSV"
)
service.process_import
end
it "does not build or save the records" do
expect(service).not_to receive(:build_record_from_row)
expect(service).not_to receive(:save_record_for_import)
service.process_import
end
end
context "when csv is not attached and csv is not downloadable" do
before :each do
allow(csv).to receive(:attached?).and_return(false)
allow(csv).to receive(:download).and_return(false)
end
it "updates the attributes" do
expect(importer).to receive(:update_attributes).with(
status: "invalid",
invalid_reason: "MISSING_CSV"
)
service.process_import
end
it "does not build or save the records" do
expect(service).not_to receive(:build_record_from_row)
expect(service).not_to receive(:save_record_for_import)
service.process_import
end
end
end
describe "#build_record_from_row" do
let(:row) { ["[email protected]", "", "cycling,pool"] }
#
# Email is a field defined on the fake model, using email as an example
# Interests is a made up field that is meant to test custom fields
#
it "sets the account id" do
allow(importer).to receive(:headers).and_return(
"0" => "email",
"1" => "",
"2" => "interests",
"3" => "",
)
record = service.build_record_from_row(row)
expect(record.account_id).to eql importer.account_id
end
it "sets the email field" do
allow(importer).to receive(:headers).and_return(
"0" => "email",
"1" => "",
"2" => "interests",
"3" => "",
)
record = service.build_record_from_row(row)
expect(record.email).to eql "[email protected]"
end
it "sets the interest field as a custom field" do
allow(importer).to receive(:headers).and_return(
"0" => "email",
"1" => "",
"2" => "interests",
"3" => "",
)
record = service.build_record_from_row(row)
expect(record.custom_fields["interests"]).to eql "cycling,pool"
end
end
describe "#save_record_for_import" do
let(:record) { double("record", save: nil) }
context "when the record is saved" do
before :each do
allow(record).to receive(:save).and_return(true)
end
it "returns true" do
expect(service.save_record_for_import(record)).to be_truthy
end
end
context "when the record is not saved" do
before :each do
allow(record).to receive(:save).and_return(false)
allow(service).to receive(:add_record_to_invalidity_list)
allow(service).to receive(:update_invalid_status)
end
it "adds the record to the invalidity list" do
expect(service).to receive(:add_record_to_invalidity_list).with(record)
service.save_record_for_import(record)
end
it "updates the invalid status" do
expect(service).to receive(:update_invalid_status)
service.save_record_for_import(record)
end
it "returns false" do
expect(service.save_record_for_import(record)).to be_falsey
end
end
end
describe "#add_record_to_invalidity_list" do
it "updates the invalid list" do
invalid_list = []
record = double("record", attributes: {})
allow(service).to receive(:invalid_list).and_return(invalid_list)
service.add_record_to_invalidity_list(record)
expect(invalid_list).to eql [record.attributes]
end
end
describe "#update_invalid_status" do
context "when the list is above the threshold" do
before :each do
allow(service).to receive(:invalid_list).and_return([1, 2, 3, 4])
end
it "updates the invalid sttatus and reason" do
expect(importer).to receive(:update_attributes).with(
status: "invalid",
invalid_reason: "INVALID_FAKE_MODELS"
)
service.update_invalid_status
end
end
context "when the list is not above the threshold" do
before :each do
allow(service).to receive(:invalid_list).and_return([1])
end
it "saves the importer" do
expect(importer).to receive(:save)
service.update_invalid_status
end
end
end
describe "#invalid_list" do
it "gets the invalid list" do
expect(importer).to receive(:invalid_fake_models)
service.invalid_list
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment