require 'rails_helper'
RSpec.describe "Template::UpgradeCustomizationService", type: :service do
describe ".call" do
let!(:funder_template) do
ft = create(:template, :published, :default, org: create(:org, :funder))
phase = create(:phase, template: ft)
create_list(:section, 4, phase: phase).each do |section|
create_list(:question, 2, section: section).each do |question|
create_list(:annotation, 2, question: question)
end
end
ft
end
let!(:template) { funder_template.customize!(create(:org, :funder)) }
before do
funder_template.publish!
template.publish!
end
subject { Template::UpgradeCustomizationService.call(template) }
context "when template is a customization of a published funder template" do
it "returns a new Template" do
expect(subject).to be_an_instance_of(Template)
end
it "returns a persisted Template" do
expect(subject).to be_persisted
end
it "increments the version number" do
template.update!(version: 2)
expect(subject.version).to eql(3)
end
it "returns a draft Template" do
expect(subject.published).to eql(false)
end
it "sets the customization_of to the family_id" do
expect(subject.customization_of).to eql(template.customization_of)
expect(subject.customization_of).to eql(funder_template.family_id)
end
it "sets the org to the template org" do
expect(subject.org).to eql(template.org)
end
it "creates new phases for this Template" do
expect { subject }.to change { Phase.count }.by(1)
end
it "creates new sections for this Template" do
expect { subject }.to change { Section.count }.by(4)
end
it "creates new questions for this Template" do
expect { subject }.to change { Question.count }.by(8)
end
it "creates new annotations for this Template" do
expect { subject }.to change { Annotation.count }.by(16)
end
end
context "when a new phase is present in funder template" do
let!(:org) { create(:org) }
let!(:template) { funder_template.customize!(org) }
before do
funder_template.phases << create(:phase)
end
it "copies the new sections" do
expect(subject.phases).to have_exactly(2).items
end
end
context "when a new section is present in funder template" do
let!(:org) { create(:org) }
let!(:template) { funder_template.customize!(org) }
before do
# Reverse the sections
phase = funder_template.phases.first
phase.sections << build(:section, title: "New funder section", number: 5, modifiable: true)
end
it "preserves the versionable_id" do
template.sections.each do |section|
matching_section = funder_template.sections.detect do |s|
s.description == section.description
end
expect(section.versionable_id).to eql(matching_section.versionable_id)
end
end
# Doesn't need to. Number should be flexible if sections are modifiable
it "preserves the number" do
# byebug
template.sections.each do |section|
matching_section = funder_template.sections.detect do |s|
s.description == section.description
end
expect(section.number).to eql(matching_section.number)
end
end
end
context "when a new question is present in funder template" do
let!(:org) { create(:org) }
let!(:template) { funder_template.customize!(org) }
before do
funder_template.sections.first.questions << create(:question)
end
it "copies the new question" do
expect(subject.questions).to have_exactly(9).items
end
end
context "when a new annotation is present in funder template" do
let!(:org) { create(:org) }
let!(:template) { funder_template.customize!(org) }
before do
funder_template.questions.first.annotations << create(:annotation)
end
it "copies the new annotation" do
expect(subject.annotations).to have_exactly(17).items
end
end
context "when a new section is present in customized template" do
let!(:org) { create(:org) }
let!(:template) { funder_template.customize!(org) }
before do
template.phases.first.sections << create(:section, modifiable: true)
end
it "adds the new section to the new customization" do
expect(subject.sections.count).to eql(funder_template.sections.count + 1)
end
end
context "when a new section is present in both templates" do
let!(:org) { create(:org) }
let!(:template) { funder_template.customize!(org) }
before do
# Gave them different numbers >:]
s = create(:section, phase: template.phases.first,
modifiable: true,
number: 6,
title: "Customized's test section")
s.questions << create(:question)
s = create(:section, phase: funder_template.phases.first,
modifiable: true,
number: 5,
title: "Funder's new section")
s.questions << create(:question)
end
it "updates the customized template's new section with the next free number" do
# Original 4 sections, plus new funder section, plus new customized section
expect(subject.sections).to have_exactly(6).items
expect(subject.sections.maximum(:number)).to eql(funder_template.sections.maximum(:number) + 1)
end
end
context "when a new annotation is present in customized template" do
let!(:org) { create(:org) }
let!(:template) { funder_template.customize!(org) }
before do
template.questions.first.annotations << create(:annotation, org: org)
@annotation = Annotation.last
end
it "copies the new annotation" do
expect(subject.annotations).to have_exactly(17).items
annotation_vals = [@annotation.text, @annotation.versionable_id]
expected_vals = subject.annotations.pluck(:text, :versionable_id)
expect(expected_vals).to include(annotation_vals)
end
end
context "when template is not a customization of a published funder template" do
let!(:template) { create(:template) }
it "raises an exception" do
expect {
subject
}.to raise_error(Template::UpgradeCustomizationService::NotACustomizationError)
end
end
context "when no published funder template exists" do
let!(:funder_template) { create(:template, :archived, org: create(:org, :funder)) }
it "raises an exception" do
expect {
subject
}.to raise_error(Template::UpgradeCustomizationService::NoFunderTemplateError)
end
end
end
end