Skip to content

[API] Integration tests — restaurant and food item modules #189

Description

@zakkiyyat

Overview

Write a comprehensive integration test suite for the restaurant and food item modules using the same Vitest + Supertest + `mongodb-memory-server` pattern established in `apps/api/src/modules/auth/tests/auth.test.ts`. Tests must run without any external services — no real MongoDB, no S3.

Dependencies: Issues #180 (Restaurant module), #181 (Food item module), and #186 (Pagination/filtering) must be merged before this issue can be completed.


Test Files

```
apps/api/src/modules/restaurants/tests/restaurant.test.ts
apps/api/src/modules/food-items/tests/food-item.test.ts
```

Both files follow the same `beforeAll` / `afterEach` / `afterAll` setup as `auth.test.ts`:

```ts
let mongoServer: MongoMemoryServer;

beforeAll(async () => {
mongoServer = await MongoMemoryServer.create();
await mongoose.connect(mongoServer.getUri());
});

afterEach(async () => {
await mongoose.connection.dropDatabase();
});

afterAll(async () => {
await mongoose.disconnect();
await mongoServer.stop();
});
```


Restaurant Test Cases (`restaurant.test.ts`)

POST /api/restaurants

  • Returns 201 and the created restaurant for an authenticated user
  • Sets `ownerId` from the JWT — ignores any `ownerId` in the request body
  • Returns 401 for unauthenticated requests
  • Returns 400 with field errors when `name` is missing
  • Returns 400 with field errors when an invalid `cuisineTag` is submitted
  • Returns 409 when the authenticated user already owns a restaurant

GET /api/restaurants

  • Returns a paginated list of active restaurants
  • Does not include soft-deleted (`isActive: false`) restaurants
  • Respects `?page` and `?limit` params and returns correct pagination metadata
  • Filters by `?cuisine=italian` returning only matching restaurants
  • Returns an empty `data` array (not 404) when no restaurants match

GET /api/restaurants/:id

  • Returns the restaurant when it exists
  • Returns 404 for a non-existent ID
  • Returns 404 for a soft-deleted restaurant

GET /api/restaurants/me

  • Returns the authenticated user's restaurant
  • Returns 404 when the user has no restaurant
  • Returns 401 when unauthenticated

PATCH /api/restaurants/:id

  • Owner can update `name` and `description`
  • Returns 403 when a different authenticated user attempts the update
  • Returns 400 for invalid field values (e.g. name too long)

DELETE /api/restaurants/:id

  • Sets `isActive: false` on the document
  • The restaurant no longer appears in the public list after deletion
  • Returns 403 when a non-owner attempts deletion

Food Item Test Cases (`food-item.test.ts`)

POST /api/restaurants/:restaurantId/food-items

  • Returns 201 and the created food item for the restaurant owner
  • Returns 403 when a different authenticated user attempts creation
  • Returns 401 for unauthenticated requests
  • Returns 400 for invalid input (missing `name`, negative `price`, unknown `dietaryTag`)
  • Returns 404 when the `restaurantId` in the path does not exist

GET /api/restaurants/:restaurantId/food-items

  • Returns only `isAvailable: true` items for public requests
  • Returns all items (including unavailable) when the owner requests with `?includeUnavailable=true`
  • Returns correct pagination metadata
  • Returns 404 when the restaurant does not exist

GET /api/restaurants/:restaurantId/food-items/:id

  • Returns the food item when it exists
  • Returns 404 for a non-existent item ID
  • Returns 404 for a soft-deleted (unavailable) item on public requests

PATCH /api/restaurants/:restaurantId/food-items/:id

  • Owner can update `name`, `price`, `isAvailable`
  • Returns 403 for non-owner
  • Returns 400 for invalid updates

DELETE /api/restaurants/:restaurantId/food-items/:id

  • Sets `isAvailable: false`
  • Item no longer appears in public list
  • Returns 403 for non-owner

Helpers

Create a `tests/helpers/` directory with shared test utilities:

```
apps/api/src/tests/helpers/
create-user.ts # Register a user and return { token, userId }
create-restaurant.ts # Create a restaurant for a user and return it
create-food-item.ts # Create a food item and return it
```

These helpers eliminate boilerplate setup in each `describe` block and make test intent clear.


Acceptance Criteria

  • `npm run test -w @discoverly/api` passes all tests with no real external dependencies
  • Each test is independent — `afterEach` drops the database, so tests do not share state
  • All 35+ test cases above are covered
  • Test file import structure matches the rest of the codebase (no relative path hacks)
  • No test takes longer than 10 seconds individually

Metadata

Metadata

Assignees

Labels

BACKENDBACKENDGrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official Campaignintermediate~2–3 day effortsprint-1Sprint 1: Restaurant & Menu Foundation

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions