agent-rules-kit
Version:
CLI tool to bootstrap AI agent rules for multiple IDEs and frameworks. Generates optimized rules for Cursor, VS Code, Claude, and 6+ other AI coding assistants.
230 lines (175 loc) • 6.57 kB
Markdown
---
title: Astro Testing Best Practices
description: Guidelines for testing Astro projects effectively
tags: [Astro, Testing, Best Practices]
always: true
---
Testing in Astro projects typically involves multiple testing types and levels:
1. **Unit Testing**: Testing individual components and utility functions
2. **Integration Testing**: Testing how components work together
3. **End-to-End Testing**: Testing complete user flows
4. **Visual Regression Testing**: Ensuring UI consistency
1. **Vitest**: For unit and integration testing
2. **Playwright**: For end-to-end testing
3. **Astro Testing Library**: For component testing
4. **Storybook**: For component development and visual testing
```typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config';
import { svelte } from '@sveltejs/vite-plugin-svelte';
export default defineConfig({
plugins: [svelte()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './tests/setup.js',
include: ['src/**/*.{test,spec}.{js,ts,jsx,tsx}'],
exclude: ['node_modules', 'dist', '.idea', '.git', '.cache'],
},
});
```
When testing Astro components:
1. **Focus on functionality**: Test what the component does, not implementation details
2. **Mock external dependencies**: Use dependency injection and mocks
3. **Test props and slots**: Ensure the component renders correctly with different inputs
Example of testing an Astro component with Vitest and Astro Testing Library:
```typescript
// Button.test.ts
import { render } from '@testing-library/svelte';
import { describe, it, expect } from 'vitest';
import Button from '../src/components/Button.astro';
describe('Button Component', () => {
it('renders with the correct text', async () => {
const { getByText } = await render(Button, {
props: { text: 'Click me' },
});
expect(getByText('Click me')).toBeTruthy();
});
it('applies the correct class based on variant prop', async () => {
const { getByRole } = await render(Button, {
props: { text: 'Submit', variant: 'primary' },
});
const button = getByRole('button');
expect(button.classList.contains('btn-primary')).toBe(true);
});
});
```
For utility functions:
1. **Test pure functions extensively**: Cover edge cases
2. **Use parameterized tests**: Test multiple inputs with the same logic
3. **Test error handling**: Ensure proper error responses
```typescript
// formatDate.test.ts
import { describe, it, expect } from 'vitest';
import { formatDate } from '../src/utils/formatDate';
describe('formatDate utility', () => {
it('formats dates correctly', () => {
expect(formatDate(new Date('2023-04-15'))).toBe('April 15, 2023');
});
it('handles invalid dates', () => {
expect(() => formatDate('not a date')).toThrow();
});
});
```
For integration tests:
1. **Focus on component interactions**: Test how components work together
2. **Mock external API calls**: Use MSW or similar tools
3. **Test user flows**: Ensure components interact correctly based on user actions
```typescript
// BlogLayout.test.ts
import { render, screen } from '@testing-library/svelte';
import { describe, it, expect, vi } from 'vitest';
import BlogLayout from '../src/layouts/BlogLayout.astro';
import { mockPost } from '../mocks/data';
// Mock fetch calls
vi.mock('../src/utils/api', () => ({
fetchRelatedPosts: vi.fn().mockResolvedValue([mockPost]),
}));
describe('BlogLayout Integration', () => {
it('renders blog post with related posts', async () => {
await render(BlogLayout, {
props: { post: mockPost },
});
// Check main content rendered
expect(screen.getByText(mockPost.title)).toBeTruthy();
// Check related posts section
expect(screen.getByText('Related Posts')).toBeTruthy();
expect(screen.getByText(mockPost.title)).toBeTruthy();
});
});
```
For E2E tests with Playwright:
1. **Test critical user flows**: Focus on key user journeys
2. **Test across browsers**: Use multiple browser contexts
3. **Take screenshots for visual verification**: Capture UI state at key points
```typescript
// navigation.spec.ts
import { test, expect } from '@playwright/test';
test('navigation works correctly', async ({ page }) => {
// Start from the homepage
await page.goto('/');
// Navigate to the about page
await page.click('text=About');
await expect(page).toHaveURL('/about');
// Check content loaded
await expect(page.locator('h1')).toHaveText('About Us');
// Navigate to blog
await page.click('text=Blog');
await expect(page).toHaveURL('/blog');
// Check blog posts are loaded
await expect(page.locator('.blog-post')).toHaveCount.greaterThan(0);
});
```
When testing content collections:
1. **Test schema validation**: Ensure content matches defined schemas
2. **Test content queries**: Verify filtering and sorting work correctly
3. **Mock getCollection responses**: For testing components that consume collections
```typescript
// contentCollection.test.ts
import { describe, it, expect, vi } from 'vitest';
import { getCollection } from 'astro:content';
// Mock the content collection
vi.mock('astro:content', () => ({
getCollection: vi.fn().mockResolvedValue([
{
id: 'post-1',
slug: 'post-1',
data: {
title: 'Test Post',
date: new Date('2023-01-01'),
},
},
]),
}));
describe('Blog Collection', () => {
it('retrieves and sorts blog posts', async () => {
const posts = await getCollection('blog');
expect(posts).toHaveLength(1);
expect(posts[0].data.title).toBe('Test Post');
});
});
```
1. **Write Tests First**: Use TDD when possible
2. **Keep Tests Independent**: Each test should run in isolation
3. **Use CI/CD Integration**: Run tests automatically on every pull request
4. **Test Accessibility**: Include accessibility checks in your tests
5. **Optimize Test Speed**: Balance coverage with execution time
6. **Regularly Review Test Coverage**: Identify and fill testing gaps
1. **Testing Implementation Details**: Focus on behavior, not internal logic
2. **Brittle Selectors**: Use data-testid or accessible selectors
3. **Slow Tests**: Mock external dependencies and optimize test runs
4. **Insufficient Mocking**: Properly mock external services and APIs
5. **Ignoring Edge Cases**: Test error states and boundary conditions