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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions