Repository navigation
[API] Integration tests — restaurant and food item modules #189
Description
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
sheyman546 commentedon Jun 16, 2026
please i will love to work on this issue and i will submit within 24hr with a quality pr thank you
maramina commentedon Jun 16, 2026
I'd love to work on this issue. It aligns well with my experience, and I can deliver a clean, well-tested PR promptly.
xeeenab commentedon Jun 27, 2026
can i pick this up?
grantfox-oss commentedon Jun 27, 2026
🦊 GrantFox — @xeeenab has been assigned to this issue as part of the Official Campaign campaign!
Next steps:
Closes #189)Good luck! Track your progress on GrantFox.
grantfox-oss commentedon Jun 27, 2026
🎉 This issue has been marked as completed on GrantFox as part of the Official Campaign campaign!
@xeeenab's PR #200 was approved and merged by @zakkiyyat.
🏆 @xeeenab: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (48 total points). Track your full progress on GrantFox.
👏 Great work, @xeeenab! Keep contributing to MixMatch-Inc.