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/templates/field_detection/config_based_spec.rb

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