@@ -114,10 +114,11 @@ describe('Immunizations Form', () => {
114114 mockToDateObjectStrict . mockImplementation ( ( dateString ) => dayjs ( dateString , isoFormat ) . toDate ( ) ) ;
115115 } ) ;
116116
117- it ( 'should render ImmunizationsForm component' , ( ) => {
117+ it ( 'should render ImmunizationsForm component' , async ( ) => {
118118 render ( < ImmunizationsForm { ...testProps } /> ) ;
119119
120- expect ( screen . getByLabelText ( / v a c c i n a t i o n d a t e / i) ) . toBeInTheDocument ( ) ;
120+ await screen . findByLabelText ( / v a c c i n a t i o n d a t e / i) ;
121+
121122 expect ( screen . getByRole ( 'combobox' , { name : / I m m u n i z a t i o n / i } ) ) . toBeInTheDocument ( ) ;
122123 expect ( screen . getByRole ( 'textbox' , { name : / n o t e / i } ) ) . toBeInTheDocument ( ) ;
123124 expect ( screen . getByText ( / V a c c i n e B a t c h I n f o r m a t i o n / i) ) . toBeInTheDocument ( ) ;
@@ -317,9 +318,61 @@ describe('Immunizations Form', () => {
317318 } ) ;
318319 } ) ;
319320
321+ it ( 'should save new immunization with expiration date in correct format' , async ( ) => {
322+ const user = userEvent . setup ( ) ;
323+
324+ // Pre-populate form with expiration date using the form subscription (same pattern as edit tests)
325+ const immunizationWithExpiration = {
326+ vaccineUuid : '782AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ,
327+ vaccinationDate : new Date ( '2024-06-15' ) . toISOString ( ) ,
328+ doseNumber : 1 ,
329+ expirationDate : new Date ( '2025-12-31' ) . toISOString ( ) ,
330+ manufacturer : 'Pfizer' ,
331+ lotNumber : 'LOT123' ,
332+ note : '' ,
333+ nextDoseDate : null ,
334+ } ;
335+
336+ immunizationFormSub . next ( immunizationWithExpiration ) ;
337+
338+ mockSavePatientImmunization . mockResolvedValue ( {
339+ status : 201 ,
340+ ok : true ,
341+ data : {
342+ id : 'new-immunization-id' ,
343+ } ,
344+ } ) ;
345+
346+ render ( < ImmunizationsForm { ...testProps } /> ) ;
347+
348+ // Verify the form is populated
349+ const expirationDateField = screen . getByRole ( 'textbox' , { name : / E x p i r a t i o n d a t e / i } ) ;
350+ expect ( expirationDateField ) . toHaveValue ( '31/12/2025' ) ;
351+
352+ // Submit without making changes
353+ const saveButton = screen . getByRole ( 'button' , { name : / S a v e / i } ) ;
354+ await user . click ( saveButton ) ;
355+
356+ // Verify that expirationDate is formatted as YYYY-MM-DD without timezone
357+ expect ( mockSavePatientImmunization ) . toHaveBeenCalledWith (
358+ expect . objectContaining ( {
359+ expirationDate : '2025-12-31' , // Date-only format, not ISO string with time/timezone
360+ lotNumber : 'LOT123' ,
361+ manufacturer : { display : 'Pfizer' } ,
362+ } ) ,
363+ undefined ,
364+ expect . any ( AbortController ) ,
365+ ) ;
366+ } ) ;
367+
320368 it ( 'should format expiration date as date-only string without timezone' , async ( ) => {
321369 const user = userEvent . setup ( ) ;
322370
371+ // Regression test for O3-4970:
372+ // Previously, expiration dates were converted to ISO strings with timezone (e.g., "2025-12-31T00:00:00.000Z"),
373+ // causing a one-day shift for users in timezones ahead of UTC. This test ensures dates are sent as
374+ // date-only strings (e.g., "2025-12-31") per FHIR date type specification, preventing timezone conversion.
375+
323376 // Setup immunization with expiration date
324377 const immunizationWithExpiration = {
325378 vaccineUuid : '782AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ,
@@ -362,6 +415,52 @@ describe('Immunizations Form', () => {
362415 expect . any ( AbortController ) ,
363416 ) ;
364417 } ) ;
418+
419+ it ( 'should preserve date format when submitting immunization with different expiration date' , async ( ) => {
420+ const user = userEvent . setup ( ) ;
421+
422+ // Load existing immunization with a different expiration date
423+ const immunizationToEdit = {
424+ vaccineUuid : '782AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ,
425+ immunizationId : 'existing-immunization-id' ,
426+ vaccinationDate : new Date ( '2024-06-15' ) . toISOString ( ) ,
427+ doseNumber : 1 ,
428+ expirationDate : new Date ( '2026-06-15' ) . toISOString ( ) ,
429+ manufacturer : 'Moderna' ,
430+ lotNumber : 'ABC123' ,
431+ note : 'Initial note' ,
432+ nextDoseDate : null ,
433+ } ;
434+
435+ immunizationFormSub . next ( immunizationToEdit ) ;
436+
437+ mockSavePatientImmunization . mockResolvedValue ( {
438+ status : 201 ,
439+ ok : true ,
440+ data : {
441+ id : immunizationToEdit . immunizationId ,
442+ } ,
443+ } ) ;
444+
445+ render ( < ImmunizationsForm { ...testProps } /> ) ;
446+
447+ // Verify expiration date is displayed
448+ const expirationDateField = screen . getByRole ( 'textbox' , { name : / E x p i r a t i o n d a t e / i } ) ;
449+ expect ( expirationDateField ) . toHaveValue ( '15/06/2026' ) ;
450+
451+ // Submit the form
452+ const saveButton = screen . getByRole ( 'button' , { name : / S a v e / i } ) ;
453+ await user . click ( saveButton ) ;
454+
455+ // Verify the date is sent in correct format (YYYY-MM-DD, not ISO string)
456+ expect ( mockSavePatientImmunization ) . toHaveBeenCalledWith (
457+ expect . objectContaining ( {
458+ expirationDate : '2026-06-15' , // Date-only format, not ISO string with time/timezone
459+ } ) ,
460+ immunizationToEdit . immunizationId ,
461+ expect . any ( AbortController ) ,
462+ ) ;
463+ } ) ;
365464} ) ;
366465
367466async function selectOption ( dropdown : HTMLElement , optionLabel : string ) {
0 commit comments