npm package: @mehdashti/testing-utils
Description: Testing utilities for Smart Platform - MSW handlers, mocks, and factories
Author: mehdashti
Latest version: 0.1.1

# @smart/testing-utils

> Testing utilities for Smart Platform - MSW handlers, mocks, and factories

## Installation

```bash
pnpm add -D @smart/testing-utils msw
```

## Features

- ✅ **MSW Handlers**: Pre-configured handlers for auth, users, and errors
- ✅ **Auth Mocks**: Mock users, tokens, and login responses
- ✅ **Data Factories**: Generate realistic test data with Faker
- ✅ **Test Helpers**: Utility functions for async testing
- ✅ **@smart/contracts**: Compatible with platform error formats

## Quick Start

### 1. Setup MSW Server

```typescript
// src/setupTests.ts
import { server } from "@smart/testing-utils/server";

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
```

### 2. Use in Tests

```typescript
import { mockUser, mockLoginResponse } from "@smart/testing-utils";

test("login flow", async () => {
  // Mock data is automatically available
  const response = await fetch("/api/auth/login", {
    method: "POST",
    body: JSON.stringify({
      email: "admin@example.com",
      password: "password",
    }),
  });

  const data = await response.json();
  expect(data.user).toEqual(mockUser);
});
```

## MSW Handlers

### Available Handlers

```typescript
import {
  handlers, // All handlers
  authHandlers, // Auth endpoints only
  userHandlers, // User endpoints only
  errorHandlers, // Error simulation
} from "@smart/testing-utils";
```

### Endpoints

**Auth**:
- `POST /api/auth/login` - Login with email/password
- `POST /api/auth/refresh` - Refresh access token
- `POST /api/auth/logout` - Logout
- `GET /api/users/me` - Get current user

**Users**:
- `GET /api/users` - List users (paginated)
- `GET /api/users/:id` - Get user by ID

**Error Simulation**:
- `POST /api/test/validation-error` - Returns 422
- `GET /api/test/server-error` - Returns 500
- `GET /api/test/rate-limit` - Returns 429

### Custom Handlers

```typescript
import { http, HttpResponse } from "msw";
import { server } from "@smart/testing-utils/server";

test("custom endpoint", () => {
  server.use(
    http.get("/api/custom", () => {
      return HttpResponse.json({ message: "custom response" });
    })
  );

  // Your test code
});
```

## Mock Data

### Auth Mocks

```typescript
import {
  mockUser, // Admin user
  mockViewerUser, // Viewer role
  mockInactiveUser, // Inactive user
  mockUsers, // Array of users
  mockTokens, // Auth tokens
  mockLoginResponse, // Full login response
} from "@smart/testing-utils";

// Use in tests
expect(user).toEqual(mockUser);

// Check roles
import { isAdmin, userHasRole } from "@smart/testing-utils";

expect(isAdmin(mockUser)).toBe(true);
expect(userHasRole(mockViewerUser, "admin")).toBe(false);
```

## Data Factories

### User Factory

```typescript
import {
  createUser,
  createAdminUser,
  createViewerUser,
  createUsers,
} from "@smart/testing-utils";

// Create a random user
const user = createUser();

// Create with specific data
const admin = createAdminUser({
  email: "admin@test.com",
  name: "Test Admin",
});

// Create multiple users
const users = createUsers(10);
```

### Pagination Factory

```typescript
import {
  createPaginationMeta,
  createPaginatedResponse,
} from "@smart/testing-utils";

const users = createUsers(5);
const response = createPaginatedResponse(users, 1, 20);

expect(response).toEqual({
  data: users,
  meta: {
    page: 1,
    page_size: 20,
    total_items: 5,
    total_pages: 1,
  },
});
```

## Test Helpers

```typescript
import {
  wait,
  waitForNextTick,
  createDelayedMock,
  createDelayedErrorMock,
} from "@smart/testing-utils";

// Wait for async operations
await wait(100);

// Wait for next tick
await waitForNextTick();

// Create delayed mock
const mockFn = createDelayedMock({ data: "test" }, 200);
const result = await mockFn(); // Resolves after 200ms

// Create error mock
const errorFn = createDelayedErrorMock(new Error("Failed"), 100);
await expect(errorFn()).rejects.toThrow("Failed");
```

## Examples

### Testing Login

```typescript
import { mockLoginResponse } from "@smart/testing-utils";

test("successful login", async () => {
  const response = await fetch("/api/auth/login", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      email: "admin@example.com",
      password: "password",
    }),
  });

  expect(response.ok).toBe(true);
  const data = await response.json();
  expect(data).toMatchObject(mockLoginResponse);
});
```

### Testing Error Handling

```typescript
test("handles validation errors", async () => {
  const response = await fetch("/api/test/validation-error", {
    method: "POST",
  });

  expect(response.status).toBe(422);
  const error = await response.json();

  expect(error).toMatchObject({
    type: "validation_error",
    status: 422,
    errors: expect.arrayContaining([
      expect.objectContaining({
        field: "email",
        message: expect.any(String),
      }),
    ]),
  });
});
```

### Testing with Custom Data

```typescript
import { createUser, createPaginatedResponse } from "@smart/testing-utils";
import { server } from "@smart/testing-utils/server";
import { http, HttpResponse } from "msw";

test("custom user list", () => {
  const customUsers = [
    createUser({ email: "user1@test.com" }),
    createUser({ email: "user2@test.com" }),
  ];

  server.use(
    http.get("/api/users", () => {
      return HttpResponse.json(
        createPaginatedResponse(customUsers, 1, 20)
      );
    })
  );

  // Your test code
});
```

## Browser Testing

For browser tests (Playwright, Cypress), use MSW browser worker:

```typescript
// src/mocks/browser.ts
import { setupWorker } from "msw/browser";
import { handlers } from "@smart/testing-utils";

export const worker = setupWorker(...handlers);
```

## License

MIT