433 lines
12 KiB
JavaScript
433 lines
12 KiB
JavaScript
const request = require("supertest");
|
|
const express = require("express");
|
|
const usersRouter = require("../../../routes/users");
|
|
|
|
// Mock all dependencies
|
|
jest.mock("../../../models", () => ({
|
|
User: {
|
|
findByPk: jest.fn(),
|
|
update: jest.fn(),
|
|
},
|
|
UserAddress: {
|
|
findAll: jest.fn(),
|
|
findByPk: jest.fn(),
|
|
create: jest.fn(),
|
|
},
|
|
}));
|
|
|
|
jest.mock("../../../middleware/auth", () => ({
|
|
authenticateToken: jest.fn((req, res, next) => {
|
|
req.user = {
|
|
id: 1,
|
|
update: jest.fn(),
|
|
};
|
|
next();
|
|
}),
|
|
}));
|
|
|
|
jest.mock("../../../services/UserService", () => ({
|
|
createUserAddress: jest.fn(),
|
|
updateUserAddress: jest.fn(),
|
|
deleteUserAddress: jest.fn(),
|
|
updateProfile: jest.fn(),
|
|
}));
|
|
|
|
jest.mock("../../../utils/logger", () => ({
|
|
info: jest.fn(),
|
|
error: jest.fn(),
|
|
warn: jest.fn(),
|
|
withRequestId: jest.fn(() => ({
|
|
info: jest.fn(),
|
|
error: jest.fn(),
|
|
warn: jest.fn(),
|
|
})),
|
|
sanitize: jest.fn((data) => data),
|
|
}));
|
|
|
|
const { User, UserAddress } = require("../../../models");
|
|
const userService = require("../../../services/UserService");
|
|
|
|
// Create express app with the router
|
|
const app = express();
|
|
app.use(express.json());
|
|
app.use("/users", usersRouter);
|
|
|
|
// Add error handler middleware
|
|
app.use((err, req, res, next) => {
|
|
res.status(500).json({ error: err.message });
|
|
});
|
|
|
|
// Mock models
|
|
const mockUserFindByPk = User.findByPk;
|
|
const mockUserUpdate = User.update;
|
|
const mockUserAddressFindAll = UserAddress.findAll;
|
|
const mockUserAddressFindByPk = UserAddress.findByPk;
|
|
const mockUserAddressCreate = UserAddress.create;
|
|
|
|
describe("Users Routes", () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
describe("GET /profile", () => {
|
|
it("should get user profile for authenticated user", async () => {
|
|
const mockUser = {
|
|
id: 1,
|
|
firstName: "John",
|
|
lastName: "Doe",
|
|
email: "john@example.com",
|
|
phone: "555-1234",
|
|
imageFilename: "profile.jpg",
|
|
};
|
|
|
|
mockUserFindByPk.mockResolvedValue(mockUser);
|
|
|
|
const response = await request(app).get("/users/profile");
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual(mockUser);
|
|
expect(mockUserFindByPk).toHaveBeenCalledWith(1, {
|
|
attributes: { exclude: ["password"] },
|
|
});
|
|
});
|
|
|
|
it("should handle database errors", async () => {
|
|
mockUserFindByPk.mockRejectedValue(new Error("Database error"));
|
|
|
|
const response = await request(app).get("/users/profile");
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Database error" });
|
|
});
|
|
});
|
|
|
|
describe("GET /addresses", () => {
|
|
it("should get user addresses", async () => {
|
|
const mockAddresses = [
|
|
{
|
|
id: 1,
|
|
userId: 1,
|
|
address1: "123 Main St",
|
|
city: "New York",
|
|
isPrimary: true,
|
|
},
|
|
{
|
|
id: 2,
|
|
userId: 1,
|
|
address1: "456 Oak Ave",
|
|
city: "Boston",
|
|
isPrimary: false,
|
|
},
|
|
];
|
|
|
|
mockUserAddressFindAll.mockResolvedValue(mockAddresses);
|
|
|
|
const response = await request(app).get("/users/addresses");
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual(mockAddresses);
|
|
expect(mockUserAddressFindAll).toHaveBeenCalledWith({
|
|
where: { userId: 1 },
|
|
order: [
|
|
["isPrimary", "DESC"],
|
|
["createdAt", "ASC"],
|
|
],
|
|
});
|
|
});
|
|
|
|
it("should handle database errors", async () => {
|
|
mockUserAddressFindAll.mockRejectedValue(new Error("Database error"));
|
|
|
|
const response = await request(app).get("/users/addresses");
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Database error" });
|
|
});
|
|
});
|
|
|
|
describe("POST /addresses", () => {
|
|
it("should create a new address", async () => {
|
|
const addressData = {
|
|
address1: "789 Pine St",
|
|
address2: "Apt 4B",
|
|
city: "Chicago",
|
|
state: "IL",
|
|
zipCode: "60601",
|
|
country: "USA",
|
|
};
|
|
|
|
const mockCreatedAddress = {
|
|
id: 3,
|
|
...addressData,
|
|
userId: 1,
|
|
};
|
|
|
|
userService.createUserAddress.mockResolvedValue(mockCreatedAddress);
|
|
|
|
const response = await request(app)
|
|
.post("/users/addresses")
|
|
.send(addressData);
|
|
|
|
expect(response.status).toBe(201);
|
|
expect(response.body).toEqual(mockCreatedAddress);
|
|
expect(userService.createUserAddress).toHaveBeenCalledWith(1, addressData);
|
|
});
|
|
|
|
it("should handle database errors during creation", async () => {
|
|
userService.createUserAddress.mockRejectedValue(new Error("Database error"));
|
|
|
|
const response = await request(app).post("/users/addresses").send({
|
|
address1: "789 Pine St",
|
|
city: "Chicago",
|
|
});
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Database error" });
|
|
});
|
|
});
|
|
|
|
describe("PUT /addresses/:id", () => {
|
|
const mockAddress = {
|
|
id: 1,
|
|
userId: 1,
|
|
address1: "123 Updated St",
|
|
city: "Updated City",
|
|
};
|
|
|
|
it("should update user address", async () => {
|
|
const updateData = {
|
|
address1: "123 Updated St",
|
|
city: "Updated City",
|
|
};
|
|
|
|
userService.updateUserAddress.mockResolvedValue(mockAddress);
|
|
|
|
const response = await request(app)
|
|
.put("/users/addresses/1")
|
|
.send(updateData);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual(mockAddress);
|
|
expect(userService.updateUserAddress).toHaveBeenCalledWith(1, "1", updateData);
|
|
});
|
|
|
|
it("should return 404 for non-existent address", async () => {
|
|
userService.updateUserAddress.mockRejectedValue(new Error("Address not found"));
|
|
|
|
const response = await request(app)
|
|
.put("/users/addresses/999")
|
|
.send({ address1: "Updated St" });
|
|
|
|
expect(response.status).toBe(404);
|
|
expect(response.body).toEqual({ error: "Address not found" });
|
|
});
|
|
|
|
it("should handle database errors", async () => {
|
|
userService.updateUserAddress.mockRejectedValue(new Error("Database error"));
|
|
|
|
const response = await request(app)
|
|
.put("/users/addresses/1")
|
|
.send({ address1: "Updated St" });
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Database error" });
|
|
});
|
|
});
|
|
|
|
describe("DELETE /addresses/:id", () => {
|
|
it("should delete user address", async () => {
|
|
userService.deleteUserAddress.mockResolvedValue();
|
|
|
|
const response = await request(app).delete("/users/addresses/1");
|
|
|
|
expect(response.status).toBe(204);
|
|
expect(userService.deleteUserAddress).toHaveBeenCalledWith(1, "1");
|
|
});
|
|
|
|
it("should return 404 for non-existent address", async () => {
|
|
userService.deleteUserAddress.mockRejectedValue(new Error("Address not found"));
|
|
|
|
const response = await request(app).delete("/users/addresses/999");
|
|
|
|
expect(response.status).toBe(404);
|
|
expect(response.body).toEqual({ error: "Address not found" });
|
|
});
|
|
|
|
it("should handle database errors", async () => {
|
|
userService.deleteUserAddress.mockRejectedValue(new Error("Database error"));
|
|
|
|
const response = await request(app).delete("/users/addresses/1");
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Database error" });
|
|
});
|
|
});
|
|
|
|
describe("GET /availability", () => {
|
|
it("should get user availability settings", async () => {
|
|
const mockUser = {
|
|
defaultAvailableAfter: "09:00",
|
|
defaultAvailableBefore: "17:00",
|
|
defaultSpecifyTimesPerDay: true,
|
|
defaultWeeklyTimes: { monday: "09:00-17:00", tuesday: "10:00-16:00" },
|
|
};
|
|
|
|
mockUserFindByPk.mockResolvedValue(mockUser);
|
|
|
|
const response = await request(app).get("/users/availability");
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual({
|
|
generalAvailableAfter: "09:00",
|
|
generalAvailableBefore: "17:00",
|
|
specifyTimesPerDay: true,
|
|
weeklyTimes: { monday: "09:00-17:00", tuesday: "10:00-16:00" },
|
|
});
|
|
expect(mockUserFindByPk).toHaveBeenCalledWith(1, {
|
|
attributes: [
|
|
"defaultAvailableAfter",
|
|
"defaultAvailableBefore",
|
|
"defaultSpecifyTimesPerDay",
|
|
"defaultWeeklyTimes",
|
|
],
|
|
});
|
|
});
|
|
|
|
it("should handle database errors", async () => {
|
|
mockUserFindByPk.mockRejectedValue(new Error("Database error"));
|
|
|
|
const response = await request(app).get("/users/availability");
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Database error" });
|
|
});
|
|
});
|
|
|
|
describe("PUT /availability", () => {
|
|
it("should update user availability settings", async () => {
|
|
const availabilityData = {
|
|
generalAvailableAfter: "08:00",
|
|
generalAvailableBefore: "18:00",
|
|
specifyTimesPerDay: false,
|
|
weeklyTimes: { monday: "08:00-18:00" },
|
|
};
|
|
|
|
mockUserUpdate.mockResolvedValue([1]);
|
|
|
|
const response = await request(app)
|
|
.put("/users/availability")
|
|
.send(availabilityData);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual({
|
|
message: "Availability updated successfully",
|
|
});
|
|
expect(mockUserUpdate).toHaveBeenCalledWith(
|
|
{
|
|
defaultAvailableAfter: "08:00",
|
|
defaultAvailableBefore: "18:00",
|
|
defaultSpecifyTimesPerDay: false,
|
|
defaultWeeklyTimes: { monday: "08:00-18:00" },
|
|
},
|
|
{
|
|
where: { id: 1 },
|
|
}
|
|
);
|
|
});
|
|
|
|
it("should handle database errors", async () => {
|
|
mockUserUpdate.mockRejectedValue(new Error("Database error"));
|
|
|
|
const response = await request(app).put("/users/availability").send({
|
|
generalAvailableAfter: "08:00",
|
|
generalAvailableBefore: "18:00",
|
|
});
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Database error" });
|
|
});
|
|
});
|
|
|
|
describe("GET /:id", () => {
|
|
it("should get public user profile by ID", async () => {
|
|
const mockUser = {
|
|
id: 2,
|
|
firstName: "Jane",
|
|
lastName: "Smith",
|
|
username: "janesmith",
|
|
imageFilename: "jane.jpg",
|
|
};
|
|
|
|
mockUserFindByPk.mockResolvedValue(mockUser);
|
|
|
|
const response = await request(app).get("/users/2");
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual(mockUser);
|
|
expect(mockUserFindByPk).toHaveBeenCalledWith("2", {
|
|
attributes: { exclude: ["password", "email", "phone", "address"] },
|
|
});
|
|
});
|
|
|
|
it("should return 404 for non-existent user", async () => {
|
|
mockUserFindByPk.mockResolvedValue(null);
|
|
|
|
const response = await request(app).get("/users/999");
|
|
|
|
expect(response.status).toBe(404);
|
|
expect(response.body).toEqual({ error: "User not found" });
|
|
});
|
|
|
|
it("should handle database errors", async () => {
|
|
mockUserFindByPk.mockRejectedValue(new Error("Database error"));
|
|
|
|
const response = await request(app).get("/users/2");
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Database error" });
|
|
});
|
|
});
|
|
|
|
describe("PUT /profile", () => {
|
|
const mockUpdatedUser = {
|
|
id: 1,
|
|
firstName: "Updated",
|
|
lastName: "User",
|
|
email: "updated@example.com",
|
|
phone: "555-9999",
|
|
};
|
|
|
|
it("should update user profile", async () => {
|
|
const profileData = {
|
|
firstName: "Updated",
|
|
lastName: "User",
|
|
email: "updated@example.com",
|
|
phone: "555-9999",
|
|
address1: "123 New St",
|
|
city: "New City",
|
|
};
|
|
|
|
userService.updateProfile.mockResolvedValue(mockUpdatedUser);
|
|
|
|
const response = await request(app)
|
|
.put("/users/profile")
|
|
.send(profileData);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual(mockUpdatedUser);
|
|
expect(userService.updateProfile).toHaveBeenCalledWith(1, profileData);
|
|
});
|
|
|
|
it("should handle database errors", async () => {
|
|
userService.updateProfile.mockRejectedValue(new Error("Database error"));
|
|
|
|
const response = await request(app).put("/users/profile").send({
|
|
firstName: "Test",
|
|
});
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Database error" });
|
|
});
|
|
});
|
|
});
|