From f3156eee613ae90ae343bd1889479b57fb5a0280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20LUDWIG?= Date: Thu, 2 May 2024 01:08:27 +0200 Subject: [PATCH] refactor: separate react/react-native --- app/application/_layout.tsx | 2 +- app/application/habits/[habitId]/index.tsx | 2 +- app/application/habits/history.tsx | 4 +- app/application/habits/index.tsx | 2 +- app/application/habits/new.tsx | 2 +- app/authentication/_layout.tsx | 2 +- infrastructure/supabase/supabase.ts | 10 ++- jest.config.json | 4 +- .../components/HabitForm/HabitCreateForm.tsx | 7 +- .../components/HabitForm/HabitEditForm.tsx | 6 +- .../HabitForm/IconSelectorModal.tsx | 0 .../components/HabitForm/IconsList.tsx | 0 .../components/HabitsMainPage/HabitCard.tsx | 0 .../components/HabitsMainPage/HabitsEmpty.tsx | 0 .../components/HabitsMainPage/HabitsList.tsx | 0 .../HabitsMainPage/HabitsMainPage.tsx | 4 +- .../ui}/ExternalLink.tsx | 0 .../ui}/TabBarIcon.tsx | 0 .../ui}/__tests__/ExternalLink.test.tsx | 2 +- .../ui}/__tests__/TabBarIcon.test.tsx | 2 +- .../__snapshots__/ExternalLink.test.tsx.snap | 0 .../__snapshots__/TabBarIcon.test.tsx.snap | 0 .../react/hooks/__tests__/useBoolean.test.ts | 29 ++++++- .../hooks/__tests__/usePresenterState.test.ts | 75 +++++++++++++++++++ presentation/react/hooks/useBoolean.ts | 4 +- tests/setup.ts | 1 + utils/__tests__/dates.test.ts | 27 ++++++- utils/__tests__/zod.test.ts | 39 ++++++++++ utils/dates.ts | 2 +- utils/zod.ts | 5 +- 30 files changed, 204 insertions(+), 27 deletions(-) rename presentation/{react => react-native}/components/HabitForm/HabitCreateForm.tsx (98%) rename presentation/{react => react-native}/components/HabitForm/HabitEditForm.tsx (97%) rename presentation/{react => react-native}/components/HabitForm/IconSelectorModal.tsx (100%) rename presentation/{react => react-native}/components/HabitForm/IconsList.tsx (100%) rename presentation/{react => react-native}/components/HabitsMainPage/HabitCard.tsx (100%) rename presentation/{react => react-native}/components/HabitsMainPage/HabitsEmpty.tsx (100%) rename presentation/{react => react-native}/components/HabitsMainPage/HabitsList.tsx (100%) rename presentation/{react => react-native}/components/HabitsMainPage/HabitsMainPage.tsx (93%) rename presentation/{react/components => react-native/ui}/ExternalLink.tsx (100%) rename presentation/{react/components => react-native/ui}/TabBarIcon.tsx (100%) rename presentation/{react/components => react-native/ui}/__tests__/ExternalLink.test.tsx (81%) rename presentation/{react/components => react-native/ui}/__tests__/TabBarIcon.test.tsx (77%) rename presentation/{react/components => react-native/ui}/__tests__/__snapshots__/ExternalLink.test.tsx.snap (100%) rename presentation/{react/components => react-native/ui}/__tests__/__snapshots__/TabBarIcon.test.tsx.snap (100%) create mode 100644 presentation/react/hooks/__tests__/usePresenterState.test.ts create mode 100644 tests/setup.ts create mode 100644 utils/__tests__/zod.test.ts diff --git a/app/application/_layout.tsx b/app/application/_layout.tsx index f27ad5d..25796d7 100644 --- a/app/application/_layout.tsx +++ b/app/application/_layout.tsx @@ -1,7 +1,7 @@ import { Redirect, Tabs } from "expo-router" import React from "react" -import { TabBarIcon } from "@/presentation/react/components/TabBarIcon" +import { TabBarIcon } from "@/presentation/react-native/ui/TabBarIcon" import { useAuthentication } from "@/presentation/react/contexts/Authentication" const TabLayout: React.FC = () => { diff --git a/app/application/habits/[habitId]/index.tsx b/app/application/habits/[habitId]/index.tsx index f1f5fd4..34e8857 100644 --- a/app/application/habits/[habitId]/index.tsx +++ b/app/application/habits/[habitId]/index.tsx @@ -1,6 +1,6 @@ import { Redirect, useLocalSearchParams } from "expo-router" -import { HabitEditForm } from "@/presentation/react/components/HabitForm/HabitEditForm" +import { HabitEditForm } from "@/presentation/react-native/components/HabitForm/HabitEditForm" import { useHabitsTracker } from "@/presentation/react/contexts/HabitsTracker" const HabitPage: React.FC = () => { diff --git a/app/application/habits/history.tsx b/app/application/habits/history.tsx index b4497fa..4975421 100644 --- a/app/application/habits/history.tsx +++ b/app/application/habits/history.tsx @@ -4,11 +4,11 @@ import { Agenda } from "react-native-calendars" import { Text } from "react-native-paper" import { SafeAreaView } from "react-native-safe-area-context" -import { getISODate, getNowDate } from "@/utils/dates" +import { getISODate, getNowDateUTC } from "@/utils/dates" const HistoryPage: React.FC = () => { const today = useMemo(() => { - return getNowDate() + return getNowDateUTC() }, []) const todayISO = getISODate(today) diff --git a/app/application/habits/index.tsx b/app/application/habits/index.tsx index 9857a24..25ab7a7 100644 --- a/app/application/habits/index.tsx +++ b/app/application/habits/index.tsx @@ -1,7 +1,7 @@ import { SafeAreaView } from "react-native-safe-area-context" import { ActivityIndicator, Button, Text } from "react-native-paper" -import { HabitsMainPage } from "@/presentation/react/components/HabitsMainPage/HabitsMainPage" +import { HabitsMainPage } from "@/presentation/react-native/components/HabitsMainPage/HabitsMainPage" import { useHabitsTracker } from "@/presentation/react/contexts/HabitsTracker" import { useAuthentication } from "@/presentation/react/contexts/Authentication" diff --git a/app/application/habits/new.tsx b/app/application/habits/new.tsx index 9f99f8d..5a4959a 100644 --- a/app/application/habits/new.tsx +++ b/app/application/habits/new.tsx @@ -1,4 +1,4 @@ -import { HabitCreateForm } from "@/presentation/react/components/HabitForm/HabitCreateForm" +import { HabitCreateForm } from "@/presentation/react-native/components/HabitForm/HabitCreateForm" import { useAuthentication } from "@/presentation/react/contexts/Authentication" const NewHabitPage: React.FC = () => { diff --git a/app/authentication/_layout.tsx b/app/authentication/_layout.tsx index cadac6f..4302423 100644 --- a/app/authentication/_layout.tsx +++ b/app/authentication/_layout.tsx @@ -1,7 +1,7 @@ import { Redirect, Tabs } from "expo-router" import React from "react" -import { TabBarIcon } from "@/presentation/react/components/TabBarIcon" +import { TabBarIcon } from "@/presentation/react-native/ui/TabBarIcon" import { useAuthentication } from "@/presentation/react/contexts/Authentication" const TabLayout: React.FC = () => { diff --git a/infrastructure/supabase/supabase.ts b/infrastructure/supabase/supabase.ts index bec2c9f..8a1dc59 100644 --- a/infrastructure/supabase/supabase.ts +++ b/infrastructure/supabase/supabase.ts @@ -1,10 +1,18 @@ -import { createClient } from "@supabase/supabase-js" +import { + createClient, + type User as SupabaseUserType, +} from "@supabase/supabase-js" import { AppState, Platform } from "react-native" import "react-native-url-polyfill/auto" import AsyncStorage from "@react-native-async-storage/async-storage" import type { Database } from "./supabase-types" +export type SupabaseUser = SupabaseUserType +export type SupabaseHabit = Database["public"]["Tables"]["habits"]["Row"] +export type SupabaseHabitProgress = + Database["public"]["Tables"]["habits_progresses"]["Row"] + const SUPABASE_URL = process.env["EXPO_PUBLIC_SUPABASE_URL"] ?? "https://wjtwtzxreersqfvfgxrz.supabase.co" diff --git a/jest.config.json b/jest.config.json index 3e6bedb..5909eb4 100644 --- a/jest.config.json +++ b/jest.config.json @@ -1,7 +1,7 @@ { "preset": "jest-expo", "roots": ["./"], - "setupFilesAfterEnv": ["@testing-library/react-native/extend-expect"], + "setupFilesAfterEnv": ["/tests/setup.ts"], "fakeTimers": { "enableGlobally": true }, @@ -10,7 +10,7 @@ "coverageReporters": ["text", "text-summary", "cobertura"], "collectCoverageFrom": [ "/**/*.{ts,tsx}", - "!/presentation/react/components/ExternalLink.tsx", + "!/presentation/react-native/ui/ExternalLink.tsx", "!/.expo", "!/app/+html.tsx", "!/app/**/_layout.tsx", diff --git a/presentation/react/components/HabitForm/HabitCreateForm.tsx b/presentation/react-native/components/HabitForm/HabitCreateForm.tsx similarity index 98% rename from presentation/react/components/HabitForm/HabitCreateForm.tsx rename to presentation/react-native/components/HabitForm/HabitCreateForm.tsx index 443ad35..34bec8f 100644 --- a/presentation/react/components/HabitForm/HabitCreateForm.tsx +++ b/presentation/react-native/components/HabitForm/HabitCreateForm.tsx @@ -24,8 +24,8 @@ import { GOAL_FREQUENCIES, GOAL_TYPES } from "@/domain/entities/Goal" import type { HabitCreateData } from "@/domain/entities/Habit" import { HabitCreateSchema } from "@/domain/entities/Habit" import type { User } from "@/domain/entities/User" -import { useHabitsTracker } from "../../contexts/HabitsTracker" -import { useBoolean } from "../../hooks/useBoolean" +import { useHabitsTracker } from "@/presentation/react/contexts/HabitsTracker" +import { useBoolean } from "@/presentation/react/hooks/useBoolean" import { IconSelectorModal } from "./IconSelectorModal" export interface HabitCreateFormProps { @@ -37,11 +37,10 @@ export const HabitCreateForm: React.FC = ({ user }) => { const { control, + formState: { errors, isValid }, handleSubmit, reset, watch, - - formState: { errors, isValid }, } = useForm({ mode: "onChange", resolver: zodResolver(HabitCreateSchema), diff --git a/presentation/react/components/HabitForm/HabitEditForm.tsx b/presentation/react-native/components/HabitForm/HabitEditForm.tsx similarity index 97% rename from presentation/react/components/HabitForm/HabitEditForm.tsx rename to presentation/react-native/components/HabitForm/HabitEditForm.tsx index f16c216..83faa2f 100644 --- a/presentation/react/components/HabitForm/HabitEditForm.tsx +++ b/presentation/react-native/components/HabitForm/HabitEditForm.tsx @@ -20,8 +20,8 @@ import ColorPicker, { import type { Habit, HabitEditData } from "@/domain/entities/Habit" import { HabitEditSchema } from "@/domain/entities/Habit" -import { useHabitsTracker } from "../../contexts/HabitsTracker" -import { useBoolean } from "../../hooks/useBoolean" +import { useHabitsTracker } from "@/presentation/react/contexts/HabitsTracker" +import { useBoolean } from "@/presentation/react/hooks/useBoolean" import { IconSelectorModal } from "./IconSelectorModal" export interface HabitEditFormProps { @@ -33,8 +33,8 @@ export const HabitEditForm: React.FC = ({ habit }) => { const { control, - handleSubmit, formState: { errors, isValid }, + handleSubmit, } = useForm({ mode: "onChange", resolver: zodResolver(HabitEditSchema), diff --git a/presentation/react/components/HabitForm/IconSelectorModal.tsx b/presentation/react-native/components/HabitForm/IconSelectorModal.tsx similarity index 100% rename from presentation/react/components/HabitForm/IconSelectorModal.tsx rename to presentation/react-native/components/HabitForm/IconSelectorModal.tsx diff --git a/presentation/react/components/HabitForm/IconsList.tsx b/presentation/react-native/components/HabitForm/IconsList.tsx similarity index 100% rename from presentation/react/components/HabitForm/IconsList.tsx rename to presentation/react-native/components/HabitForm/IconsList.tsx diff --git a/presentation/react/components/HabitsMainPage/HabitCard.tsx b/presentation/react-native/components/HabitsMainPage/HabitCard.tsx similarity index 100% rename from presentation/react/components/HabitsMainPage/HabitCard.tsx rename to presentation/react-native/components/HabitsMainPage/HabitCard.tsx diff --git a/presentation/react/components/HabitsMainPage/HabitsEmpty.tsx b/presentation/react-native/components/HabitsMainPage/HabitsEmpty.tsx similarity index 100% rename from presentation/react/components/HabitsMainPage/HabitsEmpty.tsx rename to presentation/react-native/components/HabitsMainPage/HabitsEmpty.tsx diff --git a/presentation/react/components/HabitsMainPage/HabitsList.tsx b/presentation/react-native/components/HabitsMainPage/HabitsList.tsx similarity index 100% rename from presentation/react/components/HabitsMainPage/HabitsList.tsx rename to presentation/react-native/components/HabitsMainPage/HabitsList.tsx diff --git a/presentation/react/components/HabitsMainPage/HabitsMainPage.tsx b/presentation/react-native/components/HabitsMainPage/HabitsMainPage.tsx similarity index 93% rename from presentation/react/components/HabitsMainPage/HabitsMainPage.tsx rename to presentation/react-native/components/HabitsMainPage/HabitsMainPage.tsx index eae9dc9..f424beb 100644 --- a/presentation/react/components/HabitsMainPage/HabitsMainPage.tsx +++ b/presentation/react-native/components/HabitsMainPage/HabitsMainPage.tsx @@ -3,7 +3,7 @@ import { Agenda } from "react-native-calendars" import { GOAL_FREQUENCIES } from "@/domain/entities/Goal" import type { HabitsTracker } from "@/domain/entities/HabitsTracker" -import { getISODate, getNowDate } from "@/utils/dates" +import { getISODate, getNowDateUTC } from "@/utils/dates" import { HabitsEmpty } from "./HabitsEmpty" import { HabitsList } from "./HabitsList" @@ -14,7 +14,7 @@ export interface HabitsMainPageProps { export const HabitsMainPage: React.FC = (props) => { const { habitsTracker } = props - const today = getNowDate() + const today = getNowDateUTC() const todayISO = getISODate(today) const [selectedDate, setSelectedDate] = useState(today) diff --git a/presentation/react/components/ExternalLink.tsx b/presentation/react-native/ui/ExternalLink.tsx similarity index 100% rename from presentation/react/components/ExternalLink.tsx rename to presentation/react-native/ui/ExternalLink.tsx diff --git a/presentation/react/components/TabBarIcon.tsx b/presentation/react-native/ui/TabBarIcon.tsx similarity index 100% rename from presentation/react/components/TabBarIcon.tsx rename to presentation/react-native/ui/TabBarIcon.tsx diff --git a/presentation/react/components/__tests__/ExternalLink.test.tsx b/presentation/react-native/ui/__tests__/ExternalLink.test.tsx similarity index 81% rename from presentation/react/components/__tests__/ExternalLink.test.tsx rename to presentation/react-native/ui/__tests__/ExternalLink.test.tsx index 768dbf4..db5855a 100644 --- a/presentation/react/components/__tests__/ExternalLink.test.tsx +++ b/presentation/react-native/ui/__tests__/ExternalLink.test.tsx @@ -1,6 +1,6 @@ import renderer from "react-test-renderer" -import { ExternalLink } from "@/presentation/react/components/ExternalLink" +import { ExternalLink } from "@/presentation/react-native/ui/ExternalLink" describe("", () => { it("renders correctly", () => { diff --git a/presentation/react/components/__tests__/TabBarIcon.test.tsx b/presentation/react-native/ui/__tests__/TabBarIcon.test.tsx similarity index 77% rename from presentation/react/components/__tests__/TabBarIcon.test.tsx rename to presentation/react-native/ui/__tests__/TabBarIcon.test.tsx index 6e9fd0f..efcd33a 100644 --- a/presentation/react/components/__tests__/TabBarIcon.test.tsx +++ b/presentation/react-native/ui/__tests__/TabBarIcon.test.tsx @@ -1,6 +1,6 @@ import renderer from "react-test-renderer" -import { TabBarIcon } from "@/presentation/react/components/TabBarIcon" +import { TabBarIcon } from "@/presentation/react-native/ui/TabBarIcon" describe("", () => { it("renders correctly", () => { diff --git a/presentation/react/components/__tests__/__snapshots__/ExternalLink.test.tsx.snap b/presentation/react-native/ui/__tests__/__snapshots__/ExternalLink.test.tsx.snap similarity index 100% rename from presentation/react/components/__tests__/__snapshots__/ExternalLink.test.tsx.snap rename to presentation/react-native/ui/__tests__/__snapshots__/ExternalLink.test.tsx.snap diff --git a/presentation/react/components/__tests__/__snapshots__/TabBarIcon.test.tsx.snap b/presentation/react-native/ui/__tests__/__snapshots__/TabBarIcon.test.tsx.snap similarity index 100% rename from presentation/react/components/__tests__/__snapshots__/TabBarIcon.test.tsx.snap rename to presentation/react-native/ui/__tests__/__snapshots__/TabBarIcon.test.tsx.snap diff --git a/presentation/react/hooks/__tests__/useBoolean.test.ts b/presentation/react/hooks/__tests__/useBoolean.test.ts index 0277c87..6e4dcfc 100644 --- a/presentation/react/hooks/__tests__/useBoolean.test.ts +++ b/presentation/react/hooks/__tests__/useBoolean.test.ts @@ -2,8 +2,8 @@ import { act, renderHook } from "@testing-library/react-native" import { useBoolean } from "@/presentation/react/hooks/useBoolean" -describe("hooks/useBoolean", () => { - beforeEach(() => { +describe("presentation/react/hooks/useBoolean", () => { + afterEach(() => { jest.clearAllMocks() }) @@ -11,51 +11,76 @@ describe("hooks/useBoolean", () => { for (const initialValue of initialValues) { it(`should set the initial value to ${initialValue}`, () => { + // Arrange - Given const { result } = renderHook(() => { return useBoolean({ initialValue }) }) + + // Assert - Then expect(result.current.value).toBe(initialValue) }) } it("should by default set the initial value to false", () => { + // Arrange - Given const { result } = renderHook(() => { return useBoolean() }) + + // Assert - Then expect(result.current.value).toBe(false) }) it("should toggle the value", async () => { + // Arrange - Given const { result } = renderHook(() => { return useBoolean({ initialValue: false }) }) + + // Act - When await act(() => { return result.current.toggle() }) + + // Assert - Then expect(result.current.value).toBe(true) + + // Act - When await act(() => { return result.current.toggle() }) + + // Assert - Then expect(result.current.value).toBe(false) }) it("should set the value to true", async () => { + // Arrange - Given const { result } = renderHook(() => { return useBoolean({ initialValue: false }) }) + + // Act - When await act(() => { return result.current.setTrue() }) + + // Assert - Then expect(result.current.value).toBe(true) }) it("should set the value to false", async () => { + // Arrange - Given const { result } = renderHook(() => { return useBoolean({ initialValue: true }) }) + + // Act - When await act(() => { return result.current.setFalse() }) + + // Assert - Then expect(result.current.value).toBe(false) }) }) diff --git a/presentation/react/hooks/__tests__/usePresenterState.test.ts b/presentation/react/hooks/__tests__/usePresenterState.test.ts new file mode 100644 index 0000000..4c71adf --- /dev/null +++ b/presentation/react/hooks/__tests__/usePresenterState.test.ts @@ -0,0 +1,75 @@ +import { act, renderHook } from "@testing-library/react-native" + +import { usePresenterState } from "@/presentation/react/hooks/usePresenterState" +import { Presenter } from "@/presentation/presenters/_Presenter" + +interface MockCountPresenterState { + count: number +} + +class MockCountPresenter extends Presenter { + public constructor(initialState: MockCountPresenterState) { + super(initialState) + } + + public increment(): void { + this.setState((state) => { + state.count = state.count + 1 + }) + } +} + +describe("presentation/react/hooks/usePresenterState", () => { + it("should return the initial state from the presenter", async () => { + // Arrange - Given + const initialState = { count: 0 } + const presenter = new MockCountPresenter(initialState) + + // Act - When + const { result } = renderHook(() => { + return usePresenterState(presenter) + }) + + // Assert - Then + expect(result.current).toEqual(initialState) + }) + + it("should update state when presenter state changes", async () => { + // Arrange - Given + const initialState = { count: 0 } + const presenter = new MockCountPresenter(initialState) + const subscribe = jest.spyOn(presenter, "subscribe") + const { result } = renderHook(() => { + return usePresenterState(presenter) + }) + + // Act - When + await act(() => { + presenter.increment() + }) + + // Assert - Then + expect(result.current.count).toBe(1) + expect(subscribe).toHaveBeenCalledTimes(1) + }) + + it("should unsubscribe from presenter on unmount", async () => { + // Arrange - Given + const initialState = { count: 0 } + const presenter = new MockCountPresenter(initialState) + const unsubscribe = jest.spyOn(presenter, "unsubscribe") + const { result, unmount } = renderHook(() => { + return usePresenterState(presenter) + }) + + // Act - When + unmount() + await act(() => { + presenter.increment() + }) + + // Assert - Then + expect(result.current.count).toBe(0) + expect(unsubscribe).toHaveBeenCalledTimes(1) + }) +}) diff --git a/presentation/react/hooks/useBoolean.ts b/presentation/react/hooks/useBoolean.ts index 04d6aec..047c610 100644 --- a/presentation/react/hooks/useBoolean.ts +++ b/presentation/react/hooks/useBoolean.ts @@ -2,9 +2,10 @@ import { useState } from "react" export interface UseBooleanResult { value: boolean - toggle: () => void + setValue: React.Dispatch> setTrue: () => void setFalse: () => void + toggle: () => void } export interface UseBooleanOptions { @@ -43,6 +44,7 @@ export const useBoolean = ( return { value, + setValue, toggle, setTrue, setFalse, diff --git a/tests/setup.ts b/tests/setup.ts new file mode 100644 index 0000000..39b7612 --- /dev/null +++ b/tests/setup.ts @@ -0,0 +1 @@ +import "@testing-library/react-native/extend-expect" diff --git a/utils/__tests__/dates.test.ts b/utils/__tests__/dates.test.ts index 6f28037..98316ce 100644 --- a/utils/__tests__/dates.test.ts +++ b/utils/__tests__/dates.test.ts @@ -1,6 +1,12 @@ -import { getISODate, getWeekNumber } from "../dates" +import { getISODate, getNowDateUTC, getWeekNumber } from "../dates" describe("utils/dates", () => { + afterEach(() => { + jest.clearAllMocks() + jest.resetAllMocks() + jest.useRealTimers() + }) + describe("getISODate", () => { it("should return the correct date in ISO format (e.g: 2012-05-23)", () => { // Arrange - Given @@ -15,6 +21,25 @@ describe("utils/dates", () => { }) }) + describe("getNowDateUTC", () => { + it("should return the current UTC date", () => { + // Arrange - Given + const mockDate = new Date("2024-05-01T12:00:00Z") + jest.useFakeTimers({ now: mockDate }) + Date.UTC = jest.fn(() => { + return mockDate.getTime() + }) + + // Act - When + const result = getNowDateUTC() + + // Assert - Then + const expected = new Date("2024-05-01T12:00:00.000Z") + expect(result).toEqual(expected) + expect(Date.UTC).toHaveBeenCalledTimes(1) + }) + }) + describe("getWeekNumber", () => { it("should return the correct week number for a given date (e.g: 2020-01-01)", () => { // Arrange - Given diff --git a/utils/__tests__/zod.test.ts b/utils/__tests__/zod.test.ts new file mode 100644 index 0000000..b4f366f --- /dev/null +++ b/utils/__tests__/zod.test.ts @@ -0,0 +1,39 @@ +import type { ZodIssue } from "zod" +import { ZodError } from "zod" + +import { getErrorsFieldsFromZodError } from "../zod" + +const zodIssue: ZodIssue = { + code: "too_small", + minimum: 1, + type: "string", + inclusive: true, + exact: false, + message: "String must contain at least 1 character(s)", + path: ["name"], +} + +describe("utils/zod", () => { + describe("getErrorsFieldsFromZodError", () => { + it("should return an array of the fields that have errors", () => { + // Arrange - Given + const error = new ZodError([ + { + ...zodIssue, + path: ["field1"], + }, + { + ...zodIssue, + path: ["field2"], + }, + ]) + + // Act - When + const result = getErrorsFieldsFromZodError(error) + + // Assert - Then + const expected = ["field1", "field2"] + expect(result).toEqual(expected) + }) + }) +}) diff --git a/utils/dates.ts b/utils/dates.ts index 31ab1f4..d477a76 100644 --- a/utils/dates.ts +++ b/utils/dates.ts @@ -11,7 +11,7 @@ export const getISODate = (date: Date): string => { return date.toISOString().slice(0, 10) } -export const getNowDate = (): Date => { +export const getNowDateUTC = (): Date => { const date = new Date() const milliseconds = Date.UTC( date.getFullYear(), diff --git a/utils/zod.ts b/utils/zod.ts index 44b458e..fbb6e78 100644 --- a/utils/zod.ts +++ b/utils/zod.ts @@ -3,5 +3,8 @@ import type { ZodError } from "zod" export const getErrorsFieldsFromZodError = ( error: ZodError, ): Array => { - return Object.keys(error.format()) as Array + const fields = Object.keys(error.format()) as Array + return fields.filter((field) => { + return field !== "_errors" + }) }