Merge branch 'fix/backend-unit-tests'
This commit is contained in:
@@ -295,7 +295,7 @@ describe('Auth Routes', () => {
|
||||
});
|
||||
|
||||
expect(response.status).toBe(401);
|
||||
expect(response.body.error).toBe('Unable to log in. Please check your email and password, or create an account.');
|
||||
expect(response.body.error).toBe('Please check your email and password, or create an account.');
|
||||
});
|
||||
|
||||
it('should reject login with invalid password', async () => {
|
||||
@@ -316,7 +316,7 @@ describe('Auth Routes', () => {
|
||||
});
|
||||
|
||||
expect(response.status).toBe(401);
|
||||
expect(response.body.error).toBe('Unable to log in. Please check your email and password, or create an account.');
|
||||
expect(response.body.error).toBe('Please check your email and password, or create an account.');
|
||||
expect(mockUser.incLoginAttempts).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
@@ -682,10 +682,17 @@ describe('Items Routes', () => {
|
||||
});
|
||||
|
||||
describe('POST /', () => {
|
||||
const validUuid = '550e8400-e29b-41d4-a716-446655440000';
|
||||
const newItemData = {
|
||||
name: 'New Item',
|
||||
description: 'A new test item',
|
||||
pricePerDay: 25.99
|
||||
pricePerDay: 25.99,
|
||||
address1: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipCode: '12345',
|
||||
replacementCost: 100,
|
||||
imageFilenames: [`items/${validUuid}.jpg`]
|
||||
};
|
||||
|
||||
const mockCreatedItem = {
|
||||
@@ -1077,6 +1084,11 @@ describe('Items Routes', () => {
|
||||
name: 'New Item',
|
||||
description: 'A new test item',
|
||||
pricePerDay: 25.99,
|
||||
address1: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipCode: '12345',
|
||||
replacementCost: 100,
|
||||
imageFilenames: [
|
||||
`items/${validUuid1}.jpg`,
|
||||
`items/${validUuid2}.png`
|
||||
@@ -1110,22 +1122,25 @@ describe('Items Routes', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should create item without imageFilenames', async () => {
|
||||
it('should reject item without imageFilenames', async () => {
|
||||
const itemWithoutImages = {
|
||||
name: 'New Item',
|
||||
description: 'A new test item',
|
||||
pricePerDay: 25.99
|
||||
pricePerDay: 25.99,
|
||||
address1: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipCode: '12345',
|
||||
replacementCost: 100
|
||||
};
|
||||
|
||||
mockItemCreate.mockResolvedValue({ ...mockCreatedItem, imageFilenames: null });
|
||||
mockItemFindByPk.mockResolvedValue({ ...mockCreatedItem, imageFilenames: null });
|
||||
|
||||
const response = await request(app)
|
||||
.post('/items')
|
||||
.set('Authorization', 'Bearer valid_token')
|
||||
.send(itemWithoutImages);
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.error).toContain('At least one image is required');
|
||||
});
|
||||
|
||||
it('should reject invalid S3 key format', async () => {
|
||||
@@ -1133,6 +1148,11 @@ describe('Items Routes', () => {
|
||||
name: 'New Item',
|
||||
description: 'A new test item',
|
||||
pricePerDay: 25.99,
|
||||
address1: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipCode: '12345',
|
||||
replacementCost: 100,
|
||||
imageFilenames: ['invalid-key.jpg']
|
||||
};
|
||||
|
||||
@@ -1150,6 +1170,11 @@ describe('Items Routes', () => {
|
||||
name: 'New Item',
|
||||
description: 'A new test item',
|
||||
pricePerDay: 25.99,
|
||||
address1: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipCode: '12345',
|
||||
replacementCost: 100,
|
||||
imageFilenames: [`profiles/${validUuid1}.jpg`]
|
||||
};
|
||||
|
||||
@@ -1170,6 +1195,11 @@ describe('Items Routes', () => {
|
||||
name: 'New Item',
|
||||
description: 'A new test item',
|
||||
pricePerDay: 25.99,
|
||||
address1: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipCode: '12345',
|
||||
replacementCost: 100,
|
||||
imageFilenames: tooManyImages
|
||||
};
|
||||
|
||||
@@ -1191,6 +1221,11 @@ describe('Items Routes', () => {
|
||||
name: 'New Item',
|
||||
description: 'A new test item',
|
||||
pricePerDay: 25.99,
|
||||
address1: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipCode: '12345',
|
||||
replacementCost: 100,
|
||||
imageFilenames: maxImages
|
||||
};
|
||||
|
||||
@@ -1210,6 +1245,11 @@ describe('Items Routes', () => {
|
||||
name: 'New Item',
|
||||
description: 'A new test item',
|
||||
pricePerDay: 25.99,
|
||||
address1: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipCode: '12345',
|
||||
replacementCost: 100,
|
||||
imageFilenames: [
|
||||
`items/${validUuid1}.jpg`,
|
||||
`items/${validUuid1}.jpg`
|
||||
@@ -1230,6 +1270,11 @@ describe('Items Routes', () => {
|
||||
name: 'New Item',
|
||||
description: 'A new test item',
|
||||
pricePerDay: 25.99,
|
||||
address1: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipCode: '12345',
|
||||
replacementCost: 100,
|
||||
imageFilenames: [`../items/${validUuid1}.jpg`]
|
||||
};
|
||||
|
||||
@@ -1246,6 +1291,11 @@ describe('Items Routes', () => {
|
||||
name: 'New Item',
|
||||
description: 'A new test item',
|
||||
pricePerDay: 25.99,
|
||||
address1: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipCode: '12345',
|
||||
replacementCost: 100,
|
||||
imageFilenames: [`items/${validUuid1}.exe`]
|
||||
};
|
||||
|
||||
@@ -1257,23 +1307,26 @@ describe('Items Routes', () => {
|
||||
expect(response.status).toBe(400);
|
||||
});
|
||||
|
||||
it('should handle empty imageFilenames array', async () => {
|
||||
it('should reject empty imageFilenames array', async () => {
|
||||
const itemWithEmptyImages = {
|
||||
name: 'New Item',
|
||||
description: 'A new test item',
|
||||
pricePerDay: 25.99,
|
||||
address1: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipCode: '12345',
|
||||
replacementCost: 100,
|
||||
imageFilenames: []
|
||||
};
|
||||
|
||||
mockItemCreate.mockResolvedValue({ ...mockCreatedItem, imageFilenames: [] });
|
||||
mockItemFindByPk.mockResolvedValue({ ...mockCreatedItem, imageFilenames: [] });
|
||||
|
||||
const response = await request(app)
|
||||
.post('/items')
|
||||
.set('Authorization', 'Bearer valid_token')
|
||||
.send(itemWithEmptyImages);
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.error).toContain('At least one image is required');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1333,11 +1386,8 @@ describe('Items Routes', () => {
|
||||
expect(response.status).toBe(400);
|
||||
});
|
||||
|
||||
it('should allow clearing imageFilenames with empty array', async () => {
|
||||
mockItemFindByPk
|
||||
.mockResolvedValueOnce(mockItem)
|
||||
.mockResolvedValueOnce({ ...mockUpdatedItem, imageFilenames: [] });
|
||||
mockItem.update.mockResolvedValue();
|
||||
it('should reject clearing imageFilenames with empty array', async () => {
|
||||
mockItemFindByPk.mockResolvedValueOnce(mockItem);
|
||||
|
||||
const response = await request(app)
|
||||
.put('/items/1')
|
||||
@@ -1346,12 +1396,8 @@ describe('Items Routes', () => {
|
||||
imageFilenames: []
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(mockItem.update).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
imageFilenames: []
|
||||
})
|
||||
);
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.error).toContain('At least one image is required');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -268,6 +268,14 @@ describe('Rentals Routes', () => {
|
||||
});
|
||||
|
||||
describe('POST /', () => {
|
||||
// Helper to generate future dates for testing
|
||||
const getFutureDate = (daysFromNow, hours = 10) => {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() + daysFromNow);
|
||||
date.setHours(hours, 0, 0, 0);
|
||||
return date.toISOString();
|
||||
};
|
||||
|
||||
const mockItem = {
|
||||
id: 1,
|
||||
name: 'Test Item',
|
||||
@@ -295,10 +303,11 @@ describe('Rentals Routes', () => {
|
||||
renter: { id: 1, username: 'renter1', firstName: 'Alice', lastName: 'Johnson' },
|
||||
};
|
||||
|
||||
// Use dynamic future dates to avoid "Start date cannot be in the past" errors
|
||||
const rentalData = {
|
||||
itemId: 1,
|
||||
startDateTime: '2024-01-15T10:00:00.000Z',
|
||||
endDateTime: '2024-01-15T18:00:00.000Z',
|
||||
startDateTime: getFutureDate(7, 10), // 7 days from now at 10:00
|
||||
endDateTime: getFutureDate(7, 18), // 7 days from now at 18:00
|
||||
deliveryMethod: 'pickup',
|
||||
deliveryAddress: null,
|
||||
stripePaymentMethodId: 'pm_test123',
|
||||
@@ -328,7 +337,7 @@ describe('Rentals Routes', () => {
|
||||
|
||||
const dailyRentalData = {
|
||||
...rentalData,
|
||||
endDateTime: '2024-01-17T18:00:00.000Z', // 3 days
|
||||
endDateTime: getFutureDate(10, 18), // 3 days from start (7 + 3 = 10 days from now)
|
||||
};
|
||||
|
||||
const response = await request(app)
|
||||
|
||||
Reference in New Issue
Block a user