diff --git a/.env.test b/.env.test index 3b81323..52927a1 100644 --- a/.env.test +++ b/.env.test @@ -3,6 +3,8 @@ DATABASE_URL="postgresql://diego@localhost:5432/fullstock_test?schema=public" # Admin Database (for database creation/deletion) ADMIN_DB_NAME=postgres -# Culqui Keys -CULQI_PRIVATE_KEY="sk_test_xxx" -VITE_CULQI_PUBLIC_KEY="pk_test_xxx" \ No newline at end of file +# Cloud Storage base url +CS_BASE_URL="https://fullstock-images.s3.us-east-2.amazonaws.com" + +CULQI_PRIVATE_KEY="sk_test_EC8oOLd3ZiCTKqjN" +VITE_CULQI_PUBLIC_KEY="pk_test_Ws4NXfH95QXlZgaz" \ No newline at end of file diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index b02b8e3..99febd4 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -61,6 +61,11 @@ jobs: e2e-test: runs-on: ubuntu-latest needs: [test] + env: + CS_BASE_URL: "https://fullstock-images.s3.us-east-2.amazonaws.com" + CULQI_PRIVATE_KEY: "sk_test_EC8oOLd3ZiCTKqjN" + VITE_CULQI_PUBLIC_KEY: "pk_test_Ws4NXfH95QXlZgaz" + DATABASE_URL: "postgresql://diego@localhost:5432/fullstock_test?schema=public" services: postgres: image: postgres:15 diff --git a/package.json b/package.json index f56e61e..bff0d85 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "prisma:studio": "prisma studio", "prisma:seed": "prisma db seed", "test:prisma:migrate:deploy": "dotenv -e .env.test -- prisma migrate deploy", + "test:prisma:migrate:reset": "dotenv -e .env.test -- prisma migrate reset", "test:e2e": "playwright test", "test:prisma:seed": "dotenv -e .env.test prisma db seed" }, diff --git a/src/e2e/guest-create-order.spec.ts b/src/e2e/guest-create-order.spec.ts index b9d0516..236e675 100644 --- a/src/e2e/guest-create-order.spec.ts +++ b/src/e2e/guest-create-order.spec.ts @@ -1,7 +1,12 @@ // import { createOrderFormData } from "@/lib/utils.tests"; import { expect, test } from "@playwright/test"; -import { baseUrl, cleanDatabase, createOrderFormData } from "./utils-tests-e2e"; +import { + baseUrl, + cleanDatabase, + createOrderFormData, + creditCards, +} from "./utils-tests-e2e"; export type OrderFormData = Record; @@ -33,9 +38,43 @@ test.describe("Guest", () => { await page.getByRole("button", { name: "Confirmar Orden" }).click(); + const checkoutFrame = page.locator('iframe[name="checkout_frame"]'); + await expect(checkoutFrame).toBeVisible({ timeout: 10000 }); + + const validCard = creditCards.valid; + + await checkoutFrame + .contentFrame() + .getByRole("textbox", { name: "#### #### #### ####" }) + .fill(validCard.number); + await expect( - page.getByText("¡Muchas gracias por tu compra!") + checkoutFrame.contentFrame().getByRole("img", { name: "Culqi icon" }) ).toBeVisible(); + + await checkoutFrame + .contentFrame() + .getByRole("textbox", { name: "MM/AA" }) + .fill(validCard.exp); + + await checkoutFrame + .contentFrame() + .getByRole("textbox", { name: "CVV" }) + .fill(validCard.cvv); + + await checkoutFrame + .contentFrame() + .getByRole("textbox", { name: "correo@electronico.com" }) + .fill(orderForm["Correo electrónico"]); + + await checkoutFrame + .contentFrame() + .getByRole("button", { name: "Pagar S/" }) + .click(); + + await expect(page.getByText("¡Muchas gracias por tu compra!")).toBeVisible({ + timeout: 10000, + }); await expect(page.getByTestId("orderId")).toBeVisible(); }); }); diff --git a/src/e2e/user-create-order.spec.ts b/src/e2e/user-create-order.spec.ts index 5af2716..9dc34a9 100644 --- a/src/e2e/user-create-order.spec.ts +++ b/src/e2e/user-create-order.spec.ts @@ -4,7 +4,7 @@ import { prisma } from "@/db/prisma"; import { hashPassword } from "@/lib/security"; import type { CreateUserDTO } from "@/models/user.model"; -import { baseUrl, cleanDatabase } from "./utils-tests-e2e"; +import { baseUrl, cleanDatabase, creditCards } from "./utils-tests-e2e"; test.beforeEach(async () => { await cleanDatabase(); @@ -76,9 +76,43 @@ test.describe("User", () => { await page.getByRole("button", { name: "Confirmar Orden" }).click(); + const checkoutFrame = page.locator('iframe[name="checkout_frame"]'); + await expect(checkoutFrame).toBeVisible({ timeout: 10000 }); + + const validCard = creditCards.valid; + + await checkoutFrame + .contentFrame() + .getByRole("textbox", { name: "#### #### #### ####" }) + .fill(validCard.number); + await expect( - page.getByText("¡Muchas gracias por tu compra!") + checkoutFrame.contentFrame().getByRole("img", { name: "Culqi icon" }) ).toBeVisible(); + + await checkoutFrame + .contentFrame() + .getByRole("textbox", { name: "MM/AA" }) + .fill(validCard.exp); + + await checkoutFrame + .contentFrame() + .getByRole("textbox", { name: "CVV" }) + .fill(validCard.cvv); + + await checkoutFrame + .contentFrame() + .getByRole("textbox", { name: "correo@electronico.com" }) + .fill(loginForm["Correo electrónico"]); + + await checkoutFrame + .contentFrame() + .getByRole("button", { name: "Pagar S/" }) + .click(); + + await expect(page.getByText("¡Muchas gracias por tu compra!")).toBeVisible({ + timeout: 10000, + }); await expect(page.getByTestId("orderId")).toBeVisible(); }); }); diff --git a/src/e2e/utils-tests-e2e.ts b/src/e2e/utils-tests-e2e.ts index 1d3a40f..809fdf2 100644 --- a/src/e2e/utils-tests-e2e.ts +++ b/src/e2e/utils-tests-e2e.ts @@ -19,6 +19,19 @@ export const createOrderFormData = ( ...overrides, }); +export const creditCards = { + valid: { + number: "4111 1111 1111 1111", + exp: "12/30", + cvv: "123", + }, + declined: { + number: "4000 0200 0000 0000", + exp: "12/30", + cvv: "354", + }, +}; + export async function cleanDatabase() { await prisma.order.deleteMany(); await prisma.cart.deleteMany(); diff --git a/src/lib/utils.tests.ts b/src/lib/utils.tests.ts index cb6ce33..1526f23 100644 --- a/src/lib/utils.tests.ts +++ b/src/lib/utils.tests.ts @@ -158,6 +158,7 @@ export const createTestOrder = (overrides: Partial = {}): Order => { createdAt: new Date(), updatedAt: new Date(), ...details, // Expande todos los campos de contacto sin undefined + paymentId: `payment-id-${Math.random()}`, ...overrides, } satisfies Order; }; @@ -181,6 +182,7 @@ export const createTestDBOrder = ( phone: "123456789", createdAt: new Date(), updatedAt: new Date(), + paymentId: `payment-id-${Math.random()}`, ...overrides, } satisfies PrismaOrder; }; diff --git a/src/routes/product/product.test.tsx b/src/routes/product/product.test.tsx index fe59644..f70059d 100644 --- a/src/routes/product/product.test.tsx +++ b/src/routes/product/product.test.tsx @@ -51,14 +51,14 @@ describe("Product Component", () => { expect(titleElement).toHaveTextContent("Awesome Product"); }); - it("should render product price with dollar sign", () => { + it("should render product price with correct currency", () => { // Step 1: Setup - Create test props const props = createTestProps({ price: 150.99 }); // Step 2: Mock - Component mocks already set up above // Step 3: Call - Render component render(); // Step 4: Verify - Check price is rendered correctly - expect(screen.queryByText("$150.99")).toBeInTheDocument(); + expect(screen.queryByText("S/150.99")).toBeInTheDocument(); }); it("should render product description", () => { diff --git a/src/routes/signup/index.tsx b/src/routes/signup/index.tsx index 716d1c4..46b29e1 100644 --- a/src/routes/signup/index.tsx +++ b/src/routes/signup/index.tsx @@ -94,7 +94,7 @@ export async function action({ request }: Route.ActionArgs) { export async function loader({ request }: Route.LoaderArgs) { await redirectIfAuthenticated(request); - return null; + return undefined; } export default function Signup({ actionData }: Route.ComponentProps) { diff --git a/src/services/order.service.test.ts b/src/services/order.service.test.ts index 22f80e6..f5ffa51 100644 --- a/src/services/order.service.test.ts +++ b/src/services/order.service.test.ts @@ -64,7 +64,7 @@ describe("Order Service", () => { vi.mocked(mockPrisma.order.create).mockResolvedValue(prismaOrder); - const order = await createOrder(mockedItems, mockedFormData); + const order = await createOrder(mockedItems, mockedFormData, "payment-id"); expect(mockPrisma.order.create).toHaveBeenCalledWith({ data: { userId: mockedUser.id, @@ -88,6 +88,7 @@ describe("Order Service", () => { imgSrc: item.imgSrc, })), }, + paymentId: "payment-id", }, include: { items: true, @@ -118,6 +119,7 @@ describe("Order Service", () => { zip: prismaOrder.zip, phone: prismaOrder.phone, }, + paymentId: prismaOrder.paymentId, }); }); @@ -187,9 +189,9 @@ describe("Order Service", () => { new Error("Database error") ); - await expect(createOrder(mockedItems, mockedFormData)).rejects.toThrow( - "Failed to create order" - ); + await expect( + createOrder(mockedItems, mockedFormData, "payment-id") + ).rejects.toThrow("Failed to create order"); expect(mockPrisma.order.create).toHaveBeenCalled(); });