From 40a1bfb372985876ecd946a3fef91cf1bc705fdc Mon Sep 17 00:00:00 2001 From: Tiago Farto Date: Fri, 13 Mar 2026 12:00:21 +0000 Subject: [PATCH] chore: additional tests --- .../summary/components/DateElementSummary.tsx | 10 +---- apps/web/lib/utils/date-display.test.ts | 43 +++++++++++++++++++ apps/web/lib/utils/date-display.ts | 17 ++++++++ .../components/RenderResponse.tsx | 11 ++--- 4 files changed, 66 insertions(+), 15 deletions(-) create mode 100644 apps/web/lib/utils/date-display.test.ts create mode 100644 apps/web/lib/utils/date-display.ts diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/DateElementSummary.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/DateElementSummary.tsx index 87f0506bf5..6adc63efb7 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/DateElementSummary.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/DateElementSummary.tsx @@ -3,12 +3,11 @@ import Link from "next/link"; import { useState } from "react"; import { useTranslation } from "react-i18next"; -import { parseDateByFormat } from "@formbricks/surveys/date-format"; import { TSurvey, TSurveyElementSummaryDate } from "@formbricks/types/surveys/types"; import { TUserLocale } from "@formbricks/types/user"; import { timeSince } from "@/lib/time"; import { getContactIdentifier } from "@/lib/utils/contact"; -import { formatDateWithOrdinal } from "@/lib/utils/datetime"; +import { formatStoredDateForDisplay } from "@/lib/utils/date-display"; import { PersonAvatar } from "@/modules/ui/components/avatars"; import { Button } from "@/modules/ui/components/button"; import { EmptyState } from "@/modules/ui/components/empty-state"; @@ -34,12 +33,7 @@ export const DateElementSummary = ({ elementSummary, environmentId, survey, loca const renderResponseValue = (value: string) => { const format = elementSummary.element?.format ?? "y-M-d"; - const parsedDate = parseDateByFormat(value, format); - - if (parsedDate === null) { - return `${t("common.invalid_date")}(${value})`; - } - return formatDateWithOrdinal(parsedDate); + return formatStoredDateForDisplay(value, format, `${t("common.invalid_date")}(${value})`); }; return ( diff --git a/apps/web/lib/utils/date-display.test.ts b/apps/web/lib/utils/date-display.test.ts new file mode 100644 index 0000000000..4b5e5943c6 --- /dev/null +++ b/apps/web/lib/utils/date-display.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, test } from "vitest"; +import { formatStoredDateForDisplay } from "./date-display"; + +describe("formatStoredDateForDisplay", () => { + test("returns formatted date for valid ISO string (y-M-d)", () => { + const result = formatStoredDateForDisplay("2024-03-13", "y-M-d", "fallback"); + expect(result).toContain("2024"); + expect(result).toContain("13"); + expect(result).not.toBe("fallback"); + }); + + test("returns formatted date for valid d-M-y string", () => { + const result = formatStoredDateForDisplay("20-03-2026", "d-M-y", "fallback"); + expect(result).toContain("2026"); + expect(result).toContain("20"); + expect(result).not.toBe("fallback"); + }); + + test("returns formatted date for valid M-d-y string", () => { + const result = formatStoredDateForDisplay("03-20-2026", "M-d-y", "fallback"); + expect(result).toContain("2026"); + expect(result).toContain("20"); + expect(result).not.toBe("fallback"); + }); + + test("returns fallback when value is unparseable", () => { + const fallback = "Invalid date(bad)"; + const result = formatStoredDateForDisplay("bad", "y-M-d", fallback); + expect(result).toBe(fallback); + }); + + test("returns fallback when value is empty", () => { + const fallback = "—"; + const result = formatStoredDateForDisplay("", "y-M-d", fallback); + expect(result).toBe(fallback); + }); + + test("returns fallback when value is malformed (wrong format)", () => { + const fallback = "Invalid date(13-03-2024)"; + const result = formatStoredDateForDisplay("13-03-2024", "y-M-d", fallback); + expect(result).toBe(fallback); + }); +}); diff --git a/apps/web/lib/utils/date-display.ts b/apps/web/lib/utils/date-display.ts new file mode 100644 index 0000000000..066fd6194c --- /dev/null +++ b/apps/web/lib/utils/date-display.ts @@ -0,0 +1,17 @@ +import type { TSurveyDateStorageFormat } from "@formbricks/surveys/date-format"; +import { parseDateByFormat } from "@formbricks/surveys/date-format"; +import { formatDateWithOrdinal } from "./datetime"; + +/** + * Parses a stored date string with the given format and returns a display string. + * If parsing fails, returns the provided fallback (e.g. raw value or "Invalid date(value)"). + */ +export function formatStoredDateForDisplay( + value: string, + format: TSurveyDateStorageFormat, + fallback: string +): string { + const parsed = parseDateByFormat(value, format); + if (parsed === null) return fallback; + return formatDateWithOrdinal(parsed); +} diff --git a/apps/web/modules/analysis/components/SingleResponseCard/components/RenderResponse.tsx b/apps/web/modules/analysis/components/SingleResponseCard/components/RenderResponse.tsx index 4eebf3e89e..f014a6da4f 100644 --- a/apps/web/modules/analysis/components/SingleResponseCard/components/RenderResponse.tsx +++ b/apps/web/modules/analysis/components/SingleResponseCard/components/RenderResponse.tsx @@ -1,7 +1,6 @@ import { CheckCheckIcon, MousePointerClickIcon, PhoneIcon } from "lucide-react"; import React from "react"; import { logger } from "@formbricks/logger"; -import { parseDateByFormat } from "@formbricks/surveys/date-format"; import { TResponseDataValue } from "@formbricks/types/responses"; import { TSurveyDateElement, @@ -13,7 +12,7 @@ import { cn } from "@/lib/cn"; import { getLanguageCode, getLocalizedValue } from "@/lib/i18n/utils"; import { getChoiceIdByValue } from "@/lib/response/utils"; import { processResponseData } from "@/lib/responses"; -import { formatDateWithOrdinal } from "@/lib/utils/datetime"; +import { formatStoredDateForDisplay } from "@/lib/utils/date-display"; import { renderHyperlinkedContent } from "@/modules/analysis/utils"; import { ArrayResponse } from "@/modules/ui/components/array-response"; import { FileUploadResponse } from "@/modules/ui/components/file-upload-response"; @@ -70,16 +69,14 @@ export const RenderResponse: React.FC = ({ case TSurveyElementTypeEnum.Date: if (typeof responseData === "string") { const format = (element as TSurveyDateElement).format ?? "y-M-d"; - const parsedDate = parseDateByFormat(responseData, format); - if (parsedDate === null) { + const formatted = formatStoredDateForDisplay(responseData, format, responseData); + if (formatted === responseData) { logger.warn( { elementId: element.id, format, value: responseData }, "[RenderResponse] could not parse date response value" ); - return

{responseData}

; } - const formattedDate = formatDateWithOrdinal(parsedDate); - return

{formattedDate}

; + return

{formatted}

; } break; case TSurveyElementTypeEnum.PictureSelection: