Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
06f446c
feat: add testing setup with vitest and testing-library
diegotc86 Jun 5, 2025
795a205
feat: add tests for AuthNav component and update button tests
diegotc86 Jun 5, 2025
68e5d62
feat: add product loader tests for existing, non-existing, and invali…
diegotc86 Jun 5, 2025
d62801a
feat: add comprehensive tests for Product component and service funct…
diegotc86 Jun 6, 2025
db025d4
feat: add tests for user service updateUser functionality
diegotc86 Jun 7, 2025
0a02769
feat: add password hashing functionality in updateUser tests
Angel-Briones Jun 7, 2025
a748bfe
refactor: user service tests to use helper functions for mock data cr…
Angel-Briones Jun 10, 2025
08da2de
fix: ensure password hashing is mocked correctly in updateUser tests
diegotc86 Jun 11, 2025
eae64fe
feat: add getOrCreateUser functionality with tests for existing and n…
mykeVera Jun 11, 2025
f294d92
fix: add beforeEach to clear mocks in user service tests
mykeVera Jun 11, 2025
0335b5c
refactor: move helper functions to utils.tests for better organization
Angel-Briones Jun 12, 2025
9a36f31
refactor: reorganize imports in user service tests for clarity
diegotc86 Jun 12, 2025
6ade8e0
Merge pull request #184 from codeableorg/user-service-test
Angel-Briones Jun 12, 2025
add4acf
refactor: reorder imports and enhance test data setup in product serv…
Angel-Briones Jun 12, 2025
502eeb2
refactor: enhance test data setup by utilizing createTestCategory and…
Angel-Briones Jun 12, 2025
7ac47a9
refactor: replace inline mock product definition with helper function…
Angel-Briones Jun 12, 2025
065f269
feat: add test for OrderConfirmation loader to verify orderId extraction
Angel-Briones Jun 12, 2025
f5b1880
feat: add OrderConfirmation component tests for success messages, tra…
Angel-Briones Jun 12, 2025
313c2ef
refactor: enhance product component tests with improved setup and add…
Angel-Briones Jun 13, 2025
2917096
feat: implement loader tests for signup functionality with authentica…
Jun 13, 2025
da80643
Merge pull request #186 from codeableorg/product-service-test
diegotc86 Jun 14, 2025
c363631
feat(orders): add test for order service
JanetHugarcia Jun 11, 2025
9dc3522
refactor(tests): reorganize imports and utilize test utility function…
diegotc86 Jun 14, 2025
b8ef29d
Merge pull request #185 from codeableorg/feature/order-service-test
diegotc86 Jun 14, 2025
f696249
feat: add category service tests for getAllCategories and getCategory…
jhonattan Jun 12, 2025
8b9941a
refactor: add helper function to mocked `Category` in `utils.test.ts`
Angel-Briones Jun 14, 2025
7643698
Merge pull request #187 from codeableorg/category-service-test
diegotc86 Jun 14, 2025
2024d2f
refactor: simplify loader function by removing unnecessary return sta…
diegotc86 Jun 14, 2025
567246c
Merge pull request #190 from codeableorg/kelly/signup
diegotc86 Jun 14, 2025
c5fc62e
refactor: reorder user model import for consistency in utils.tests.ts
diegotc86 Jun 14, 2025
4747348
refactor: improve NotFound component structure and enhance product se…
diegotc86 Jun 14, 2025
881f199
Merge pull request #189 from codeableorg/product-route-module-test
diegotc86 Jun 14, 2025
6c89778
refactor: simplify order-confirmation.test component by removing unne…
Angel-Briones Jun 19, 2025
f8ac0ca
Merge pull request #188 from codeableorg/OrderConfirmation-route-modu…
diegotc86 Jun 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,234 changes: 1,226 additions & 8 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"migrate:dev": "tsx src/db/scripts/migrate.ts",
"reset-db:dev": "npm run drop-db:dev && npm run create-db:dev && npm run migrate:dev && npm run seed:dev",
"seed": "node dist/db/scripts/seed.js",
"seed:dev": "tsx src/db/scripts/seed.ts"
"seed:dev": "tsx src/db/scripts/seed.ts",
"test": "vitest"
},
"dependencies": {
"@hookform/resolvers": "^4.1.3",
Expand Down Expand Up @@ -48,6 +49,9 @@
"devDependencies": {
"@eslint/js": "^9.15.0",
"@react-router/dev": "^7.5.1",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@types/jsonwebtoken": "^9.0.9",
"@types/node": "^22.10.2",
"@types/pg": "^8.15.2",
Expand All @@ -61,14 +65,17 @@
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"global-jsdom": "^26.0.0",
"globals": "^15.12.0",
"jsdom": "^26.1.0",
"postcss": "^8.5.3",
"react-router-devtools": "^1.1.10",
"tailwindcss": "^3.4.17",
"tsx": "^4.19.4",
"typescript": "~5.6.2",
"typescript-eslint": "^8.15.0",
"vite": "^6.0.1",
"vite-tsconfig-paths": "^5.1.4"
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^3.2.1"
}
}
30 changes: 30 additions & 0 deletions src/components/ui/button/button.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { render, screen } from "@testing-library/react";
import { describe, it, expect } from "vitest";

import { Button } from "@/components/ui";

describe("Button Component", () => {
it("render correctly", () => {
render(<Button>Click me</Button>);

const button = screen.queryByRole("button", {
name: /click me/i,
});

expect(button).toBeInTheDocument();
});

it("render secondary variant correctly", () => {
render(<Button variant="secondary">Click me</Button>);

const button = screen.queryByRole("button", {
name: /click me/i,
});

expect(button).toHaveClass(
"bg-secondary",
"text-secondary-foreground",
"hover:bg-secondary-hover"
);
});
});
75 changes: 75 additions & 0 deletions src/lib/utils.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { vi } from "vitest";

import type { Category } from "@/models/category.model";
import type { Product } from "@/models/product.model";
import type { User } from "@/models/user.model";

import type { Session } from "react-router";

type TestRequestConfig = {
url?: string;
headers?: HeadersInit;
};

// Helper functions for creating commonly used test objects
export const createTestUser = (overrides?: Partial<User>): User => ({
id: 1,
email: "",
name: null,
password: null,
isGuest: false,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
...overrides,
});

export const createTestRequest = (overrides?: TestRequestConfig): Request => {
const defaultConfig: TestRequestConfig = {
url: "http://localhost/test",
headers: { Cookie: "session=mock-session-id" },
};

const config = { ...defaultConfig, ...overrides };
return new Request(config.url!, {
headers: { ...defaultConfig.headers, ...config.headers },
});
};

export const createMockSession = (userId: number | null): Session => ({
id: "mock-session-id",
data: {},
has: vi.fn(),
get: vi.fn().mockReturnValue(userId), // Default userId in session
set: vi.fn(),
flash: vi.fn(),
unset: vi.fn(),
});

export const createTestProduct = (overrides?: Partial<Product>): Product => ({
id: 1,
title: "Test Product",
imgSrc: "/test-image.jpg",
alt: "Test alt text",
price: 100,
description: "Test description",
categoryId: 1,
isOnSale: false,
features: ["Feature 1", "Feature 2"],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
...overrides,
});

export const createTestCategory = (
overrides?: Partial<Category>
): Category => ({
id: 1,
title: "Polos",
slug: "polos",
imgSrc: "/images/polos.jpg",
alt: "Colección de polos para programadores",
description: "Explora nuestra colección de polos para programadores",
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
...overrides,
});
14 changes: 8 additions & 6 deletions src/routes/not-found/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import { Button, Container, Section } from "@/components/ui";
export default function NotFound() {
return (
<Container>
<Section className='flex justify-center items-center'>
<div className='text-center'>
<p className='text-base font-semibold text-accent-foreground'>404</p>
<h1 className='text-4xl leading-9 font-bold tracking-tight text-foreground mt-4 sm:text-6xl sm:leading-none'>Página no encontrada</h1>
<p className='text-lg font-medium text-muted-foreground mt-6 sm:text-xl leading-none'>
<Section className="flex justify-center items-center">
<div className="text-center" data-testid="not-found">
<p className="text-base font-semibold text-accent-foreground">404</p>
<h1 className="text-4xl leading-9 font-bold tracking-tight text-foreground mt-4 sm:text-6xl sm:leading-none">
Página no encontrada
</h1>
<p className="text-lg font-medium text-muted-foreground mt-6 sm:text-xl leading-none">
No pudimos encontrar la página que estás buscando.
</p>
<Button className='mt-10' asChild size="xl">
<Button className="mt-10" asChild size="xl">
<Link to="/">Regresar al inicio</Link>
</Button>
</div>
Expand Down
27 changes: 27 additions & 0 deletions src/routes/order-confirmation/order-confirmation.loader.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { describe, expect, it } from "vitest";

import { loader } from ".";

describe("OrderConfirmation loader", () => {
// Helper function to create loader arguments
const createLoaderArgs = (orderId: string) => ({
params: { orderId },
request: new Request(`http://localhost/order-confirmation/${orderId}`),
context: {},
});

it("should return orderId from params", async () => {
// Step 1: Setup - Create test data
const testOrderId = "testOrderId-123"; // Example order ID

// Step 2: Mock - Not needed as loader has no dependencies

// Step 3: Call service function
const result = await loader(createLoaderArgs(testOrderId));

// Step 4: Verify expected behavior
expect(result).toEqual({
orderId: testOrderId,
});
});
});
50 changes: 50 additions & 0 deletions src/routes/order-confirmation/order-confirmation.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";

import OrderConfirmation from ".";
import type { Route } from "./+types";

// Creates minimal test props for OrderConfirmation component
const createTestProps = (orderId = "test-123"): Route.ComponentProps => ({
loaderData: { orderId },
params: vi.fn() as any,
matches: vi.fn() as any,
});

describe("OrderConfirmation", () => {
describe("Success Messages Display", () => {
it("should display all success messages correctly", () => {
// Step 1: Setup - Create test props
const props = createTestProps();
// Step 2: Mock
// Step 3: Call - Render component
render(<OrderConfirmation {...props} />);
// Step 4: Verify - Check all success messages
const expectedMessages = [
"¡Muchas gracias por tu compra!",
"Tu orden está en camino",
"Llegaremos a la puerta de tu domicilio lo antes posible",
];
expectedMessages.forEach((message) => {
expect(screen.queryByText(message)).toBeInTheDocument();
});
});
});

describe("Order Tracking Information", () => {
it("should display correct tracking code section", () => {
// Step 1: Setup - Create test props with a specific order ID
const testOrderId = "order-456";
const props = createTestProps(testOrderId);
// Step 2: Mock
// Step 3: Call - Render component
render(<OrderConfirmation {...props} />);
// Step 4: Verify - Check tracking code section
const trackingCodeLabel = screen.queryByText("Código de seguimiento");
expect(trackingCodeLabel).toBeInTheDocument();

const trackingCode = screen.queryByText(testOrderId);
expect(trackingCode).toBeInTheDocument();
});
});
});
51 changes: 51 additions & 0 deletions src/routes/product/product.loader.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { describe, expect, it, vi } from "vitest";

import { createTestProduct } from "@/lib/utils.tests";
import * as productService from "@/services/product.service";

import { loader } from ".";

// Mock the product service
vi.mock("@/services/product.service", () => ({
getProductById: vi.fn(), // mock function
}));

const mockGetProductById = vi.mocked(productService.getProductById);

describe("Product loader", () => {
const createLoaderArgs = (id: string) => ({
params: { id },
request: new Request(`http://localhost/products/${id}`),
context: {},
});

it("returns a product when it exists", async () => {
const mockProduct = createTestProduct();

mockGetProductById.mockResolvedValue(mockProduct);

const result = await loader(createLoaderArgs("1"));

expect(result.product).toBeDefined();
expect(result.product).toEqual(mockProduct);
expect(mockGetProductById).toHaveBeenCalledWith(1);
});

it("returns empty object when product does not exist", async () => {
mockGetProductById.mockRejectedValue(new Error("Product not found"));

const result = await loader(createLoaderArgs("999"));

expect(result).toEqual({});
expect(mockGetProductById).toHaveBeenCalledWith(999);
});

it("handles invalid product id", async () => {
mockGetProductById.mockRejectedValue(new Error("Invalid ID"));

const result = await loader(createLoaderArgs("invalid"));

expect(result).toEqual({});
expect(mockGetProductById).toHaveBeenCalledWith(NaN);
});
});
Loading