require "test_helper" class WorkflowTest < ActiveSupport::TestCase def setup @artefact = FactoryGirl.create(:artefact) end def template_users user = User.create(name: "Bob") other_user = User.create(name: "James") return user, other_user end def template_programme p = ProgrammeEdition.new(slug:"childcare", title:"Children", panopticon_id: @artefact.id) p.save p end def template_guide edition = FactoryGirl.create(:guide_edition, slug: "childcare", title: "One", panopticon_id: @artefact.id) edition.save edition end def publisher_and_guide user = User.create(name: "Ben") other_user = User.create(name: "James") guide = user.create_edition(:guide, panopticon_id: @artefact.id, overview: "My Overview", title: "My Title", slug: "my-title") edition = guide request_review(user, edition) approve_review(other_user, edition) send_fact_check(user, edition) receive_fact_check(user, edition) other_user.progress(edition, { request_type: :approve_fact_check, comment: "Looks good to me" }) user.progress(edition, { request_type: :publish, comment: "PUBLISHED!" }) return user, guide end def template_user_and_published_transaction user = User.create(name: "Ben") other_user = User.create(name: "James") transaction = user.create_edition(:transaction, title: "My title", slug: "my-title", panopticon_id: @artefact.id, need_to_know: "Credit card required") transaction.save request_review(user, transaction) transaction.save approve_review(other_user, transaction) transaction.save user.progress(transaction, { request_type: :publish, comment: "Let's go"}) transaction.save return user, transaction end context "#status_text" do should "return a capitalized text representation of the state" do assert_equal 'Ready', FactoryGirl.build(:edition, state: 'ready').status_text end should "also return scheduled publishing time when the state is scheduled for publishing" do edition = FactoryGirl.build(:edition, :scheduled_for_publishing) expected_status_text = 'Scheduled for publishing on ' + edition.publish_at.strftime("%d/%m/%Y %H:%M") assert_equal expected_status_text, edition.status_text end end context "#locked_for_edit?" do should "return true if edition is scheduled for publishing for published" do assert FactoryGirl.build(:edition, :scheduled_for_publishing).locked_for_edits? assert FactoryGirl.build(:edition, :published).locked_for_edits? end should "return false if in draft state" do refute FactoryGirl.build(:edition, state: 'draft').locked_for_edits? end end test "permits the creation of new editions" do user, transaction = template_user_and_published_transaction assert transaction.persisted? assert transaction.published? reloaded_transaction = TransactionEdition.find(transaction.id) new_edition = user.new_version(reloaded_transaction) assert new_edition.save end test "should allow creation of new editions from GuideEdition to AnswerEdition" do user, guide = publisher_and_guide new_edition = user.new_version(guide, AnswerEdition) assert_equal "AnswerEdition", new_edition._type end test "a new answer is in draft" do g = AnswerEdition.new(slug: "childcare", panopticon_id: @artefact.id, title: "My new answer") assert g.draft? end test "a new guide has draft but isn't published" do g = FactoryGirl.create(:guide_edition, panopticon_id: @artefact.id) assert g.draft? refute g.published? end test "a guide should be marked as having reviewables if requested for review" do guide = template_guide user = User.create(name:"Ben") refute guide.in_review? refute guide.review_requested_at request_review(user, guide) assert guide.in_review? assert_in_delta Time.zone.now.to_f, guide.review_requested_at.to_f, 1.0 end test "guide workflow" do user = User.create(name: "Ben") other_user = User.create(name: "James") guide = user.create_edition(:guide, title: "My Title", slug: "my-title", panopticon_id: @artefact.id) edition = guide assert edition.can_request_review? request_review(user, edition) refute edition.can_request_review? assert edition.can_request_amendments? request_amendments(other_user, edition) refute edition.can_request_amendments? request_review(user, edition) assert edition.can_approve_review? approve_review(other_user, edition) assert edition.can_publish? end test "when fact check has been initiated it can be skipped" do user = User.create(name: "Ben") other_user = User.create(name: "James") edition = user.create_edition(:guide, panopticon_id: @artefact.id, overview: "My Overview", title: "My Title", slug: "my-title") request_review(user, edition) approve_review(other_user, edition) send_fact_check(user, edition) assert other_user.progress(edition, { request_type: :skip_fact_check, comment: 'Fact check not received in time' }) edition.reload assert edition.can_publish? assert edition.actions.detect { |e| e.request_type == 'skip_fact_check' } end # until we improve the validation to produce few or no false positives test "when processing fact check, it is not validated" do user = User.create(name: "Ben") other_user = User.create(name: "James") guide = user.create_edition(:guide, panopticon_id: FactoryGirl.create(:artefact).id, overview: "My Overview", title: "My Title", slug: "my-title") edition = guide request_review(user, edition) approve_review(other_user, edition) send_fact_check(user, edition) receive_fact_check(user, edition, "Text.content that the SafeHtml validator would catch") assert_equal "Text.content that the SafeHtml validator would catch", edition.actions.last.comment end test "fact_check_received can go back to out for fact_check" do user = User.create(name: "Ben") other_user = User.create(name: "James") guide = user.create_edition(:guide, panopticon_id: FactoryGirl.create(:artefact).id, overview: "My Overview", title: "My Title", slug: "my-title") edition = guide request_review(user, edition) approve_review(other_user, edition) send_fact_check(user, edition) receive_fact_check(user, edition, "Text.content that the SafeHtml validator would catch") send_fact_check(user, edition, "Out of office reply triggered receive_fact_check") assert(edition.actions.last.comment.include? "Out of office reply triggered receive_fact_check") end test "when processing fact check, an edition can request for amendments" do user = User.create(name: "Ben") other_user = User.create(name: "James") guide = user.create_edition(:guide, panopticon_id: FactoryGirl.create(:artefact).id, overview: "My Overview", title: "My Title", slug: "my-title") edition = guide request_review(user, edition) approve_review(other_user, edition) send_fact_check(user, edition) request_amendments(other_user, edition) assert_equal 'request_amendments', edition.actions.last.request_type assert_equal "More amendments are required", edition.actions.last.comment end test "ready items may require further amendments" do user = User.create(name: "Ben") other_user = User.create(name: "James") another_user = User.create(name: "Fiona") guide = user.create_edition(:guide, panopticon_id: FactoryGirl.create(:artefact).id, overview: "My Overview", title: "My Title", slug: "my-title") edition = guide request_review(user, edition) approve_review(other_user, edition) request_amendments(other_user, edition) assert_equal "More amendments are required", edition.actions.last.comment end test "check counting reviews" do user = User.create(name: "Ben") other_user = User.create(name: "James") guide = user.create_edition(:guide, title: "My Title", slug: "my-title", panopticon_id: @artefact.id) edition = guide assert_equal 0, guide.rejected_count request_review(user, edition) request_amendments(other_user, edition) assert_equal 1, guide.rejected_count request_review(user, edition) approve_review(other_user, edition) assert_equal 1, guide.rejected_count end test "user should not be able to review a guide they requested review for" do user = User.create(name: "Ben") guide = user.create_edition(:guide, title: "My Title", slug: "my-title", panopticon_id: @artefact.id) edition = guide assert edition.can_request_review? request_review(user, edition) refute request_amendments(user, edition) end test "user should not be able to okay a guide they requested review for" do user = User.create(name: "Ben") guide = user.create_edition(:guide, title: "My Title", slug: "my-title", panopticon_id: @artefact.id) edition = guide assert edition.can_request_review? request_review(user, edition) refute approve_review(user, edition) end test "a new programme has drafts but isn't published" do p = template_programme assert p.draft? refute p.published? end test "a programme should be marked as having reviewables if requested for review" do programme = template_programme user, other_user = template_users refute programme.in_review? request_review(user, programme) assert programme.in_review?, "A review was not requested for this programme." end test "programme workflow" do user, other_user = template_users edition = user.create_edition(:programme, panopticon_id: @artefact.id, title: "My title", slug: "my-slug") assert edition.can_request_review? request_review(user, edition) refute edition.can_request_review? assert edition.can_request_amendments? request_amendments(other_user, edition) refute edition.can_request_amendments? request_review(user, edition) assert edition.can_approve_review? approve_review(other_user, edition) assert edition.can_request_amendments? assert edition.can_publish? end test "user should not be able to okay a programme they requested review for" do user, other_user = template_users edition = user.create_edition(:programme, panopticon_id: @artefact.id, title: "My title", slug: "my-slug") assert edition.can_request_review? request_review(user, edition) refute approve_review(user, edition) end test "you can only create a new edition from a published edition" do user, other_user = template_users edition = user.create_edition(:programme, panopticon_id: @artefact.id, title: "My title", slug: "my-slug") refute edition.published? refute user.new_version(edition) end test "an edition can be moved into archive state" do user, other_user = template_users edition = user.create_edition(:programme, panopticon_id: @artefact.id, title: "My title", slug: "my-slug") user.progress(edition, { request_type: :archive }) assert_equal "archived", edition.state end # Mongoid 2.x marks array fields as dirty whenever they are accessed. # See https://github.com/mongoid/mongoid/issues/2311 # This behaviour has been patched in lib/mongoid/monkey_patches.rb # in order to prevent workflow validation failures for editions # with array fields. # test "not_editing_published_item should not consider unchanged array fields as changes" do bs = FactoryGirl.create(:business_support_edition, state: 'published', sectors: []) assert_empty bs.errors bs.sectors # Access the Array field bs.valid? assert_empty bs.errors bs.sectors << 'education' assert_equal ['sectors'], bs.changes.keys bs.valid? assert_equal "Published editions can't be edited", bs.errors[:base].first end test "User can request amendments for an edition they just approved" do user_1, user_2 = template_users edition = user_1.create_edition(:answer, panopticon_id: @artefact.id, title: "Answer foo", slug: "answer-foo") edition.body = "body content" user_1.assign(edition, user_2) request_review(user_1, edition) assert edition.in_review? approve_review(user_2, edition) assert edition.ready? request_amendments(user_2, edition) assert edition.amends_needed? end test "important_note returns last non-resolved important note" do user = User.create(name: "Ben") edition = template_guide user.record_note(edition, 'this is an important note', Action::IMPORTANT_NOTE) request_review(user, edition) assert_equal edition.important_note.comment, 'this is an important note' user.record_note(edition, nil, Action::IMPORTANT_NOTE_RESOLVED) assert_nil edition.important_note end context "creating a new version of an edition" do setup do @user = User.new @edition = FactoryGirl.create(:edition, state: :published) end should "return false if the edition is not published" do @edition.update_attribute(:state, :in_review) assert_nil @user.new_version(@edition) end should "record the action" do new_version = @user.new_version(@edition) assert_equal 'new_version', new_version.actions.last.request_type end should "return the new edition" do new_version = @user.new_version(@edition) assert_include new_version.previous_siblings.to_a, @edition end context "creating an edition of a different type" do should "build a clone of a new type" do assert_equal GuideEdition, @user.new_version(@edition, "GuideEdition").class end should "record the action" do new_version = @user.new_version(@edition) assert_equal 'new_version', new_version.actions.last.request_type end end context "when building the edition fails" do setup do @edition.stubs(:build_clone).returns(nil) end should "not record the action" do assert_no_difference '@edition.actions.count' do @user.new_version(@edition) end end should "return nil" do assert_nil @user.new_version(@edition) end end end context "#receive_fact_check" do setup do @edition = FactoryGirl.create(:guide_edition_with_two_parts, state: :fact_check) # Internal links must start with a forward slash eg [link text](/link-destination) @edition.parts.first.update_attribute(:body, "[register and tax your vehicle](registering-an-imported-vehicle)") end should "transition an edition with link validation errors to fact_check_received state" do assert @edition.invalid? receive_fact_check(User.new, @edition) assert_equal "fact_check_received", @edition.reload.state end should "record the action" do assert_difference '@edition.actions.count', 1 do receive_fact_check(User.new, @edition) end assert_equal "receive_fact_check", @edition.actions.last.request_type end end context "#schedule_for_publishing" do setup do @user = FactoryGirl.build(:user) @publish_at = 1.day.from_now.utc @activity_details = { publish_at: @publish_at, comment: "Go schedule !" } end should "return false when scheduling an already published edition" do edition = FactoryGirl.create(:edition, state: 'published') refute schedule_for_publishing(@user, edition, @activity_details) end should "schedule an edition for publishing if it is ready" do edition = FactoryGirl.create(:edition, state: 'ready') schedule_for_publishing(@user, edition, @activity_details) assert edition.scheduled_for_publishing? assert_equal @publish_at.to_i, edition.publish_at.to_i end should "record the action" do edition = FactoryGirl.create(:edition, state: 'ready') options = { comment: "Go schedule !", request_details: { scheduled_time: @publish_at } } assert_difference 'edition.actions.count', 1 do schedule_for_publishing(@user, edition, @activity_details) end assert_equal 'schedule_for_publishing', edition.actions.last.request_type end end end