From e56feac831f84bddc7a388d23c829f1b1e2b1913 Mon Sep 17 00:00:00 2001 From: Denis Lugowski Date: Mon, 2 Mar 2026 14:37:06 +0100 Subject: [PATCH] feat(frontend): Add useFormStepper test --- .../unit/composables/useFormStepper.spec.ts | 237 ++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 legalconsenthub/test/unit/composables/useFormStepper.spec.ts diff --git a/legalconsenthub/test/unit/composables/useFormStepper.spec.ts b/legalconsenthub/test/unit/composables/useFormStepper.spec.ts new file mode 100644 index 0000000..78c37ef --- /dev/null +++ b/legalconsenthub/test/unit/composables/useFormStepper.spec.ts @@ -0,0 +1,237 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' +import type { FormElementSectionDto } from '../../../.api-client' +import { useFormStepper } from '../../../app/composables/useFormStepper' +import { ref } from 'vue' + +describe('useFormStepper', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + describe('visibleSections', () => { + it('should skip only template sections and keep non-template sections', () => { + const sections: FormElementSectionDto[] = [ + { + id: '1', + title: 'Normal Section', + shortTitle: 'Normal', + description: 'A normal section', + isTemplate: false, + formElementSubSections: [] + }, + { + id: '2', + title: 'Template Section', + shortTitle: 'Tmpl', + description: 'A template section', + isTemplate: true, + formElementSubSections: [] + } + ] + + const composable = useFormStepper(sections) + const stepperItems = composable.stepperItems.value + + expect(stepperItems).toHaveLength(1) + expect(stepperItems[0]?.title).toBe('Normal') + }) + }) + + describe('stepperItems', () => { + it('should be empty when no sections provided', () => { + const composable = useFormStepper([]) + const stepperItems = composable.stepperItems.value + + expect(stepperItems).toEqual([]) + expect(stepperItems).toHaveLength(0) + }) + + it('should return empty array when all sections are templates', () => { + const sections: FormElementSectionDto[] = [ + { + id: '1', + title: 'Template 1', + shortTitle: 'T1', + description: 'Template description', + isTemplate: true, + formElementSubSections: [] + }, + { + id: '2', + title: 'Template 2', + shortTitle: 'T2', + description: 'Another template', + isTemplate: true, + formElementSubSections: [] + } + ] + + const composable = useFormStepper(sections) + const stepperItems = composable.stepperItems.value + + expect(stepperItems).toHaveLength(0) + }) + + it('should update stepperItems when formElementSections changes', async () => { + const sections = ref([ + { + id: '1', + title: 'Section 1', + shortTitle: 'S1', + description: 'First', + isTemplate: false, + formElementSubSections: [] + } + ]) + + const composable = useFormStepper(sections) + expect(composable.stepperItems.value).toHaveLength(1) + + // Update sections by mutating the ref + sections.value = [ + ...sections.value, + { + id: '2', + title: 'Section 2', + shortTitle: 'S2', + description: 'Second', + isTemplate: false, + formElementSubSections: [] + } + ] + + const stepperItems = composable.stepperItems.value + expect(stepperItems).toHaveLength(2) + }) + }) + + describe('currentFormElementSection', () => { + it('should return the section at activeStepperItemIndex', () => { + const sections: FormElementSectionDto[] = [ + { + id: '1', + title: 'Section 1', + shortTitle: 'S1', + description: 'First', + isTemplate: false, + formElementSubSections: [] + }, + { + id: '2', + title: 'Section 2', + shortTitle: 'S2', + description: 'Second', + isTemplate: false, + formElementSubSections: [] + }, + { + id: '3', + title: 'Section 3', + shortTitle: 'S3', + description: 'Third', + isTemplate: false, + formElementSubSections: [] + } + ] + + const composable = useFormStepper(sections) + + // Initially at index 0 + let current = composable.currentFormElementSection.value + expect(current?.id).toBe('1') + + // Change index to 1 + composable.activeStepperItemIndex.value = 1 + current = composable.currentFormElementSection.value + expect(current?.id).toBe('2') + + // Change index to 2 + composable.activeStepperItemIndex.value = 2 + current = composable.currentFormElementSection.value + expect(current?.id).toBe('3') + }) + + it('should filter templates when determining current section', () => { + const sections: FormElementSectionDto[] = [ + { + id: '1', + title: 'Section 1', + shortTitle: 'S1', + description: 'First', + isTemplate: false, + formElementSubSections: [] + }, + { + id: '2', + title: 'Template Section', + shortTitle: 'T1', + description: 'Template', + isTemplate: true, + formElementSubSections: [] + }, + { + id: '3', + title: 'Section 3', + shortTitle: 'S3', + description: 'Third', + isTemplate: false, + formElementSubSections: [] + } + ] + + const composable = useFormStepper(sections) + + // activeStepperItemIndex refers to visible sections only + composable.activeStepperItemIndex.value = 1 + const current = composable.currentFormElementSection.value + // Should get the second visible section (id 3), skipping template + expect(current?.id).toBe('3') + }) + }) + + describe('undefined formElementSections', () => { + it('should handle undefined formElementSections', () => { + const composable = useFormStepper(undefined) + const stepperItems = composable.stepperItems.value + + expect(stepperItems).toEqual([]) + expect(stepperItems).toHaveLength(0) + }) + + it('should default to empty array and return undefined for currentSection', () => { + const composable = useFormStepper(undefined) + + expect(composable.stepperItems.value).toHaveLength(0) + expect(composable.currentFormElementSection.value).toBeUndefined() + }) + }) + + describe('stepper and navigateStepper', () => { + it.each` + direction + ${'forward'} + ${'backward'} + `( + 'should call onNavigate callback if provided during navigation ($direction)', + async ({ direction }: { direction: 'forward' | 'backward' }) => { + const sections: FormElementSectionDto[] = [ + { + id: '1', + title: 'Section 1', + shortTitle: 'S1', + description: 'First', + isTemplate: false, + formElementSubSections: [] + } + ] + + const onNavigate = vi.fn() + const composable = useFormStepper(sections, { onNavigate }) + + await composable.navigateStepper(direction) + + expect(onNavigate).toHaveBeenCalled() + } + ) + }) +})