Skip to content

Commit cdb4452

Browse files
committed
feat: integrate blog system with homepage preview section
1 parent 39ea7e4 commit cdb4452

14 files changed

Lines changed: 793 additions & 105 deletions
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { BlogPreviewSection } from '@/components/sections/blog-preview-section';
3+
import { BlogPost } from '@/types';
4+
5+
// Mock blog posts data
6+
const mockPosts: BlogPost[] = [
7+
{
8+
title: 'Building Offline-First Apps',
9+
slug: 'building-offline-first-apps',
10+
date: new Date('2025-01-15'),
11+
excerpt: 'Real-time synchronization strategies for mobile applications',
12+
tags: ['React Native', 'Offline', 'Sync'],
13+
category: 'Mobile Development',
14+
content: '',
15+
readingTime: 8,
16+
published: true
17+
},
18+
{
19+
title: 'Microservices Architecture Patterns',
20+
slug: 'microservices-architecture-patterns',
21+
date: new Date('2025-01-10'),
22+
excerpt: 'Best practices for designing scalable microservices',
23+
tags: ['Microservices', 'Architecture', 'Scalability'],
24+
category: 'Backend Development',
25+
content: '',
26+
readingTime: 12,
27+
published: true
28+
},
29+
{
30+
title: 'Modern CSS Techniques',
31+
slug: 'modern-css-techniques',
32+
date: new Date('2025-01-05'),
33+
excerpt: 'Advanced CSS features for modern web development',
34+
tags: ['CSS', 'Frontend', 'Web Development'],
35+
category: 'Frontend Development',
36+
content: '',
37+
readingTime: 6,
38+
published: true
39+
}
40+
];
41+
42+
describe('BlogPreviewSection', () => {
43+
it('renders section header "Latest Blog Posts"', () => {
44+
render(<BlogPreviewSection posts={mockPosts} />);
45+
46+
expect(screen.getByText('Latest Blog Posts')).toBeInTheDocument();
47+
});
48+
49+
it('renders 3 latest blog posts', () => {
50+
render(<BlogPreviewSection posts={mockPosts} />);
51+
52+
expect(screen.getByText('Building Offline-First Apps')).toBeInTheDocument();
53+
expect(screen.getByText('Microservices Architecture Patterns')).toBeInTheDocument();
54+
expect(screen.getByText('Modern CSS Techniques')).toBeInTheDocument();
55+
});
56+
57+
it('renders "View All Posts" link', () => {
58+
render(<BlogPreviewSection posts={mockPosts} />);
59+
60+
const viewAllLink = screen.getByRole('link', { name: /view all posts/i });
61+
expect(viewAllLink).toBeInTheDocument();
62+
expect(viewAllLink).toHaveAttribute('href', '/blog');
63+
});
64+
65+
it('renders blog post cards with correct structure', () => {
66+
render(<BlogPreviewSection posts={mockPosts} />);
67+
68+
const blogCards = screen.getAllByTestId('blog-post-card');
69+
expect(blogCards).toHaveLength(3);
70+
});
71+
72+
it('displays blog post excerpts', () => {
73+
render(<BlogPreviewSection posts={mockPosts} />);
74+
75+
expect(screen.getByText('Real-time synchronization strategies for mobile applications')).toBeInTheDocument();
76+
expect(screen.getByText('Best practices for designing scalable microservices')).toBeInTheDocument();
77+
expect(screen.getByText('Advanced CSS features for modern web development')).toBeInTheDocument();
78+
});
79+
80+
it('displays blog post categories', () => {
81+
render(<BlogPreviewSection posts={mockPosts} />);
82+
83+
expect(screen.getByText('Mobile Development')).toBeInTheDocument();
84+
expect(screen.getByText('Backend Development')).toBeInTheDocument();
85+
expect(screen.getByText('Frontend Development')).toBeInTheDocument();
86+
});
87+
88+
it('displays reading time for each post', () => {
89+
render(<BlogPreviewSection posts={mockPosts} />);
90+
91+
expect(screen.getByText('8 min read')).toBeInTheDocument();
92+
expect(screen.getByText('12 min read')).toBeInTheDocument();
93+
expect(screen.getByText('6 min read')).toBeInTheDocument();
94+
});
95+
96+
it('has responsive grid layout', () => {
97+
render(<BlogPreviewSection posts={mockPosts} />);
98+
99+
const container = screen.getByTestId('blog-preview-grid');
100+
expect(container).toHaveClass('grid', 'grid-cols-1', 'md:grid-cols-2', 'lg:grid-cols-3');
101+
});
102+
103+
it('follows homepage section styling patterns', () => {
104+
render(<BlogPreviewSection posts={mockPosts} />);
105+
106+
const section = screen.getByTestId('blog-preview-section');
107+
expect(section).toHaveClass('py-20', 'bg-[#ffffff]', 'dark:bg-[#0d1117]');
108+
});
109+
110+
it('has proper section container with max width', () => {
111+
render(<BlogPreviewSection posts={mockPosts} />);
112+
113+
const container = screen.getByTestId('blog-preview-container');
114+
expect(container).toHaveClass('max-w-6xl', 'mx-auto', 'px-4');
115+
});
116+
117+
it('uses correct typography for section header', () => {
118+
render(<BlogPreviewSection posts={mockPosts} />);
119+
120+
const header = screen.getByText('Latest Blog Posts');
121+
expect(header).toHaveClass('font-mono', 'text-[2rem]', 'md:text-[2.5rem]', 'font-semibold');
122+
});
123+
124+
it('handles empty posts array gracefully', () => {
125+
render(<BlogPreviewSection posts={[]} />);
126+
127+
expect(screen.getByText('Latest Blog Posts')).toBeInTheDocument();
128+
expect(screen.getByText('View All Posts')).toBeInTheDocument();
129+
expect(screen.queryByTestId('blog-post-card')).not.toBeInTheDocument();
130+
});
131+
});
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { render, screen } from '@testing-library/react';
2+
import Home from '../page';
3+
4+
describe('Homepage Blog Integration', () => {
5+
it('renders blog preview section on homepage', () => {
6+
render(<Home />);
7+
8+
expect(screen.getByText('Latest Blog Posts')).toBeInTheDocument();
9+
});
10+
11+
it('displays 3 latest blog posts on homepage', () => {
12+
render(<Home />);
13+
14+
expect(screen.getByText('Building Offline-First Apps')).toBeInTheDocument();
15+
expect(screen.getByText('Microservices Architecture Patterns')).toBeInTheDocument();
16+
expect(screen.getByText('Modern CSS Techniques')).toBeInTheDocument();
17+
});
18+
19+
it('shows "View All Posts" link on homepage', () => {
20+
render(<Home />);
21+
22+
const viewAllLink = screen.getByRole('link', { name: /view all posts/i });
23+
expect(viewAllLink).toBeInTheDocument();
24+
expect(viewAllLink).toHaveAttribute('href', '/blog');
25+
});
26+
27+
it('displays blog post excerpts on homepage', () => {
28+
render(<Home />);
29+
30+
expect(screen.getByText('Real-time synchronization strategies for mobile applications')).toBeInTheDocument();
31+
expect(screen.getByText('Best practices for designing scalable microservices')).toBeInTheDocument();
32+
expect(screen.getByText('Advanced CSS features for modern web development')).toBeInTheDocument();
33+
});
34+
35+
it('shows blog post categories on homepage', () => {
36+
render(<Home />);
37+
38+
expect(screen.getByText('Mobile Development')).toBeInTheDocument();
39+
expect(screen.getByText('Backend Development')).toBeInTheDocument();
40+
expect(screen.getByText('Frontend Development')).toBeInTheDocument();
41+
});
42+
43+
it('displays reading time for each blog post on homepage', () => {
44+
render(<Home />);
45+
46+
expect(screen.getByText('8 min read')).toBeInTheDocument();
47+
expect(screen.getByText('12 min read')).toBeInTheDocument();
48+
expect(screen.getByText('6 min read')).toBeInTheDocument();
49+
});
50+
51+
it('maintains proper section order on homepage', () => {
52+
render(<Home />);
53+
54+
// Check that blog section appears after Professional Journey and before Contact
55+
const sections = screen.getAllByRole('region');
56+
const blogSection = screen.getByText('Latest Blog Posts').closest('section');
57+
const contactSection = screen.getByText('Available for new opportunities').closest('section');
58+
59+
expect(blogSection).toBeInTheDocument();
60+
expect(contactSection).toBeInTheDocument();
61+
});
62+
63+
it('blog preview cards have proper hover effects', () => {
64+
render(<Home />);
65+
66+
const blogCards = screen.getAllByTestId('blog-post-card');
67+
expect(blogCards).toHaveLength(3);
68+
69+
// Check that cards have the expected hover classes
70+
blogCards.forEach(card => {
71+
expect(card).toHaveClass('hover:border-l-8', 'transition-all');
72+
});
73+
});
74+
75+
it('blog section follows homepage design patterns', () => {
76+
render(<Home />);
77+
78+
const blogSection = screen.getByText('Latest Blog Posts').closest('section');
79+
expect(blogSection).toHaveClass('py-20', 'bg-[#ffffff]', 'dark:bg-[#0d1117]');
80+
});
81+
82+
it('blog section has responsive grid layout', () => {
83+
render(<Home />);
84+
85+
const grid = screen.getByTestId('blog-preview-grid');
86+
expect(grid).toHaveClass('grid', 'grid-cols-1', 'md:grid-cols-2', 'lg:grid-cols-3');
87+
});
88+
89+
it('blog section header uses correct typography', () => {
90+
render(<Home />);
91+
92+
const header = screen.getByText('Latest Blog Posts');
93+
expect(header).toHaveClass('font-mono', 'text-[2rem]', 'md:text-[2.5rem]', 'font-semibold');
94+
});
95+
});

0 commit comments

Comments
 (0)