Skip to content

Commit

Permalink
Merge pull request #61 from atlp-rwanda/ft-product-review-#187419185
Browse files Browse the repository at this point in the history
#187419185(Product-review): A buyer should be able to provide a review on a product they have bought successfully, rating+feedback
  • Loading branch information
teerenzo authored May 21, 2024
2 parents 45b9acc + 7fe6dcc commit c709966
Show file tree
Hide file tree
Showing 15 changed files with 749 additions and 17 deletions.
143 changes: 141 additions & 2 deletions __test__/product.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import User from "../src/sequelize/models/users";
import bcrypt from "bcryptjs";
import { Role } from "../src/sequelize/models/roles";
import redisClient from "../src/config/redis";
import { response } from "express";
import { placeOrder } from "../src/services/payment.service";
import Cart from "../src/sequelize/models/Cart";
import CartItem from "../src/sequelize/models/CartItem";
import OrderItem from "../src/sequelize/models/orderItems";

const userData: any = {
name: "yvanna",
Expand Down Expand Up @@ -82,6 +87,7 @@ describe("Testing product Routes", () => {

afterAll(async () => {
await Product.destroy({where:{}});
await Cart.destroy({where: {}})
await sequelize.close();
await redisClient.quit()
});
Expand Down Expand Up @@ -286,8 +292,140 @@ test('It should remove a product from user wishlist', async () => {
.set("Authorization", "Bearer " + buyerToken);
expect(response.status).toBe(200)
})
let reviewId:any;
let cart:any;
test("Buyer should be able to add an item to the cart", async () => {
const response = await request(app)
.post("/api/v1/carts")
.send({
productId,
quantity: 1,
})
.set("Authorization", `Bearer ${buyerToken}`);
await request(app)
.post("/api/v1/carts")
.send({
productId,
quantity: 1,
})
.set("Authorization", `Bearer ${buyerToken}`);
expect(response.status).toBe(201);
});

test("should return user cart if he has one", async () => {
const response = await request(app).get("/api/v1/carts").set("Authorization", `Bearer ${buyerToken}`);
expect(response.status).toBe(200);
cart = response.body
});


test("it should create an order", async() => {
const response = await placeOrder(cart)
expect(response?.status).toBe("pending")
})

test("Buyer should be able to remove an item from the cart", async () => {
const response = await request(app)
.put("/api/v1/carts")
.send({
productId: productId,
})
.set("Authorization", "Bearer " + buyerToken);
expect(response.status).toBe(200);
});

test("it should return 201 when review created on products", async() => {
const response = await request(app)
.post(`/api/v1/products/${productId}/reviews`)
.send({
rating: 4,
feedback: "product is amazing"
})
.set("Authorization", "Bearer " + buyerToken)
expect(response.status).toBe(201)
})

test("should return 403 and not allow to reveiw a product twice", async () => {
const response = await request(app)
.post(`/api/v1/products/${productId}/reviews`)
.send({
rating: 3,
feedback: "awesome products ever seen."
})
.set("Authorization", "Bearer " + buyerToken)
expect(response.status).toBe(403)
expect(response.body).toEqual({
status: 403,
message: "Not allowed to review a product twice."
})
})

test("it should 404 error wrong path", async() => {
const response = await request(app)
.post(`/api/v1/products/review`)
.send({
rating: 3,
feedback: "awesome products ever seen."
})
expect(response.status).toBe(404)
},40000)

test("should return 200 when all products reveiws fetched", async () => {
const response = await request(app)
.get(`/api/v1/products/${productId}/reviews`)
expect(response.status).toBe(200)
reviewId = response.body.reviewProduct[0].id
},40000)

test("should return 201 when update existing review on product", async () => {
const response = await request(app)
.patch(`/api/v1/products/${productId}/reviews`)
.send({
id: reviewId,
rating: 3,
feedback: "awesome products ever seen..."
})
.set("Authorization", "Bearer " + buyerToken)
expect(response.status).toBe(201)
},40000)

test("it should return 200 when delete a review of the product", async () => {
const response = await request(app)
.delete(`/api/v1/products/${productId}/reviews`)
.send({
id: reviewId
})
.set("Authorization", "Bearer " + buyerToken)
expect(response.body.message).toBe("You successfully deleted the review.")
},40000)

test("it should return 404 when delete a invalid id of review of the product", async () => {
const response = await request(app)
.delete(`/api/v1/products/${productId}/reviews`)
.send({
id: 900
})
.set("Authorization", "Bearer " + buyerToken)
expect(response.status).toBe(404)
},40000)

test("when product not found", async() => {
const response = await request(app)
.get("/api/v1/products/123/reviews")
expect(response.status).toBe(200)
expect(response.body).toEqual({
status: 200,
message: "No review yet, Be first to review. "
})
})

test("Return 500 for handle error", async () => {
const response = await request(app)
.get("/api/v1/products/review")
expect(response.status).toBe(500)
})
test('It should return status 200 for removed Product',async() =>{
await OrderItem.destroy({where: {productId}})
const response = await request(app)
.delete(`/api/v1/products/${productId}`)
.set("Authorization", "Bearer " + token);
Expand All @@ -296,7 +434,7 @@ test('It should remove a product from user wishlist', async () => {

test('It should return status 404 Not found',async() =>{
const response = await request(app)
.get('/api/v1/products/1')
.get('/api/v1/products/1999')
.set("Authorization", "Bearer " + token);
expect(response.status).toBe(404);
},20000);
Expand All @@ -323,7 +461,7 @@ test('It should return status 200 for removed category',async() =>{
.get("/api/v1/products/search")
.send(searchProduct)
.set("Authorization", "Bearer " + token);
expect(response.body.status).toBe(404);
expect(response.status).toBe(200);
});

it("changing product availability without login", async ()=>{
Expand All @@ -338,4 +476,5 @@ test('It should return status 200 for removed category',async() =>{
.set("Authorization", "Bearer " + token);
expect(response.body.message).toBe('Product not found')
})

});
123 changes: 122 additions & 1 deletion src/controllers/productControllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import * as mailService from "../services/mail.service"
import { removedProductTemplate } from "../email-templates/removed";
import { updateProductTemplate } from "../email-templates/updated";
import { createdProductTemplate } from "../email-templates/created";
import { createReview, deleteReview, getProductReviews, updateReview } from "../services/product.service";
import Review from "../sequelize/models/reviews";

export const fetchProducts = async(req:Request,res:Response) =>{
try {
Expand Down Expand Up @@ -204,7 +206,7 @@ export const removeProducts = async (req: Request, res: Response) => {
} catch (error:any) {
res.status(500).json({
status:500,
error: error.message,
message: error.message,
});
}
}
Expand All @@ -231,3 +233,122 @@ export const productAvailability = async (req: Request, res: Response) => {
return res.status(500).json({ message: 'Internal server error' });
}
};

export const getreviewController = async(req: Request, res: Response) => {
try {
const productId = req.params.pid
const reviewProduct = await getProductReviews(productId)
if (reviewProduct.length === 0) {
return res.status(200)
.json({
status: 200,
message: "No review yet, Be first to review. "
})
}
return res.status(200).json({
status: 200,
message: "review retrieve successfully",
reviewProduct
})
} catch (error: any) {
res.status(500).json(
error.message
)
}
}

export const addReviewController = async(req: Request, res: Response) => {
try {
const reviewObj:any = {
// @ts-ignore
userId : req.user.id,
productId : req.params.pid,
rating : req.body.rating,
feedback: req.body.feedback
}
await createReview(reviewObj)
return res.status(201)
.json({
status: 201,
message: "you have successfully create a review!"
})

} catch (error: any) {
if (error.message === "Can't review a product twice.") {
return res.status(403).json({
status: 403,
message: "Not allowed to review a product twice."
});
}

return res.status(500).json({
status: 500,
message: "Internal server error.",
error: error.message
});
}
}

export const deleteReviewController = async (req: Request, res: Response) => {
try {
const reviewData:any ={
//@ts-ignore
userId: req.user.id,
reviewId: req.body.id
}

await deleteReview(reviewData)
return res.status(200).
json({
status: 200,
message: "You successfully deleted the review."
})

} catch (error:any) {
if (error.message === "Review not found!") {
return res.status(404).
json({
status: 404,
message: "Review not found, please try again."
})
}
return res.status(500).
json({
status: 500,
message:error.message
})
}
}

export const updateReviewController = async (req: Request, res: Response) => {
try {

const updateObj:any = {
//@ts-ignore
userId: req.user.id,
productId: req.params.pid,
reviewId: req.body.id,
rating: req.body.rating,
feedback: req.body.feedback
}
await updateReview(updateObj)
return res.status(201).
json({
status: 201,
message: "You successfully updated your review.",
})
} catch (error:any) {
if (error.message === "Review not found") {
return res.status(404).
json({
status: 404,
message: "Can't update review not found"
})
}
return res.status(500).
json({
status: 500,
error: error.message
})
}
}
Loading

0 comments on commit c709966

Please sign in to comment.