diff --git a/apps/backend/src/donations/donations.controller.spec.ts b/apps/backend/src/donations/donations.controller.spec.ts index 9f5b9909..a13af53c 100644 --- a/apps/backend/src/donations/donations.controller.spec.ts +++ b/apps/backend/src/donations/donations.controller.spec.ts @@ -3,9 +3,21 @@ import { DonationsController } from './donations.controller'; import { Test, TestingModule } from '@nestjs/testing'; import { mock } from 'jest-mock-extended'; import { Donation } from './donations.entity'; +import { CreateDonationDto } from './dtos/create-donation.dto'; +import { DonationStatus, RecurrenceEnum } from './types'; const mockDonationService = mock(); +const donation1: Partial = { + donationId: 1, + status: DonationStatus.MATCHED, +}; + +const donation2: Partial = { + donationId: 2, + status: DonationStatus.FULFILLED, +}; + describe('DonationsController', () => { let controller: DonationsController; @@ -29,6 +41,20 @@ describe('DonationsController', () => { expect(controller).toBeDefined(); }); + describe('GET /', () => { + it('should call donationService.getAll and return array of donations', async () => { + mockDonationService.getAll.mockResolvedValueOnce([ + donation1, + donation2, + ] as Donation[]); + + const result = await controller.getAllDonations(); + + expect(result).toEqual([donation1, donation2]); + expect(mockDonationService.getAll).toHaveBeenCalled(); + }); + }); + describe('GET /count', () => { it.each([[0], [5]])('should return %i donations', async (count) => { mockDonationService.getNumberOfDonations.mockResolvedValue(count); @@ -52,4 +78,46 @@ describe('DonationsController', () => { expect(mockDonationService.findOne).toHaveBeenCalledWith(1); }); }); + + describe('POST /create', () => { + it('should call donationService.create and return the created donation', async () => { + const createBody: Partial = { + foodManufacturerId: 1, + recurrence: RecurrenceEnum.MONTHLY, + recurrenceFreq: 3, + occurrencesRemaining: 2, + }; + + const createdDonation: Partial = { + donationId: 1, + ...createBody, + dateDonated: new Date(), + status: DonationStatus.AVAILABLE, + }; + + mockDonationService.create.mockResolvedValueOnce( + createdDonation as Donation, + ); + + const result = await controller.createDonation( + createBody as CreateDonationDto, + ); + + expect(result).toEqual(createdDonation); + expect(mockDonationService.create).toHaveBeenCalledWith(createBody); + }); + }); + + describe('PATCH /:donationId/fulfill', () => { + it('should call donationService.fulfill and return updated donation', async () => { + const donationId = 1; + + mockDonationService.fulfill.mockResolvedValueOnce(donation1 as Donation); + + const result = await controller.fulfillDonation(donationId); + + expect(result).toEqual(donation1); + expect(mockDonationService.fulfill).toHaveBeenCalledWith(donationId); + }); + }); }); diff --git a/apps/backend/src/donations/donations.controller.ts b/apps/backend/src/donations/donations.controller.ts index 95a7363b..2862ebb6 100644 --- a/apps/backend/src/donations/donations.controller.ts +++ b/apps/backend/src/donations/donations.controller.ts @@ -5,7 +5,6 @@ import { Get, Patch, Param, - NotFoundException, ParseIntPipe, } from '@nestjs/common'; import { ApiBody } from '@nestjs/swagger'; @@ -76,10 +75,6 @@ export class DonationsController { async fulfillDonation( @Param('donationId', ParseIntPipe) donationId: number, ): Promise { - const updatedDonation = await this.donationService.fulfill(donationId); - if (!updatedDonation) { - throw new NotFoundException('Donation not found'); - } - return updatedDonation; + return this.donationService.fulfill(donationId); } } diff --git a/apps/backend/src/donations/donations.service.spec.ts b/apps/backend/src/donations/donations.service.spec.ts index 84da409c..aae4c56a 100644 --- a/apps/backend/src/donations/donations.service.spec.ts +++ b/apps/backend/src/donations/donations.service.spec.ts @@ -6,6 +6,7 @@ import { FoodManufacturer } from '../foodManufacturers/manufacturers.entity'; import { RecurrenceEnum, DayOfWeek } from './types'; import { RepeatOnDaysDto } from './dtos/create-donation.dto'; import { testDataSource } from '../config/typeormTestDataSource'; +import { NotFoundException } from '@nestjs/common'; jest.setTimeout(60000); @@ -129,7 +130,34 @@ describe('DonationService', () => { expect(service).toBeDefined(); }); - describe('getDonationCount', () => { + describe('findOne', () => { + it('should return a donation with the corresponding id', async () => { + const donationId = 1; + const result = await service.findOne(donationId); + expect(result).toBeDefined(); + expect(result.donationId).toBe(donationId); + expect(result.foodManufacturer).toBeDefined(); + }); + + it('should throw NotFoundException for non-existent donation', async () => { + await expect(service.findOne(999)).rejects.toThrow( + new NotFoundException('Donation 999 not found'), + ); + }); + }); + + describe('getAll', () => { + it('returns all donations in the database with food manufacturer relation', async () => { + const donations = await service.getAll(); + expect(donations).toHaveLength(4); + + donations.forEach((d) => { + expect(d.foodManufacturer).toBeDefined(); + }); + }); + }); + + describe('getNumberOfDonations', () => { it('returns total number of donations in the database', async () => { const donationCount = await service.getNumberOfDonations(); expect(donationCount).toEqual(4); diff --git a/apps/backend/src/donations/donations.service.ts b/apps/backend/src/donations/donations.service.ts index 3e58fcc9..2f378986 100644 --- a/apps/backend/src/donations/donations.service.ts +++ b/apps/backend/src/donations/donations.service.ts @@ -35,7 +35,7 @@ export class DonationService { return donation; } - async getAll() { + async getAll(): Promise { return this.repo.find({ relations: ['foodManufacturer'], }); diff --git a/apps/backend/src/foodRequests/request.controller.spec.ts b/apps/backend/src/foodRequests/request.controller.spec.ts index f8cac0c4..ee029966 100644 --- a/apps/backend/src/foodRequests/request.controller.spec.ts +++ b/apps/backend/src/foodRequests/request.controller.spec.ts @@ -14,12 +14,26 @@ import { MatchingManufacturersDto, } from './dtos/matching.dto'; import { FoodManufacturer } from '../foodManufacturers/manufacturers.entity'; +import { Pantry } from '../pantries/pantries.entity'; const mockRequestsService = mock(); -const foodRequest: Partial = { +const foodRequest1: Partial = { requestId: 1, pantryId: 1, + pantry: { + pantryId: 1, + pantryName: 'Test Pantry 1', + } as Pantry, +}; + +const foodRequest2: Partial = { + requestId: 2, + pantryId: 2, + pantry: { + pantryId: 2, + pantryName: 'Test Pantry 2', + } as Pantry, }; describe('RequestsController', () => { @@ -48,25 +62,39 @@ describe('RequestsController', () => { expect(controller).toBeDefined(); }); + describe('GET /', () => { + it('should call requestsService.getAll and return array of food requests', async () => { + mockRequestsService.getAll.mockResolvedValueOnce([ + foodRequest1, + foodRequest2, + ] as FoodRequest[]); + + const result = await controller.getAllFoodRequests(); + + expect(result).toEqual([foodRequest1, foodRequest2]); + expect(mockRequestsService.getAll).toHaveBeenCalled(); + }); + }); + describe('GET /:requestId', () => { it('should call requestsService.findOne and return a specific food request', async () => { const requestId = 1; mockRequestsService.findOne.mockResolvedValueOnce( - foodRequest as FoodRequest, + foodRequest1 as FoodRequest, ); const result = await controller.getRequest(requestId); - expect(result).toEqual(foodRequest); + expect(result).toEqual(foodRequest1); expect(mockRequestsService.findOne).toHaveBeenCalledWith(requestId); }); }); - describe('GET /get-all-requests/:pantryId', () => { + describe('GET /:pantryId/all', () => { it('should call requestsService.find and return all food requests for a specific pantry', async () => { const foodRequests: Partial[] = [ - foodRequest, + foodRequest1, { requestId: 2, pantryId: 1, diff --git a/apps/backend/src/foodRequests/request.controller.ts b/apps/backend/src/foodRequests/request.controller.ts index 935dab39..4f7a86cc 100644 --- a/apps/backend/src/foodRequests/request.controller.ts +++ b/apps/backend/src/foodRequests/request.controller.ts @@ -25,6 +25,12 @@ import { export class RequestsController { constructor(private requestsService: RequestsService) {} + @Roles(Role.ADMIN) + @Get() + async getAllFoodRequests(): Promise { + return this.requestsService.getAll(); + } + @Roles(Role.PANTRY, Role.ADMIN) @Get('/:requestId') async getRequest( diff --git a/apps/backend/src/foodRequests/request.service.spec.ts b/apps/backend/src/foodRequests/request.service.spec.ts index 99432e50..567fbd7f 100644 --- a/apps/backend/src/foodRequests/request.service.spec.ts +++ b/apps/backend/src/foodRequests/request.service.spec.ts @@ -72,6 +72,23 @@ describe('RequestsService', () => { expect(service).toBeDefined(); }); + describe('getAll', () => { + it('should return all requests with request details, pantryId, and pantryName', async () => { + const result = await service.getAll(); + expect(result).toHaveLength(4); + result.forEach((r) => { + expect(r.requestId).toBeDefined(); + expect(r.requestedSize).toBeDefined(); + expect(r.requestedFoodTypes).toBeDefined(); + expect(r.additionalInformation).toBeDefined(); + expect(r.requestedAt).toBeDefined(); + expect(r.status).toBeDefined(); + expect(r.pantry.pantryId).toBeDefined(); + expect(r.pantry.pantryName).toBeDefined(); + }); + }); + }); + describe('findOne', () => { it('should return a food request with the corresponding id', async () => { const requestId = 1; diff --git a/apps/backend/src/foodRequests/request.service.ts b/apps/backend/src/foodRequests/request.service.ts index 0a3290fd..44f1c6b0 100644 --- a/apps/backend/src/foodRequests/request.service.ts +++ b/apps/backend/src/foodRequests/request.service.ts @@ -42,6 +42,23 @@ export class RequestsService { return request; } + async getAll(): Promise { + return this.repo + .createQueryBuilder('request') + .leftJoin('request.pantry', 'pantry') + .select([ + 'request.requestId', + 'request.requestedSize', + 'request.requestedFoodTypes', + 'request.additionalInformation', + 'request.requestedAt', + 'request.status', + 'pantry.pantryId', + 'pantry.pantryName', + ]) + .getMany(); + } + async getOrderDetails(requestId: number): Promise { validateId(requestId, 'Request');