Write comprehensive TypeScript tests with Jest or Vitest, including unit, integration, and E2E tests.
# TypeScript Testing with Jest & Vitest
Master TypeScript testing with Jest and Vitest using Google Antigravity IDE. This comprehensive guide covers test configuration, mocking strategies, and best practices for type-safe testing.
## Why Jest & Vitest?
Jest provides a mature testing ecosystem while Vitest offers blazing-fast Vite-native testing. Google Antigravity IDE's Gemini 3 engine helps you write comprehensive tests with intelligent suggestions.
## Vitest Configuration
```typescript
// vitest.config.ts
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({
plugins: [react(), tsconfigPaths()],
test: {
globals: true,
environment: "jsdom",
setupFiles: ["./src/test/setup.ts"],
include: ["src/**/*.{test,spec}.{ts,tsx}"],
coverage: {
provider: "v8",
reporter: ["text", "json", "html"],
exclude: ["node_modules/", "src/test/"],
thresholds: {
global: { branches: 80, functions: 80, lines: 80, statements: 80 },
},
},
mockReset: true,
restoreMocks: true,
},
});
```
## Jest Configuration
```typescript
// jest.config.ts
import type { Config } from "jest";
const config: Config = {
preset: "ts-jest",
testEnvironment: "jsdom",
roots: ["<rootDir>/src"],
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
"\\.(css|less|scss)$": "identity-obj-proxy",
},
setupFilesAfterEnv: ["<rootDir>/src/test/setup.ts"],
collectCoverageFrom: [
"src/**/*.{ts,tsx}",
"!src/**/*.d.ts",
"!src/test/**",
],
coverageThreshold: {
global: { branches: 80, functions: 80, lines: 80, statements: 80 },
},
transform: {
"^.+\\.tsx?$": ["ts-jest", { tsconfig: "tsconfig.test.json" }],
},
};
export default config;
```
## Test Setup
```typescript
// src/test/setup.ts
import "@testing-library/jest-dom";
import { cleanup } from "@testing-library/react";
import { afterEach, vi } from "vitest";
// Cleanup after each test
afterEach(() => {
cleanup();
});
// Mock window.matchMedia
Object.defineProperty(window, "matchMedia", {
writable: true,
value: vi.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: vi.fn(),
removeListener: vi.fn(),
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
dispatchEvent: vi.fn(),
})),
});
// Mock IntersectionObserver
global.IntersectionObserver = vi.fn().mockImplementation(() => ({
observe: vi.fn(),
unobserve: vi.fn(),
disconnect: vi.fn(),
}));
```
## Unit Testing
```typescript
// services/user.service.test.ts
import { describe, it, expect, vi, beforeEach } from "vitest";
import { UserService } from "./user.service";
import { UserRepository } from "./user.repository";
vi.mock("./user.repository");
describe("UserService", () => {
let userService: UserService;
let mockRepository: jest.Mocked<UserRepository>;
beforeEach(() => {
mockRepository = new UserRepository() as jest.Mocked<UserRepository>;
userService = new UserService(mockRepository);
});
describe("getUser", () => {
it("should return user when found", async () => {
const mockUser = { id: "1", name: "John", email: "john@example.com" };
mockRepository.findById.mockResolvedValue(mockUser);
const result = await userService.getUser("1");
expect(result).toEqual(mockUser);
expect(mockRepository.findById).toHaveBeenCalledWith("1");
});
it("should throw NotFoundError when user not found", async () => {
mockRepository.findById.mockResolvedValue(null);
await expect(userService.getUser("999")).rejects.toThrow(NotFoundError);
});
});
describe("createUser", () => {
it("should hash password before saving", async () => {
const dto = { name: "John", email: "john@example.com", password: "secret" };
await userService.createUser(dto);
expect(mockRepository.create).toHaveBeenCalledWith(
expect.objectContaining({
name: "John",
email: "john@example.com",
password: expect.not.stringContaining("secret"),
})
);
});
});
});
```
## Component Testing
```typescript
// components/UserCard.test.tsx
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
import { UserCard } from "./UserCard";
describe("UserCard", () => {
const mockUser = { id: "1", name: "John Doe", email: "john@example.com" };
it("renders user information", () => {
render(<UserCard user={mockUser} />);
expect(screen.getByText("John Doe")).toBeInTheDocument();
expect(screen.getByText("john@example.com")).toBeInTheDocument();
});
it("calls onDelete when delete button clicked", async () => {
const onDelete = vi.fn();
render(<UserCard user={mockUser} onDelete={onDelete} />);
fireEvent.click(screen.getByRole("button", { name: /delete/i }));
await waitFor(() => {
expect(onDelete).toHaveBeenCalledWith("1");
});
});
});
```
## Integration Testing
```typescript
// api/users.integration.test.ts
import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { createTestServer, TestDatabase } from "../test/utils";
describe("Users API", () => {
let server: TestServer;
let db: TestDatabase;
beforeAll(async () => {
db = await TestDatabase.create();
server = await createTestServer(db);
});
afterAll(async () => {
await server.close();
await db.cleanup();
});
it("POST /users creates a new user", async () => {
const response = await server.inject({
method: "POST",
url: "/users",
payload: { name: "John", email: "john@test.com" },
});
expect(response.statusCode).toBe(201);
expect(response.json()).toMatchObject({ name: "John" });
});
});
```
## Best Practices
- Use describe blocks to organize related tests
- Mock external dependencies at module level
- Test behavior, not implementation details
- Maintain high coverage thresholds
- Use testing-library for component tests
- Run tests in parallel for speed
Google Antigravity IDE provides intelligent test generation and automatically suggests missing test cases for your TypeScript code.This TypeScript prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their typescript implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For TypeScript projects, consider mentioning your framework version, coding style, and any specific libraries you're using.