Coding Assessment: Building a Blogging Application
Topic: Build a TypeScript-based blogging application with a client side (viewing/filtering posts) and an admin side (creating/modifying posts). You will implement core features and write unit tests using Vitest or Playwright and end-to-end tests using Playwright.
Please fork and clone this repository and continue with instructions below:
🎯 Goals
- Use both unit testing strategies to test your approach (Reacy-Testing-Library vs Playwright).
- Write all necessary End-to-End tests
- Try to achieve 100% coverage across the whole app. You can visualise your coverage in the vitest UI.

Narrative
You’re a developer at BlogSphere, a startup creating a platform for writers. Your task is to build a blogging app where users can browse posts (filtered by date or tag) and admins can manage content. Your code must be reliable, so you’ll write tests to ensure everything works. This project mirrors real-world full-stack development, teaching you React, TypeScript, routing, and testing.
Assessment Overview:
- Client Side: Users can view a list of posts, filter by date (newest/oldest), or filter by tag (e.g., “tech,” “lifestyle”).
- Admin Side: Admins can create new posts or edit existing ones via a form.
- Tech Stack: React, TypeScript, React Router, Vitest (unit tests), Playwright (E2E tests).
- Deliverables: Complete the provided starter code and write tests to verify functionality.
Background
1. Vitest + Testing Library with JSDOM
What is it?
- Vitest: A fast, modern testing framework optimized for Vite-based projects (like our TypeScript blogging app).
- Testing Library: A library for testing UI components by simulating user interactions (e.g., clicking, typing).
- JSDOM: A JavaScript implementation of the DOM, allowing tests to run in a Node.js environment without a real browser.
How it works: You write tests to render React components in a simulated DOM (JSDOM), interact with them (e.g., click a button), and assert outcomes (e.g., a post appears).
Example (Testing a PostList component):
import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import PostList from './PostList';
describe('PostList', () => {
it('renders posts correctly', () => {
const posts = [{ id: 1, title: 'First Post', date: '2025-04-13' }];
render(<PostList posts={posts} />);
expect(screen.getByText('First Post')).toBeInTheDocument();
});
});
Advantages:
- Speed: Tests run in Node.js, so they’re faster than browser-based tests. No need to launch a browser.
- Simplicity: Testing Library encourages user-centric testing, focusing on what users see and do (e.g., “click the publish button”).
- Lightweight Setup: No browser dependencies, ideal for CI/CD pipelines.
- Great for Unit Tests: Perfect for isolating components (e.g., testing a PostFilter component without rendering the whole app).
Disadvantages:
- Not a Real Browser: JSDOM mimics the DOM but isn’t perfect. It may miss browser-specific quirks (e.g., CSS rendering, native events).
- Limited End-to-End Testing: JSDOM focuses on components, not full app flows (e.g., navigating from a post to a tag-filtered view).
- Mocking Overhead: Complex interactions (e.g., drag-and-drop, animations) often require mocks, which can be brittle.
Pitfalls:
- Over-Mocking: Students sometimes mock too much (e.g., APIs, hooks), leading to tests that pass but don’t reflect reality.
- JSDOM Limitations: Subtle bugs (e.g., focus management, media queries) may slip through because JSDOM doesn’t fully replicate browsers.
- Learning Curve: Testing Library’s philosophy (“test like a user”) can feel abstract for beginners.
2. Playwright Component Testing
What is it?
- Playwright: A browser automation tool (like Puppeteer) that also supports component testing.
- Component Testing: Renders React components in a real browser (e.g., Chromium, Firefox) using Playwright’s API, combining unit testing with browser realism.
How it works: You mount a component in a browser, interact with it using Playwright’s methods (e.g., click
, fill
), and assert results. It’s like Vitest but in a real browser environment.
Example (Testing the same PostList component):
import { test, expect } from '@playwright/experimental-ct-react';
import PostList from './PostList';
test('renders posts correctly', async ({ mount }) => {
const posts = [{ id: 1, title: 'First Post', date: '2025-04-13' }];
const component = await mount(<PostList posts={posts} />);
await expect(component.getByText('First Post')).toBeVisible();
});
Advantages:
- Real Browser Environment: Tests run in Chromium, Firefox, or WebKit, catching browser-specific bugs (e.g., rendering, events).
- End-to-End Capabilities: Playwright can test full app flows (e.g., admin creating a post, then viewing it as a user), unlike JSDOM’s component focus.
- Rich Interactions: Native support for complex actions (e.g., file uploads, hover states) without mocking.
- Debugging Power: Built-in tools like screenshots, videos, and browser dev tools make debugging intuitive.
Disadvantages:
- Slower: Launching a browser takes time, making tests slower than JSDOM (e.g., 100ms vs. 10ms per test).
- Heavier Setup: Requires installing browser binaries, which can complicate CI/CD or student laptops.
- Less Isolated: Browser tests may inadvertently test more than intended (e.g., global styles affecting a component).
- Overkill for Simple Tests: For small, isolated components (e.g., a Button), a full browser may be unnecessary.
Pitfalls:
- Flakiness: Browser tests can fail due to timing issues (e.g., animations, network delays), frustrating beginners.
- Resource Intensive: Running many tests in parallel eats CPU/memory, slowing down development.
- Temptation to Over-Test: Students may write overly broad tests (e.g., testing navigation in a component test), blurring unit vs. E2E lines.
When to Use Each?
- Vitest + Testing Library (JSDOM):
- Best for unit testing individual components (e.g., PostList, FilterByTag).
- Ideal for fast feedback during development.
- Use when testing logic-heavy components (e.g., a date sorter) or when browser quirks are unlikely.
- Example: In our blogging app, use it to test the AdminForm’s validation logic.
- Playwright Component Testing:
- Best for integration testing components with browser-specific behaviour (e.g., CSS transitions, focus trapping).
- Ideal for critical user flows (e.g., ensuring the “Publish Post” button works across browsers).
- Use when you need confidence in production-like environments.
- Example: In our blogging app, use it to test the PostList’s tag-filtering UI across Chromium and Firefox.
- Playwright End-To-End testing
- Best for final system tests, when all parts of the application are running
- Use when you need confidence during production deployments.
- Example: In our blogging app, before every deploy
Practical Tips for Our Blogging App
For your coding assessment (building the blogging app), you’ll write tests for both the client (e.g., filtering posts by date) and admin (e.g., creating posts). Here’s how to approach testing:
- Use Vitest + Testing Library to test components like PostList or AdminForm in isolation. For example, ensure PostList renders posts sorted by date.
- Use Playwright to test flows like “admin publishes a post, then views it on the client side.” This catches real-world issues (e.g., browser rendering).
- Combine Both: Write fast Vitest unit tests for logic, then selective Playwright tests for key interactions. This balances speed and reliability.
Conclusion
Both Vitest with Testing Library and Playwright component testing are powerful, but they serve different needs. Vitest is your go-to for quick, isolated tests, while Playwright shines for browser-realistic scenarios. In our blogging app, you’ll use both: Vitest to ensure your PostFilter logic works, and Playwright to verify the user experience across browsers. Avoid pitfalls like over-mocking in JSDOM or flaky Playwright tests by keeping tests focused and well-structured.