820 lines
25 KiB
JavaScript
820 lines
25 KiB
JavaScript
const request = require("supertest");
|
|
const express = require("express");
|
|
const jwt = require("jsonwebtoken");
|
|
|
|
// Mock dependencies
|
|
jest.mock("jsonwebtoken");
|
|
jest.mock("../../../models", () => ({
|
|
User: {
|
|
findByPk: jest.fn(),
|
|
create: jest.fn(),
|
|
findOne: jest.fn(),
|
|
},
|
|
Item: {},
|
|
}));
|
|
|
|
jest.mock("../../../services/stripeService", () => ({
|
|
getCheckoutSession: jest.fn(),
|
|
createConnectedAccount: jest.fn(),
|
|
createAccountLink: jest.fn(),
|
|
getAccountStatus: jest.fn(),
|
|
createCustomer: jest.fn(),
|
|
createSetupCheckoutSession: jest.fn(),
|
|
}));
|
|
|
|
// Mock auth middleware
|
|
jest.mock("../../../middleware/auth", () => ({
|
|
authenticateToken: (req, res, next) => {
|
|
// Mock authenticated user
|
|
if (req.headers.authorization) {
|
|
req.user = { id: 1 };
|
|
next();
|
|
} else {
|
|
res.status(401).json({ error: "No token provided" });
|
|
}
|
|
},
|
|
requireVerifiedEmail: (req, res, next) => next(),
|
|
}));
|
|
|
|
// Mock logger
|
|
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(),
|
|
})),
|
|
}));
|
|
|
|
const { User } = require("../../../models");
|
|
const StripeService = require("../../../services/stripeService");
|
|
const stripeRoutes = require("../../../routes/stripe");
|
|
|
|
// Set up Express app for testing
|
|
const app = express();
|
|
app.use(express.json());
|
|
app.use("/stripe", stripeRoutes);
|
|
|
|
// Error handler middleware
|
|
app.use((err, req, res, next) => {
|
|
res.status(500).json({ error: err.message });
|
|
});
|
|
|
|
describe("Stripe Routes", () => {
|
|
let consoleSpy, consoleErrorSpy;
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
|
|
// Set up console spies
|
|
consoleSpy = jest.spyOn(console, "log").mockImplementation();
|
|
consoleErrorSpy = jest.spyOn(console, "error").mockImplementation();
|
|
});
|
|
|
|
afterEach(() => {
|
|
consoleSpy.mockRestore();
|
|
consoleErrorSpy.mockRestore();
|
|
});
|
|
|
|
describe("GET /checkout-session/:sessionId", () => {
|
|
it("should retrieve checkout session successfully", async () => {
|
|
const mockSession = {
|
|
status: "complete",
|
|
payment_status: "paid",
|
|
customer_details: {
|
|
email: "test@example.com",
|
|
},
|
|
setup_intent: {
|
|
id: "seti_123456789",
|
|
status: "succeeded",
|
|
},
|
|
metadata: {
|
|
userId: "1",
|
|
},
|
|
};
|
|
|
|
StripeService.getCheckoutSession.mockResolvedValue(mockSession);
|
|
|
|
const response = await request(app).get(
|
|
"/stripe/checkout-session/cs_123456789",
|
|
);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual({
|
|
status: "complete",
|
|
payment_status: "paid",
|
|
customer_email: "test@example.com",
|
|
setup_intent: {
|
|
id: "seti_123456789",
|
|
status: "succeeded",
|
|
},
|
|
metadata: {
|
|
userId: "1",
|
|
},
|
|
});
|
|
|
|
expect(StripeService.getCheckoutSession).toHaveBeenCalledWith(
|
|
"cs_123456789",
|
|
);
|
|
});
|
|
|
|
it("should handle missing customer_details gracefully", async () => {
|
|
const mockSession = {
|
|
status: "complete",
|
|
payment_status: "paid",
|
|
customer_details: null,
|
|
setup_intent: null,
|
|
metadata: {},
|
|
};
|
|
|
|
StripeService.getCheckoutSession.mockResolvedValue(mockSession);
|
|
|
|
const response = await request(app).get(
|
|
"/stripe/checkout-session/cs_123456789",
|
|
);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual({
|
|
status: "complete",
|
|
payment_status: "paid",
|
|
customer_email: undefined,
|
|
setup_intent: null,
|
|
metadata: {},
|
|
});
|
|
});
|
|
|
|
it("should handle checkout session retrieval errors", async () => {
|
|
const error = new Error("Session not found");
|
|
StripeService.getCheckoutSession.mockRejectedValue(error);
|
|
|
|
const response = await request(app).get(
|
|
"/stripe/checkout-session/invalid_session",
|
|
);
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Session not found" });
|
|
});
|
|
|
|
it("should handle missing session ID", async () => {
|
|
const error = new Error("Invalid session ID");
|
|
StripeService.getCheckoutSession.mockRejectedValue(error);
|
|
|
|
const response = await request(app).get("/stripe/checkout-session/");
|
|
|
|
expect(response.status).toBe(404);
|
|
});
|
|
});
|
|
|
|
describe("POST /accounts", () => {
|
|
const mockUser = {
|
|
id: 1,
|
|
email: "test@example.com",
|
|
stripeConnectedAccountId: null,
|
|
update: jest.fn(),
|
|
};
|
|
|
|
beforeEach(() => {
|
|
mockUser.update.mockReset();
|
|
mockUser.stripeConnectedAccountId = null;
|
|
});
|
|
|
|
it("should create connected account successfully", async () => {
|
|
const mockAccount = {
|
|
id: "acct_123456789",
|
|
email: "test@example.com",
|
|
country: "US",
|
|
};
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createConnectedAccount.mockResolvedValue(mockAccount);
|
|
mockUser.update.mockResolvedValue(mockUser);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/accounts")
|
|
.set("Authorization", "Bearer valid_token");
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual({
|
|
stripeConnectedAccountId: "acct_123456789",
|
|
success: true,
|
|
});
|
|
|
|
expect(User.findByPk).toHaveBeenCalledWith(1);
|
|
expect(StripeService.createConnectedAccount).toHaveBeenCalledWith({
|
|
email: "test@example.com",
|
|
country: "US",
|
|
});
|
|
expect(mockUser.update).toHaveBeenCalledWith({
|
|
stripeConnectedAccountId: "acct_123456789",
|
|
});
|
|
});
|
|
|
|
it("should return error if user not found", async () => {
|
|
User.findByPk.mockResolvedValue(null);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/accounts")
|
|
.set("Authorization", "Bearer valid_token");
|
|
|
|
expect(response.status).toBe(404);
|
|
expect(response.body).toEqual({ error: "User not found" });
|
|
expect(StripeService.createConnectedAccount).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should return error if user already has connected account", async () => {
|
|
const userWithAccount = {
|
|
...mockUser,
|
|
stripeConnectedAccountId: "acct_existing",
|
|
};
|
|
|
|
User.findByPk.mockResolvedValue(userWithAccount);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/accounts")
|
|
.set("Authorization", "Bearer valid_token");
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body).toEqual({
|
|
error: "User already has a connected account",
|
|
});
|
|
expect(StripeService.createConnectedAccount).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const response = await request(app).post("/stripe/accounts");
|
|
|
|
expect(response.status).toBe(401);
|
|
expect(response.body).toEqual({ error: "No token provided" });
|
|
});
|
|
|
|
it("should handle Stripe account creation errors", async () => {
|
|
const error = new Error("Invalid email address");
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createConnectedAccount.mockRejectedValue(error);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/accounts")
|
|
.set("Authorization", "Bearer valid_token");
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Invalid email address" });
|
|
});
|
|
|
|
it("should handle database update errors", async () => {
|
|
const mockAccount = { id: "acct_123456789" };
|
|
const dbError = new Error("Database update failed");
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createConnectedAccount.mockResolvedValue(mockAccount);
|
|
mockUser.update.mockRejectedValue(dbError);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/accounts")
|
|
.set("Authorization", "Bearer valid_token");
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Database update failed" });
|
|
});
|
|
});
|
|
|
|
describe("POST /account-links", () => {
|
|
const mockUser = {
|
|
id: 1,
|
|
stripeConnectedAccountId: "acct_123456789",
|
|
};
|
|
|
|
it("should create account link successfully", async () => {
|
|
const mockAccountLink = {
|
|
url: "https://connect.stripe.com/setup/e/acct_123456789",
|
|
expires_at: Date.now() + 3600,
|
|
};
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createAccountLink.mockResolvedValue(mockAccountLink);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/account-links")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({
|
|
refreshUrl: "http://localhost:3000/refresh",
|
|
returnUrl: "http://localhost:3000/return",
|
|
});
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual({
|
|
url: mockAccountLink.url,
|
|
expiresAt: mockAccountLink.expires_at,
|
|
});
|
|
|
|
expect(StripeService.createAccountLink).toHaveBeenCalledWith(
|
|
"acct_123456789",
|
|
"http://localhost:3000/refresh",
|
|
"http://localhost:3000/return",
|
|
);
|
|
});
|
|
|
|
it("should return error if no connected account found", async () => {
|
|
const userWithoutAccount = {
|
|
id: 1,
|
|
stripeConnectedAccountId: null,
|
|
};
|
|
|
|
User.findByPk.mockResolvedValue(userWithoutAccount);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/account-links")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({
|
|
refreshUrl: "http://localhost:3000/refresh",
|
|
returnUrl: "http://localhost:3000/return",
|
|
});
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body).toEqual({ error: "No connected account found" });
|
|
expect(StripeService.createAccountLink).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should return error if user not found", async () => {
|
|
User.findByPk.mockResolvedValue(null);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/account-links")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({
|
|
refreshUrl: "http://localhost:3000/refresh",
|
|
returnUrl: "http://localhost:3000/return",
|
|
});
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body).toEqual({ error: "No connected account found" });
|
|
});
|
|
|
|
it("should validate required URLs", async () => {
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/account-links")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({
|
|
refreshUrl: "http://localhost:3000/refresh",
|
|
// Missing returnUrl
|
|
});
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body).toEqual({
|
|
error: "refreshUrl and returnUrl are required",
|
|
});
|
|
expect(StripeService.createAccountLink).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should validate both URLs are provided", async () => {
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/account-links")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({
|
|
returnUrl: "http://localhost:3000/return",
|
|
// Missing refreshUrl
|
|
});
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body).toEqual({
|
|
error: "refreshUrl and returnUrl are required",
|
|
});
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const response = await request(app).post("/stripe/account-links").send({
|
|
refreshUrl: "http://localhost:3000/refresh",
|
|
returnUrl: "http://localhost:3000/return",
|
|
});
|
|
|
|
expect(response.status).toBe(401);
|
|
});
|
|
|
|
it("should handle Stripe account link creation errors", async () => {
|
|
const error = new Error("Account not found");
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createAccountLink.mockRejectedValue(error);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/account-links")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({
|
|
refreshUrl: "http://localhost:3000/refresh",
|
|
returnUrl: "http://localhost:3000/return",
|
|
});
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Account not found" });
|
|
});
|
|
});
|
|
|
|
describe("GET /account-status", () => {
|
|
const mockUser = {
|
|
id: 1,
|
|
stripeConnectedAccountId: "acct_123456789",
|
|
stripePayoutsEnabled: true,
|
|
stripeRequirementsCurrentlyDue: [],
|
|
stripeRequirementsPastDue: [],
|
|
stripeDisabledReason: null,
|
|
update: jest.fn().mockResolvedValue(true),
|
|
};
|
|
|
|
it("should get account status successfully", async () => {
|
|
const mockAccountStatus = {
|
|
id: "acct_123456789",
|
|
details_submitted: true,
|
|
payouts_enabled: true,
|
|
capabilities: {
|
|
transfers: { status: "active" },
|
|
},
|
|
requirements: {
|
|
pending_verification: [],
|
|
currently_due: [],
|
|
past_due: [],
|
|
},
|
|
};
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.getAccountStatus.mockResolvedValue(mockAccountStatus);
|
|
|
|
const response = await request(app)
|
|
.get("/stripe/account-status")
|
|
.set("Authorization", "Bearer valid_token");
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual({
|
|
accountId: "acct_123456789",
|
|
detailsSubmitted: true,
|
|
payoutsEnabled: true,
|
|
capabilities: {
|
|
transfers: { status: "active" },
|
|
},
|
|
requirements: {
|
|
pending_verification: [],
|
|
currently_due: [],
|
|
past_due: [],
|
|
},
|
|
});
|
|
|
|
expect(StripeService.getAccountStatus).toHaveBeenCalledWith(
|
|
"acct_123456789",
|
|
);
|
|
});
|
|
|
|
it("should return error if no connected account found", async () => {
|
|
const userWithoutAccount = {
|
|
id: 1,
|
|
stripeConnectedAccountId: null,
|
|
};
|
|
|
|
User.findByPk.mockResolvedValue(userWithoutAccount);
|
|
|
|
const response = await request(app)
|
|
.get("/stripe/account-status")
|
|
.set("Authorization", "Bearer valid_token");
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body).toEqual({ error: "No connected account found" });
|
|
expect(StripeService.getAccountStatus).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should return error if user not found", async () => {
|
|
User.findByPk.mockResolvedValue(null);
|
|
|
|
const response = await request(app)
|
|
.get("/stripe/account-status")
|
|
.set("Authorization", "Bearer valid_token");
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body).toEqual({ error: "No connected account found" });
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const response = await request(app).get("/stripe/account-status");
|
|
|
|
expect(response.status).toBe(401);
|
|
});
|
|
|
|
it("should handle Stripe account status retrieval errors", async () => {
|
|
const error = new Error("Account not found");
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.getAccountStatus.mockRejectedValue(error);
|
|
|
|
const response = await request(app)
|
|
.get("/stripe/account-status")
|
|
.set("Authorization", "Bearer valid_token");
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Account not found" });
|
|
});
|
|
});
|
|
|
|
describe("POST /create-setup-checkout-session", () => {
|
|
const mockUser = {
|
|
id: 1,
|
|
email: "test@example.com",
|
|
firstName: "John",
|
|
lastName: "Doe",
|
|
stripeCustomerId: null,
|
|
update: jest.fn(),
|
|
};
|
|
|
|
beforeEach(() => {
|
|
mockUser.update.mockReset();
|
|
mockUser.stripeCustomerId = null;
|
|
});
|
|
|
|
it("should create setup checkout session for new customer", async () => {
|
|
const mockCustomer = {
|
|
id: "cus_123456789",
|
|
email: "test@example.com",
|
|
};
|
|
|
|
const mockSession = {
|
|
id: "cs_123456789",
|
|
client_secret: "cs_123456789_secret_test",
|
|
};
|
|
|
|
const rentalData = {
|
|
itemId: "123",
|
|
startDate: "2023-12-01",
|
|
endDate: "2023-12-03",
|
|
};
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createCustomer.mockResolvedValue(mockCustomer);
|
|
StripeService.createSetupCheckoutSession.mockResolvedValue(mockSession);
|
|
mockUser.update.mockResolvedValue(mockUser);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/create-setup-checkout-session")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({ rentalData });
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual({
|
|
clientSecret: "cs_123456789_secret_test",
|
|
sessionId: "cs_123456789",
|
|
});
|
|
|
|
expect(User.findByPk).toHaveBeenCalledWith(1);
|
|
expect(StripeService.createCustomer).toHaveBeenCalledWith({
|
|
email: "test@example.com",
|
|
name: "John Doe",
|
|
metadata: {
|
|
userId: "1",
|
|
},
|
|
});
|
|
expect(mockUser.update).toHaveBeenCalledWith({
|
|
stripeCustomerId: "cus_123456789",
|
|
});
|
|
expect(StripeService.createSetupCheckoutSession).toHaveBeenCalledWith({
|
|
customerId: "cus_123456789",
|
|
metadata: {
|
|
rentalData: JSON.stringify(rentalData),
|
|
},
|
|
});
|
|
});
|
|
|
|
it("should use existing customer ID if available", async () => {
|
|
const userWithCustomer = {
|
|
...mockUser,
|
|
stripeCustomerId: "cus_existing123",
|
|
};
|
|
|
|
const mockSession = {
|
|
id: "cs_123456789",
|
|
client_secret: "cs_123456789_secret_test",
|
|
};
|
|
|
|
User.findByPk.mockResolvedValue(userWithCustomer);
|
|
StripeService.createSetupCheckoutSession.mockResolvedValue(mockSession);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/create-setup-checkout-session")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({});
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toEqual({
|
|
clientSecret: "cs_123456789_secret_test",
|
|
sessionId: "cs_123456789",
|
|
});
|
|
|
|
expect(StripeService.createCustomer).not.toHaveBeenCalled();
|
|
expect(userWithCustomer.update).not.toHaveBeenCalled();
|
|
expect(StripeService.createSetupCheckoutSession).toHaveBeenCalledWith({
|
|
customerId: "cus_existing123",
|
|
metadata: {},
|
|
});
|
|
});
|
|
|
|
it("should handle session without rental data", async () => {
|
|
const mockCustomer = {
|
|
id: "cus_123456789",
|
|
};
|
|
|
|
const mockSession = {
|
|
id: "cs_123456789",
|
|
client_secret: "cs_123456789_secret_test",
|
|
};
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createCustomer.mockResolvedValue(mockCustomer);
|
|
StripeService.createSetupCheckoutSession.mockResolvedValue(mockSession);
|
|
mockUser.update.mockResolvedValue(mockUser);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/create-setup-checkout-session")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({});
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(StripeService.createSetupCheckoutSession).toHaveBeenCalledWith({
|
|
customerId: "cus_123456789",
|
|
metadata: {},
|
|
});
|
|
});
|
|
|
|
it("should return error if user not found", async () => {
|
|
User.findByPk.mockResolvedValue(null);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/create-setup-checkout-session")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({});
|
|
|
|
expect(response.status).toBe(404);
|
|
expect(response.body).toEqual({ error: "User not found" });
|
|
expect(StripeService.createCustomer).not.toHaveBeenCalled();
|
|
expect(StripeService.createSetupCheckoutSession).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const response = await request(app)
|
|
.post("/stripe/create-setup-checkout-session")
|
|
.send({});
|
|
|
|
expect(response.status).toBe(401);
|
|
});
|
|
|
|
it("should handle customer creation errors", async () => {
|
|
const error = new Error("Invalid email address");
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createCustomer.mockRejectedValue(error);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/create-setup-checkout-session")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({});
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Invalid email address" });
|
|
});
|
|
|
|
it("should handle database update errors", async () => {
|
|
const mockCustomer = { id: "cus_123456789" };
|
|
const dbError = new Error("Database update failed");
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createCustomer.mockResolvedValue(mockCustomer);
|
|
mockUser.update.mockRejectedValue(dbError);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/create-setup-checkout-session")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({});
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Database update failed" });
|
|
});
|
|
|
|
it("should handle session creation errors", async () => {
|
|
const mockCustomer = { id: "cus_123456789" };
|
|
const sessionError = new Error("Session creation failed");
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createCustomer.mockResolvedValue(mockCustomer);
|
|
mockUser.update.mockResolvedValue(mockUser);
|
|
StripeService.createSetupCheckoutSession.mockRejectedValue(sessionError);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/create-setup-checkout-session")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({});
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Session creation failed" });
|
|
});
|
|
|
|
it("should handle complex rental data", async () => {
|
|
const mockCustomer = { id: "cus_123456789" };
|
|
const mockSession = {
|
|
id: "cs_123456789",
|
|
client_secret: "cs_123456789_secret_test",
|
|
};
|
|
|
|
const complexRentalData = {
|
|
itemId: "123",
|
|
startDate: "2023-12-01",
|
|
endDate: "2023-12-03",
|
|
totalAmount: 150.0,
|
|
additionalServices: ["cleaning", "delivery"],
|
|
notes: "Special instructions",
|
|
};
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createCustomer.mockResolvedValue(mockCustomer);
|
|
StripeService.createSetupCheckoutSession.mockResolvedValue(mockSession);
|
|
mockUser.update.mockResolvedValue(mockUser);
|
|
|
|
const response = await request(app)
|
|
.post("/stripe/create-setup-checkout-session")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.send({ rentalData: complexRentalData });
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(StripeService.createSetupCheckoutSession).toHaveBeenCalledWith({
|
|
customerId: "cus_123456789",
|
|
metadata: {
|
|
rentalData: JSON.stringify(complexRentalData),
|
|
},
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Error handling and edge cases", () => {
|
|
it("should handle malformed JSON in rental data", async () => {
|
|
const mockUser = {
|
|
id: 1,
|
|
email: "test@example.com",
|
|
firstName: "John",
|
|
lastName: "Doe",
|
|
stripeCustomerId: "cus_123456789",
|
|
};
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
|
|
// This should work fine as Express will parse valid JSON
|
|
const response = await request(app)
|
|
.post("/stripe/create-setup-checkout-session")
|
|
.set("Authorization", "Bearer valid_token")
|
|
.set("Content-Type", "application/json")
|
|
.send('{"rentalData":{"itemId":"123"}}');
|
|
|
|
expect(response.status).toBe(200);
|
|
});
|
|
|
|
it("should handle very large session IDs", async () => {
|
|
const longSessionId = "cs_" + "a".repeat(100);
|
|
const error = new Error("Session ID too long");
|
|
|
|
StripeService.getCheckoutSession.mockRejectedValue(error);
|
|
|
|
const response = await request(app).get(
|
|
`/stripe/checkout-session/${longSessionId}`,
|
|
);
|
|
|
|
expect(response.status).toBe(500);
|
|
expect(response.body).toEqual({ error: "Session ID too long" });
|
|
});
|
|
|
|
it("should handle concurrent requests for same user", async () => {
|
|
const mockUser = {
|
|
id: 1,
|
|
email: "test@example.com",
|
|
stripeConnectedAccountId: null,
|
|
update: jest.fn().mockResolvedValue({}),
|
|
};
|
|
|
|
const mockAccount = { id: "acct_123456789" };
|
|
|
|
User.findByPk.mockResolvedValue(mockUser);
|
|
StripeService.createConnectedAccount.mockResolvedValue(mockAccount);
|
|
|
|
// Simulate concurrent requests
|
|
const [response1, response2] = await Promise.all([
|
|
request(app)
|
|
.post("/stripe/accounts")
|
|
.set("Authorization", "Bearer valid_token"),
|
|
request(app)
|
|
.post("/stripe/accounts")
|
|
.set("Authorization", "Bearer valid_token"),
|
|
]);
|
|
|
|
// Both should succeed (in this test scenario)
|
|
expect(response1.status).toBe(200);
|
|
expect(response2.status).toBe(200);
|
|
});
|
|
});
|
|
});
|