import { describe, expect, it } from 'vitest' import type { ReservationV4TaskCardFieldResult } from '@/types/reservation' import { buildReservationV4ConfirmedPayload, buildReservationV4InitialFieldValues, buildReservationV4ReviewOverrides, isReservationV4ConfirmWritableField, isReservationV4ReviewWritableField, reservationV4LookupKindForOptionsSource, stringifyReservationV4SafeDisplayValue, validateReservationV4Fields, } from '@/utils/reservationV4FieldRules' function createV4Field( field_pointer: string, overrides: Partial = {}, ): ReservationV4TaskCardFieldResult { return { field_path: field_pointer.replace(/^\//, '').replace(/\//g, '.'), field_pointer, display_name: overrides.display_name ?? field_pointer, value: overrides.value ?? '', editable: overrides.editable ?? true, required: overrides.required ?? false, control_type: overrides.control_type ?? 'TEXT', edit_scope: overrides.edit_scope ?? 'NORMAL_TASK', write_target: overrides.write_target ?? 'CONFIRMED_PAYLOAD_JSON', options_source: overrides.options_source ?? null, raw_readonly: overrides.raw_readonly ?? false, validation_errors: overrides.validation_errors ?? [], control_hint: overrides.control_hint ?? null, } } describe('reservationV4FieldRules', () => { it('builds initial values from backend fields using field pointers', () => { const fields = [ createV4Field('/basic_information/account_code', { value: 'HANATOUR' }), createV4Field('/business_fields/after/room_items/0/room_type_code', { value: 'TWN' }), ] expect(buildReservationV4InitialFieldValues(fields)).toEqual({ '/basic_information/account_code': 'HANATOUR', '/business_fields/after/room_items/0/room_type_code': 'TWN', }) }) it('submits only editable confirm fields and keeps nested pointer structure', () => { const fields = [ createV4Field('/basic_information/account_code', { value: 'OLD' }), createV4Field('/basic_information/read_only_label', { value: 'VISIBLE_ONLY', editable: true, raw_readonly: true, }), createV4Field('/business_fields/after/room_items/0/room_type_code', { value: 'KING', edit_scope: 'MANUAL_REVIEW_ONLY', write_target: 'REVIEW_RESOLUTION_FIELD_OVERRIDES', }), ] const payload = buildReservationV4ConfirmedPayload(fields, { '/basic_information/account_code': 'HANATOUR', '/basic_information/read_only_label': 'SHOULD_NOT_SEND', '/business_fields/after/room_items/0/room_type_code': 'TWN', }) expect(payload).toEqual({ basic_information: { account_code: 'HANATOUR', }, }) }) it('uses field_pointer for review resolution overrides', () => { const fields = [ createV4Field('/business_fields/after/room_items/0/room_type_code', { value: '', edit_scope: 'MANUAL_REVIEW_ONLY', write_target: 'REVIEW_RESOLUTION_FIELD_OVERRIDES', }), createV4Field('/business_fields/after/room_items/0/room_type_raw', { value: 'TWN', editable: false, write_target: 'NONE', }), ] expect(buildReservationV4ReviewOverrides(fields, { '/business_fields/after/room_items/0/room_type_code': 'TWN', '/business_fields/after/room_items/0/room_type_raw': 'Twin', })).toEqual([ { field_pointer: '/business_fields/after/room_items/0/room_type_code', value: 'TWN', }, ]) }) it('does not submit fields with missing V4 write metadata', () => { const confirmField = createV4Field('/business_fields/after/room_items/0/rate_code') confirmField.edit_scope = null confirmField.write_target = null const reviewField = createV4Field('/business_fields/after/room_items/0/room_type_code', { edit_scope: 'MANUAL_REVIEW_ONLY', }) reviewField.write_target = null expect(isReservationV4ConfirmWritableField(confirmField)).toBe(false) expect(isReservationV4ReviewWritableField(reviewField)).toBe(false) expect(buildReservationV4ConfirmedPayload([confirmField], { '/business_fields/after/room_items/0/rate_code': 'BAR', })).toEqual({}) expect(buildReservationV4ReviewOverrides([reviewField], { '/business_fields/after/room_items/0/room_type_code': 'TWN', })).toEqual([]) }) it('allows review overrides only for basic information and business fields', () => { const fields = [ createV4Field('/source_message/subject', { edit_scope: 'MANUAL_REVIEW_ONLY', write_target: 'REVIEW_RESOLUTION_FIELD_OVERRIDES', }), createV4Field('/business_fields/after/room_items/0/room_type_code', { edit_scope: 'MANUAL_REVIEW_ONLY', write_target: 'REVIEW_RESOLUTION_FIELD_OVERRIDES', }), ] expect(buildReservationV4ReviewOverrides(fields, { '/source_message/subject': 'SHOULD_NOT_SEND', '/business_fields/after/room_items/0/room_type_code': 'TWN', })).toEqual([ { field_pointer: '/business_fields/after/room_items/0/room_type_code', value: 'TWN', }, ]) }) it('redacts nested raw body, evidence and URL values from safe display text', () => { const text = stringifyReservationV4SafeDisplayValue({ business_fields: { group_code: 'GRP-001', raw_evidence: 'raw email body', nested: { room_type_code: 'TWN', oss_url: 'https://oss.example/private-file.pdf', }, safe_url_value: 'https://oss.example/also-hidden.pdf', }, }, 'empty', 'hidden') expect(text).toContain('GRP-001') expect(text).toContain('TWN') expect(text).not.toContain('raw email body') expect(text).not.toContain('https://oss.example') expect(text).not.toContain('oss_url') }) it('redacts direct URL-like display values', () => { expect(stringifyReservationV4SafeDisplayValue( 'https://oss.example/private-file.pdf', 'empty', 'hidden', )).toBe('hidden') }) it('validates only editable visible fields', () => { const fields = [ createV4Field('/basic_information/account_code', { display_name: 'Account', required: true, }), createV4Field('/business_fields/after/room_items/0/room_type_code', { display_name: 'Room type', required: true, editable: false, }), ] expect(validateReservationV4Fields(fields, { '/basic_information/account_code': '', '/business_fields/after/room_items/0/room_type_code': '', })).toEqual({ '/basic_information/account_code': 'Account is required', }) }) it('maps V4 options_source to lookup kinds without returning fixed catalog options', () => { expect(reservationV4LookupKindForOptionsSource('reservation_v4_account_catalog')).toBe('ACCOUNT') expect(reservationV4LookupKindForOptionsSource('RESERVATION_V4_ROOM_TYPE_CATALOG')).toBe('ROOM_TYPE') expect(reservationV4LookupKindForOptionsSource('reservation_v4_rate_code_catalog')).toBe('RATE_CODE') expect(reservationV4LookupKindForOptionsSource('static_enum')).toBeNull() }) })