You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5.0 KiB
5.0 KiB
MSW Testing Guide - Simplified
Clean, composable mock server setup with just 2 patterns.
Quick Start
import {mockServer, mockData} from '../utils/msw-helpers';
// 90% of cases - just declare what data you want
mockServer.setup({
posts: [mockData.post({title: 'My Post'})],
feedback: [{id: '1', score: 1, message: 'Great!'}]
});
The Two Patterns
Pattern 1: Declarative Data (90% of cases)
Just arrays of data for Ghost API endpoints:
mockServer.setup({
posts: [
mockData.post({title: 'Post 1'}),
mockData.post({title: 'Post 2'})
],
feedback: [
{id: '1', score: 1, message: 'Great!'},
{id: '2', score: 0, message: 'Needs work'}
],
links: [], // Empty array = no results
newsletterBasicStats: [{post_id: 'post-1', open_rate: 0.3}]
});
Available endpoints:
posts→/ghost/api/admin/posts/*feedback→/ghost/api/admin/feedback/*links→/ghost/api/admin/links/newsletterBasicStats→/ghost/api/admin/stats/newsletter-basic-stats/newsletterClickStats→/ghost/api/admin/stats/newsletter-click-stats/
Pattern 2: Custom Handlers (10% of cases)
For everything complex - errors, external APIs, conditional logic:
import {endpoint, when} from '../utils/msw-helpers';
mockServer.setup({
// Standard data
posts: [mockData.post()],
// Complex scenarios go in customHandlers
customHandlers: [
// External APIs
endpoint.get('/api/external', {data: 'test'}),
endpoint.post('/api/webhook', {success: true}, 201),
// Error scenarios
endpoint.get('/ghost/api/admin/posts/*', {error: 'Server error'}, 500),
// Conditional responses
when('get', '/ghost/api/admin/feedback/*', [
{if: req => req.url.includes('score=1'), response: {feedback: positiveFeedback}},
{if: req => req.url.includes('score=0'), response: {feedback: negativeFeedback}}
], {feedback: []})
]
});
Practical Examples
Basic Hook Testing
test('loads post data', () => {
mockServer.setup({
posts: [mockData.post({id: 'test-id', title: 'Test Post'})]
});
const {result} = renderHook(() => usePost('test-id'), {
wrapper: createTestWrapper()
});
expect(result.current.data?.title).toBe('Test Post');
});
Error Scenarios
test('handles server errors', () => {
mockServer.setup({
customHandlers: [
endpoint.get('/ghost/api/admin/posts/*', {error: 'Server error'}, 500)
]
});
// Test error handling...
});
Complex Component Testing
test('PostAnalytics with full data', () => {
mockServer.setup({
posts: [mockData.post({
id: 'post-1',
count: {clicks: 100, positive_feedback: 5, negative_feedback: 2}
})],
feedback: [
{id: '1', score: 1, message: 'Great!'},
{id: '2', score: 0, message: 'Needs work'}
],
links: [
{id: 'link-1', clicks: 50, link: {title: 'Link', to: '/page'}}
]
});
render(<PostAnalytics postId="post-1" />, {wrapper: createTestWrapper()});
// Assertions...
});
Reusable Test Scenarios
// Store scenarios as plain objects
const successScenario = {
posts: [mockData.post({title: 'Success Post'})],
feedback: [{id: '1', score: 1, message: 'Good!'}]
};
const errorScenario = {
customHandlers: [
endpoint.get('/ghost/api/admin/posts/*', {error: 'Failed'}, 500)
]
};
// Reuse across tests
test('success case', () => {
mockServer.setup(successScenario);
// Test...
});
test('error case', () => {
mockServer.setup(errorScenario);
// Test...
});
// Compose scenarios
test('mixed case', () => {
mockServer.setup({
...successScenario,
customHandlers: [
endpoint.get('/api/external', {data: 'external'})
]
});
// Test...
});
Built-in Defaults
These are automatically included in every test:
site- Basic site infoconfig- App configurationsettings- Ghost settingstinybirdToken- Analytics token
Override if needed:
mockServer.setup({
site: {url: 'https://custom.com', title: 'Custom Site'},
config: {stats: {enabled: false}}
});
Mock Data Factories
Use mockData for consistent test data:
// With defaults
mockData.post() // → {id: 'test-post-id', title: 'Test Post', ...}
// With overrides
mockData.post({title: 'Custom Title', count: {clicks: 999}})
// Direct arrays (when you need simple data)
const posts = [
{id: '1', title: 'Post 1'},
{id: '2', title: 'Post 2'}
];
Quick Helper
For PostAnalyticsProvider tests:
import {setupPostAnalyticsProvider} from '../utils/msw-helpers';
test('with analytics provider', () => {
setupPostAnalyticsProvider('my-post-id');
// Provider will have post data available
});