diff --git a/src/services/mocker/msw/controllers/index.ts b/src/services/mocker/msw/controllers/index.ts index c7e5265..4b43cdb 100755 --- a/src/services/mocker/msw/controllers/index.ts +++ b/src/services/mocker/msw/controllers/index.ts @@ -1,2 +1,2 @@ -export * from "./reminder"; -export * from "./reminderGroup"; +export { setupRemindersController } from "./reminder"; +export { setupReminderGroupsController } from "./reminderGroup"; diff --git a/src/services/mocker/msw/controllers/reminder.ts b/src/services/mocker/msw/controllers/reminder.ts index 5c6b702..4f88166 100644 --- a/src/services/mocker/msw/controllers/reminder.ts +++ b/src/services/mocker/msw/controllers/reminder.ts @@ -13,49 +13,80 @@ import { import { getUrlSearchParams } from "shared"; -import { db } from "../db"; +import { TDb } from "../db"; import { urlPrefix } from "../utils"; -export const getReminders = http.get(urlPrefix("/reminders"), ({ request }) => { - const reminders = db.reminder.getAll(); +export const setupRemindersController = (db: TDb) => { + const getReminders = http.get(urlPrefix("/reminders"), ({ request }) => { + const reminders = db.reminder.getAll(); - const searchParams = getUrlSearchParams(request.url); + const searchParams = getUrlSearchParams(request.url); - let data: TReminder[] = reminders; + let data: TReminder[] = reminders; - if (searchParams["groupId"]) { - data = data.filter((reminder) => reminder?.group?.id === searchParams["groupId"]); - } + if (searchParams["groupId"]) { + data = data.filter((reminder) => reminder?.group?.id === searchParams["groupId"]); + } - if (searchParams["state"]) { - data = data.filter((reminder) => reminder.state === searchParams["state"]); - } + if (searchParams["state"]) { + data = data.filter((reminder) => reminder.state === searchParams["state"]); + } - return HttpResponse.json({ data }, { status: 200 }); -}); + return HttpResponse.json({ data }, { status: 200 }); + }); -export const createReminder = http.post< - never, - TCreateReminderRequestPayload, - TCreateReminderResponsePayload | THTTPError ->(urlPrefix("/reminders"), async ({ request }) => { - const { title, groupId } = await request.json(); + const createReminder = http.post( + urlPrefix("/reminders"), + async ({ request }) => { + const { title, groupId } = await request.json(); - const group = db.reminderGroup.getAll().find((group) => group.id === groupId); + const group = db.reminderGroup.getAll().find((group) => group.id === groupId); - if (groupId && !group) { - return HttpResponse.json({ message: `Reminder Group with id ${groupId} not found!` }, { status: 404 }); - } + if (groupId && !group) { + return HttpResponse.json({ message: `Reminder Group with id ${groupId} not found!` }, { status: 404 }); + } - const newReminder = db.reminder.create({ title, group }); + const newReminder = db.reminder.create({ title, group }); + + return HttpResponse.json({ data: newReminder }, { status: 201 }); + } + ); + + const deleteReminder = http.delete<{ id: TDeleteReminderRequestPayload }, never, TDeleteReminderResponsePayload>( + urlPrefix("/reminders/:id"), + ({ params }) => { + const reminder = db.reminder.findFirst({ + where: { + id: { + equals: params.id, + }, + }, + }); - return HttpResponse.json({ data: newReminder }, { status: 201 }); -}); + if (!reminder) { + return HttpResponse.json({ message: `Reminder with id ${params.id} not found!` }, { status: 404 }); + } + + db.reminder.delete({ + where: { + id: { + equals: params.id, + }, + }, + }); + + return HttpResponse.json({ message: `Reminder with id ${params.id} deleted!` }, { status: 200 }); + } + ); + + const updateReminder = http.patch< + { id: TUpdateReminderRequestPayload["id"] }, + TUpdateReminderRequestPayload, + TUpdateReminderResponsePayload | THTTPError + >(urlPrefix("/reminders/:id"), async ({ request, params }) => { + const { groupId, ...requestBody } = await request.json(); -export const deleteReminder = http.delete<{ id: TDeleteReminderRequestPayload }, never, TDeleteReminderResponsePayload>( - urlPrefix("/reminders/:id"), - ({ params }) => { const reminder = db.reminder.findFirst({ where: { id: { @@ -68,59 +99,31 @@ export const deleteReminder = http.delete<{ id: TDeleteReminderRequestPayload }, return HttpResponse.json({ message: `Reminder with id ${params.id} not found!` }, { status: 404 }); } - db.reminder.delete({ + const group = db.reminderGroup.findFirst({ where: { id: { - equals: params.id, + equals: groupId, }, }, }); - return HttpResponse.json({ message: `Reminder with id ${params.id} deleted!` }, { status: 200 }); - } -); + if (groupId && !group) { + return HttpResponse.json({ message: `Reminder Group with id ${groupId} not found!` }, { status: 404 }); + } -export const updateReminder = http.patch< - { id: TUpdateReminderRequestPayload["id"] }, - TUpdateReminderRequestPayload, - TUpdateReminderResponsePayload | THTTPError ->(urlPrefix("/reminders/:id"), async ({ request, params }) => { - const { groupId, ...requestBody } = await request.json(); - - const reminder = db.reminder.findFirst({ - where: { - id: { - equals: params.id, + const updatedReminder = db.reminder.update({ + where: { + id: { + equals: params.id, + }, }, - }, - }); - - if (!reminder) { - return HttpResponse.json({ message: `Reminder with id ${params.id} not found!` }, { status: 404 }); - } - - const group = db.reminderGroup.findFirst({ - where: { - id: { - equals: groupId, + data: { + ...(requestBody as any), }, - }, - }); + }) as TReminder; - if (groupId && !group) { - return HttpResponse.json({ message: `Reminder Group with id ${groupId} not found!` }, { status: 404 }); - } + return HttpResponse.json({ data: updatedReminder }, { status: 200 }); + }); - const updatedReminder = db.reminder.update({ - where: { - id: { - equals: params.id, - }, - }, - data: { - ...(requestBody as any), - }, - }) as TReminder; - - return HttpResponse.json({ data: updatedReminder }, { status: 200 }); -}); + return [getReminders, createReminder, deleteReminder, updateReminder]; +}; diff --git a/src/services/mocker/msw/controllers/reminderGroup.ts b/src/services/mocker/msw/controllers/reminderGroup.ts index e0e8027..2ff88d9 100644 --- a/src/services/mocker/msw/controllers/reminderGroup.ts +++ b/src/services/mocker/msw/controllers/reminderGroup.ts @@ -13,105 +13,109 @@ import { THTTPError, } from "types"; -import { db } from "../db"; +import { TDb } from "../db"; import { urlPrefix } from "../utils"; -export const getReminderGroups = http.get(urlPrefix("/reminder-groups"), () => { - return HttpResponse.json({ data: db.reminderGroup.getAll() }, { status: 200 }); -}); - -export const getReminderGroup = http.get< - { id: TGetReminderGroupRequestPayload }, - never, - TGetReminderGroupResponsePayload | THTTPError ->(urlPrefix("/reminder-groups/:id"), ({ params }) => { - const reminderGroup = db.reminderGroup.findFirst({ - where: { - id: { - equals: params.id, - }, - }, +export const setupReminderGroupsController = (db: TDb) => { + const getReminderGroups = http.get(urlPrefix("/reminder-groups"), () => { + return HttpResponse.json({ data: db.reminderGroup.getAll() }, { status: 200 }); }); - if (!reminderGroup) { - return HttpResponse.json({ message: `Reminder Group with id ${params.id} not found!` }, { status: 404 }); - } + const getReminderGroup = http.get< + { id: TGetReminderGroupRequestPayload }, + never, + TGetReminderGroupResponsePayload | THTTPError + >(urlPrefix("/reminder-groups/:id"), ({ params }) => { + const reminderGroup = db.reminderGroup.findFirst({ + where: { + id: { + equals: params.id, + }, + }, + }); - return HttpResponse.json({ data: reminderGroup }, { status: 200 }); -}); + if (!reminderGroup) { + return HttpResponse.json({ message: `Reminder Group with id ${params.id} not found!` }, { status: 404 }); + } -export const createReminderGroup = http.post< - never, - TCreateReminderGroupRequestPayload, - TCreateReminderGroupResponsePayload | THTTPError ->(urlPrefix("/reminder-groups"), async ({ request }) => { - const requestBody = await request.json(); + return HttpResponse.json({ data: reminderGroup }, { status: 200 }); + }); - const reminderGroup = db.reminderGroup.create({ - ...requestBody, + const createReminderGroup = http.post< + never, + TCreateReminderGroupRequestPayload, + TCreateReminderGroupResponsePayload | THTTPError + >(urlPrefix("/reminder-groups"), async ({ request }) => { + const requestBody = await request.json(); + + const reminderGroup = db.reminderGroup.create({ + ...requestBody, + }); + + return HttpResponse.json({ data: reminderGroup }, { status: 201 }); }); - return HttpResponse.json({ data: reminderGroup }, { status: 201 }); -}); - -export const deleteReminderGroup = http.delete< - { id: TDeleteReminderGroupRequestPayload }, - never, - TDeleteReminderGroupResponsePayload | THTTPError ->(urlPrefix("/reminder-groups/:id"), ({ params }) => { - const reminderGroup = db.reminderGroup.findFirst({ - where: { - id: { - equals: params.id, + const deleteReminderGroup = http.delete< + { id: TDeleteReminderGroupRequestPayload }, + never, + TDeleteReminderGroupResponsePayload | THTTPError + >(urlPrefix("/reminder-groups/:id"), ({ params }) => { + const reminderGroup = db.reminderGroup.findFirst({ + where: { + id: { + equals: params.id, + }, }, - }, - }); + }); - if (!reminderGroup) { - return HttpResponse.json({ message: `Reminder Group with id ${params.id} not found!` }, { status: 404 }); - } + if (!reminderGroup) { + return HttpResponse.json({ message: `Reminder Group with id ${params.id} not found!` }, { status: 404 }); + } - db.reminderGroup.delete({ - where: { - id: { - equals: params.id, + db.reminderGroup.delete({ + where: { + id: { + equals: params.id, + }, }, - }, - }); + }); - return HttpResponse.json({ message: `Reminder Group with id ${params.id} deleted!` }, { status: 200 }); -}); + return HttpResponse.json({ message: `Reminder Group with id ${params.id} deleted!` }, { status: 200 }); + }); -export const updateReminderGroup = http.patch< - { id: TUpdateReminderGroupRequestPayload["id"] }, - TUpdateReminderGroupRequestPayload, - TUpdateReminderGroupResponsePayload | THTTPError ->(urlPrefix("/reminder-groups/:id"), async ({ request, params }) => { - const requestBody = await request.json(); - - const reminderGroup = db.reminderGroup.findFirst({ - where: { - id: { - equals: params.id, + const updateReminderGroup = http.patch< + { id: TUpdateReminderGroupRequestPayload["id"] }, + TUpdateReminderGroupRequestPayload, + TUpdateReminderGroupResponsePayload | THTTPError + >(urlPrefix("/reminder-groups/:id"), async ({ request, params }) => { + const requestBody = await request.json(); + + const reminderGroup = db.reminderGroup.findFirst({ + where: { + id: { + equals: params.id, + }, }, - }, - }); + }); - if (!reminderGroup) { - return HttpResponse.json({ message: `Reminder Group with id ${params.id} not found!` }, { status: 404 }); - } + if (!reminderGroup) { + return HttpResponse.json({ message: `Reminder Group with id ${params.id} not found!` }, { status: 404 }); + } - const updatedReminder = db.reminderGroup.update({ - where: { - id: { - equals: params.id, + const updatedReminder = db.reminderGroup.update({ + where: { + id: { + equals: params.id, + }, }, - }, - data: { - ...requestBody, - }, - }) as TReminderGroup; + data: { + ...requestBody, + }, + }) as TReminderGroup; + + return HttpResponse.json({ data: updatedReminder }, { status: 200 }); + }); - return HttpResponse.json({ data: updatedReminder }, { status: 200 }); -}); + return [getReminderGroups, getReminderGroup, createReminderGroup, deleteReminderGroup, updateReminderGroup]; +}; diff --git a/src/services/mocker/msw/db.ts b/src/services/mocker/msw/db.ts index b9e0e90..7cd4c9c 100644 --- a/src/services/mocker/msw/db.ts +++ b/src/services/mocker/msw/db.ts @@ -1,4 +1,4 @@ -import { factory, nullable, oneOf, primaryKey } from "@mswjs/data"; +import { factory, nullable, oneOf, primaryKey, drop } from "@mswjs/data"; import { uuid } from "shared"; @@ -58,3 +58,7 @@ export const buildScenarios = (db: TDb) => { }; return builder; }; + +export const dropDb = (db: TDb) => { + drop(db); +}; diff --git a/src/services/mocker/msw/handlers.ts b/src/services/mocker/msw/handlers.ts index adf7e9e..1954ca4 100755 --- a/src/services/mocker/msw/handlers.ts +++ b/src/services/mocker/msw/handlers.ts @@ -1,3 +1,7 @@ import * as controllers from "./controllers"; +import { TDb } from "./db"; -export const handlers = [...Object.values(controllers)]; +export const setupHandlers = (db: TDb) => [ + ...controllers.setupReminderGroupsController(db), + ...controllers.setupRemindersController(db), +]; diff --git a/src/services/mocker/msw/server.ts b/src/services/mocker/msw/server.ts index c7115fb..f97881e 100755 --- a/src/services/mocker/msw/server.ts +++ b/src/services/mocker/msw/server.ts @@ -2,7 +2,7 @@ import { setupWorker } from "msw/browser"; import { db, buildScenarios } from "./db"; -import { handlers } from "./handlers"; +import { setupHandlers } from "./handlers"; const PUBLIC_URL = process.env.REACT_APP_PUBLIC_URL; @@ -10,6 +10,8 @@ export const runServer = () => { // NOTE: seed data buildScenarios(db).withReminders(5).withReminderGroups({ remindersPerGroup: 2 }); + const handlers = setupHandlers(db); + const worker = setupWorker(...handlers); return worker.start({ diff --git a/src/tests/jest.setupAfterEnv.ts b/src/tests/jest.setupAfterEnv.ts index bc5fa6b..bc14db2 100644 --- a/src/tests/jest.setupAfterEnv.ts +++ b/src/tests/jest.setupAfterEnv.ts @@ -5,8 +5,6 @@ import "@testing-library/jest-dom"; import ResizeObserver from "resize-observer-polyfill"; -import "./utils/testServer"; - global.ResizeObserver = ResizeObserver; // Mocking the matchMedia API diff --git a/src/tests/utils/testServer.ts b/src/tests/utils/testServer.ts index 04096f9..8805a5f 100644 --- a/src/tests/utils/testServer.ts +++ b/src/tests/utils/testServer.ts @@ -2,23 +2,32 @@ import { setupServer } from "msw/node"; import { beforeAll, afterEach, afterAll } from "@jest/globals"; -import { handlers } from "services/mocker/msw/handlers"; +import { setupHandlers, db, dropDb } from "services/mocker/msw"; -const runTestServer = () => { - return setupServer(...handlers); -}; +export const testServer = setupServer(...setupHandlers(db)); -export const testServer = runTestServer(); +beforeAll(() => + testServer.listen({ + onUnhandledRequest(request) { + // eslint-disable-next-line no-console + console.log("Unhandled %s %s", request.method, request.url); + }, + }) +); + +afterEach(() => { + testServer.resetHandlers(); + dropDb(db); +}); + +afterAll(() => { + testServer.close(); +}); -beforeAll(() => testServer.listen({ onUnhandledRequest: "error" })); -afterEach(() => testServer.resetHandlers()); -afterAll(() => testServer.close()); // NOTE: simple outgoing request listener logger testServer.events.on("request:start", ({ request }) => { // eslint-disable-next-line no-console console.log("MSW intercepted:", request.method, request.url); }); -export { db, buildScenarios, urlPrefix } from "services/mocker/msw"; - export { HttpResponse, http } from "msw"; diff --git a/src/views/Reminders/ReminderGroupsList/ReminderGroupsList.spec.tsx b/src/views/Reminders/ReminderGroupsList/ReminderGroupsList.spec.tsx index f953875..d32e3ce 100644 --- a/src/views/Reminders/ReminderGroupsList/ReminderGroupsList.spec.tsx +++ b/src/views/Reminders/ReminderGroupsList/ReminderGroupsList.spec.tsx @@ -2,7 +2,9 @@ import { screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { render, testServer, HttpResponse, http, db, buildScenarios, urlPrefix } from "tests/utils"; +import { db, buildScenarios, urlPrefix } from "services/mocker/msw"; + +import { render, testServer, HttpResponse, http } from "tests/utils"; import { ReminderGroupsList } from "./ReminderGroupsList"; @@ -13,10 +15,6 @@ describe("ReminderGroupsList", () => { const getCancelBtn = () => screen.getByTestId("reminder-group-item-create-cancel"); const getTextInput = () => screen.getByTestId("reminder-group-item-create-text"); - buildScenarios(db) - .withReminders(5) - .withReminderGroups({ reminderGroups: ["Work", "Home", "Personal"], remindersPerGroup: 2 }); - return { result: render(), getAddListBtn, @@ -27,6 +25,10 @@ describe("ReminderGroupsList", () => { }; it("should render reminder groups list", async () => { + buildScenarios(db) + .withReminders(5) + .withReminderGroups({ reminderGroups: ["Work", "Home", "Personal"], remindersPerGroup: 2 }); + setup(); await waitFor(() => { @@ -36,10 +38,10 @@ describe("ReminderGroupsList", () => { expect(screen.getAllByRole("listitem")).toHaveLength(4); }); - it("should render toast on error", async () => { + it("should handle negative scenario for fetching reminder groups", async () => { testServer.use( http.get(urlPrefix("/reminder-groups"), () => { - return HttpResponse.json({ message: "Error fetching reminder groups" }, { status: 404 }); + return HttpResponse.json({ message: "Error" }, { status: 404 }); }) ); @@ -67,4 +69,28 @@ describe("ReminderGroupsList", () => { expect(screen.getByText("New Reminder Group")).toBeInTheDocument(); }); }); + + it("should handle negative scenario for adding reminder group", async () => { + testServer.use( + http.post(urlPrefix("/reminder-groups"), () => { + return HttpResponse.json({ message: "Error" }, { status: 404 }); + }) + ); + + const { getAddListBtn, getTextInput, getSaveBtn } = setup(); + + await userEvent.click(getAddListBtn()); + + await waitFor(() => { + expect(getTextInput()).toBeInTheDocument(); + }); + + await userEvent.type(getTextInput(), "New Reminder Group"); + + await userEvent.click(getSaveBtn()); + + await waitFor(() => { + expect(screen.getByText("Error creating reminder group")).toBeInTheDocument(); + }); + }); });