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