- packages/shared: PlanningView/PlanningItemView, exported.
- apps/api: planning module (service + route), mounted at /planning.
GET /planning/current returns the authenticated user's household's
planning covering today, or null (no error) when there isn't one yet —
the expected state until planning creation exists.
- Tests: Mocha (apps/api/test/planning.test.ts) + Cucumber
(features/planning.feature), same conventions as auth.
- packages/express-tools: fixed AsyncRequestHandler/wrapAsyncHandler's
Locals generic constraint (Record<string, unknown> -> Record<string,
any>, matching Express's own Response<ResBody, LocalsObj>) — the first
endpoint combining requireAuth/AuthLocals with an async handler exposed
that the stricter constraint rejected plain interfaces Response itself
accepts fine.
- Docs: README.md ("Planning" section) + specs/backend-architecture.md.
First commit of the home-page-after-login feature (see plan discussed in
chat) — frontend layout/routing/HomePage follow in subsequent commits on
this same branch/PR.
59 lines
2.3 KiB
TypeScript
59 lines
2.3 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { Given, Then, When } from "@cucumber/cucumber";
|
|
import { prisma } from "../../src/db/prisma.js";
|
|
import type { CustomWorld } from "../support/world.js";
|
|
|
|
When("I request the current planning", async function (this: CustomWorld) {
|
|
this.response = await this.agent.get("/planning/current");
|
|
});
|
|
|
|
Then("the current planning response should be empty", function (this: CustomWorld) {
|
|
assert.equal(this.response.body, null);
|
|
});
|
|
|
|
// Creates the planning/recipe rows directly via Prisma rather than through
|
|
// the API — there's no "create a planning" endpoint yet (see
|
|
// specs/batch-cooking-architecture.md, "Calcul batch-cooking" is still
|
|
// TODO), so this is the only way to get a household into a state where it
|
|
// has one. Reads the household off the already-authenticated agent (via
|
|
// `GET /auth/me`) rather than taking it as a step argument, since the
|
|
// scenario never names it explicitly.
|
|
Given(
|
|
"my household has a planning covering today with recipe {string} on {string} for {string}",
|
|
async function (this: CustomWorld, recipeName: string, weekDay: string, meal: string) {
|
|
const me = await this.agent.get("/auth/me");
|
|
const houseId: number = me.body.houseId;
|
|
|
|
const recipe = await prisma.recipe.create({ data: { name: recipeName } });
|
|
const today = new Date();
|
|
const planning = await prisma.planning.create({
|
|
data: {
|
|
houseId,
|
|
startDate: new Date(
|
|
Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate() - 2),
|
|
),
|
|
finishDate: new Date(
|
|
Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate() + 2),
|
|
),
|
|
},
|
|
});
|
|
await prisma.planningItem.create({
|
|
data: { planningId: planning.id, weekDay, meal, recipeId: recipe.id },
|
|
});
|
|
},
|
|
);
|
|
|
|
Then(
|
|
"the current planning response should include recipe {string} on {string} for {string}",
|
|
function (this: CustomWorld, recipeName: string, weekDay: string, meal: string) {
|
|
const items = this.response.body.items as Array<{
|
|
weekDay: string;
|
|
meal: string;
|
|
recipe: { name: string };
|
|
}>;
|
|
const item = items.find((i) => i.recipe.name === recipeName);
|
|
assert.ok(item, `expected an item with recipe "${recipeName}", got ${JSON.stringify(items)}`);
|
|
assert.equal(item.weekDay, weekDay);
|
|
assert.equal(item.meal, meal);
|
|
},
|
|
);
|