You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
docuseal/spec/lib/submissions/upload_to_paperless_spec.rb

280 lines
9.5 KiB

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Submissions::UploadToPaperless do
let(:account) { create(:account) }
let(:user) { create(:user, account:) }
let(:template) { create(:template, account:, author: user, name: 'Employment Contract') }
let(:submission) { create(:submission, :with_submitters, template:, created_by_user: user) }
let(:paperless_url) { 'http://paperless:8000' }
let(:paperless_token) { 'test-token-abc123' }
before do
submission.submitters.each_with_index do |submitter, i|
submitter.update!(completed_at: i.hours.ago, name: "Signer #{i + 1}")
end
allow(ENV).to receive(:fetch).and_call_original
allow(ENV).to receive(:[]).and_call_original
allow(ENV).to receive(:[]).with('PAPERLESS_NGX_URL').and_return(paperless_url)
allow(ENV).to receive(:[]).with('PAPERLESS_NGX_TOKEN').and_return(paperless_token)
stub_request(:post, "#{paperless_url}/api/documents/post_document/")
.to_return(status: 200, body: '"550e8400-e29b-41d4-a716-446655440000"')
end
describe '.call' do
context 'when submission has a combined document' do
before do
blob = ActiveStorage::Blob.create_and_upload!(
io: Rails.root.join('spec/fixtures/sample-document.pdf').open,
filename: 'combined-result.pdf',
content_type: 'application/pdf'
)
ActiveStorage::Attachment.create!(blob:, name: 'combined_document', record: submission)
end
it 'uploads the combined document to paperless-ngx' do
described_class.call(submission)
expect(WebMock).to have_requested(:post, "#{paperless_url}/api/documents/post_document/")
.with(headers: { 'Authorization' => "Token #{paperless_token}" })
.once
end
it 'sends the correct title with template name and submitter names' do
described_class.call(submission)
expect(WebMock).to(have_requested(:post, "#{paperless_url}/api/documents/post_document/")
.with { |req| req.body.include?('Employment Contract') && req.body.include?('Signer') })
end
it 'sends the created date' do
described_class.call(submission)
expect(WebMock).to(have_requested(:post, "#{paperless_url}/api/documents/post_document/")
.with { |req| req.body.include?('created') })
end
it 'returns the task UUIDs from paperless-ngx' do
result = described_class.call(submission)
expect(result).to include('550e8400-e29b-41d4-a716-446655440000')
end
end
context 'when submission has an audit trail' do
before do
blob = ActiveStorage::Blob.create_and_upload!(
io: Rails.root.join('spec/fixtures/sample-document.pdf').open,
filename: 'audit-trail.pdf',
content_type: 'application/pdf'
)
ActiveStorage::Attachment.create!(blob:, name: 'audit_trail', record: submission)
end
it 'uploads the audit trail to paperless-ngx' do
described_class.call(submission)
expect(WebMock).to(have_requested(:post, "#{paperless_url}/api/documents/post_document/")
.with { |req| req.body.include?('Audit') }
.once)
end
end
context 'when submission has both combined document and audit trail' do
before do
combined_blob = ActiveStorage::Blob.create_and_upload!(
io: Rails.root.join('spec/fixtures/sample-document.pdf').open,
filename: 'combined-result.pdf',
content_type: 'application/pdf'
)
ActiveStorage::Attachment.create!(blob: combined_blob, name: 'combined_document', record: submission)
audit_blob = ActiveStorage::Blob.create_and_upload!(
io: Rails.root.join('spec/fixtures/sample-document.pdf').open,
filename: 'audit-trail.pdf',
content_type: 'application/pdf'
)
ActiveStorage::Attachment.create!(blob: audit_blob, name: 'audit_trail', record: submission)
end
it 'uploads both documents to paperless-ngx' do
described_class.call(submission)
expect(WebMock).to have_requested(:post, "#{paperless_url}/api/documents/post_document/").twice
end
end
context 'when submission has no combined document but has submitter documents' do
before do
submitter = submission.submitters.first
blob = ActiveStorage::Blob.create_and_upload!(
io: Rails.root.join('spec/fixtures/sample-document.pdf').open,
filename: 'signed-result.pdf',
content_type: 'application/pdf'
)
ActiveStorage::Attachment.create!(blob:, name: 'documents', record: submitter)
end
it 'uploads the submitter documents to paperless-ngx' do
described_class.call(submission)
expect(WebMock).to have_requested(:post, "#{paperless_url}/api/documents/post_document/")
.at_least_once
end
end
context 'when paperless-ngx env vars are not configured' do
before do
allow(ENV).to receive(:[]).with('PAPERLESS_NGX_URL').and_return(nil)
allow(ENV).to receive(:[]).with('PAPERLESS_NGX_TOKEN').and_return(nil)
end
it 'does nothing and returns nil' do
result = described_class.call(submission)
expect(result).to be_nil
expect(WebMock).not_to have_requested(:post, /paperless/)
end
end
context 'when paperless-ngx returns an error' do
before do
stub_request(:post, "#{paperless_url}/api/documents/post_document/")
.to_return(status: 500, body: 'Internal Server Error')
blob = ActiveStorage::Blob.create_and_upload!(
io: Rails.root.join('spec/fixtures/sample-document.pdf').open,
filename: 'combined-result.pdf',
content_type: 'application/pdf'
)
ActiveStorage::Attachment.create!(blob:, name: 'combined_document', record: submission)
end
it 'raises an UploadError' do
expect { described_class.call(submission) }.to raise_error(Submissions::UploadToPaperless::UploadError)
end
end
context 'when paperless-ngx connection fails' do
before do
stub_request(:post, "#{paperless_url}/api/documents/post_document/")
.to_timeout
blob = ActiveStorage::Blob.create_and_upload!(
io: Rails.root.join('spec/fixtures/sample-document.pdf').open,
filename: 'combined-result.pdf',
content_type: 'application/pdf'
)
ActiveStorage::Attachment.create!(blob:, name: 'combined_document', record: submission)
end
it 'raises a connection error' do
expect { described_class.call(submission) }.to raise_error(Faraday::ConnectionFailed)
end
end
end
describe '.configured?' do
context 'when both env vars are set' do
it 'returns true' do
expect(described_class.configured?).to be true
end
end
context 'when URL is missing' do
before do
allow(ENV).to receive(:[]).with('PAPERLESS_NGX_URL').and_return(nil)
end
it 'returns false' do
expect(described_class.configured?).to be false
end
end
context 'when token is missing' do
before do
allow(ENV).to receive(:[]).with('PAPERLESS_NGX_TOKEN').and_return(nil)
end
it 'returns false' do
expect(described_class.configured?).to be false
end
end
end
describe '.health_check' do
context 'when not configured' do
before do
allow(ENV).to receive(:[]).with('PAPERLESS_NGX_URL').and_return(nil)
allow(ENV).to receive(:[]).with('PAPERLESS_NGX_TOKEN').and_return(nil)
end
it 'returns configured false with no error' do
result = described_class.health_check
expect(result).to eq(configured: false, reachable: false, url: nil, error: nil)
end
end
context 'when configured and reachable' do
before do
stub_request(:get, "#{paperless_url}/api/")
.with(headers: { 'Authorization' => "Token #{paperless_token}" })
.to_return(status: 200, body: '{"version": "2.0"}')
end
it 'returns configured and reachable with the URL' do
result = described_class.health_check
expect(result).to eq(configured: true, reachable: true, url: paperless_url, error: nil)
end
end
context 'when configured but server returns error' do
before do
stub_request(:get, "#{paperless_url}/api/")
.to_return(status: 500, body: 'Internal Server Error')
end
it 'returns configured but unreachable with HTTP status error' do
result = described_class.health_check
expect(result).to eq(configured: true, reachable: false, url: paperless_url, error: 'HTTP 500')
end
end
context 'when configured but connection times out' do
before do
stub_request(:get, "#{paperless_url}/api/")
.to_timeout
end
it 'returns configured but unreachable with timeout error' do
result = described_class.health_check
expect(result[:configured]).to be true
expect(result[:reachable]).to be false
expect(result[:url]).to eq(paperless_url)
expect(result[:error]).to be_present
end
end
context 'when configured but connection refused' do
before do
stub_request(:get, "#{paperless_url}/api/")
.to_raise(Faraday::ConnectionFailed.new('Connection refused'))
end
it 'returns configured but unreachable with connection error' do
result = described_class.health_check
expect(result).to eq(configured: true, reachable: false, url: paperless_url, error: 'Connection refused')
end
end
end
end