Skip to content

Commit

Permalink
create more comprehensive tests for get procedures
Browse files Browse the repository at this point in the history
  • Loading branch information
dlustre committed Apr 26, 2024
1 parent c6f2755 commit d61ddcd
Show file tree
Hide file tree
Showing 10 changed files with 242 additions and 119 deletions.
2 changes: 1 addition & 1 deletion packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"dev": "echo 'Add dev script here'",
"build": "echo 'Add build script here'",
"with-env": "dotenv -e ../../.env --",
"test": "npx vitest run --config vitest.config.ts",
"test": "pnpm with-env vitest run --config vitest.config.ts",
"lint": "eslint ."
},
"dependencies": {
Expand Down
4 changes: 2 additions & 2 deletions packages/api/src/events/services/scrape.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ describe("insert menu into db", () => {
trx.rollback();
});
}).rejects.toThrowError("Rollback");
}, 10_000);
});
});
}, 10_000);
58 changes: 27 additions & 31 deletions packages/api/src/menus/procedures/getMenu.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { TRPCError } from "@trpc/server";
import { format, isToday } from "date-fns";
import { describe, expect, it } from "vitest";

import { getRestaurantId } from "@zotmeal/utils";

import type { GetMenuParams } from "..";
import { GetMenuSchema } from "..";
import { createCaller, createTRPCContext } from "../..";
import { TRPCError } from "@trpc/server";

describe("getMenu", () => {
it("hello", () => {
console.log("hello");
});
});
describe("getMenu", () => it("hello", () => console.log("hello")));

describe("GetMenuSchema validates properly", () => {
it("parses valid params", () => {
Expand Down Expand Up @@ -43,47 +43,43 @@ describe("GetMenuSchema validates properly", () => {
});

describe("menu.get", () => {
// this test will not pass because the database is empty
const ctx = createTRPCContext({});
const ctx = createTRPCContext({ headers: new Headers() });
const caller = createCaller(ctx);
const date = format(new Date(), "MM/d/yyyy");

// it("should get today's brandywine lunch menu", async () => {
// const menu = caller.menu.get({
// date: "1/24/2024",
// periodName: "breakfast",
// restaurantName: "brandywine",
// })
// await expect(menu).resolves.toBeTruthy();
// console.log("menu:", await menu); // should have a more robust test
// });
it("should get today's brandywine lunch menu", async () => {
const menu = await caller.menu.get({
date,
periodName: "lunch",
restaurantName: "brandywine",
});
expect(menu).toBeTruthy();
expect(isToday(menu.date)).toBeTruthy();
expect(menu.restaurantId).toEqual(getRestaurantId("brandywine"));
});

// TODO: finish implementing this once the database is populated.
// each error should have a different message
// TODO: have each invalid input give unique TRPCError message
it("should not get an invalid menu", async () => {
// invalid date (these tests fails)
/*
const invalidDate = caller.menu.get({
date: "1/24/1984",
periodName: "breakfast",
periodName: "lunch",
restaurantName: "brandywine",
})
});
await expect(invalidDate).rejects.toThrowError(TRPCError);

// invalid period
const invalidPeriod = caller.menu.get({
date: "1/24/2024",
date,
periodName: "latelatenight" as "latenight",
restaurantName: "brandywine",
})
});
await expect(invalidPeriod).rejects.toThrowError(TRPCError);
*/

// invalid restaurant
const invalidRestaurant = caller.menu.get({
date: "1/24/2024",
periodName: "breakfast",
date,
periodName: "lunch",
restaurantName: "antwine" as "anteatery",
})
});

await expect(invalidRestaurant).rejects.toThrowError(TRPCError);
});
});
3 changes: 1 addition & 2 deletions packages/api/src/menus/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ const helloProcedure = publicProcedure.query(async (opts) => {
const res = await axios.get("https://jsonplaceholder.typicode.com/todos/1");
const _ = opts;
console.log(res.data);
console.log("hello");
return "hello";
return "menu -> hello";
});

export const menuRouter = createTRPCRouter({
Expand Down
66 changes: 25 additions & 41 deletions packages/api/src/menus/services/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ import { TRPCError } from "@trpc/server";
import { z } from "zod";

import type { Drizzle } from "@zotmeal/db";
import type { Dish, Menu, Station } from "@zotmeal/db/src/schema";
import { eq } from "@zotmeal/db";
import {
DishMenuStationJoint,
DishTable,
MenuTable,
StationTable,
import type {
Menu,
MenuWithRelations,
StationWithRelations,
} from "@zotmeal/db/src/schema";
import { MenuTable } from "@zotmeal/db/src/schema";
import { parseDate } from "@zotmeal/utils";
import { DateRegex } from "@zotmeal/validators";

Expand All @@ -25,19 +23,11 @@ export const GetMenuSchema = z.object({
restaurantName: z.string(),
}) satisfies z.ZodType<GetMenuParams>;

// deliberate choice to exclude nutrition on dish model, the list view will not contain the full dish nutrition details
interface StationResult extends Station {
dishes: Dish[];
}

interface MenuResult extends Menu {
stations: StationResult[];
}

export async function getMenu(
db: Drizzle,
params: GetMenuParams,
): Promise<MenuResult | null> {
): Promise<MenuWithRelations | null> {
console.log("GET MENU params:", params);
const date = parseDate(params.date);
if (!date) {
throw new TRPCError({
Expand All @@ -54,44 +44,38 @@ export async function getMenu(
throw new TRPCError({ message: "restaurant not found", code: "NOT_FOUND" });
}

const rows = await db
.select()
.from(DishMenuStationJoint)
.innerJoin(MenuTable, eq(DishMenuStationJoint.menuId, MenuTable.id))
.innerJoin(DishTable, eq(DishMenuStationJoint.dishId, DishTable.id))
.innerJoin(
StationTable,
eq(DishMenuStationJoint.stationId, StationTable.id),
);

// this way we dont need to explicitly do join. drizzle will performs join behind the scenes
// const rowsRelation = await db.query.DishMenuStationJoint.findMany({
// with: {
// dish: true,
// menu: true,
// station: true,
// },
// });
const rows = await db.query.DishMenuStationJoint.findMany({
with: {
dish: {
with: {
dietRestriction: true,
nutritionInfo: true,
},
},
menu: true,
station: true,
},
});

let menuResult: MenuResult | null = null;
const stationsResult: Record<string, StationResult> = {};
let menuResult: MenuWithRelations | null = null;
const stationsResult: Record<string, StationWithRelations> = {};

for (const row of rows) {
if (!menuResult) {
menuResult = {
...row.menus,
...row.menu,
stations: [],
};
}
const { dishes: dish, menus, stations: station } = row;
const { dish, menu, station, menuId, stationId } = row;
if (!(station.id in stationsResult)) {
stationsResult[station.id] = {
...station,
dishes: [],
};
}
stationsResult[station.id]?.dishes.push(dish);
console.log(dish, menus, station);
stationsResult[station.id]?.dishes.push({ ...dish, menuId, stationId });
console.log(dish, menu, station);
}
if (!menuResult) {
return null;
Expand Down
38 changes: 20 additions & 18 deletions packages/api/src/schedules/procedures/getSchedule.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { format, isToday } from "date-fns";
import { describe, expect, it } from "vitest";

import { createDrizzle, MenuTable } from "@zotmeal/db";
import { PeriodEnum } from "@zotmeal/db/src/schema";

import type { GetScheduleParams } from "../services/schedule";
import { createCaller, createTRPCContext } from "../..";
Expand Down Expand Up @@ -37,23 +38,24 @@ describe("getScheduleSchema validates properly", () => {
});

describe("getSchedule", () => {
const db = createDrizzle({ connectionString: process.env.DB_URL! });
const ctx = createTRPCContext({ db });
const ctx = createTRPCContext({ headers: new Headers() });
const caller = createCaller(ctx);

it("should get schedule", async () => {
const menuRows = await db.select().from(MenuTable);

// TODO: have a better way to run this test in integration
if (menuRows.length === 0) {
expect(true).toBeTruthy();
} else {
const schedule = await caller.schedule.get({
date: "04/22/2024",
restaurantName: "brandywine",
});

expect(schedule).toBeTruthy();
}
const date = format(new Date(), "MM/d/yyyy");

it("should get today's brandywine schedule", async () => {
const schedule = await caller.schedule.get({
date,
restaurantName: "brandywine",
});
expect(schedule).toBeTruthy();
PeriodEnum.enumValues.forEach((period) => {
const fetchedPeriod = schedule[period];

if (!fetchedPeriod) {
return;
}

expect(isToday(fetchedPeriod.start)).toBeTruthy();
});
});
});
14 changes: 7 additions & 7 deletions packages/api/src/schedules/services/schedule.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { TRPCError } from "@trpc/server";
import { format } from "date-fns";
import { z } from "zod";

import type { Drizzle, Period } from "@zotmeal/db";
Expand Down Expand Up @@ -36,7 +37,9 @@ export async function getSchedule(
const restaurantId =
RESTAURANT_TO_ID[params.restaurantName]?.toString() ?? "";
const fetchedPeriods = await db.query.MenuTable.findMany({

Check failure on line 39 in packages/api/src/schedules/services/schedule.ts

View workflow job for this annotation

GitHub Actions / test

src/schedules/procedures/getSchedule.test.ts > getSchedule > should get today's brandywine schedule

{ stack: 'AggregateError: \n' + ' at /home/runner/work/ZotMeal/ZotMeal/node_modules/pg-pool/index.js:45:11\n' + ' at processTicksAndRejections (node:internal/process/task_queues:95:5)\n' + ' at file:///home/runner/work/ZotMeal/ZotMeal/node_modules/src/node-postgres/session.ts:65:19\n' + ' at Module.getSchedule (/home/runner/work/ZotMeal/ZotMeal/packages/api/src/schedules/services/schedule.ts:39:26)\n' + ' at /home/runner/work/ZotMeal/ZotMeal/packages/api/src/schedules/procedures/getSchedule.ts:9:22\n' + ' at resolveMiddleware (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/procedureBuilder.mjs:103:30)\n' + ' at callRecursive (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/procedureBuilder.mjs:153:32)\n' + ' at callRecursive (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/procedureBuilder.mjs:153:32)\n' + ' at procedure (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/procedureBuilder.mjs:183:24)\n' + ' at file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/router.mjs:111:28', message: '', cause: { stack: 'AggregateError: \n' + ' at /home/runner/work/ZotMeal/ZotMeal/node_modules/pg-pool/index.js:45:11\n' + ' at processTicksAndRejections (node:internal/process/task_queues:95:5)\n' + ' at file:///home/runner/work/ZotMeal/ZotMeal/node_modules/src/node-postgres/session.ts:65:19\n' + ' at Module.getSchedule (/home/runner/work/ZotMeal/ZotMeal/packages/api/src/schedules/services/schedule.ts:39:26)\n' + ' at /home/runner/work/ZotMeal/ZotMeal/packages/api/src/schedules/procedures/getSchedule.ts:9:22\n' + ' at resolveMiddleware (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/procedureBuilder.mjs:103:30)\n' + ' at callRecursive (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/procedureBuilder.mjs:153:32)\n' + ' at callRecursive (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/procedureBuilder.mjs:153:32)\n' + ' at procedure (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/procedureBuilder.mjs:183:24)\n' + ' at file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/router.mjs:111:28', errors: [ [Object], [Object] ], code: 'ECONNREFUSED', message: '', constructor: 'Function<AggregateError>', name: 'AggregateError', toString: 'Function<toString>' }, code: 'INTERNAL_SERVER_ERROR', name: 'TRPCError', stackStr: 'AggregateError: \n' + ' at /home/runner/work/ZotMeal/ZotMeal/node_modules/pg-pool/index.js:45:11\n' + ' at processTicksAndRejections (node:internal/process/task_queues:95:5)\n' + ' at file:///home/runner/work/ZotMeal/ZotMeal/node_modules/src/node-postgres/session.ts:65:19\n' + ' at Module.getSchedule (/home/runner/work/ZotMeal/ZotMeal/packages/api/src/schedules/services/schedule.ts:39:26)\n' + ' at /home/runner/work/ZotMeal/ZotMeal/packages/api/src/schedules/procedures/getSchedule.ts:9:22\n' + ' at resolveMiddleware (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/procedureBuilder.mjs:103:30)\n' + ' at callRecursive (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/procedureBuilder.mjs:153:32)\n' + ' at callRecursive (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/procedureBuilder.mjs:153:32)\n' + ' at procedure (file:///home/runner/work/ZotMeal/ZotMeal/node_modules/@trpc/server/dist/unstable-core-do-not-import/pro
where: (menu, { eq }) => eq(menu.restaurantId, restaurantId),
where: (menu, { eq }) =>
eq(menu.restaurantId, restaurantId) &&
eq(menu.date, format(date, "MM/dd/yyyy")),
columns: {
start: true,
end: true,
Expand All @@ -45,10 +48,7 @@ export async function getSchedule(
},
});

const schedule: ScheduleResult = {};
for (const Period of fetchedPeriods) {
const { period, start, end, price } = Period;
schedule[period] = { start, end, price };
}
return schedule;
return Object.fromEntries(
fetchedPeriods.map(({ period, ...data }) => [period, data]),
);
}
6 changes: 4 additions & 2 deletions packages/api/src/trpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ const db = createDrizzle({
});

export const createTRPCContext = (opts: {
// headers: Headers;
headers: Headers;
// session: Session | null;
}) => {
console.log(">>> tRPC Request from", "something", "by", "someone");
const source = opts.headers.get("x-trpc-source") ?? "unknown";

console.log(">>> tRPC Request from", source, "by", "someone");
return {
...opts,
db,
Expand Down
2 changes: 1 addition & 1 deletion packages/db/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@zotmeal/prettier-config": "workspace:^0.1.0",
"@zotmeal/tsconfig": "workspace:^0.1.0",
"dotenv-cli": "^7.4.1",
"drizzle-kit": "^0.20.14",
"drizzle-kit": "^0.20.17",
"eslint": "^8.57.0",
"prettier": "^3.2.5",
"typescript": "^5.4.3"
Expand Down
Loading

0 comments on commit d61ddcd

Please sign in to comment.