essential forum code
This commit is contained in:
@@ -1,823 +0,0 @@
|
||||
const request = require('supertest');
|
||||
const express = require('express');
|
||||
const itemRequestsRouter = require('../../../routes/itemRequests');
|
||||
|
||||
// Mock all dependencies
|
||||
jest.mock('../../../models', () => ({
|
||||
ItemRequest: {
|
||||
findAndCountAll: jest.fn(),
|
||||
findAll: jest.fn(),
|
||||
findByPk: jest.fn(),
|
||||
create: jest.fn(),
|
||||
},
|
||||
ItemRequestResponse: {
|
||||
findByPk: jest.fn(),
|
||||
create: jest.fn(),
|
||||
},
|
||||
User: jest.fn(),
|
||||
Item: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../middleware/auth', () => ({
|
||||
authenticateToken: jest.fn((req, res, next) => {
|
||||
req.user = { id: 1 };
|
||||
next();
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('sequelize', () => ({
|
||||
Op: {
|
||||
or: Symbol('or'),
|
||||
iLike: Symbol('iLike'),
|
||||
},
|
||||
}));
|
||||
|
||||
const { ItemRequest, ItemRequestResponse, User, Item } = require('../../../models');
|
||||
|
||||
// Create express app with the router
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use('/item-requests', itemRequestsRouter);
|
||||
|
||||
// Mock models
|
||||
const mockItemRequestFindAndCountAll = ItemRequest.findAndCountAll;
|
||||
const mockItemRequestFindAll = ItemRequest.findAll;
|
||||
const mockItemRequestFindByPk = ItemRequest.findByPk;
|
||||
const mockItemRequestCreate = ItemRequest.create;
|
||||
const mockItemRequestResponseFindByPk = ItemRequestResponse.findByPk;
|
||||
const mockItemRequestResponseCreate = ItemRequestResponse.create;
|
||||
|
||||
describe('ItemRequests Routes', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('GET /', () => {
|
||||
it('should get item requests with default pagination and status', async () => {
|
||||
const mockRequestsData = {
|
||||
count: 25,
|
||||
rows: [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Need a Camera',
|
||||
description: 'Looking for a DSLR camera for weekend photography',
|
||||
status: 'open',
|
||||
requesterId: 2,
|
||||
createdAt: '2024-01-15T10:00:00.000Z',
|
||||
requester: {
|
||||
id: 2,
|
||||
username: 'jane_doe',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Power Drill Needed',
|
||||
description: 'Need a drill for home improvement project',
|
||||
status: 'open',
|
||||
requesterId: 3,
|
||||
createdAt: '2024-01-14T10:00:00.000Z',
|
||||
requester: {
|
||||
id: 3,
|
||||
username: 'bob_smith',
|
||||
firstName: 'Bob',
|
||||
lastName: 'Smith'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
mockItemRequestFindAndCountAll.mockResolvedValue(mockRequestsData);
|
||||
|
||||
const response = await request(app)
|
||||
.get('/item-requests');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual({
|
||||
requests: mockRequestsData.rows,
|
||||
totalPages: 2,
|
||||
currentPage: 1,
|
||||
totalRequests: 25
|
||||
});
|
||||
expect(mockItemRequestFindAndCountAll).toHaveBeenCalledWith({
|
||||
where: { status: 'open' },
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'requester',
|
||||
attributes: ['id', 'username', 'firstName', 'lastName']
|
||||
}
|
||||
],
|
||||
limit: 20,
|
||||
offset: 0,
|
||||
order: [['createdAt', 'DESC']]
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter requests with search query', async () => {
|
||||
const mockSearchResults = {
|
||||
count: 5,
|
||||
rows: [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Need a Camera',
|
||||
description: 'Looking for a DSLR camera',
|
||||
status: 'open'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
mockItemRequestFindAndCountAll.mockResolvedValue(mockSearchResults);
|
||||
|
||||
const response = await request(app)
|
||||
.get('/item-requests?search=camera&page=1&limit=10');
|
||||
|
||||
const { Op } = require('sequelize');
|
||||
expect(mockItemRequestFindAndCountAll).toHaveBeenCalledWith({
|
||||
where: {
|
||||
status: 'open',
|
||||
[Op.or]: [
|
||||
{ title: { [Op.iLike]: '%camera%' } },
|
||||
{ description: { [Op.iLike]: '%camera%' } }
|
||||
]
|
||||
},
|
||||
include: expect.any(Array),
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
order: [['createdAt', 'DESC']]
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle custom pagination', async () => {
|
||||
const mockData = { count: 50, rows: [] };
|
||||
mockItemRequestFindAndCountAll.mockResolvedValue(mockData);
|
||||
|
||||
const response = await request(app)
|
||||
.get('/item-requests?page=3&limit=5');
|
||||
|
||||
expect(mockItemRequestFindAndCountAll).toHaveBeenCalledWith({
|
||||
where: { status: 'open' },
|
||||
include: expect.any(Array),
|
||||
limit: 5,
|
||||
offset: 10, // (3-1) * 5
|
||||
order: [['createdAt', 'DESC']]
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter by custom status', async () => {
|
||||
const mockData = { count: 10, rows: [] };
|
||||
mockItemRequestFindAndCountAll.mockResolvedValue(mockData);
|
||||
|
||||
await request(app)
|
||||
.get('/item-requests?status=fulfilled');
|
||||
|
||||
expect(mockItemRequestFindAndCountAll).toHaveBeenCalledWith({
|
||||
where: { status: 'fulfilled' },
|
||||
include: expect.any(Array),
|
||||
limit: 20,
|
||||
offset: 0,
|
||||
order: [['createdAt', 'DESC']]
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle database errors', async () => {
|
||||
mockItemRequestFindAndCountAll.mockRejectedValue(new Error('Database error'));
|
||||
|
||||
const response = await request(app)
|
||||
.get('/item-requests');
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.body).toEqual({ error: 'Database error' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /my-requests', () => {
|
||||
it('should get user\'s own requests with responses', async () => {
|
||||
const mockRequests = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'My Camera Request',
|
||||
description: 'Need a camera',
|
||||
status: 'open',
|
||||
requesterId: 1,
|
||||
requester: {
|
||||
id: 1,
|
||||
username: 'john_doe',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe'
|
||||
},
|
||||
responses: [
|
||||
{
|
||||
id: 1,
|
||||
message: 'I have a Canon DSLR available',
|
||||
responder: {
|
||||
id: 2,
|
||||
username: 'jane_doe',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe'
|
||||
},
|
||||
existingItem: {
|
||||
id: 5,
|
||||
name: 'Canon EOS 5D',
|
||||
description: 'Professional DSLR camera'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
mockItemRequestFindAll.mockResolvedValue(mockRequests);
|
||||
|
||||
const response = await request(app)
|
||||
.get('/item-requests/my-requests');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual(mockRequests);
|
||||
expect(mockItemRequestFindAll).toHaveBeenCalledWith({
|
||||
where: { requesterId: 1 },
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'requester',
|
||||
attributes: ['id', 'username', 'firstName', 'lastName']
|
||||
},
|
||||
{
|
||||
model: ItemRequestResponse,
|
||||
as: 'responses',
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'responder',
|
||||
attributes: ['id', 'username', 'firstName', 'lastName']
|
||||
},
|
||||
{
|
||||
model: Item,
|
||||
as: 'existingItem'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
order: [['createdAt', 'DESC']]
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle database errors', async () => {
|
||||
mockItemRequestFindAll.mockRejectedValue(new Error('Database error'));
|
||||
|
||||
const response = await request(app)
|
||||
.get('/item-requests/my-requests');
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.body).toEqual({ error: 'Database error' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /:id', () => {
|
||||
it('should get specific request with responses', async () => {
|
||||
const mockRequest = {
|
||||
id: 1,
|
||||
title: 'Camera Request',
|
||||
description: 'Need a DSLR camera',
|
||||
status: 'open',
|
||||
requesterId: 2,
|
||||
requester: {
|
||||
id: 2,
|
||||
username: 'jane_doe',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe'
|
||||
},
|
||||
responses: [
|
||||
{
|
||||
id: 1,
|
||||
message: 'I have a Canon DSLR',
|
||||
responder: {
|
||||
id: 1,
|
||||
username: 'john_doe',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe'
|
||||
},
|
||||
existingItem: null
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
mockItemRequestFindByPk.mockResolvedValue(mockRequest);
|
||||
|
||||
const response = await request(app)
|
||||
.get('/item-requests/1');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual(mockRequest);
|
||||
expect(mockItemRequestFindByPk).toHaveBeenCalledWith('1', {
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'requester',
|
||||
attributes: ['id', 'username', 'firstName', 'lastName']
|
||||
},
|
||||
{
|
||||
model: ItemRequestResponse,
|
||||
as: 'responses',
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'responder',
|
||||
attributes: ['id', 'username', 'firstName', 'lastName']
|
||||
},
|
||||
{
|
||||
model: Item,
|
||||
as: 'existingItem'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('should return 404 for non-existent request', async () => {
|
||||
mockItemRequestFindByPk.mockResolvedValue(null);
|
||||
|
||||
const response = await request(app)
|
||||
.get('/item-requests/999');
|
||||
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body).toEqual({ error: 'Item request not found' });
|
||||
});
|
||||
|
||||
it('should handle database errors', async () => {
|
||||
mockItemRequestFindByPk.mockRejectedValue(new Error('Database error'));
|
||||
|
||||
const response = await request(app)
|
||||
.get('/item-requests/1');
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.body).toEqual({ error: 'Database error' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /', () => {
|
||||
it('should create a new item request', async () => {
|
||||
const requestData = {
|
||||
title: 'Need a Drill',
|
||||
description: 'Looking for a power drill for weekend project',
|
||||
category: 'tools',
|
||||
budget: 50,
|
||||
location: 'New York'
|
||||
};
|
||||
|
||||
const mockCreatedRequest = {
|
||||
id: 3,
|
||||
...requestData,
|
||||
requesterId: 1,
|
||||
status: 'open'
|
||||
};
|
||||
|
||||
const mockRequestWithRequester = {
|
||||
...mockCreatedRequest,
|
||||
requester: {
|
||||
id: 1,
|
||||
username: 'john_doe',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe'
|
||||
}
|
||||
};
|
||||
|
||||
mockItemRequestCreate.mockResolvedValue(mockCreatedRequest);
|
||||
mockItemRequestFindByPk.mockResolvedValue(mockRequestWithRequester);
|
||||
|
||||
const response = await request(app)
|
||||
.post('/item-requests')
|
||||
.send(requestData);
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
expect(response.body).toEqual(mockRequestWithRequester);
|
||||
expect(mockItemRequestCreate).toHaveBeenCalledWith({
|
||||
...requestData,
|
||||
requesterId: 1
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle database errors during creation', async () => {
|
||||
mockItemRequestCreate.mockRejectedValue(new Error('Database error'));
|
||||
|
||||
const response = await request(app)
|
||||
.post('/item-requests')
|
||||
.send({
|
||||
title: 'Test Request',
|
||||
description: 'Test description'
|
||||
});
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.body).toEqual({ error: 'Database error' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('PUT /:id', () => {
|
||||
const mockRequest = {
|
||||
id: 1,
|
||||
title: 'Original Title',
|
||||
requesterId: 1,
|
||||
update: jest.fn()
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockItemRequestFindByPk.mockResolvedValue(mockRequest);
|
||||
});
|
||||
|
||||
it('should update item request for owner', async () => {
|
||||
const updateData = {
|
||||
title: 'Updated Title',
|
||||
description: 'Updated description'
|
||||
};
|
||||
|
||||
const mockUpdatedRequest = {
|
||||
...mockRequest,
|
||||
...updateData,
|
||||
requester: {
|
||||
id: 1,
|
||||
username: 'john_doe',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe'
|
||||
}
|
||||
};
|
||||
|
||||
mockRequest.update.mockResolvedValue();
|
||||
mockItemRequestFindByPk
|
||||
.mockResolvedValueOnce(mockRequest)
|
||||
.mockResolvedValueOnce(mockUpdatedRequest);
|
||||
|
||||
const response = await request(app)
|
||||
.put('/item-requests/1')
|
||||
.send(updateData);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual({
|
||||
id: 1,
|
||||
title: 'Updated Title',
|
||||
description: 'Updated description',
|
||||
requesterId: 1,
|
||||
requester: {
|
||||
id: 1,
|
||||
username: 'john_doe',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe'
|
||||
}
|
||||
});
|
||||
expect(mockRequest.update).toHaveBeenCalledWith(updateData);
|
||||
});
|
||||
|
||||
it('should return 404 for non-existent request', async () => {
|
||||
mockItemRequestFindByPk.mockResolvedValue(null);
|
||||
|
||||
const response = await request(app)
|
||||
.put('/item-requests/999')
|
||||
.send({ title: 'Updated' });
|
||||
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body).toEqual({ error: 'Item request not found' });
|
||||
});
|
||||
|
||||
it('should return 403 for unauthorized user', async () => {
|
||||
const unauthorizedRequest = { ...mockRequest, requesterId: 2 };
|
||||
mockItemRequestFindByPk.mockResolvedValue(unauthorizedRequest);
|
||||
|
||||
const response = await request(app)
|
||||
.put('/item-requests/1')
|
||||
.send({ title: 'Updated' });
|
||||
|
||||
expect(response.status).toBe(403);
|
||||
expect(response.body).toEqual({ error: 'Unauthorized' });
|
||||
});
|
||||
|
||||
it('should handle database errors', async () => {
|
||||
mockItemRequestFindByPk.mockRejectedValue(new Error('Database error'));
|
||||
|
||||
const response = await request(app)
|
||||
.put('/item-requests/1')
|
||||
.send({ title: 'Updated' });
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.body).toEqual({ error: 'Database error' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE /:id', () => {
|
||||
const mockRequest = {
|
||||
id: 1,
|
||||
requesterId: 1,
|
||||
destroy: jest.fn()
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockItemRequestFindByPk.mockResolvedValue(mockRequest);
|
||||
});
|
||||
|
||||
it('should delete item request for owner', async () => {
|
||||
mockRequest.destroy.mockResolvedValue();
|
||||
|
||||
const response = await request(app)
|
||||
.delete('/item-requests/1');
|
||||
|
||||
expect(response.status).toBe(204);
|
||||
expect(mockRequest.destroy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return 404 for non-existent request', async () => {
|
||||
mockItemRequestFindByPk.mockResolvedValue(null);
|
||||
|
||||
const response = await request(app)
|
||||
.delete('/item-requests/999');
|
||||
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body).toEqual({ error: 'Item request not found' });
|
||||
});
|
||||
|
||||
it('should return 403 for unauthorized user', async () => {
|
||||
const unauthorizedRequest = { ...mockRequest, requesterId: 2 };
|
||||
mockItemRequestFindByPk.mockResolvedValue(unauthorizedRequest);
|
||||
|
||||
const response = await request(app)
|
||||
.delete('/item-requests/1');
|
||||
|
||||
expect(response.status).toBe(403);
|
||||
expect(response.body).toEqual({ error: 'Unauthorized' });
|
||||
});
|
||||
|
||||
it('should handle database errors', async () => {
|
||||
mockItemRequestFindByPk.mockRejectedValue(new Error('Database error'));
|
||||
|
||||
const response = await request(app)
|
||||
.delete('/item-requests/1');
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.body).toEqual({ error: 'Database error' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /:id/responses', () => {
|
||||
const mockRequest = {
|
||||
id: 1,
|
||||
requesterId: 2,
|
||||
status: 'open',
|
||||
increment: jest.fn()
|
||||
};
|
||||
|
||||
const mockResponseData = {
|
||||
message: 'I have a drill you can borrow',
|
||||
price: 25,
|
||||
existingItemId: 5
|
||||
};
|
||||
|
||||
const mockCreatedResponse = {
|
||||
id: 1,
|
||||
...mockResponseData,
|
||||
itemRequestId: 1,
|
||||
responderId: 1
|
||||
};
|
||||
|
||||
const mockResponseWithDetails = {
|
||||
...mockCreatedResponse,
|
||||
responder: {
|
||||
id: 1,
|
||||
username: 'john_doe',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe'
|
||||
},
|
||||
existingItem: {
|
||||
id: 5,
|
||||
name: 'Power Drill',
|
||||
description: 'Cordless power drill'
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockItemRequestFindByPk.mockResolvedValue(mockRequest);
|
||||
mockItemRequestResponseCreate.mockResolvedValue(mockCreatedResponse);
|
||||
mockItemRequestResponseFindByPk.mockResolvedValue(mockResponseWithDetails);
|
||||
});
|
||||
|
||||
it('should create a response to item request', async () => {
|
||||
mockRequest.increment.mockResolvedValue();
|
||||
|
||||
const response = await request(app)
|
||||
.post('/item-requests/1/responses')
|
||||
.send(mockResponseData);
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
expect(response.body).toEqual(mockResponseWithDetails);
|
||||
expect(mockItemRequestResponseCreate).toHaveBeenCalledWith({
|
||||
...mockResponseData,
|
||||
itemRequestId: '1',
|
||||
responderId: 1
|
||||
});
|
||||
expect(mockRequest.increment).toHaveBeenCalledWith('responseCount');
|
||||
});
|
||||
|
||||
it('should return 404 for non-existent request', async () => {
|
||||
mockItemRequestFindByPk.mockResolvedValue(null);
|
||||
|
||||
const response = await request(app)
|
||||
.post('/item-requests/999/responses')
|
||||
.send(mockResponseData);
|
||||
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body).toEqual({ error: 'Item request not found' });
|
||||
});
|
||||
|
||||
it('should prevent responding to own request', async () => {
|
||||
const ownRequest = { ...mockRequest, requesterId: 1 };
|
||||
mockItemRequestFindByPk.mockResolvedValue(ownRequest);
|
||||
|
||||
const response = await request(app)
|
||||
.post('/item-requests/1/responses')
|
||||
.send(mockResponseData);
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body).toEqual({ error: 'Cannot respond to your own request' });
|
||||
});
|
||||
|
||||
it('should prevent responding to closed request', async () => {
|
||||
const closedRequest = { ...mockRequest, status: 'fulfilled' };
|
||||
mockItemRequestFindByPk.mockResolvedValue(closedRequest);
|
||||
|
||||
const response = await request(app)
|
||||
.post('/item-requests/1/responses')
|
||||
.send(mockResponseData);
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body).toEqual({ error: 'Cannot respond to closed request' });
|
||||
});
|
||||
|
||||
it('should handle database errors', async () => {
|
||||
mockItemRequestResponseCreate.mockRejectedValue(new Error('Database error'));
|
||||
|
||||
const response = await request(app)
|
||||
.post('/item-requests/1/responses')
|
||||
.send(mockResponseData);
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.body).toEqual({ error: 'Database error' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('PUT /responses/:responseId/status', () => {
|
||||
const mockResponse = {
|
||||
id: 1,
|
||||
status: 'pending',
|
||||
itemRequest: {
|
||||
id: 1,
|
||||
requesterId: 1
|
||||
},
|
||||
update: jest.fn()
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockItemRequestResponseFindByPk.mockResolvedValue(mockResponse);
|
||||
});
|
||||
|
||||
it('should update response status to accepted and fulfill request', async () => {
|
||||
const updatedResponse = {
|
||||
...mockResponse,
|
||||
status: 'accepted',
|
||||
responder: {
|
||||
id: 2,
|
||||
username: 'jane_doe',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe'
|
||||
},
|
||||
existingItem: null
|
||||
};
|
||||
|
||||
mockResponse.update.mockResolvedValue();
|
||||
mockResponse.itemRequest.update = jest.fn().mockResolvedValue();
|
||||
mockItemRequestResponseFindByPk
|
||||
.mockResolvedValueOnce(mockResponse)
|
||||
.mockResolvedValueOnce(updatedResponse);
|
||||
|
||||
const response = await request(app)
|
||||
.put('/item-requests/responses/1/status')
|
||||
.send({ status: 'accepted' });
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual({
|
||||
id: 1,
|
||||
status: 'accepted',
|
||||
itemRequest: {
|
||||
id: 1,
|
||||
requesterId: 1
|
||||
},
|
||||
responder: {
|
||||
id: 2,
|
||||
username: 'jane_doe',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe'
|
||||
},
|
||||
existingItem: null
|
||||
});
|
||||
expect(mockResponse.update).toHaveBeenCalledWith({ status: 'accepted' });
|
||||
expect(mockResponse.itemRequest.update).toHaveBeenCalledWith({ status: 'fulfilled' });
|
||||
});
|
||||
|
||||
it('should update response status without fulfilling request', async () => {
|
||||
const updatedResponse = { ...mockResponse, status: 'declined' };
|
||||
mockResponse.update.mockResolvedValue();
|
||||
mockItemRequestResponseFindByPk
|
||||
.mockResolvedValueOnce(mockResponse)
|
||||
.mockResolvedValueOnce(updatedResponse);
|
||||
|
||||
const response = await request(app)
|
||||
.put('/item-requests/responses/1/status')
|
||||
.send({ status: 'declined' });
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(mockResponse.update).toHaveBeenCalledWith({ status: 'declined' });
|
||||
expect(mockResponse.itemRequest.update).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return 404 for non-existent response', async () => {
|
||||
mockItemRequestResponseFindByPk.mockResolvedValue(null);
|
||||
|
||||
const response = await request(app)
|
||||
.put('/item-requests/responses/999/status')
|
||||
.send({ status: 'accepted' });
|
||||
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body).toEqual({ error: 'Response not found' });
|
||||
});
|
||||
|
||||
it('should return 403 for unauthorized user', async () => {
|
||||
const unauthorizedResponse = {
|
||||
...mockResponse,
|
||||
itemRequest: { ...mockResponse.itemRequest, requesterId: 2 }
|
||||
};
|
||||
mockItemRequestResponseFindByPk.mockResolvedValue(unauthorizedResponse);
|
||||
|
||||
const response = await request(app)
|
||||
.put('/item-requests/responses/1/status')
|
||||
.send({ status: 'accepted' });
|
||||
|
||||
expect(response.status).toBe(403);
|
||||
expect(response.body).toEqual({ error: 'Only the requester can update response status' });
|
||||
});
|
||||
|
||||
it('should handle database errors', async () => {
|
||||
mockItemRequestResponseFindByPk.mockRejectedValue(new Error('Database error'));
|
||||
|
||||
const response = await request(app)
|
||||
.put('/item-requests/responses/1/status')
|
||||
.send({ status: 'accepted' });
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.body).toEqual({ error: 'Database error' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edge cases', () => {
|
||||
it('should handle empty search results', async () => {
|
||||
mockItemRequestFindAndCountAll.mockResolvedValue({ count: 0, rows: [] });
|
||||
|
||||
const response = await request(app)
|
||||
.get('/item-requests?search=nonexistent');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.requests).toEqual([]);
|
||||
expect(response.body.totalRequests).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle zero page calculation', async () => {
|
||||
mockItemRequestFindAndCountAll.mockResolvedValue({ count: 0, rows: [] });
|
||||
|
||||
const response = await request(app)
|
||||
.get('/item-requests');
|
||||
|
||||
expect(response.body.totalPages).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle request without optional fields', async () => {
|
||||
const minimalRequest = {
|
||||
title: 'Basic Request',
|
||||
description: 'Simple description'
|
||||
};
|
||||
|
||||
const mockCreated = { id: 1, ...minimalRequest, requesterId: 1 };
|
||||
const mockWithRequester = {
|
||||
...mockCreated,
|
||||
requester: { id: 1, username: 'test' }
|
||||
};
|
||||
|
||||
mockItemRequestCreate.mockResolvedValue(mockCreated);
|
||||
mockItemRequestFindByPk.mockResolvedValue(mockWithRequester);
|
||||
|
||||
const response = await request(app)
|
||||
.post('/item-requests')
|
||||
.send(minimalRequest);
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
expect(mockItemRequestCreate).toHaveBeenCalledWith({
|
||||
...minimalRequest,
|
||||
requesterId: 1
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user