require 'test_helper'
require 'capybara/rails'

class AttachmentReplacementIntegrationTest < ActionDispatch::IntegrationTest
  extend Minitest::Spec::DSL
  include Capybara::DSL
  include Rails.application.routes.url_helpers

  context 'given a draft document with a file attachment' do
    let(:managing_editor) { create(:managing_editor) }

    let(:filename) { 'sample.docx' }
    let(:file) { File.open(path_to_attachment(filename)) }
    let(:attachment) { build(:file_attachment, attachable: edition, file: file) }
    let(:asset_id) { 'asset-id' }

    let(:replacement_filename) { 'sample.rtf' }

    let(:edition) { create(:news_article) }

    before do
      login_as(managing_editor)
      edition.attachments << attachment
      setup_publishing_api_for(edition)
      stub_whitehall_asset(filename, id: asset_id)
      VirusScanHelpers.simulate_virus_scan
    end

    context 'when attachment is replaced' do
      before do
        visit admin_news_article_path(edition)
        click_link 'Modify attachments'
        @attachment_url = find('.existing-attachments a', text: filename)[:href]
        within '.existing-attachments' do
          click_link 'Edit'
        end
        fill_in 'Title', with: 'Attachment Title'
        attach_file 'Replace file', path_to_attachment(replacement_filename)
        click_button 'Save'
        assert_text "Attachment 'Attachment Title' updated"

        VirusScanHelpers.simulate_virus_scan
      end

      it 'redirects requests for attachment to replacement' do
        visit admin_news_article_path(edition)
        click_link 'Modify attachments'
        replacement_url = find('.existing-attachments a', text: replacement_filename)[:href]

        logout

        get @attachment_url
        assert_redirected_to replacement_url
      end
    end
  end

private

  def ends_with(expected)
    ->(actual) { actual.end_with?(expected) }
  end

  def setup_publishing_api_for(edition)
    publishing_api_has_links(
      content_id: edition.document.content_id,
      links: {}
    )
  end

  def path_to_attachment(filename)
    fixture_path.join(filename)
  end

  def stub_whitehall_asset(filename, attributes = {})
    url_id = "http://asset-manager/assets/#{attributes[:id]}"
    Services.asset_manager.stubs(:whitehall_asset)
      .with(&ends_with(filename))
      .returns(attributes.merge(id: url_id).stringify_keys)
  end
end

Add integration test to demonstrate attachment replacement behaviour
Add integration test to demonstrate attachment replacement behaviour

When an attachment file is *replaced* with another file, the
attachment's URL path changes (both the AttachmentData ID and,
potentially, the filename parts). However, requests for the original
attachment URL are refirected to the new URL by this code in
AttachmentsController#fail [1].

Note that replacing the attachment's file creates a new AttachmentData
and a new asset in Asset Manager.

This test currently just demonstrates the existing behaviour, but I plan
to add to it to test that we are updating the Asset Manager asset
corresponding to the original attachment file with a replacement ID
pointing at the asset corresponding to the new attachment file.

[1]:
https://github.com/alphagov/whitehall/blob/e65558ad9daf6091a33fc5eedc04850789fcff32/app/controllers/attachments_controller.rb#L45-L47
