text changes

This commit is contained in:
jackiettran
2026-01-21 19:20:07 -05:00
parent 420e0efeb4
commit 5d3c124d3e
31 changed files with 16387 additions and 4053 deletions

View File

@@ -6,12 +6,12 @@
* cancellation flows.
*/
const request = require('supertest');
const express = require('express');
const cookieParser = require('cookie-parser');
const jwt = require('jsonwebtoken');
const { sequelize, User, Item, Rental } = require('../../models');
const rentalRoutes = require('../../routes/rentals');
const request = require("supertest");
const express = require("express");
const cookieParser = require("cookie-parser");
const jwt = require("jsonwebtoken");
const { sequelize, User, Item, Rental } = require("../../models");
const rentalRoutes = require("../../routes/rentals");
// Test app setup
const createTestApp = () => {
@@ -21,11 +21,11 @@ const createTestApp = () => {
// Add request ID middleware
app.use((req, res, next) => {
req.id = 'test-request-id';
req.id = "test-request-id";
next();
});
app.use('/rentals', rentalRoutes);
app.use("/rentals", rentalRoutes);
return app;
};
@@ -34,7 +34,7 @@ const generateAuthToken = (user) => {
return jwt.sign(
{ id: user.id, jwtVersion: user.jwtVersion || 0 },
process.env.JWT_ACCESS_SECRET,
{ expiresIn: '15m' }
{ expiresIn: "15m" },
);
};
@@ -42,11 +42,11 @@ const generateAuthToken = (user) => {
const createTestUser = async (overrides = {}) => {
const defaultData = {
email: `user-${Date.now()}-${Math.random().toString(36).slice(2)}@example.com`,
password: 'TestPassword123!',
firstName: 'Test',
lastName: 'User',
password: "TestPassword123!",
firstName: "Test",
lastName: "User",
isVerified: true,
authProvider: 'local',
authProvider: "local",
};
return User.create({ ...defaultData, ...overrides });
@@ -54,17 +54,17 @@ const createTestUser = async (overrides = {}) => {
const createTestItem = async (ownerId, overrides = {}) => {
const defaultData = {
name: 'Test Item',
description: 'A test item for rental',
pricePerDay: 25.00,
pricePerHour: 5.00,
replacementCost: 500.00,
condition: 'excellent',
name: "Test Item",
description: "A test item for rental",
pricePerDay: 25.0,
pricePerHour: 5.0,
replacementCost: 500.0,
condition: "excellent",
isAvailable: true,
pickUpAvailable: true,
ownerId,
city: 'Test City',
state: 'California',
city: "Test City",
state: "California",
};
return Item.create({ ...defaultData, ...overrides });
@@ -84,15 +84,15 @@ const createTestRental = async (itemId, renterId, ownerId, overrides = {}) => {
totalAmount: 0,
platformFee: 0,
payoutAmount: 0,
status: 'pending',
paymentStatus: 'pending',
deliveryMethod: 'pickup',
status: "pending",
paymentStatus: "pending",
deliveryMethod: "pickup",
};
return Rental.create({ ...defaultData, ...overrides });
};
describe('Rental Integration Tests', () => {
describe("Rental Integration Tests", () => {
let app;
let owner;
let renter;
@@ -100,9 +100,9 @@ describe('Rental Integration Tests', () => {
beforeAll(async () => {
// Set test environment variables
process.env.NODE_ENV = 'test';
process.env.JWT_ACCESS_SECRET = 'test-access-secret';
process.env.JWT_REFRESH_SECRET = 'test-refresh-secret';
process.env.NODE_ENV = "test";
process.env.JWT_ACCESS_SECRET = "test-access-secret";
process.env.JWT_REFRESH_SECRET = "test-refresh-secret";
// Sync database
await sequelize.sync({ force: true });
@@ -122,32 +122,32 @@ describe('Rental Integration Tests', () => {
// Create test users
owner = await createTestUser({
email: 'owner@example.com',
firstName: 'Item',
lastName: 'Owner',
stripeConnectedAccountId: 'acct_test_owner',
email: "owner@example.com",
firstName: "Item",
lastName: "Owner",
stripeConnectedAccountId: "acct_test_owner",
});
renter = await createTestUser({
email: 'renter@example.com',
firstName: 'Item',
lastName: 'Renter',
email: "renter@example.com",
firstName: "Item",
lastName: "Renter",
});
// Create test item
item = await createTestItem(owner.id);
});
describe('GET /rentals/renting', () => {
it('should return rentals where user is the renter', async () => {
describe("GET /rentals/renting", () => {
it("should return rentals where user is the renter", async () => {
// Create a rental where renter is the renter
await createTestRental(item.id, renter.id, owner.id);
const token = generateAuthToken(renter);
const response = await request(app)
.get('/rentals/renting')
.set('Cookie', [`accessToken=${token}`])
.get("/rentals/renting")
.set("Cookie", [`accessToken=${token}`])
.expect(200);
expect(Array.isArray(response.body)).toBe(true);
@@ -155,37 +155,35 @@ describe('Rental Integration Tests', () => {
expect(response.body[0].renterId).toBe(renter.id);
});
it('should return empty array for user with no rentals', async () => {
it("should return empty array for user with no rentals", async () => {
const token = generateAuthToken(renter);
const response = await request(app)
.get('/rentals/renting')
.set('Cookie', [`accessToken=${token}`])
.get("/rentals/renting")
.set("Cookie", [`accessToken=${token}`])
.expect(200);
expect(Array.isArray(response.body)).toBe(true);
expect(response.body.length).toBe(0);
});
it('should require authentication', async () => {
const response = await request(app)
.get('/rentals/renting')
.expect(401);
it("should require authentication", async () => {
const response = await request(app).get("/rentals/renting").expect(401);
expect(response.body.code).toBeDefined();
});
});
describe('GET /rentals/owning', () => {
it('should return rentals where user is the owner', async () => {
describe("GET /rentals/owning", () => {
it("should return rentals where user is the owner", async () => {
// Create a rental where owner is the item owner
await createTestRental(item.id, renter.id, owner.id);
const token = generateAuthToken(owner);
const response = await request(app)
.get('/rentals/owning')
.set('Cookie', [`accessToken=${token}`])
.get("/rentals/owning")
.set("Cookie", [`accessToken=${token}`])
.expect(200);
expect(Array.isArray(response.body)).toBe(true);
@@ -194,208 +192,213 @@ describe('Rental Integration Tests', () => {
});
});
describe('PUT /rentals/:id/status', () => {
describe("PUT /rentals/:id/status", () => {
let rental;
beforeEach(async () => {
rental = await createTestRental(item.id, renter.id, owner.id);
});
it('should allow owner to confirm a pending rental', async () => {
it("should allow owner to confirm a pending rental", async () => {
const token = generateAuthToken(owner);
const response = await request(app)
.put(`/rentals/${rental.id}/status`)
.set('Cookie', [`accessToken=${token}`])
.send({ status: 'confirmed' })
.set("Cookie", [`accessToken=${token}`])
.send({ status: "confirmed" })
.expect(200);
expect(response.body.status).toBe('confirmed');
expect(response.body.status).toBe("confirmed");
// Verify in database
await rental.reload();
expect(rental.status).toBe('confirmed');
expect(rental.status).toBe("confirmed");
});
it('should allow renter to update status (no owner-only restriction)', async () => {
it("should allow renter to update status (no owner-only restriction)", async () => {
const token = generateAuthToken(renter);
const response = await request(app)
.put(`/rentals/${rental.id}/status`)
.set('Cookie', [`accessToken=${token}`])
.send({ status: 'confirmed' })
.set("Cookie", [`accessToken=${token}`])
.send({ status: "confirmed" })
.expect(200);
// Note: API currently allows both owner and renter to update status
// Owner-specific logic (payment processing) only runs for owner
await rental.reload();
expect(rental.status).toBe('confirmed');
expect(rental.status).toBe("confirmed");
});
it('should handle confirming already confirmed rental (idempotent)', async () => {
it("should handle confirming already confirmed rental (idempotent)", async () => {
// First confirm it
await rental.update({ status: 'confirmed' });
await rental.update({ status: "confirmed" });
const token = generateAuthToken(owner);
// API allows re-confirming (idempotent operation)
const response = await request(app)
.put(`/rentals/${rental.id}/status`)
.set('Cookie', [`accessToken=${token}`])
.send({ status: 'confirmed' })
.set("Cookie", [`accessToken=${token}`])
.send({ status: "confirmed" })
.expect(200);
// Status should remain confirmed
await rental.reload();
expect(rental.status).toBe('confirmed');
expect(rental.status).toBe("confirmed");
});
});
describe('PUT /rentals/:id/decline', () => {
describe("PUT /rentals/:id/decline", () => {
let rental;
beforeEach(async () => {
rental = await createTestRental(item.id, renter.id, owner.id);
});
it('should allow owner to decline a pending rental', async () => {
it("should allow owner to decline a pending rental", async () => {
const token = generateAuthToken(owner);
const response = await request(app)
.put(`/rentals/${rental.id}/decline`)
.set('Cookie', [`accessToken=${token}`])
.send({ reason: 'Item not available for those dates' })
.set("Cookie", [`accessToken=${token}`])
.send({ reason: "Item not available for those dates" })
.expect(200);
expect(response.body.status).toBe('declined');
expect(response.body.status).toBe("declined");
// Verify in database
await rental.reload();
expect(rental.status).toBe('declined');
expect(rental.declineReason).toBe('Item not available for those dates');
expect(rental.status).toBe("declined");
expect(rental.declineReason).toBe("Item not available for those dates");
});
it('should not allow declining already declined rental', async () => {
await rental.update({ status: 'declined' });
it("should not allow declining already declined rental", async () => {
await rental.update({ status: "declined" });
const token = generateAuthToken(owner);
const response = await request(app)
.put(`/rentals/${rental.id}/decline`)
.set('Cookie', [`accessToken=${token}`])
.send({ reason: 'Already declined' })
.set("Cookie", [`accessToken=${token}`])
.send({ reason: "Already declined" })
.expect(400);
expect(response.body.error).toBeDefined();
});
});
describe('POST /rentals/:id/cancel', () => {
describe("POST /rentals/:id/cancel", () => {
let rental;
beforeEach(async () => {
rental = await createTestRental(item.id, renter.id, owner.id, {
status: 'confirmed',
paymentStatus: 'paid',
status: "confirmed",
paymentStatus: "paid",
});
});
it('should allow renter to cancel their rental', async () => {
it("should allow renter to cancel their rental", async () => {
const token = generateAuthToken(renter);
const response = await request(app)
.post(`/rentals/${rental.id}/cancel`)
.set('Cookie', [`accessToken=${token}`])
.send({ reason: 'Change of plans' })
.set("Cookie", [`accessToken=${token}`])
.send({ reason: "Change of plans" })
.expect(200);
// Response format is { rental: {...}, refund: {...} }
expect(response.body.rental.status).toBe('cancelled');
expect(response.body.rental.cancelledBy).toBe('renter');
expect(response.body.rental.status).toBe("cancelled");
expect(response.body.rental.cancelledBy).toBe("renter");
// Verify in database
await rental.reload();
expect(rental.status).toBe('cancelled');
expect(rental.cancelledBy).toBe('renter');
expect(rental.status).toBe("cancelled");
expect(rental.cancelledBy).toBe("renter");
expect(rental.cancelledAt).toBeDefined();
});
it('should allow owner to cancel their rental', async () => {
it("should allow owner to cancel their rental", async () => {
const token = generateAuthToken(owner);
const response = await request(app)
.post(`/rentals/${rental.id}/cancel`)
.set('Cookie', [`accessToken=${token}`])
.send({ reason: 'Item broken' })
.set("Cookie", [`accessToken=${token}`])
.send({ reason: "Item broken" })
.expect(200);
expect(response.body.rental.status).toBe('cancelled');
expect(response.body.rental.cancelledBy).toBe('owner');
expect(response.body.rental.status).toBe("cancelled");
expect(response.body.rental.cancelledBy).toBe("owner");
});
it('should not allow cancelling completed rental', async () => {
await rental.update({ status: 'completed', paymentStatus: 'paid' });
it("should not allow cancelling completed rental", async () => {
await rental.update({ status: "completed", paymentStatus: "paid" });
const token = generateAuthToken(renter);
// RefundService throws error which becomes 500 via next(error)
const response = await request(app)
.post(`/rentals/${rental.id}/cancel`)
.set('Cookie', [`accessToken=${token}`])
.send({ reason: 'Too late' });
.set("Cookie", [`accessToken=${token}`])
.send({ reason: "Too late" });
// Expect error (could be 400 or 500 depending on error middleware)
expect(response.status).toBeGreaterThanOrEqual(400);
});
it('should not allow unauthorized user to cancel rental', async () => {
const otherUser = await createTestUser({ email: 'other@example.com' });
it("should not allow unauthorized user to cancel rental", async () => {
const otherUser = await createTestUser({ email: "other@example.com" });
const token = generateAuthToken(otherUser);
const response = await request(app)
.post(`/rentals/${rental.id}/cancel`)
.set('Cookie', [`accessToken=${token}`])
.send({ reason: 'Not my rental' });
.set("Cookie", [`accessToken=${token}`])
.send({ reason: "Not my rental" });
// Expect error (could be 403 or 500 depending on error middleware)
expect(response.status).toBeGreaterThanOrEqual(400);
});
});
describe('GET /rentals/pending-requests-count', () => {
it('should return count of pending rental requests for owner', async () => {
describe("GET /rentals/pending-requests-count", () => {
it("should return count of pending rental requests for owner", async () => {
// Create multiple pending rentals
await createTestRental(item.id, renter.id, owner.id, { status: 'pending' });
await createTestRental(item.id, renter.id, owner.id, { status: 'pending' });
await createTestRental(item.id, renter.id, owner.id, { status: 'confirmed' });
await createTestRental(item.id, renter.id, owner.id, {
status: "pending",
});
await createTestRental(item.id, renter.id, owner.id, {
status: "pending",
});
await createTestRental(item.id, renter.id, owner.id, {
status: "confirmed",
});
const token = generateAuthToken(owner);
const response = await request(app)
.get('/rentals/pending-requests-count')
.set('Cookie', [`accessToken=${token}`])
.get("/rentals/pending-requests-count")
.set("Cookie", [`accessToken=${token}`])
.expect(200);
expect(response.body.count).toBe(2);
});
it('should return 0 for user with no pending requests', async () => {
it("should return 0 for user with no pending requests", async () => {
const token = generateAuthToken(renter);
const response = await request(app)
.get('/rentals/pending-requests-count')
.set('Cookie', [`accessToken=${token}`])
.get("/rentals/pending-requests-count")
.set("Cookie", [`accessToken=${token}`])
.expect(200);
expect(response.body.count).toBe(0);
});
});
describe('Rental Lifecycle', () => {
it('should complete full rental lifecycle: pending -> confirmed -> active -> completed', async () => {
describe("Rental Lifecycle", () => {
it("should complete full rental lifecycle: pending -> confirmed -> active -> completed", async () => {
// Create pending free rental (totalAmount: 0 is default)
const rental = await createTestRental(item.id, renter.id, owner.id, {
status: 'pending',
status: "pending",
startDateTime: new Date(Date.now() - 60 * 60 * 1000), // Started 1 hour ago
endDateTime: new Date(Date.now() + 60 * 60 * 1000), // Ends in 1 hour
});
@@ -405,52 +408,52 @@ describe('Rental Integration Tests', () => {
// Step 1: Owner confirms rental (works for free rentals)
let response = await request(app)
.put(`/rentals/${rental.id}/status`)
.set('Cookie', [`accessToken=${ownerToken}`])
.send({ status: 'confirmed' })
.set("Cookie", [`accessToken=${ownerToken}`])
.send({ status: "confirmed" })
.expect(200);
expect(response.body.status).toBe('confirmed');
expect(response.body.status).toBe("confirmed");
// Step 2: Rental is now "active" because status is confirmed and startDateTime has passed
// Note: "active" is a computed status, not stored. The stored status remains "confirmed"
// Step 2: Rental is now "active" because status is confirmed and startDateTime has passed.
// "active" is a computed status, not stored. The stored status remains "confirmed"
await rental.reload();
expect(rental.status).toBe('confirmed'); // Stored status is still 'confirmed'
expect(rental.status).toBe("confirmed"); // Stored status is still 'confirmed'
// isActive() returns true because status='confirmed' and startDateTime is in the past
// Step 3: Owner marks rental as completed (via mark-return with status='returned')
response = await request(app)
.post(`/rentals/${rental.id}/mark-return`)
.set('Cookie', [`accessToken=${ownerToken}`])
.send({ status: 'returned' })
.set("Cookie", [`accessToken=${ownerToken}`])
.send({ status: "returned" })
.expect(200);
expect(response.body.rental.status).toBe('completed');
expect(response.body.rental.status).toBe("completed");
// Verify final state
await rental.reload();
expect(rental.status).toBe('completed');
expect(rental.status).toBe("completed");
});
});
describe('Review System', () => {
describe("Review System", () => {
let completedRental;
beforeEach(async () => {
completedRental = await createTestRental(item.id, renter.id, owner.id, {
status: 'completed',
paymentStatus: 'paid',
status: "completed",
paymentStatus: "paid",
});
});
it('should allow renter to review item', async () => {
it("should allow renter to review item", async () => {
const token = generateAuthToken(renter);
const response = await request(app)
.post(`/rentals/${completedRental.id}/review-item`)
.set('Cookie', [`accessToken=${token}`])
.set("Cookie", [`accessToken=${token}`])
.send({
rating: 5,
review: 'Great item, worked perfectly!',
review: "Great item, worked perfectly!",
})
.expect(200);
@@ -459,19 +462,19 @@ describe('Rental Integration Tests', () => {
// Verify in database
await completedRental.reload();
expect(completedRental.itemRating).toBe(5);
expect(completedRental.itemReview).toBe('Great item, worked perfectly!');
expect(completedRental.itemReview).toBe("Great item, worked perfectly!");
expect(completedRental.itemReviewSubmittedAt).toBeDefined();
});
it('should allow owner to review renter', async () => {
it("should allow owner to review renter", async () => {
const token = generateAuthToken(owner);
const response = await request(app)
.post(`/rentals/${completedRental.id}/review-renter`)
.set('Cookie', [`accessToken=${token}`])
.set("Cookie", [`accessToken=${token}`])
.send({
rating: 4,
review: 'Good renter, returned on time.',
review: "Good renter, returned on time.",
})
.expect(200);
@@ -480,33 +483,40 @@ describe('Rental Integration Tests', () => {
// Verify in database
await completedRental.reload();
expect(completedRental.renterRating).toBe(4);
expect(completedRental.renterReview).toBe('Good renter, returned on time.');
expect(completedRental.renterReview).toBe(
"Good renter, returned on time.",
);
});
it('should not allow review of non-completed rental', async () => {
const pendingRental = await createTestRental(item.id, renter.id, owner.id, {
status: 'pending',
});
it("should not allow review of non-completed rental", async () => {
const pendingRental = await createTestRental(
item.id,
renter.id,
owner.id,
{
status: "pending",
},
);
const token = generateAuthToken(renter);
const response = await request(app)
.post(`/rentals/${pendingRental.id}/review-item`)
.set('Cookie', [`accessToken=${token}`])
.set("Cookie", [`accessToken=${token}`])
.send({
rating: 5,
review: 'Cannot review yet',
review: "Cannot review yet",
})
.expect(400);
expect(response.body.error).toBeDefined();
});
it('should not allow duplicate reviews', async () => {
it("should not allow duplicate reviews", async () => {
// First review
await completedRental.update({
itemRating: 5,
itemReview: 'First review',
itemReview: "First review",
itemReviewSubmittedAt: new Date(),
});
@@ -514,31 +524,39 @@ describe('Rental Integration Tests', () => {
const response = await request(app)
.post(`/rentals/${completedRental.id}/review-item`)
.set('Cookie', [`accessToken=${token}`])
.set("Cookie", [`accessToken=${token}`])
.send({
rating: 3,
review: 'Second review attempt',
review: "Second review attempt",
})
.expect(400);
expect(response.body.error).toContain('already');
expect(response.body.error).toContain("already");
});
});
describe('Database Constraints', () => {
it('should not allow rental with invalid item ID', async () => {
describe("Database Constraints", () => {
it("should not allow rental with invalid item ID", async () => {
await expect(
createTestRental('00000000-0000-0000-0000-000000000000', renter.id, owner.id)
createTestRental(
"00000000-0000-0000-0000-000000000000",
renter.id,
owner.id,
),
).rejects.toThrow();
});
it('should not allow rental with invalid user IDs', async () => {
it("should not allow rental with invalid user IDs", async () => {
await expect(
createTestRental(item.id, '00000000-0000-0000-0000-000000000000', owner.id)
createTestRental(
item.id,
"00000000-0000-0000-0000-000000000000",
owner.id,
),
).rejects.toThrow();
});
it('should cascade delete rentals when item is deleted', async () => {
it("should cascade delete rentals when item is deleted", async () => {
const rental = await createTestRental(item.id, renter.id, owner.id);
// Delete the item
@@ -550,10 +568,10 @@ describe('Rental Integration Tests', () => {
});
});
describe('Concurrent Operations', () => {
it('should handle concurrent status updates (last write wins)', async () => {
describe("Concurrent Operations", () => {
it("should handle concurrent status updates (last write wins)", async () => {
const rental = await createTestRental(item.id, renter.id, owner.id, {
status: 'pending',
status: "pending",
});
const ownerToken = generateAuthToken(owner);
@@ -562,22 +580,22 @@ describe('Rental Integration Tests', () => {
const [confirmResult, declineResult] = await Promise.allSettled([
request(app)
.put(`/rentals/${rental.id}/status`)
.set('Cookie', [`accessToken=${ownerToken}`])
.send({ status: 'confirmed' }),
.set("Cookie", [`accessToken=${ownerToken}`])
.send({ status: "confirmed" }),
request(app)
.put(`/rentals/${rental.id}/decline`)
.set('Cookie', [`accessToken=${ownerToken}`])
.send({ reason: 'Declining instead' }),
.set("Cookie", [`accessToken=${ownerToken}`])
.send({ reason: "Declining instead" }),
]);
// Both requests may succeed (no optimistic locking)
// Verify rental ends up in a valid state
await rental.reload();
expect(['confirmed', 'declined']).toContain(rental.status);
expect(["confirmed", "declined"]).toContain(rental.status);
// At least one should have succeeded
const successes = [confirmResult, declineResult].filter(
r => r.status === 'fulfilled' && r.value.status === 200
(r) => r.status === "fulfilled" && r.value.status === 200,
);
expect(successes.length).toBeGreaterThanOrEqual(1);
});

View File

@@ -98,7 +98,7 @@ describe("Stripe Routes", () => {
StripeService.getCheckoutSession.mockResolvedValue(mockSession);
const response = await request(app).get(
"/stripe/checkout-session/cs_123456789"
"/stripe/checkout-session/cs_123456789",
);
expect(response.status).toBe(200);
@@ -116,7 +116,7 @@ describe("Stripe Routes", () => {
});
expect(StripeService.getCheckoutSession).toHaveBeenCalledWith(
"cs_123456789"
"cs_123456789",
);
});
@@ -132,7 +132,7 @@ describe("Stripe Routes", () => {
StripeService.getCheckoutSession.mockResolvedValue(mockSession);
const response = await request(app).get(
"/stripe/checkout-session/cs_123456789"
"/stripe/checkout-session/cs_123456789",
);
expect(response.status).toBe(200);
@@ -150,7 +150,7 @@ describe("Stripe Routes", () => {
StripeService.getCheckoutSession.mockRejectedValue(error);
const response = await request(app).get(
"/stripe/checkout-session/invalid_session"
"/stripe/checkout-session/invalid_session",
);
expect(response.status).toBe(500);
@@ -261,7 +261,6 @@ describe("Stripe Routes", () => {
expect(response.status).toBe(500);
expect(response.body).toEqual({ error: "Invalid email address" });
// Note: route uses logger instead of console.error
});
it("should handle database update errors", async () => {
@@ -313,7 +312,7 @@ describe("Stripe Routes", () => {
expect(StripeService.createAccountLink).toHaveBeenCalledWith(
"acct_123456789",
"http://localhost:3000/refresh",
"http://localhost:3000/return"
"http://localhost:3000/return",
);
});
@@ -413,7 +412,6 @@ describe("Stripe Routes", () => {
expect(response.status).toBe(500);
expect(response.body).toEqual({ error: "Account not found" });
// Note: route uses logger instead of console.error
});
});
@@ -466,7 +464,7 @@ describe("Stripe Routes", () => {
});
expect(StripeService.getAccountStatus).toHaveBeenCalledWith(
"acct_123456789"
"acct_123456789",
);
});
@@ -516,7 +514,6 @@ describe("Stripe Routes", () => {
expect(response.status).toBe(500);
expect(response.body).toEqual({ error: "Account not found" });
// Note: route uses logger instead of console.error
});
});
@@ -682,7 +679,6 @@ describe("Stripe Routes", () => {
expect(response.status).toBe(500);
expect(response.body).toEqual({ error: "Invalid email address" });
// Note: route uses logger.withRequestId().error() instead of console.error
});
it("should handle database update errors", async () => {
@@ -785,7 +781,7 @@ describe("Stripe Routes", () => {
StripeService.getCheckoutSession.mockRejectedValue(error);
const response = await request(app).get(
`/stripe/checkout-session/${longSessionId}`
`/stripe/checkout-session/${longSessionId}`,
);
expect(response.status).toBe(500);

View File

@@ -159,7 +159,7 @@ describe("EmailClient", () => {
);
expect(SendEmailCommand).toHaveBeenCalledWith({
Source: "Village Share <noreply@villageshare.app>",
Source: "Village Share <noreply@email.com>",
Destination: {
ToAddresses: ["test@example.com"],
},
@@ -253,7 +253,7 @@ describe("EmailClient", () => {
expect(SendEmailCommand).toHaveBeenCalledWith(
expect.objectContaining({
ReplyToAddresses: ["support@villageshare.app"],
ReplyToAddresses: ["support@email.com"],
}),
);
});

View File

@@ -123,7 +123,7 @@ describe("UserEngagementEmailService", () => {
ownerName: "John",
itemName: "Power Drill",
deletionReason: "Violated community guidelines",
supportEmail: "support@villageshare.com",
supportEmail: "support@email.com",
dashboardUrl: "http://localhost:3000/owning",
}),
);
@@ -183,7 +183,7 @@ describe("UserEngagementEmailService", () => {
expect.objectContaining({
userName: "John",
banReason: "Multiple policy violations",
supportEmail: "support@villageshare.com",
supportEmail: "support@email.com",
}),
);
expect(service.emailClient.sendEmail).toHaveBeenCalledWith(