Compare commits

...

16 Commits

Author SHA1 Message Date
abhi1992002
4864c8d377 fix format 2026-01-22 13:03:32 +05:30
abhi1992002
4a2a6a3c6a chore: update CI workflow to generate API client without force option
- Modified the CI workflow to use `pnpm generate:api` instead of `pnpm generate:api:force` for generating the API client, streamlining the process before running integration tests.
2026-01-22 12:59:04 +05:30
abhi1992002
7176f52492 chore: update CI workflow to generate API client before running tests
- Added a step to generate the API client using `pnpm generate:api:force` in the CI workflow before executing integration tests.
2026-01-22 12:53:38 +05:30
abhi1992002
d8bede1dd5 chore: update CI workflow to include integration tests
- Renamed the existing test job to `e2e_test` for clarity.
- Added a new `integration_test` job that runs on `ubuntu-latest`.
- Configured steps for checking out the repository, setting up Node.js, enabling corepack, restoring dependencies, and running unit tests using pnpm.
2026-01-22 12:42:15 +05:30
Abhimanyu Yadav
3cdbd48423 Merge branch 'dev' into abhi/integration-test-setup 2026-01-22 09:47:33 +05:30
abhi1992002
9ab5d1704b chore: remove outdated AGENTS.md file from tests directory
- Deleted AGENTS.md, which contained frontend testing rules and guidelines, as it is no longer relevant to the current testing framework and practices.
2026-01-22 09:47:19 +05:30
Abhimanyu Yadav
cd76330183 Merge branch 'dev' into abhi/integration-test-setup 2026-01-21 21:26:09 +05:30
abhi1992002
1b4ced3a13 fix: update mock Supabase client to return session data
- Modified the `refreshSession` method in the mock Supabase client to return a session object along with the user, improving the accuracy of the mock implementation for testing purposes.
2026-01-21 19:23:47 +05:30
abhi1992002
25dbab8cf7 fix: restore happy-dom dependency in package.json and pnpm-lock.yaml
- Removed `happy-dom` from dependencies in `package.json` and `pnpm-lock.yaml`.
- Re-added `happy-dom` to `devDependencies` in `package.json` and updated its entry in `pnpm-lock.yaml` to ensure proper testing environment setup.
2026-01-21 19:22:42 +05:30
abhi1992002
d9ca19672d fix lint 2026-01-21 19:19:01 +05:30
abhi1992002
6e2c7ffbeb fix format 2026-01-21 19:09:38 +05:30
abhi1992002
da978a7410 feat: enhance testing setup and API schema
- Updated `orval.config.ts` to configure MSW for API mocking with detailed settings.
- Added `happy-dom` as a new dependency for testing environment.
- Modified `vitest.config.mts` to use `happy-dom` for the testing environment.
- Introduced new boolean properties `has_sensitive_action` and `sensitive_action_safe_mode` in `openapi.json` for better control over agent behavior.
- Removed obsolete test files and utility functions to streamline the testing process.
- Updated test setup to improve isolation and configuration.
2026-01-21 18:53:15 +05:30
abhi1992002
6960ba8f3e refactor: clean up testing environment configuration and enhance test setup
- Removed `NEXT_PUBLIC_IS_TESTING_ENVIRONMENT` variable from `.env.default` as it is no longer needed.
- Updated Vitest configuration to include a setup file for tests.
- Cleaned up `layout.tsx` by removing the testing environment check and mock initialization.
- Updated `MainMarketplacePage.test.tsx` to use a custom render utility for better test isolation.
- Deleted unused `Badge.test.tsx` file to streamline test suite.
- Added comments in `mocks/index.ts` to clarify usage context for mocks.
2026-01-21 13:54:25 +05:30
abhi1992002
b22a4098bb feat: Introduce testing environment configuration and mock setup
- Added `NEXT_PUBLIC_IS_TESTING_ENVIRONMENT` variable to `.env.default` for testing environment indication.
- Updated `orval.config.ts` to enable mocking during API calls.
- Modified `layout.tsx` to initialize mocks when in testing environment.
- Removed `has_sensitive_action` properties from `openapi.json` to streamline API schema.
- Implemented `isTestingEnvironment` function in `environment` service for environment checks.
2026-01-21 13:32:55 +05:30
abhi1992002
1a5010f9e5 feat: Add unit testing scripts and configure Vitest for frontend testing
- Introduced new npm scripts for unit testing: `test:unit` and `test:unit:watch`.
- Updated Vitest configuration to include test files located in `src/**/*.test.tsx`.
2026-01-21 13:11:13 +05:30
abhi1992002
12f47eda10 feat: Set up Vitest and React Testing Library for frontend testing and document testing rules. 2026-01-21 12:09:00 +05:30
17 changed files with 1578 additions and 129 deletions

View File

@@ -128,7 +128,7 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
exitOnceUploaded: true
test:
e2e_test:
runs-on: big-boi
needs: setup
strategy:
@@ -258,3 +258,39 @@ jobs:
- name: Print Final Docker Compose logs
if: always()
run: docker compose -f ../docker-compose.yml logs
integration_test:
runs-on: ubuntu-latest
needs: setup
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "22.18.0"
- name: Enable corepack
run: corepack enable
- name: Restore dependencies cache
uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: ${{ needs.setup.outputs.cache-key }}
restore-keys: |
${{ runner.os }}-pnpm-${{ hashFiles('autogpt_platform/frontend/pnpm-lock.yaml') }}
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Generate API client
run: pnpm generate:api
- name: Run Integration Tests
run: pnpm test:unit

View File

@@ -29,4 +29,4 @@ NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY=
NEXT_PUBLIC_TURNSTILE=disabled
# PR previews
NEXT_PUBLIC_PREVIEW_STEALING_DEV=
NEXT_PUBLIC_PREVIEW_STEALING_DEV=

View File

@@ -16,6 +16,12 @@ export default defineConfig({
client: "react-query",
httpClient: "fetch",
indexFiles: false,
mock: {
type: "msw",
baseUrl: "http://localhost:3000/api/proxy",
generateEachHttpStatus: true,
delay: 0,
},
override: {
mutator: {
path: "./mutators/custom-mutator.ts",

View File

@@ -15,6 +15,8 @@
"types": "tsc --noEmit",
"test": "NEXT_PUBLIC_PW_TEST=true next build --turbo && playwright test",
"test-ui": "NEXT_PUBLIC_PW_TEST=true next build --turbo && playwright test --ui",
"test:unit": "vitest run",
"test:unit:watch": "vitest",
"test:no-build": "playwright test",
"gentests": "playwright codegen http://localhost:3000",
"storybook": "storybook dev -p 6006",
@@ -118,6 +120,7 @@
},
"devDependencies": {
"@chromatic-com/storybook": "4.1.2",
"happy-dom": "20.3.4",
"@opentelemetry/instrumentation": "0.209.0",
"@playwright/test": "1.56.1",
"@storybook/addon-a11y": "9.1.5",
@@ -127,6 +130,8 @@
"@storybook/nextjs": "9.1.5",
"@tanstack/eslint-plugin-query": "5.91.2",
"@tanstack/react-query-devtools": "5.90.2",
"@testing-library/dom": "10.4.1",
"@testing-library/react": "16.3.2",
"@types/canvas-confetti": "1.9.0",
"@types/lodash": "4.17.20",
"@types/negotiator": "0.6.4",
@@ -135,6 +140,7 @@
"@types/react-dom": "18.3.5",
"@types/react-modal": "3.16.3",
"@types/react-window": "1.8.8",
"@vitejs/plugin-react": "5.1.2",
"axe-playwright": "2.2.2",
"chromatic": "13.3.3",
"concurrently": "9.2.1",
@@ -153,7 +159,9 @@
"require-in-the-middle": "8.0.1",
"storybook": "9.1.5",
"tailwindcss": "3.4.17",
"typescript": "5.9.3"
"typescript": "5.9.3",
"vite-tsconfig-paths": "6.0.4",
"vitest": "4.0.17"
},
"msw": {
"workerDirectory": [

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
import { expect, test } from "vitest";
import { render, screen } from "@/tests/integrations/test-utils";
import { MainMarkeplacePage } from "../MainMarketplacePage";
import { server } from "@/mocks/mock-server";
import { getDeleteV2DeleteStoreSubmissionMockHandler422 } from "@/app/api/__generated__/endpoints/store/store.msw";
// Only for CI testing purpose, will remove it in future PR
test("MainMarketplacePage", async () => {
server.use(getDeleteV2DeleteStoreSubmissionMockHandler422());
render(<MainMarkeplacePage />);
expect(
await screen.findByText("Featured agents", { exact: false }),
).toBeDefined();
});

View File

@@ -1,81 +0,0 @@
// import { render, screen } from "@testing-library/react";
// import { describe, expect, it } from "vitest";
// import { Badge } from "./Badge";
// describe("Badge Component", () => {
// it("renders badge with content", () => {
// render(<Badge variant="success">Success</Badge>);
// expect(screen.getByText("Success")).toBeInTheDocument();
// });
// it("applies correct variant styles", () => {
// const { rerender } = render(<Badge variant="success">Success</Badge>);
// let badge = screen.getByText("Success");
// expect(badge).toHaveClass("bg-green-100", "text-green-800");
// rerender(<Badge variant="error">Error</Badge>);
// badge = screen.getByText("Error");
// expect(badge).toHaveClass("bg-red-100", "text-red-800");
// rerender(<Badge variant="info">Info</Badge>);
// badge = screen.getByText("Info");
// expect(badge).toHaveClass("bg-slate-100", "text-slate-800");
// });
// it("applies custom className", () => {
// render(
// <Badge variant="success" className="custom-class">
// Success
// </Badge>,
// );
// const badge = screen.getByText("Success");
// expect(badge).toHaveClass("custom-class");
// });
// it("renders as span element", () => {
// render(<Badge variant="success">Success</Badge>);
// const badge = screen.getByText("Success");
// expect(badge.tagName).toBe("SPAN");
// });
// it("renders children correctly", () => {
// render(
// <Badge variant="success">
// <span>Custom</span> Content
// </Badge>,
// );
// expect(screen.getByText("Custom")).toBeInTheDocument();
// expect(screen.getByText("Content")).toBeInTheDocument();
// });
// it("supports all badge variants", () => {
// const variants = ["success", "error", "info"] as const;
// variants.forEach((variant) => {
// const { unmount } = render(
// <Badge variant={variant} data-testid={`badge-${variant}`}>
// {variant}
// </Badge>,
// );
// expect(screen.getByTestId(`badge-${variant}`)).toBeInTheDocument();
// unmount();
// });
// });
// it("handles long text content", () => {
// render(
// <Badge variant="info">
// Very long text that should be handled properly by the component
// </Badge>,
// );
// const badge = screen.getByText(/Very long text/);
// expect(badge).toBeInTheDocument();
// expect(badge).toHaveClass("overflow-hidden", "text-ellipsis");
// });
// });

View File

@@ -0,0 +1,13 @@
// We are not using this for tests because Vitest runs our tests in a Node.js environment.
// However, we can use it for development purposes to test our UI in the browser with fake data.
export async function initMocks() {
if (typeof window === "undefined") {
const { server } = await import("./mock-server");
server.listen({ onUnhandledRequest: "bypass" });
console.log("[MSW] Server mock initialized");
} else {
const { worker } = await import("./mock-browser");
await worker.start({ onUnhandledRequest: "bypass" });
console.log("[MSW] Browser mock initialized");
}
}

View File

@@ -0,0 +1,4 @@
import { setupWorker } from "msw/browser";
import { mockHandlers } from "./mock-handlers";
export const worker = setupWorker(...mockHandlers);

View File

@@ -0,0 +1,48 @@
import { getAdminMock } from "@/app/api/__generated__/endpoints/admin/admin.msw";
import { getAnalyticsMock } from "@/app/api/__generated__/endpoints/analytics/analytics.msw";
import { getApiKeysMock } from "@/app/api/__generated__/endpoints/api-keys/api-keys.msw";
import { getAuthMock } from "@/app/api/__generated__/endpoints/auth/auth.msw";
import { getBlocksMock } from "@/app/api/__generated__/endpoints/blocks/blocks.msw";
import { getChatMock } from "@/app/api/__generated__/endpoints/chat/chat.msw";
import { getCreditsMock } from "@/app/api/__generated__/endpoints/credits/credits.msw";
import { getDefaultMock } from "@/app/api/__generated__/endpoints/default/default.msw";
import { getEmailMock } from "@/app/api/__generated__/endpoints/email/email.msw";
import { getExecutionsMock } from "@/app/api/__generated__/endpoints/executions/executions.msw";
import { getFilesMock } from "@/app/api/__generated__/endpoints/files/files.msw";
import { getGraphsMock } from "@/app/api/__generated__/endpoints/graphs/graphs.msw";
import { getHealthMock } from "@/app/api/__generated__/endpoints/health/health.msw";
import { getIntegrationsMock } from "@/app/api/__generated__/endpoints/integrations/integrations.msw";
import { getLibraryMock } from "@/app/api/__generated__/endpoints/library/library.msw";
import { getMetricsMock } from "@/app/api/__generated__/endpoints/metrics/metrics.msw";
import { getOauthMock } from "@/app/api/__generated__/endpoints/oauth/oauth.msw";
import { getOnboardingMock } from "@/app/api/__generated__/endpoints/onboarding/onboarding.msw";
import { getOttoMock } from "@/app/api/__generated__/endpoints/otto/otto.msw";
import { getPresetsMock } from "@/app/api/__generated__/endpoints/presets/presets.msw";
import { getSchedulesMock } from "@/app/api/__generated__/endpoints/schedules/schedules.msw";
import { getStoreMock } from "@/app/api/__generated__/endpoints/store/store.msw";
// Pass hard-coded data to individual handler functions to override faker-generated data.
export const mockHandlers = [
...getAdminMock(),
...getAnalyticsMock(),
...getApiKeysMock(),
...getAuthMock(),
...getBlocksMock(),
...getChatMock(),
...getCreditsMock(),
...getDefaultMock(),
...getEmailMock(),
...getExecutionsMock(),
...getFilesMock(),
...getGraphsMock(),
...getHealthMock(),
...getIntegrationsMock(),
...getLibraryMock(),
...getMetricsMock(),
...getOauthMock(),
...getOnboardingMock(),
...getOttoMock(),
...getPresetsMock(),
...getSchedulesMock(),
...getStoreMock(),
];

View File

@@ -0,0 +1,4 @@
import { setupServer } from "msw/node";
import { mockHandlers } from "./mock-handlers";
export const server = setupServer(...mockHandlers);

View File

@@ -0,0 +1,220 @@
# Frontend Testing Rules 🧪
## Testing Types Overview
| Type | Tool | Speed | Purpose |
| --------------- | --------------------- | --------------- | -------------------------------- |
| **E2E** | Playwright | Slow (~5s/test) | Real browser, full user journeys |
| **Integration** | Vitest + RTL | Fast (~100ms) | Component + mocked API |
| **Unit** | Vitest + RTL | Fastest (~10ms) | Individual functions/components |
| **Visual** | Storybook + Chromatic | N/A | UI appearance, design system |
---
## When to Use Each
### ✅ E2E Tests (Playwright)
**Use for:** Critical user journeys that MUST work in a real browser.
- Authentication flows (login, signup, logout)
- Payment or sensitive transactions
- Flows requiring real browser APIs (clipboard, downloads)
- Cross-page navigation that must work end-to-end
**Location:** `src/tests/*.spec.ts` (centralized, as there will be fewer of them)
### ✅ Integration Tests (Vitest + RTL)
**Use for:** Testing components with their dependencies (API calls, state).
- Page-level behavior with mocked API responses
- Components that fetch data
- User interactions that trigger API calls
- Feature flows within a single page
**Location:** Place tests in a `__tests__` folder next to the component:
```
ComponentName/
__tests__/
main.test.tsx
some-flow.test.tsx
ComponentName.tsx
useComponentName.ts
```
**Start at page level:** Initially write integration tests at the "page" level. No need to write them for every small component.
```
/library/
__tests__/
main.test.tsx
searching-agents.test.tsx
agents-pagination.test.tsx
page.tsx
useLibraryPage.ts
```
Start with a `main.test.tsx` file and split into smaller files as it grows.
**What integration tests should do:**
1. Render a page or complex modal (e.g., `AgentPublishModal`)
2. Mock API requests via MSW
3. Assert UI scenarios via Testing Library
```tsx
// Example: Test page renders data from API
import { server } from "@/mocks/mock-server";
import { getDeleteV2DeleteStoreSubmissionMockHandler422 } from "@/app/api/__generated__/endpoints/store/store.msw";
test("shows error when submission fails", async () => {
// Override default handler to return error status
server.use(getDeleteV2DeleteStoreSubmissionMockHandler422());
render(<MarketplacePage />);
await screen.findByText("Featured Agents");
// ... assert error UI
});
```
**Tip:** Use `findBy...` methods most of the time—they wait for elements to appear, so async code won't cause flaky tests. The regular `getBy...` methods don't wait and error immediately.
### ✅ Unit Tests (Vitest + RTL)
**Use for:** Testing isolated components and utility functions.
- Pure utility functions (`lib/utils.ts`)
- Component rendering with various props
- Component state changes
- Custom hooks
**Location:** Co-located with the file: `Component.test.tsx` next to `Component.tsx`
```tsx
// Example: Test component renders correctly
render(<AgentCard title="My Agent" />);
expect(screen.getByText("My Agent")).toBeInTheDocument();
```
### ✅ Storybook Tests (Visual)
**Use for:** Design system, visual appearance, component documentation.
- Atoms (Button, Input, Badge)
- Molecules (Dialog, Card)
- Visual states (hover, disabled, loading)
- Responsive layouts
**Location:** Co-located: `Component.stories.tsx` next to `Component.tsx`
---
## Decision Flowchart
```
Does it need a REAL browser/backend?
├─ YES → E2E (Playwright)
└─ NO
└─ Does it involve API calls or complex state?
├─ YES → Integration (Vitest + RTL)
└─ NO
└─ Is it about visual appearance?
├─ YES → Storybook
└─ NO → Unit (Vitest + RTL)
```
---
## What NOT to Test
❌ Third-party library internals (Radix UI, React Query)
❌ CSS styling details (use Storybook)
❌ Simple prop-passing components with no logic
❌ TypeScript types
---
## File Organization
```
src/
├── components/
│ └── atoms/
│ └── Button/
│ ├── Button.tsx
│ ├── Button.test.tsx # Unit test
│ └── Button.stories.tsx # Visual test
├── app/
│ └── (platform)/
│ └── marketplace/
│ └── components/
│ └── MainMarketplacePage/
│ ├── __tests__/
│ │ ├── main.test.tsx # Integration test
│ │ └── search-agents.test.tsx # Integration test
│ ├── MainMarketplacePage.tsx
│ └── useMainMarketplacePage.ts
├── lib/
│ ├── utils.ts
│ └── utils.test.ts # Unit test
├── mocks/
│ ├── mock-handlers.ts # MSW handlers (auto-generated via Orval)
│ └── mock-server.ts # MSW server setup
└── tests/
├── integrations/
│ ├── test-utils.tsx # Testing utilities
│ └── vitest.setup.tsx # Integration test setup
└── *.spec.ts # E2E tests (Playwright) - centralized
```
---
## Priority Matrix
| Component Type | Test Priority | Recommended Test |
| ------------------- | ------------- | ---------------- |
| Pages/Features | **Highest** | Integration |
| Custom Hooks | High | Unit |
| Utility Functions | High | Unit |
| Organisms (complex) | High | Integration |
| Molecules | Medium | Unit + Storybook |
| Atoms | Medium | Storybook only\* |
\*Atoms are typically simple enough that Storybook visual tests suffice.
---
## MSW Mocking
API mocking is handled via MSW (Mock Service Worker). Handlers are auto-generated by Orval from the OpenAPI schema.
**Default behavior:** All client-side requests are intercepted and return 200 status with faker-generated data.
**Override for specific tests:** Use generated error handlers to test non-OK status scenarios:
```tsx
import { server } from "@/mocks/mock-server";
import { getDeleteV2DeleteStoreSubmissionMockHandler422 } from "@/app/api/__generated__/endpoints/store/store.msw";
test("shows error when deletion fails", async () => {
server.use(getDeleteV2DeleteStoreSubmissionMockHandler422());
render(<MyComponent />);
// ... assert error UI
});
```
**Generated handlers location:** `src/app/api/__generated__/endpoints/*/` - each endpoint has handlers for different status codes.
---
## Golden Rules
1. **Test behavior, not implementation** - Query by role/text, not class names
2. **One assertion per concept** - Tests should be focused
3. **Mock at boundaries** - Mock API calls, not internal functions
4. **Co-locate integration tests** - Keep `__tests__/` folder next to the component
5. **E2E is expensive** - Only for critical happy paths; prefer integration tests
6. **AI agents are good at writing integration tests** - Start with these when adding test coverage

View File

@@ -0,0 +1,25 @@
import { vi } from "vitest";
const mockSupabaseClient = {
auth: {
getUser: vi.fn().mockResolvedValue({
data: { user: null },
error: null,
}),
getSession: vi.fn().mockResolvedValue({
data: { session: null },
error: null,
}),
signOut: vi.fn().mockResolvedValue({ error: null }),
refreshSession: vi.fn().mockResolvedValue({
data: { session: null, user: null },
error: null,
}),
},
};
export const mockSupabaseRequest = () => {
vi.mock("@/lib/supabase/server/getServerSupabase", () => ({
getServerSupabase: vi.fn().mockResolvedValue(mockSupabaseClient),
}));
};

View File

@@ -0,0 +1,63 @@
import { vi } from "vitest";
export const mockNextjsModules = () => {
vi.mock("next/image", () => ({
__esModule: true,
default: ({
fill: _fill,
priority: _priority,
quality: _quality,
placeholder: _placeholder,
blurDataURL: _blurDataURL,
loader: _loader,
...props
}: any) => {
// eslint-disable-next-line jsx-a11y/alt-text, @next/next/no-img-element
return <img {...props} />;
},
}));
vi.mock("next/headers", () => ({
cookies: vi.fn(() => ({
get: vi.fn(() => undefined),
getAll: vi.fn(() => []),
set: vi.fn(),
delete: vi.fn(),
has: vi.fn(() => false),
})),
headers: vi.fn(() => new Headers()),
}));
vi.mock("next/dist/server/request/cookies", () => ({
cookies: vi.fn(() => ({
get: vi.fn(() => undefined),
getAll: vi.fn(() => []),
set: vi.fn(),
delete: vi.fn(),
has: vi.fn(() => false),
})),
}));
vi.mock("next/navigation", () => ({
useRouter: () => ({
push: vi.fn(),
replace: vi.fn(),
prefetch: vi.fn(),
back: vi.fn(),
forward: vi.fn(),
refresh: vi.fn(),
}),
usePathname: () => "/marketplace",
useSearchParams: () => new URLSearchParams(),
useParams: () => ({}),
}));
vi.mock("next/link", () => ({
__esModule: true,
default: ({ children, href, ...props }: any) => (
<a href={href} {...props}>
{children}
</a>
),
}));
};

View File

@@ -0,0 +1,36 @@
import { BackendAPIProvider } from "@/lib/autogpt-server-api/context";
import OnboardingProvider from "@/providers/onboarding/onboarding-provider";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { render, RenderOptions } from "@testing-library/react";
import { ReactElement, ReactNode } from "react";
function createTestQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
}
function TestProviders({ children }: { children: ReactNode }) {
const queryClient = createTestQueryClient();
return (
<QueryClientProvider client={queryClient}>
<BackendAPIProvider>
<OnboardingProvider>{children}</OnboardingProvider>
</BackendAPIProvider>
</QueryClientProvider>
);
}
function customRender(
ui: ReactElement,
options?: Omit<RenderOptions, "wrapper">,
) {
return render(ui, { wrapper: TestProviders, ...options });
}
export * from "@testing-library/react";
export { customRender as render };

View File

@@ -0,0 +1,12 @@
import { beforeAll, afterAll, afterEach } from "vitest";
import { server } from "@/mocks/mock-server";
import { mockNextjsModules } from "./setup-nextjs-mocks";
import { mockSupabaseRequest } from "./mock-supabase-request";
beforeAll(() => {
mockNextjsModules();
mockSupabaseRequest(); // If you need user's data - please mock supabase actions in your specific test - it sends null user [It's only to avoid cookies() call]
return server.listen({ onUnhandledRequest: "error" });
});
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

View File

@@ -0,0 +1,12 @@
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({
plugins: [tsconfigPaths(), react()],
test: {
environment: "happy-dom",
include: ["src/**/*.test.tsx"],
setupFiles: ["./src/tests/integrations/vitest.setup.tsx"],
},
});