Skip to content
This repository has been archived by the owner on Dec 6, 2024. It is now read-only.

Commit

Permalink
Merge pull request #76 from ikemHood/fix-72
Browse files Browse the repository at this point in the history
Implement Flag Product
  • Loading branch information
EjembiEmmanuel authored Nov 27, 2024
2 parents 9a98a6e + 01abcef commit 6e6c95d
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 4 deletions.
52 changes: 52 additions & 0 deletions backend/src/product/product.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Test, TestingModule } from '@nestjs/testing';
import { ProductController } from './product.controller';
import { ProductService } from './product.service';
import { ProductDto } from './dto/product.dto';
import { HttpException } from '@nestjs/common';

describe('ProductsController', () => {
let controller: ProductController;
Expand All @@ -15,6 +16,8 @@ describe('ProductsController', () => {
provide: ProductService,
useValue: {
submitProduct: jest.fn(),
flagProduct: jest.fn(),
getFlaggedProducts: jest.fn(),
},
},
],
Expand Down Expand Up @@ -64,4 +67,53 @@ describe('ProductsController', () => {
await expect(controller.uploadProduct(dto)).rejects.toThrow();
});
});

describe('flagProduct', () => {
const mockFlagProductDto = {
name: 'Suspicious Product',
image: 'http://example.com/suspicious.jpg',
reason: 'Fake product',
};

it('should successfully flag a product', async () => {
const mockResponse = {
id: '1',
...mockFlagProductDto,
};
jest.spyOn(service, 'flagProduct').mockResolvedValue(mockResponse);

const result = await controller.flagProduct(mockFlagProductDto);

expect(result).toEqual(mockResponse);
expect(service.flagProduct).toHaveBeenCalledWith(mockFlagProductDto);
});

it('should throw HttpException when flagging fails', async () => {
jest
.spyOn(service, 'flagProduct')
.mockRejectedValue(new Error('Failed to flag'));

await expect(controller.flagProduct(mockFlagProductDto)).rejects.toThrow(
HttpException
);
});
});

describe('getFlaggedProducts', () => {
it('should return all flagged products', async () => {
const mockFlaggedProducts = [
{ id: '1', name: 'Product 1', image: 'image1.jpg', reason: 'Fake' },
{ id: '2', name: 'Product 2', image: 'image2.jpg', reason: 'Expired' },
];

jest
.spyOn(service, 'getFlaggedProducts')
.mockResolvedValue(mockFlaggedProducts);

const result = await controller.getFlaggedProducts();

expect(result).toEqual(mockFlaggedProducts);
expect(service.getFlaggedProducts).toHaveBeenCalled();
});
});
});
14 changes: 14 additions & 0 deletions backend/src/product/product.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Param,
} from '@nestjs/common';
import { ProductDto } from './dto/product.dto';
import { FlagProductDto } from './dto/flag-product.dto';
import { ProductService } from './product.service';

@Controller('product')
Expand Down Expand Up @@ -48,4 +49,17 @@ export class ProductController {
async getFlaggedProducts() {
return this.productService.getFlaggedProducts();
}

@Post('flag')
async flagProduct(@Body() flagProductDto: FlagProductDto) {
try {
return await this.productService.flagProduct(flagProductDto);
} catch (error) {
console.error('Error:', error.message);
throw new HttpException(
{ error: error.message },
HttpStatus.INTERNAL_SERVER_ERROR
);
}
}
}
80 changes: 79 additions & 1 deletion backend/src/product/product.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ProductService } from './product.service';
import { ProductDto } from './dto/product.dto';
import { PrismaService } from '../prisma/prisma.service';
import { InternalServerErrorException } from '@nestjs/common';

describe('ProductsService', () => {
let service: ProductService;
let prismaService: PrismaService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ProductService],
providers: [
ProductService,
{
provide: PrismaService,
useValue: {
flaggedProduct: {
create: jest.fn(),
findMany: jest.fn(),
},
},
},
],
}).compile();

service = module.get<ProductService>(ProductService);
prismaService = module.get<PrismaService>(PrismaService);
});

it('should be defined', () => {
Expand Down Expand Up @@ -53,4 +68,67 @@ describe('ProductsService', () => {
);
});
});

describe('flagProduct', () => {
const mockFlagProductDto = {
name: 'Suspicious Product',
image: 'http://example.com/suspicious.jpg',
reason: 'Fake product',
};

it('should successfully flag a product', async () => {
const mockCreatedProduct = {
id: '1',
...mockFlagProductDto,
};
jest
.spyOn(prismaService.flaggedProduct, 'create')
.mockResolvedValue(mockCreatedProduct);

const result = await service.flagProduct(mockFlagProductDto);

expect(result).toEqual(mockCreatedProduct);
expect(prismaService.flaggedProduct.create).toHaveBeenCalledWith({
data: mockFlagProductDto,
});
});

it('should throw InternalServerErrorException when flagging fails', async () => {
jest
.spyOn(prismaService.flaggedProduct, 'create')
.mockRejectedValue(new Error('Database error'));

await expect(service.flagProduct(mockFlagProductDto)).rejects.toThrow(
InternalServerErrorException
);
});
});

describe('getFlaggedProducts', () => {
it('should return all flagged products', async () => {
const mockFlaggedProducts = [
{ id: '1', name: 'Product 1', image: 'image1.jpg', reason: 'Fake' },
{ id: '2', name: 'Product 2', image: 'image2.jpg', reason: 'Expired' },
];

jest
.spyOn(prismaService.flaggedProduct, 'findMany')
.mockResolvedValue(mockFlaggedProducts);

const result = await service.getFlaggedProducts();

expect(result).toEqual(mockFlaggedProducts);
expect(prismaService.flaggedProduct.findMany).toHaveBeenCalled();
});

it('should throw InternalServerErrorException when fetch fails', async () => {
jest
.spyOn(prismaService.flaggedProduct, 'findMany')
.mockRejectedValue(new Error('Database error'));

await expect(service.getFlaggedProducts()).rejects.toThrow(
InternalServerErrorException
);
});
});
});
22 changes: 19 additions & 3 deletions backend/src/product/product.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import {
Injectable,
InternalServerErrorException,
} from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { PrismaService } from '../prisma/prisma.service';
import { ProductDto } from './dto/product.dto';
import { Product } from 'src/interfaces/Product';
import { generateProductId } from 'src/common/utils/generateProductId';
import { FlagProductDto } from './dto/flag-product.dto';
import { Product } from '../interfaces/Product';
import { generateProductId } from '../common/utils/generateProductId';

@Injectable()
export class ProductService {
Expand Down Expand Up @@ -122,4 +123,19 @@ export class ProductService {
);
}
}

async flagProduct(flagProductDto: FlagProductDto) {
try {
return await this.prisma.flaggedProduct.create({
data: {
name: flagProductDto.name,
image: flagProductDto.image,
reason: flagProductDto.reason,
},
});
} catch (error) {
console.error('Error flagging product:', error);
throw new InternalServerErrorException('Failed to flag product');
}
}
}

0 comments on commit 6e6c95d

Please sign in to comment.