mirror of https://github.com/docusealco/docuseal
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.
208 lines
6.5 KiB
208 lines
6.5 KiB
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
require 'templates/field_detection'
|
|
require 'templates/field_detection/config_based'
|
|
|
|
RSpec.describe Templates::FieldDetection::ConfigBased do
|
|
let(:user) { create(:user) }
|
|
let(:template) { create(:template, account: user.account, author: user) }
|
|
let(:attachment) { template.schema_documents.first }
|
|
let(:documents) { template.schema_documents.preload(:blob) }
|
|
|
|
describe '.call' do
|
|
context 'with absolute position fields' do
|
|
let(:config) do
|
|
{
|
|
'submitters' => [{ 'name' => 'signer' }],
|
|
'fields' => [
|
|
{
|
|
'name' => 'full-name',
|
|
'type' => 'text',
|
|
'submitter' => 'signer',
|
|
'required' => true,
|
|
'position' => { 'page' => 0, 'x' => 0.10, 'y' => 0.20, 'w' => 0.30, 'h' => 0.04 }
|
|
}
|
|
]
|
|
}
|
|
end
|
|
|
|
it 'places fields at absolute coordinates' do
|
|
fields = described_class.call(template, config, documents)
|
|
|
|
expect(fields.length).to eq(1)
|
|
field = fields.first
|
|
expect(field['name']).to eq('full-name')
|
|
expect(field['type']).to eq('text')
|
|
expect(field['required']).to be(true)
|
|
expect(field['areas'].first['page']).to eq(0)
|
|
expect(field['areas'].first['x']).to be_within(0.001).of(0.10)
|
|
expect(field['areas'].first['y']).to be_within(0.001).of(0.20)
|
|
expect(field['areas'].first['w']).to be_within(0.001).of(0.30)
|
|
expect(field['areas'].first['h']).to be_within(0.001).of(0.04)
|
|
end
|
|
|
|
it 'saves fields to the template' do
|
|
described_class.call(template, config, documents)
|
|
template.reload
|
|
|
|
expect(template.fields.length).to eq(1)
|
|
expect(template.fields.first['name']).to eq('full-name')
|
|
end
|
|
|
|
it 'assigns submitter_uuid from the config submitter map' do
|
|
fields = described_class.call(template, config, documents)
|
|
|
|
signer = template.submitters.find { |s| s['name'].downcase == 'signer' }
|
|
expect(signer).to be_present
|
|
expect(fields.first['submitter_uuid']).to eq(signer['uuid'])
|
|
end
|
|
end
|
|
|
|
context 'with negative page index' do
|
|
let(:config) do
|
|
{
|
|
'submitters' => [{ 'name' => 'signer' }],
|
|
'fields' => [
|
|
{
|
|
'name' => 'last-page-sig',
|
|
'type' => 'signature',
|
|
'submitter' => 'signer',
|
|
'position' => { 'page' => -1, 'x' => 0.50, 'y' => 0.80, 'w' => 0.25, 'h' => 0.05 }
|
|
}
|
|
]
|
|
}
|
|
end
|
|
|
|
it 'resolves -1 to the last page' do
|
|
fields = described_class.call(template, config, documents)
|
|
|
|
expect(fields.length).to eq(1)
|
|
area = fields.first['areas'].first
|
|
expect(area['page']).to be >= 0
|
|
end
|
|
end
|
|
|
|
context 'with unknown submitter role' do
|
|
let(:config) do
|
|
{
|
|
'submitters' => [],
|
|
'fields' => [
|
|
{
|
|
'name' => 'orphan-field',
|
|
'type' => 'text',
|
|
'submitter' => 'nonexistent_role',
|
|
'position' => { 'page' => 0, 'x' => 0.10, 'y' => 0.20, 'w' => 0.30, 'h' => 0.04 }
|
|
}
|
|
]
|
|
}
|
|
end
|
|
|
|
it 'falls back to first existing submitter' do
|
|
fields = described_class.call(template, config, documents)
|
|
|
|
expect(fields.length).to eq(1)
|
|
expect(fields.first['submitter_uuid']).to eq(template.submitters.first['uuid'])
|
|
end
|
|
end
|
|
|
|
context 'with no attachment' do
|
|
it 'returns empty array' do
|
|
empty_template = create(:template, account: user.account, author: user, attachment_count: 0)
|
|
|
|
config = { 'submitters' => [], 'fields' => [] }
|
|
result = described_class.call(empty_template, config)
|
|
|
|
expect(result).to eq([])
|
|
end
|
|
end
|
|
|
|
context 'with multiple submitters' do
|
|
let(:config) do
|
|
{
|
|
'submitters' => [{ 'name' => 'seller' }, { 'name' => 'buyer' }],
|
|
'fields' => [
|
|
{
|
|
'name' => 'seller-sig',
|
|
'type' => 'signature',
|
|
'submitter' => 'seller',
|
|
'position' => { 'page' => 0, 'x' => 0.1, 'y' => 0.5, 'w' => 0.2, 'h' => 0.05 }
|
|
},
|
|
{
|
|
'name' => 'buyer-sig',
|
|
'type' => 'signature',
|
|
'submitter' => 'buyer',
|
|
'position' => { 'page' => 0, 'x' => 0.5, 'y' => 0.5, 'w' => 0.2, 'h' => 0.05 }
|
|
}
|
|
]
|
|
}
|
|
end
|
|
|
|
it 'assigns correct submitter_uuid to each field' do
|
|
fields = described_class.call(template, config, documents)
|
|
|
|
seller = template.submitters.find { |s| s['name'].downcase == 'seller' }
|
|
buyer = template.submitters.find { |s| s['name'].downcase == 'buyer' }
|
|
|
|
expect(fields.length).to eq(2)
|
|
expect(fields[0]['submitter_uuid']).to eq(seller['uuid'])
|
|
expect(fields[1]['submitter_uuid']).to eq(buyer['uuid'])
|
|
end
|
|
end
|
|
|
|
context 'with out-of-range page index' do
|
|
let(:config) do
|
|
{
|
|
'submitters' => [{ 'name' => 'signer' }],
|
|
'fields' => [
|
|
{
|
|
'name' => 'impossible-field',
|
|
'type' => 'text',
|
|
'submitter' => 'signer',
|
|
'position' => { 'page' => 999, 'x' => 0.1, 'y' => 0.2, 'w' => 0.3, 'h' => 0.04 }
|
|
}
|
|
]
|
|
}
|
|
end
|
|
|
|
it 'skips fields with invalid page index' do
|
|
fields = described_class.call(template, config, documents)
|
|
|
|
expect(fields).to be_empty
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '.resolve_page_index' do
|
|
it 'returns page as-is for positive indices' do
|
|
expect(described_class.resolve_page_index(0, 5)).to eq(0)
|
|
expect(described_class.resolve_page_index(2, 5)).to eq(2)
|
|
end
|
|
|
|
it 'resolves negative indices from end' do
|
|
expect(described_class.resolve_page_index(-1, 5)).to eq(4)
|
|
expect(described_class.resolve_page_index(-2, 3)).to eq(1)
|
|
end
|
|
|
|
it 'returns nil for zero total pages' do
|
|
expect(described_class.resolve_page_index(0, 0)).to be_nil
|
|
end
|
|
end
|
|
|
|
describe '.clamp' do
|
|
it 'clamps values between 0.0 and 1.0' do
|
|
expect(described_class.clamp(-0.5)).to eq(0.0)
|
|
expect(described_class.clamp(0.5)).to eq(0.5)
|
|
expect(described_class.clamp(1.5)).to eq(1.0)
|
|
end
|
|
end
|
|
|
|
describe '.clamp_dimension' do
|
|
it 'enforces minimum dimension of 0.001' do
|
|
expect(described_class.clamp_dimension(0.0)).to eq(0.001)
|
|
expect(described_class.clamp_dimension(0.5)).to eq(0.5)
|
|
expect(described_class.clamp_dimension(1.5)).to eq(1.0)
|
|
end
|
|
end
|
|
end
|