Newer
Older
dmpopidor / spec / services / template / upgrade_customization_service_spec.rb
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)) }

    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 section is present in funder template" do

      let!(:org) { create(:org) }

      let!(:template) { funder_template.customize!(org) }

      before do
        # Shuffle the sections
        phase = funder_template.phases.first
        Section.update_numbers!(*phase.sections.ids.shuffle, parent: phase)
      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.number).not_to eql(matching_section.number)
          expect(section.versionable_id).to eql(matching_section.versionable_id)
          expect(section.description).to eql(matching_section.description)
        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 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 phase" 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
        funder_template.phases.first.sections << create(:section)
      end

      it "copies the new sections" do
        expect(subject.sections).to have_exactly(5).items
      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 annotation is present in Org 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