Files
Wyndham-RSVN/client/src/tests/reservationV4FieldRules.spec.ts
T
2026-07-19 15:35:58 +07:00

200 lines
7.0 KiB
TypeScript

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> = {},
): 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()
})
})