From 1cbf51e5ea012a628c5f96091c1ce773eb126877 Mon Sep 17 00:00:00 2001 From: joshuakrueger-dfx Date: Fri, 31 Jul 2026 13:44:25 +0200 Subject: [PATCH] fix(kyc): declare financial question conditions in the API contract getQuestions has returned conditions since #2071, but KycFinancialQuestion never declared the field. Generated clients therefore do not know about it and cannot evaluate which questions still apply to a given set of answers before submitting the questionnaire. Runtime behaviour is unchanged. The added spec pins the mapping so that the declaration and what the endpoint actually sends cannot drift apart. --- .../kyc/dto/output/kyc-financial-out.dto.ts | 15 ++++++ .../__tests__/financial.service.spec.ts | 48 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/subdomains/generic/kyc/services/integration/__tests__/financial.service.spec.ts diff --git a/src/subdomains/generic/kyc/dto/output/kyc-financial-out.dto.ts b/src/subdomains/generic/kyc/dto/output/kyc-financial-out.dto.ts index e6da6c4af3..589c000729 100644 --- a/src/subdomains/generic/kyc/dto/output/kyc-financial-out.dto.ts +++ b/src/subdomains/generic/kyc/dto/output/kyc-financial-out.dto.ts @@ -10,6 +10,14 @@ export class KycFinancialOption { text: string; } +export class KycFinancialCondition { + @ApiProperty({ description: 'Key of the prerequisite question that must be answered first.' }) + question: string; + + @ApiProperty({ description: 'Answer value of the prerequisite question that activates this question.' }) + response: string; +} + export class KycFinancialQuestion { @ApiProperty({ description: 'Question key' }) key: string; @@ -25,6 +33,13 @@ export class KycFinancialQuestion { @ApiPropertyOptional({ description: 'Response options', type: KycFinancialOption, isArray: true }) options?: KycFinancialOption[]; + + @ApiPropertyOptional({ + description: 'Preconditions under which this question applies. Omitted when the question is always applicable.', + type: KycFinancialCondition, + isArray: true, + }) + conditions?: KycFinancialCondition[]; } export class KycFinancialOutData extends KycFinancialInData { diff --git a/src/subdomains/generic/kyc/services/integration/__tests__/financial.service.spec.ts b/src/subdomains/generic/kyc/services/integration/__tests__/financial.service.spec.ts new file mode 100644 index 0000000000..8cee482b51 --- /dev/null +++ b/src/subdomains/generic/kyc/services/integration/__tests__/financial.service.spec.ts @@ -0,0 +1,48 @@ +import { mock } from 'jest-mock-extended'; +import { I18nService } from 'nestjs-i18n'; +import { AccountType } from 'src/subdomains/generic/user/models/user-data/account-type.enum'; +import { getFinancialQuestions } from '../../../config/financial-questions'; +import { FinancialService } from '../financial.service'; + +describe('FinancialService', () => { + let service: FinancialService; + const i18n = mock(); + + beforeEach(() => { + jest.clearAllMocks(); + i18n.translate.mockImplementation((key: string) => key); + service = new FinancialService(i18n); + }); + + describe('getQuestions', () => { + it('maps conditions from the catalog and omits them when absent', () => { + const accountType = AccountType.PERSONAL; + const catalog = getFinancialQuestions(accountType); + const withConditions = catalog.filter((q) => q.conditions?.length); + const withoutConditions = catalog.filter((q) => !q.conditions?.length); + + expect(withConditions.length).toBeGreaterThan(0); + expect(withoutConditions.length).toBeGreaterThan(0); + + const questions = service.getQuestions('en', accountType); + + expect(questions).toHaveLength(catalog.length); + + catalog.forEach((catalogQuestion, index) => { + const mapped = questions[index]; + expect(mapped.key).toBe(catalogQuestion.key); + + if (catalogQuestion.conditions?.length) { + expect(mapped.conditions).toEqual(catalogQuestion.conditions); + for (const condition of mapped.conditions) { + expect(Object.keys(condition).sort()).toEqual(['question', 'response']); + expect(typeof condition.question).toBe('string'); + expect(typeof condition.response).toBe('string'); + } + } else { + expect(mapped.conditions).toBeUndefined(); + } + }); + }); + }); +});