Automated Testing with Google Antigravity: AI-Generated Tests for Jest, Vitest & Playwright | Antigravity AI Directory | Google Antigravity Directory
Automated Testing with Google Antigravity: AI-Gene... Tutorials Automated Testing with Google Antigravity: AI-Generated Tests for Jest, Vitest & Playwright Automated Testing with Google Antigravity: AI-Generated Tests for Jest, Vitest & Playwright
Testing is essential but time-consuming. Google Antigravity with Gemini 3 can generate comprehensive test suites in seconds. This guide shows you how to leverage AI for testing at every level.
Why Use Antigravity for Testing?
Gemini 3 understands your code deeply, enabling:
Unit test generation from function signatures
Integration tests that understand component relationships
E2E tests that model user flows
Edge case discovery humans often miss
Test maintenance as code evolves
Setting Up Your Testing Environment
For React/Next.js Projects (Vitest)
npm install -D vitest @testing-library/react @testing-library/jest-dom jsdom
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
globals: true,
setupFiles: './tests/setup.ts',
},
})
For Node.js Projects (Jest)
npm install -D jest @types/jest ts-jest
// jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/src'],
testMatch: ['**/__tests__/**/*.ts', '**/*.test.ts'],
};
For E2E Testing (Playwright)
npm install -D @playwright/test
npx playwright install
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './e2e',
fullyParallel: true,
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
},
});
Generating Unit Tests
Basic Function Testing
Related Posts Antigravity + Supabase: Build a Complete App in 30 Minutes (Step-by-Step Tutorial) Build a full-stack application with Google Antigravity and Supabase in under 30 minutes. This hands-on tutorial covers authentication, database, real-time subscriptions, and deployment—complete with copy-paste prompts.
Next.js 15 + Antigravity: The Ultimate React Developer Workflow (2025) Master the perfect Next.js 15 development workflow with Google Antigravity. Learn Server Components, Server Actions, App Router patterns, and production-ready prompts that 10x your React development speed.
Antigravity for Python Developers: Django, FastAPI & Flask Complete Workflows (2025) Master Google Antigravity for Python development. Complete guide covering Django, FastAPI, and Flask workflows with production-ready prompts, MCP server integrations, and real-world examples.
// utils/validation.ts
export function validateEmail(email: string): boolean {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
export function validatePassword(password: string): {
valid: boolean;
errors: string[];
} {
const errors: string[] = [];
if (password.length < 8) {
errors.push('Password must be at least 8 characters');
}
if (!/[A-Z]/.test(password)) {
errors.push('Password must contain uppercase letter');
}
if (!/[0-9]/.test(password)) {
errors.push('Password must contain a number');
}
return { valid: errors.length === 0, errors };
}
Ask Antigravity: "Generate comprehensive unit tests for this validation module"
// utils/__tests__/validation.test.ts
import { describe, it, expect } from 'vitest';
import { validateEmail, validatePassword } from '../validation';
describe('validateEmail', () => {
it('should return true for valid emails', () => {
expect(validateEmail('user@example.com')).toBe(true);
expect(validateEmail('test.user@domain.co.uk')).toBe(true);
expect(validateEmail('user+tag@example.org')).toBe(true);
});
it('should return false for invalid emails', () => {
expect(validateEmail('invalid')).toBe(false);
expect(validateEmail('no@domain')).toBe(false);
expect(validateEmail('@nodomain.com')).toBe(false);
expect(validateEmail('spaces in@email.com')).toBe(false);
expect(validateEmail('')).toBe(false);
});
it('should handle edge cases', () => {
expect(validateEmail('a@b.co')).toBe(true);
expect(validateEmail('very.long.email.address@subdomain.domain.com')).toBe(true);
});
});
describe('validatePassword', () => {
it('should return valid for strong passwords', () => {
const result = validatePassword('SecurePass1');
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
it('should reject short passwords', () => {
const result = validatePassword('Short1');
expect(result.valid).toBe(false);
expect(result.errors).toContain('Password must be at least 8 characters');
});
it('should reject passwords without uppercase', () => {
const result = validatePassword('lowercase123');
expect(result.valid).toBe(false);
expect(result.errors).toContain('Password must contain uppercase letter');
});
it('should reject passwords without numbers', () => {
const result = validatePassword('NoNumbers');
expect(result.valid).toBe(false);
expect(result.errors).toContain('Password must contain a number');
});
it('should accumulate multiple errors', () => {
const result = validatePassword('weak');
expect(result.valid).toBe(false);
expect(result.errors.length).toBeGreaterThan(1);
});
it('should handle edge cases', () => {
expect(validatePassword('Exactly8!').valid).toBe(false); // no number
expect(validatePassword('Exactly8A').valid).toBe(true);
expect(validatePassword('').valid).toBe(false);
});
});
Testing React Components
Component Under Test // components/LoginForm.tsx
'use client';
import { useState } from 'react';
interface LoginFormProps {
onSubmit: (email: string, password: string) => Promise<void>;
onForgotPassword?: () => void;
}
export default function LoginForm({ onSubmit, onForgotPassword }: LoginFormProps) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
setLoading(true);
try {
await onSubmit(email, password);
} catch (err) {
setError(err instanceof Error ? err.message : 'Login failed');
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit} data-testid="login-form">
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
data-testid="email-input"
required
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
data-testid="password-input"
required
/>
{error && <div data-testid="error-message">{error}</div>}
<button type="submit" disabled={loading} data-testid="submit-button">
{loading ? 'Logging in...' : 'Login'}
</button>
{onForgotPassword && (
<button type="button" onClick={onForgotPassword} data-testid="forgot-password">
Forgot Password?
</button>
)}
</form>
);
}
Ask Antigravity: "Generate tests for this LoginForm component"
// components/__tests__/LoginForm.test.tsx
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi } from 'vitest';
import LoginForm from '../LoginForm';
describe('LoginForm', () => {
const mockOnSubmit = vi.fn();
const mockOnForgotPassword = vi.fn();
beforeEach(() => {
vi.clearAllMocks();
});
it('renders all form elements', () => {
render(<LoginForm onSubmit={mockOnSubmit} />);
expect(screen.getByTestId('email-input')).toBeInTheDocument();
expect(screen.getByTestId('password-input')).toBeInTheDocument();
expect(screen.getByTestId('submit-button')).toBeInTheDocument();
});
it('updates input values on change', async () => {
const user = userEvent.setup();
render(<LoginForm onSubmit={mockOnSubmit} />);
const emailInput = screen.getByTestId('email-input');
const passwordInput = screen.getByTestId('password-input');
await user.type(emailInput, 'test@example.com');
await user.type(passwordInput, 'password123');
expect(emailInput).toHaveValue('test@example.com');
expect(passwordInput).toHaveValue('password123');
});
it('calls onSubmit with email and password', async () => {
const user = userEvent.setup();
mockOnSubmit.mockResolvedValueOnce(undefined);
render(<LoginForm onSubmit={mockOnSubmit} />);
await user.type(screen.getByTestId('email-input'), 'test@example.com');
await user.type(screen.getByTestId('password-input'), 'password123');
await user.click(screen.getByTestId('submit-button'));
expect(mockOnSubmit).toHaveBeenCalledWith('test@example.com', 'password123');
});
it('displays loading state during submission', async () => {
const user = userEvent.setup();
mockOnSubmit.mockImplementation(() => new Promise(() => {})); // Never resolves
render(<LoginForm onSubmit={mockOnSubmit} />);
await user.type(screen.getByTestId('email-input'), 'test@example.com');
await user.type(screen.getByTestId('password-input'), 'password123');
await user.click(screen.getByTestId('submit-button'));
expect(screen.getByTestId('submit-button')).toHaveTextContent('Logging in...');
expect(screen.getByTestId('submit-button')).toBeDisabled();
});
it('displays error message on failure', async () => {
const user = userEvent.setup();
mockOnSubmit.mockRejectedValueOnce(new Error('Invalid credentials'));
render(<LoginForm onSubmit={mockOnSubmit} />);
await user.type(screen.getByTestId('email-input'), 'test@example.com');
await user.type(screen.getByTestId('password-input'), 'wrongpassword');
await user.click(screen.getByTestId('submit-button'));
await waitFor(() => {
expect(screen.getByTestId('error-message')).toHaveTextContent('Invalid credentials');
});
});
it('renders forgot password button when handler provided', () => {
render(<LoginForm onSubmit={mockOnSubmit} onForgotPassword={mockOnForgotPassword} />);
expect(screen.getByTestId('forgot-password')).toBeInTheDocument();
});
it('does not render forgot password button when handler not provided', () => {
render(<LoginForm onSubmit={mockOnSubmit} />);
expect(screen.queryByTestId('forgot-password')).not.toBeInTheDocument();
});
it('calls onForgotPassword when clicked', async () => {
const user = userEvent.setup();
render(<LoginForm onSubmit={mockOnSubmit} onForgotPassword={mockOnForgotPassword} />);
await user.click(screen.getByTestId('forgot-password'));
expect(mockOnForgotPassword).toHaveBeenCalled();
});
});
E2E Testing with Playwright
Generating User Flow Tests Ask Antigravity: "Generate Playwright E2E tests for user authentication flow"
// e2e/auth.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Authentication Flow', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test('should display login form', async ({ page }) => {
await page.click('[data-testid="login-button"]');
await expect(page.locator('[data-testid="login-form"]')).toBeVisible();
});
test('should login successfully with valid credentials', async ({ page }) => {
await page.click('[data-testid="login-button"]');
await page.fill('[data-testid="email-input"]', 'test@example.com');
await page.fill('[data-testid="password-input"]', 'ValidPass123');
await page.click('[data-testid="submit-button"]');
await expect(page.locator('[data-testid="user-menu"]')).toBeVisible();
await expect(page).toHaveURL('/dashboard');
});
test('should show error for invalid credentials', async ({ page }) => {
await page.click('[data-testid="login-button"]');
await page.fill('[data-testid="email-input"]', 'wrong@example.com');
await page.fill('[data-testid="password-input"]', 'wrongpassword');
await page.click('[data-testid="submit-button"]');
await expect(page.locator('[data-testid="error-message"]')).toContainText('Invalid');
});
test('should redirect to login when accessing protected route', async ({ page }) => {
await page.goto('/dashboard');
await expect(page).toHaveURL('/login?redirect=/dashboard');
});
test('should logout successfully', async ({ page }) => {
// Login first
await page.click('[data-testid="login-button"]');
await page.fill('[data-testid="email-input"]', 'test@example.com');
await page.fill('[data-testid="password-input"]', 'ValidPass123');
await page.click('[data-testid="submit-button"]');
// Wait for login
await expect(page.locator('[data-testid="user-menu"]')).toBeVisible();
// Logout
await page.click('[data-testid="user-menu"]');
await page.click('[data-testid="logout-button"]');
await expect(page.locator('[data-testid="login-button"]')).toBeVisible();
await expect(page).toHaveURL('/');
});
});
Test-Driven Development (TDD) Workflow
Step 1: Describe What You Want You: "I need a shopping cart module that can add items, remove items, calculate totals, and apply discount codes"
Step 2: Antigravity Generates Tests First // cart/__tests__/cart.test.ts
import { describe, it, expect, beforeEach } from 'vitest';
import { Cart, CartItem } from '../cart';
describe('Cart', () => {
let cart: Cart;
beforeEach(() => {
cart = new Cart();
});
describe('addItem', () => {
it('should add a new item to cart', () => {
cart.addItem({ id: '1', name: 'Product', price: 10, quantity: 1 });
expect(cart.items).toHaveLength(1);
});
it('should increase quantity for existing item', () => {
cart.addItem({ id: '1', name: 'Product', price: 10, quantity: 1 });
cart.addItem({ id: '1', name: 'Product', price: 10, quantity: 2 });
expect(cart.items).toHaveLength(1);
expect(cart.items[0].quantity).toBe(3);
});
});
describe('removeItem', () => {
it('should remove item from cart', () => {
cart.addItem({ id: '1', name: 'Product', price: 10, quantity: 1 });
cart.removeItem('1');
expect(cart.items).toHaveLength(0);
});
it('should throw for non-existent item', () => {
expect(() => cart.removeItem('999')).toThrow('Item not found');
});
});
describe('getTotal', () => {
it('should calculate total correctly', () => {
cart.addItem({ id: '1', name: 'A', price: 10, quantity: 2 });
cart.addItem({ id: '2', name: 'B', price: 15, quantity: 1 });
expect(cart.getTotal()).toBe(35);
});
it('should return 0 for empty cart', () => {
expect(cart.getTotal()).toBe(0);
});
});
describe('applyDiscount', () => {
it('should apply percentage discount', () => {
cart.addItem({ id: '1', name: 'A', price: 100, quantity: 1 });
cart.applyDiscount({ code: 'SAVE10', type: 'percentage', value: 10 });
expect(cart.getTotal()).toBe(90);
});
it('should apply fixed discount', () => {
cart.addItem({ id: '1', name: 'A', price: 100, quantity: 1 });
cart.applyDiscount({ code: 'SAVE20', type: 'fixed', value: 20 });
expect(cart.getTotal()).toBe(80);
});
it('should not allow total below zero', () => {
cart.addItem({ id: '1', name: 'A', price: 10, quantity: 1 });
cart.applyDiscount({ code: 'BIG', type: 'fixed', value: 100 });
expect(cart.getTotal()).toBe(0);
});
});
});
Step 3: Implement to Pass Tests You: "Now implement the Cart class to pass all these tests"
// cart/cart.ts
export interface CartItem {
id: string;
name: string;
price: number;
quantity: number;
}
export interface Discount {
code: string;
type: 'percentage' | 'fixed';
value: number;
}
export class Cart {
items: CartItem[] = [];
private discount: Discount | null = null;
addItem(item: CartItem): void {
const existing = this.items.find(i => i.id === item.id);
if (existing) {
existing.quantity += item.quantity;
} else {
this.items.push({ ...item });
}
}
removeItem(id: string): void {
const index = this.items.findIndex(i => i.id === id);
if (index === -1) {
throw new Error('Item not found');
}
this.items.splice(index, 1);
}
getTotal(): number {
const subtotal = this.items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);
if (!this.discount) return subtotal;
let total: number;
if (this.discount.type === 'percentage') {
total = subtotal * (1 - this.discount.value / 100);
} else {
total = subtotal - this.discount.value;
}
return Math.max(0, total);
}
applyDiscount(discount: Discount): void {
this.discount = discount;
}
}
GEMINI.md Testing Configuration Add testing context to your project:
# Testing Configuration
## Framework
- Unit/Integration: Vitest
- E2E: Playwright
- Coverage target: 80%
## Conventions
- Test files: `*.test.ts` next to source
- E2E tests: `/e2e` directory
- Use data-testid for E2E selectors
## When Generating Tests
- Include edge cases
- Test error conditions
- Mock external dependencies
- Use descriptive test names
- Follow AAA pattern (Arrange, Act, Assert)
Running Tests in Antigravity
Integrated Terminal # Run all tests
npm test
# Run with coverage
npm test -- --coverage
# Run E2E tests
npx playwright test
# Run specific test file
npm test -- validation.test.ts
Keyboard Shortcuts
Cmd+Shift+T - Run tests for current file
Cmd+Shift+R - Run last test
Cmd+; - Toggle test panel
Conclusion Google Antigravity transforms testing from a chore into an efficient workflow. By leveraging Gemini 3's understanding of your code, you can:
Generate comprehensive test suites instantly
Follow TDD naturally
Maintain tests as code evolves
Catch edge cases you'd miss manually
Configure your testing framework
Add testing context to GEMINI.md
Ask Antigravity to generate tests
Review and refine the output
Quality tests lead to quality code. Let AI handle the boilerplate while you focus on the logic.
Link Slot Gacor Mahjong333 Link Alternatif Resmi