feat(frontend): Add useSectionSpawning test
This commit is contained in:
464
legalconsenthub/test/unit/composables/useSectionSpawning.spec.ts
Normal file
464
legalconsenthub/test/unit/composables/useSectionSpawning.spec.ts
Normal file
@@ -0,0 +1,464 @@
|
|||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import { useSectionSpawning } from '../../../app/composables/useSectionSpawning'
|
||||||
|
import type {
|
||||||
|
FormElementSectionDto,
|
||||||
|
FormElementSubSectionDto,
|
||||||
|
FormElementDto,
|
||||||
|
FormOptionDto,
|
||||||
|
SectionSpawnTriggerDto,
|
||||||
|
FormElementType
|
||||||
|
} from '../../../.api-client'
|
||||||
|
|
||||||
|
// Helper to create a FormOptionDto
|
||||||
|
function createOption(value: string, label: string): FormOptionDto {
|
||||||
|
return {
|
||||||
|
value,
|
||||||
|
label,
|
||||||
|
processingPurpose: 'NONE',
|
||||||
|
employeeDataCategory: 'NONE'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to create a FormElementDto
|
||||||
|
function createFormElement(
|
||||||
|
reference: string,
|
||||||
|
title: string,
|
||||||
|
type: FormElementType,
|
||||||
|
options: FormOptionDto[] = [],
|
||||||
|
sectionSpawnTriggers: SectionSpawnTriggerDto[] = []
|
||||||
|
): FormElementDto {
|
||||||
|
return {
|
||||||
|
id: `id-${reference}`,
|
||||||
|
reference,
|
||||||
|
title,
|
||||||
|
type,
|
||||||
|
options,
|
||||||
|
sectionSpawnTriggers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to create a SectionSpawnTriggerDto
|
||||||
|
function createSpawnTrigger(
|
||||||
|
templateReference: string,
|
||||||
|
conditionType: 'SHOW' | 'HIDE' = 'SHOW',
|
||||||
|
expectedValue: string = 'true',
|
||||||
|
operator: 'EQUALS' | 'NOT_EQUALS' | 'IS_EMPTY' | 'IS_NOT_EMPTY' | 'CONTAINS' | 'NOT_CONTAINS' = 'EQUALS'
|
||||||
|
): SectionSpawnTriggerDto {
|
||||||
|
return {
|
||||||
|
templateReference,
|
||||||
|
sectionSpawnConditionType: conditionType,
|
||||||
|
sectionSpawnExpectedValue: expectedValue,
|
||||||
|
sectionSpawnOperator: operator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to create a template section with title interpolation
|
||||||
|
function createTemplateSection(
|
||||||
|
templateReference: string,
|
||||||
|
title: string,
|
||||||
|
titleTemplate?: string,
|
||||||
|
shortTitle?: string,
|
||||||
|
description?: string,
|
||||||
|
formElementSubSections: FormElementSubSectionDto[] = []
|
||||||
|
): FormElementSectionDto {
|
||||||
|
return {
|
||||||
|
id: `template-${templateReference}`,
|
||||||
|
title,
|
||||||
|
shortTitle,
|
||||||
|
description,
|
||||||
|
titleTemplate,
|
||||||
|
isTemplate: true,
|
||||||
|
templateReference,
|
||||||
|
formElementSubSections
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('useSectionSpawning', () => {
|
||||||
|
it('should remove spawned section when condition no longer met', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template Section')
|
||||||
|
const spawnedSection: FormElementSectionDto = {
|
||||||
|
id: 'spawned-1',
|
||||||
|
title: 'Spawned Section',
|
||||||
|
isTemplate: false,
|
||||||
|
spawnedFromElementReference: 'trigger_1',
|
||||||
|
templateReference: 'template-1',
|
||||||
|
formElementSubSections: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'true', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('true', 'No'), createOption('false', 'Yes')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection, spawnedSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1)
|
||||||
|
expect(result[0]!.isTemplate).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should NOT remove spawned section if another trigger for same template still satisfies condition', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template Section')
|
||||||
|
const spawnedSection: FormElementSectionDto = {
|
||||||
|
id: 'spawned-1',
|
||||||
|
title: 'Spawned Section',
|
||||||
|
isTemplate: false,
|
||||||
|
spawnedFromElementReference: 'trigger_1',
|
||||||
|
templateReference: 'template-1',
|
||||||
|
formElementSubSections: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const trigger1 = createSpawnTrigger('template-1', 'SHOW', 'true', 'EQUALS')
|
||||||
|
const trigger2 = createSpawnTrigger('template-1', 'SHOW', 'maybe', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('false', 'No'), createOption('false', 'Yes'), createOption('true', 'Maybe')],
|
||||||
|
[trigger1, trigger2]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection, spawnedSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(2)
|
||||||
|
expect(result[1]!.spawnedFromElementReference).toBe('trigger_1')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should update titles with {{triggerValue}} interpolation when value changes', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection(
|
||||||
|
'template-1',
|
||||||
|
'Section title',
|
||||||
|
'Section template title {{triggerValue}}',
|
||||||
|
'Short title {{triggerValue}}',
|
||||||
|
'Description {{triggerValue}}'
|
||||||
|
)
|
||||||
|
const spawnedSection: FormElementSectionDto = {
|
||||||
|
id: 'spawned-1',
|
||||||
|
title: 'Section OldValue',
|
||||||
|
shortTitle: 'Short OldValue',
|
||||||
|
description: 'Description OldValue',
|
||||||
|
isTemplate: false,
|
||||||
|
spawnedFromElementReference: 'trigger_1',
|
||||||
|
templateReference: 'template-1',
|
||||||
|
formElementSubSections: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'yes', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('false', 'No'), createOption('true', 'Yes')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection, spawnedSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result[1]!.title).toBe('Section template title Yes')
|
||||||
|
expect(result[1]!.shortTitle).toBe('Short title Yes')
|
||||||
|
expect(result[1]!.description).toBe('Description Yes')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should insert spawned section after template section', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template Section')
|
||||||
|
const otherSection: FormElementSectionDto = {
|
||||||
|
id: 'other-1',
|
||||||
|
title: 'Other Section',
|
||||||
|
isTemplate: false,
|
||||||
|
formElementSubSections: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'Yes', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('false', 'No'), createOption('true', 'Yes')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection, otherSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(3)
|
||||||
|
expect(result[0]!.isTemplate).toBe(true)
|
||||||
|
expect(result[1]!.spawnedFromElementReference).toBe('trigger_1')
|
||||||
|
expect(result[2]!.id).toBe('other-1')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle TEXTFIELD element value extraction', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Section {{triggerValue}}', 'Section {{triggerValue}}')
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'john', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement('trigger_1', 'Name', 'TEXTFIELD', [createOption('john', '')], [trigger])
|
||||||
|
|
||||||
|
const sections = [templateSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(2)
|
||||||
|
expect(result[1]!.title).toBe('Section john')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should interpolate shortTitle with {{triggerValue}}', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template', undefined, 'Short {{triggerValue}}')
|
||||||
|
const spawnedSection: FormElementSectionDto = {
|
||||||
|
id: 'spawned-1',
|
||||||
|
title: 'Spawned',
|
||||||
|
shortTitle: 'Short OldValue',
|
||||||
|
isTemplate: false,
|
||||||
|
spawnedFromElementReference: 'trigger_1',
|
||||||
|
templateReference: 'template-1',
|
||||||
|
formElementSubSections: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'yes', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('false', 'No'), createOption('true', 'Yes')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection, spawnedSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result[1]!.shortTitle).toBe('Short Yes')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should interpolate description with {{triggerValue}}', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection(
|
||||||
|
'template-1',
|
||||||
|
'Template',
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
'Description {{triggerValue}}'
|
||||||
|
)
|
||||||
|
const spawnedSection: FormElementSectionDto = {
|
||||||
|
id: 'spawned-1',
|
||||||
|
title: 'Spawned',
|
||||||
|
description: 'Description OldValue',
|
||||||
|
isTemplate: false,
|
||||||
|
spawnedFromElementReference: 'trigger_1',
|
||||||
|
templateReference: 'template-1',
|
||||||
|
formElementSubSections: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'yes', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('false', 'No'), createOption('true', 'Yes')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection, spawnedSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result[1]!.description).toBe('Description Yes')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should preserve non-triggering elements during processing', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template')
|
||||||
|
const nonTriggerElement = createFormElement('other_1', 'Other', 'TEXTFIELD', [createOption('value', '')])
|
||||||
|
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'Yes', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('false', 'No'), createOption('true', 'Yes')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement, nonTriggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(2)
|
||||||
|
expect(result[1]!.spawnedFromElementReference).toBe('trigger_1')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle empty trigger list on element', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('false', 'No'), createOption('true', 'Yes')],
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('operators', () => {
|
||||||
|
describe('EQUALS', () => {
|
||||||
|
it('should spawn section when SHOW/EQUALS condition is met with SELECT element', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template Section', 'Section Title Template')
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'Yes', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('false', 'No'), createOption('true', 'Yes')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const result = processSpawnTriggers([templateSection], [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(2)
|
||||||
|
expect(result[1]!.spawnedFromElementReference).toBe('trigger_1')
|
||||||
|
expect(result[1]!.templateReference).toBe('template-1')
|
||||||
|
expect(result[1]!.title).toBe('Section Title Template')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should NOT spawn section when SHOW/EQUALS condition is NOT met', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template Section')
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'Yes', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('true', 'No'), createOption('false', 'Yes')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle case-insensitive comparison for EQUALS operator', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template')
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'YES', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('false', 'No'), createOption('true', 'yes')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('NOT_EQUALS', () => {
|
||||||
|
it('should handle NOT_EQUALS operator', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template')
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'Yes', 'NOT_EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('true', 'No'), createOption('false', 'Yes')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(2)
|
||||||
|
expect(result[1]!.spawnedFromElementReference).toBe('trigger_1')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('IS_EMPTY', () => {
|
||||||
|
it('should handle IS_EMPTY operator', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template Section')
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'PLACEHOLDER', 'IS_EMPTY')
|
||||||
|
const triggerElement = createFormElement('trigger_1', 'Trigger', 'TEXTFIELD', [createOption('', '')], [trigger])
|
||||||
|
|
||||||
|
const sections = [templateSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(2)
|
||||||
|
expect(result[1]!.spawnedFromElementReference).toBe('trigger_1')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('IS_NOT_EMPTY', () => {
|
||||||
|
it('should handle IS_NOT_EMPTY operator', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template Section')
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'SHOW', 'PLACEHOLDER', 'IS_NOT_EMPTY')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'TEXTFIELD',
|
||||||
|
[createOption('some value', '')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(2)
|
||||||
|
expect(result[1]!.spawnedFromElementReference).toBe('trigger_1')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('HIDE', () => {
|
||||||
|
it('should handle HIDE condition type', () => {
|
||||||
|
const { processSpawnTriggers } = useSectionSpawning()
|
||||||
|
|
||||||
|
const templateSection = createTemplateSection('template-1', 'Template Section')
|
||||||
|
const trigger = createSpawnTrigger('template-1', 'HIDE', 'No', 'EQUALS')
|
||||||
|
const triggerElement = createFormElement(
|
||||||
|
'trigger_1',
|
||||||
|
'Trigger',
|
||||||
|
'SELECT',
|
||||||
|
[createOption('true', 'No'), createOption('false', 'Yes')],
|
||||||
|
[trigger]
|
||||||
|
)
|
||||||
|
|
||||||
|
const sections = [templateSection]
|
||||||
|
const result = processSpawnTriggers(sections, [triggerElement])
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user