Compare commits
2 Commits
76102d48a9
...
a0d63ff04a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0d63ff04a | ||
|
|
e408880cae |
@@ -295,7 +295,7 @@ describe('Auth Routes', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(response.status).toBe(401);
|
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 () => {
|
it('should reject login with invalid password', async () => {
|
||||||
@@ -316,7 +316,7 @@ describe('Auth Routes', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(response.status).toBe(401);
|
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();
|
expect(mockUser.incLoginAttempts).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -682,10 +682,17 @@ describe('Items Routes', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /', () => {
|
describe('POST /', () => {
|
||||||
|
const validUuid = '550e8400-e29b-41d4-a716-446655440000';
|
||||||
const newItemData = {
|
const newItemData = {
|
||||||
name: 'New Item',
|
name: 'New Item',
|
||||||
description: 'A new test 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 = {
|
const mockCreatedItem = {
|
||||||
@@ -1077,6 +1084,11 @@ describe('Items Routes', () => {
|
|||||||
name: 'New Item',
|
name: 'New Item',
|
||||||
description: 'A new test 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: [
|
imageFilenames: [
|
||||||
`items/${validUuid1}.jpg`,
|
`items/${validUuid1}.jpg`,
|
||||||
`items/${validUuid2}.png`
|
`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 = {
|
const itemWithoutImages = {
|
||||||
name: 'New Item',
|
name: 'New Item',
|
||||||
description: 'A new test 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)
|
const response = await request(app)
|
||||||
.post('/items')
|
.post('/items')
|
||||||
.set('Authorization', 'Bearer valid_token')
|
.set('Authorization', 'Bearer valid_token')
|
||||||
.send(itemWithoutImages);
|
.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 () => {
|
it('should reject invalid S3 key format', async () => {
|
||||||
@@ -1133,6 +1148,11 @@ describe('Items Routes', () => {
|
|||||||
name: 'New Item',
|
name: 'New Item',
|
||||||
description: 'A new test 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: ['invalid-key.jpg']
|
imageFilenames: ['invalid-key.jpg']
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1150,6 +1170,11 @@ describe('Items Routes', () => {
|
|||||||
name: 'New Item',
|
name: 'New Item',
|
||||||
description: 'A new test 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: [`profiles/${validUuid1}.jpg`]
|
imageFilenames: [`profiles/${validUuid1}.jpg`]
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1170,6 +1195,11 @@ describe('Items Routes', () => {
|
|||||||
name: 'New Item',
|
name: 'New Item',
|
||||||
description: 'A new test 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: tooManyImages
|
imageFilenames: tooManyImages
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1191,6 +1221,11 @@ describe('Items Routes', () => {
|
|||||||
name: 'New Item',
|
name: 'New Item',
|
||||||
description: 'A new test 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: maxImages
|
imageFilenames: maxImages
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1210,6 +1245,11 @@ describe('Items Routes', () => {
|
|||||||
name: 'New Item',
|
name: 'New Item',
|
||||||
description: 'A new test 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: [
|
imageFilenames: [
|
||||||
`items/${validUuid1}.jpg`,
|
`items/${validUuid1}.jpg`,
|
||||||
`items/${validUuid1}.jpg`
|
`items/${validUuid1}.jpg`
|
||||||
@@ -1230,6 +1270,11 @@ describe('Items Routes', () => {
|
|||||||
name: 'New Item',
|
name: 'New Item',
|
||||||
description: 'A new test 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/${validUuid1}.jpg`]
|
imageFilenames: [`../items/${validUuid1}.jpg`]
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1246,6 +1291,11 @@ describe('Items Routes', () => {
|
|||||||
name: 'New Item',
|
name: 'New Item',
|
||||||
description: 'A new test 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/${validUuid1}.exe`]
|
imageFilenames: [`items/${validUuid1}.exe`]
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1257,23 +1307,26 @@ describe('Items Routes', () => {
|
|||||||
expect(response.status).toBe(400);
|
expect(response.status).toBe(400);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle empty imageFilenames array', async () => {
|
it('should reject empty imageFilenames array', async () => {
|
||||||
const itemWithEmptyImages = {
|
const itemWithEmptyImages = {
|
||||||
name: 'New Item',
|
name: 'New Item',
|
||||||
description: 'A new test 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: []
|
imageFilenames: []
|
||||||
};
|
};
|
||||||
|
|
||||||
mockItemCreate.mockResolvedValue({ ...mockCreatedItem, imageFilenames: [] });
|
|
||||||
mockItemFindByPk.mockResolvedValue({ ...mockCreatedItem, imageFilenames: [] });
|
|
||||||
|
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.post('/items')
|
.post('/items')
|
||||||
.set('Authorization', 'Bearer valid_token')
|
.set('Authorization', 'Bearer valid_token')
|
||||||
.send(itemWithEmptyImages);
|
.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);
|
expect(response.status).toBe(400);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow clearing imageFilenames with empty array', async () => {
|
it('should reject clearing imageFilenames with empty array', async () => {
|
||||||
mockItemFindByPk
|
mockItemFindByPk.mockResolvedValueOnce(mockItem);
|
||||||
.mockResolvedValueOnce(mockItem)
|
|
||||||
.mockResolvedValueOnce({ ...mockUpdatedItem, imageFilenames: [] });
|
|
||||||
mockItem.update.mockResolvedValue();
|
|
||||||
|
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.put('/items/1')
|
.put('/items/1')
|
||||||
@@ -1346,12 +1396,8 @@ describe('Items Routes', () => {
|
|||||||
imageFilenames: []
|
imageFilenames: []
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(400);
|
||||||
expect(mockItem.update).toHaveBeenCalledWith(
|
expect(response.body.error).toContain('At least one image is required');
|
||||||
expect.objectContaining({
|
|
||||||
imageFilenames: []
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -268,6 +268,14 @@ describe('Rentals Routes', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /', () => {
|
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 = {
|
const mockItem = {
|
||||||
id: 1,
|
id: 1,
|
||||||
name: 'Test Item',
|
name: 'Test Item',
|
||||||
@@ -295,10 +303,11 @@ describe('Rentals Routes', () => {
|
|||||||
renter: { id: 1, username: 'renter1', firstName: 'Alice', lastName: 'Johnson' },
|
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 = {
|
const rentalData = {
|
||||||
itemId: 1,
|
itemId: 1,
|
||||||
startDateTime: '2024-01-15T10:00:00.000Z',
|
startDateTime: getFutureDate(7, 10), // 7 days from now at 10:00
|
||||||
endDateTime: '2024-01-15T18:00:00.000Z',
|
endDateTime: getFutureDate(7, 18), // 7 days from now at 18:00
|
||||||
deliveryMethod: 'pickup',
|
deliveryMethod: 'pickup',
|
||||||
deliveryAddress: null,
|
deliveryAddress: null,
|
||||||
stripePaymentMethodId: 'pm_test123',
|
stripePaymentMethodId: 'pm_test123',
|
||||||
@@ -328,7 +337,7 @@ describe('Rentals Routes', () => {
|
|||||||
|
|
||||||
const dailyRentalData = {
|
const dailyRentalData = {
|
||||||
...rentalData,
|
...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)
|
const response = await request(app)
|
||||||
|
|||||||
Reference in New Issue
Block a user