Skip to content

Commit c303361

Browse files
committed
Implement and debug case study list and item view page e2e tests
1 parent 31e1e0b commit c303361

7 files changed

Lines changed: 411 additions & 132 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
title: "Getting Started with Astro"
3+
description: "Learn the fundamentals of building fast, content-focused websites with Astro"
4+
author: kevin-firko
5+
tags: ["typescript", "cms"]
6+
image:
7+
src: "/assets/images/placeholder-article.jpg"
8+
alt: "Getting Started with Astro"
9+
publishDate: 2024-01-15
10+
isDraft: false
11+
featured: true
12+
---
13+
14+
## Introduction
15+
16+
Astro is a modern static site builder that delivers lightning-fast performance by shipping zero JavaScript by default. This guide will help you get started with Astro and understand its core concepts.
17+
18+
## Why Choose Astro?
19+
20+
Astro offers several advantages for building content-focused websites:
21+
22+
- **Zero JavaScript by Default**: Only ship the JavaScript you need
23+
- **Framework Agnostic**: Use React, Vue, Svelte, or any framework
24+
- **Built-in Optimizations**: Automatic image optimization, CSS bundling, and more
25+
- **Island Architecture**: Interactive components load independently
26+
27+
## Getting Started
28+
29+
To create a new Astro project, run:
30+
31+
```bash
32+
npm create astro@latest
33+
```
34+
35+
Follow the prompts to set up your project with your preferred configuration.
36+
37+
## Project Structure
38+
39+
A typical Astro project structure looks like this:
40+
41+
```
42+
/
43+
├── public/
44+
│ └── favicon.svg
45+
├── src/
46+
│ ├── components/
47+
│ ├── layouts/
48+
│ └── pages/
49+
└── astro.config.mjs
50+
```
51+
52+
## Creating Your First Page
53+
54+
Pages in Astro are created in the `src/pages` directory. Here's a simple example:
55+
56+
```astro
57+
---
58+
const title = "My First Astro Page"
59+
---
60+
61+
<html>
62+
<head>
63+
<title>{title}</title>
64+
</head>
65+
<body>
66+
<h1>Welcome to Astro!</h1>
67+
</body>
68+
</html>
69+
```
70+
71+
## Conclusion
72+
73+
Astro provides a powerful foundation for building fast, modern websites. Its component-based architecture and performance optimizations make it an excellent choice for content-focused sites.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
---
2+
title: "TypeScript Best Practices for Modern Development"
3+
description: "Essential TypeScript patterns and practices to write safer, more maintainable code"
4+
author: kevin-firko
5+
tags: ["typescript", "code"]
6+
image:
7+
src: "/assets/images/placeholder-article.jpg"
8+
alt: "TypeScript Best Practices"
9+
publishDate: 2024-02-20
10+
isDraft: false
11+
featured: false
12+
---
13+
14+
## Introduction
15+
16+
TypeScript has become the standard for building scalable JavaScript applications. This guide covers essential best practices for writing clean, type-safe TypeScript code.
17+
18+
## Type Safety First
19+
20+
Always leverage TypeScript's type system to catch errors at compile time:
21+
22+
```typescript
23+
// Good: Explicit types
24+
interface User {
25+
id: string
26+
name: string
27+
email: string
28+
}
29+
30+
function getUser(id: string): User {
31+
// Implementation
32+
}
33+
34+
// Avoid: Using 'any'
35+
function processData(data: any) {
36+
// Type safety lost
37+
}
38+
```
39+
40+
## Use Strict Mode
41+
42+
Enable strict mode in your `tsconfig.json`:
43+
44+
```json
45+
{
46+
"compilerOptions": {
47+
"strict": true,
48+
"noImplicitAny": true,
49+
"strictNullChecks": true
50+
}
51+
}
52+
```
53+
54+
## Utility Types
55+
56+
TypeScript provides powerful utility types:
57+
58+
```typescript
59+
// Partial - makes all properties optional
60+
type PartialUser = Partial<User>
61+
62+
// Pick - select specific properties
63+
type UserPreview = Pick<User, 'name' | 'email'>
64+
65+
// Omit - exclude specific properties
66+
type UserWithoutId = Omit<User, 'id'>
67+
```
68+
69+
## Discriminated Unions
70+
71+
Use discriminated unions for type-safe state management:
72+
73+
```typescript
74+
type LoadingState =
75+
| { status: 'idle' }
76+
| { status: 'loading' }
77+
| { status: 'success'; data: User[] }
78+
| { status: 'error'; error: string }
79+
80+
function renderState(state: LoadingState) {
81+
switch (state.status) {
82+
case 'loading':
83+
return 'Loading...'
84+
case 'success':
85+
return state.data.map(user => user.name)
86+
case 'error':
87+
return state.error
88+
default:
89+
return null
90+
}
91+
}
92+
```
93+
94+
## Generic Constraints
95+
96+
Use generic constraints to create flexible, type-safe functions:
97+
98+
```typescript
99+
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
100+
return obj[key]
101+
}
102+
103+
const user: User = { id: '1', name: 'John', email: 'john@example.com' }
104+
const name = getProperty(user, 'name') // Type: string
105+
```
106+
107+
## Conclusion
108+
109+
Following these TypeScript best practices will help you write more maintainable, error-free code. Start with strict mode, leverage the type system, and use advanced features like discriminated unions and generics.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
---
2+
title: "E-Commerce Platform Modernization"
3+
description: "How we helped a retail company modernize their e-commerce platform for better performance and scalability"
4+
tags: ["cms", "react"]
5+
publishDate: 2024-03-10
6+
isDraft: false
7+
featured: true
8+
author: "webstack-builders"
9+
client: "RetailCo"
10+
industry: "Retail"
11+
projectType: "Platform Modernization"
12+
duration: "6 months"
13+
---
14+
15+
## Challenge
16+
17+
RetailCo was struggling with an outdated e-commerce platform that couldn't handle peak traffic during sales events. The existing system was slow, difficult to maintain, and lacked modern features customers expected.
18+
19+
## Solution
20+
21+
We implemented a comprehensive platform modernization strategy:
22+
23+
### Technical Approach
24+
25+
- Migrated to a headless architecture using modern frameworks
26+
- Implemented edge caching and CDN optimization
27+
- Redesigned the checkout flow for better conversion
28+
- Integrated with modern payment providers
29+
30+
### Key Features
31+
32+
- **Performance**: 70% faster page load times
33+
- **Scalability**: Handles 10x traffic during peak periods
34+
- **Mobile**: Responsive design with mobile-first approach
35+
- **Analytics**: Real-time insights into customer behavior
36+
37+
## Results
38+
39+
The new platform delivered impressive results:
40+
41+
- **40% increase** in conversion rate
42+
- **70% faster** page load times
43+
- **99.9% uptime** during peak sales events
44+
- **25% reduction** in cart abandonment
45+
46+
## Technologies Used
47+
48+
- React for the frontend
49+
- Node.js for the backend
50+
- PostgreSQL for data storage
51+
- Redis for caching
52+
- AWS for hosting and CDN
53+
54+
## Conclusion
55+
56+
By modernizing their e-commerce platform, RetailCo was able to provide a better customer experience, handle increased traffic, and see significant improvements in key business metrics.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
title: "Enterprise API Platform Development"
3+
description: "Building a scalable API platform to power integrations across multiple business units"
4+
tags: ["apiDesign", "graphql"]
5+
publishDate: 2024-04-15
6+
isDraft: false
7+
featured: false
8+
author: "webstack-builders"
9+
client: "TechCorp"
10+
industry: "Technology"
11+
projectType: "API Development"
12+
duration: "8 months"
13+
---
14+
15+
## Challenge
16+
17+
TechCorp needed a unified API platform to connect disparate systems across their organization. Multiple business units were building their own integrations, leading to duplication, inconsistency, and security concerns.
18+
19+
## Solution
20+
21+
We designed and built a comprehensive enterprise API platform:
22+
23+
### Architecture
24+
25+
- RESTful API design following best practices
26+
- OAuth 2.0 for authentication and authorization
27+
- Rate limiting and quota management
28+
- Comprehensive API documentation
29+
30+
### Key Components
31+
32+
- **API Gateway**: Centralized entry point for all API traffic
33+
- **Developer Portal**: Self-service documentation and API keys
34+
- **Monitoring**: Real-time metrics and alerting
35+
- **Versioning**: Backward-compatible API evolution
36+
37+
## Implementation
38+
39+
The platform was rolled out in phases:
40+
41+
1. **Phase 1**: Core infrastructure and authentication
42+
2. **Phase 2**: First set of business APIs
43+
3. **Phase 3**: Developer portal and documentation
44+
4. **Phase 4**: Advanced features and monitoring
45+
46+
## Results
47+
48+
The API platform transformed how TechCorp's systems communicate:
49+
50+
- **50+ APIs** launched in the first year
51+
- **10M+ API calls** per day
52+
- **99.99% uptime** SLA achieved
53+
- **30% reduction** in integration costs
54+
55+
## Technologies Used
56+
57+
- Node.js and Express for API services
58+
- Kong for API gateway
59+
- PostgreSQL for data persistence
60+
- Redis for caching and rate limiting
61+
- Kubernetes for orchestration
62+
63+
## Conclusion
64+
65+
The enterprise API platform provided TechCorp with a scalable, secure foundation for integrations, enabling faster development and better collaboration across business units.

‎test/e2e/specs/02-pages/case-studies.spec.ts‎

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,60 +4,56 @@
44
*/
55
import { test, expect } from '@playwright/test'
66
import { TEST_URLS } from '../../fixtures/test-data'
7+
import { setupConsoleErrorChecker } from '@test/e2e/helpers/console-errors'
78

89
test.describe('Case Studies List Page', () => {
910
test.beforeEach(async ({ page }) => {
1011
await page.goto(TEST_URLS.caseStudies)
1112
})
1213

13-
test.skip('@wip page loads with correct title', async ({ page }) => {
14-
// Expected: Case studies page should have descriptive title
15-
// Actual: Unknown - needs testing
14+
test('@ready page loads with correct title', async ({ page }) => {
1615
await expect(page).toHaveTitle(/Case Studies/)
1716
})
1817

19-
test.skip('@wip hero section displays', async ({ page }) => {
20-
// Expected: Should have hero section with heading
21-
// Actual: Unknown - needs testing
18+
test('@ready hero section displays', async ({ page }) => {
2219
await expect(page.locator('h1')).toBeVisible()
20+
await expect(page.locator('h1')).toContainText(/Case Studies/)
2321
})
2422

25-
test.skip('@wip case studies grid displays', async ({ page }) => {
26-
// Expected: Should show grid of case study cards
27-
// Actual: Unknown - needs testing
28-
const caseStudyCards = page.locator('article')
29-
await expect(caseStudyCards.first()).toBeVisible()
23+
test('@ready case studies list displays', async ({ page }) => {
24+
const caseStudyList = page.locator('.case-study-item, article')
25+
await expect(caseStudyList.first()).toBeVisible()
26+
})
27+
28+
test('@ready case study cards have required elements', async ({ page }) => {
29+
const caseStudyList = page.locator('.case-study-item, article')
30+
const firstCard = caseStudyList.first()
31+
const heading = firstCard.locator('h2, h3').first()
32+
await expect(heading).toBeVisible()
33+
await expect(firstCard.locator('a').first()).toBeVisible()
3034
})
3135

32-
test.skip('@wip case study cards have required elements', async ({ page }) => {
33-
// Expected: Each card should have image, title, description
34-
// Actual: Unknown - needs testing
35-
const firstCard = page.locator('article').first()
36-
await expect(firstCard.locator('img')).toBeVisible()
37-
await expect(firstCard.locator('h2, h3')).toBeVisible()
36+
test('@ready case study links are functional', async ({ page }) => {
37+
const firstLink = page.locator('.case-study-item a, article a').first()
38+
await expect(firstLink).toHaveAttribute('href', /\/case-studies\//)
3839
})
3940

40-
test.skip('@wip case study links are functional', async ({ page }) => {
41-
// Expected: Clicking case study should navigate to detail page
42-
// Actual: Unknown - needs testing
43-
const firstLink = page.locator('article a').first()
44-
await expect(firstLink).toHaveAttribute('href', /.+/)
41+
test('@ready clicking case study navigates to detail page', async ({ page }) => {
42+
const firstLink = page.locator('.case-study-item a, article a').first()
43+
await firstLink.click()
44+
await expect(page).toHaveURL(/\/case-studies\/.+/)
4545
})
4646

47-
test.skip('@wip industry/tag filtering works', async ({ page }) => {
48-
// Expected: If filters exist, they should work
49-
// Actual: Unknown - needs testing
50-
// Check if filter UI exists
47+
test('@ready page is responsive on mobile', async ({ page }) => {
48+
await page.setViewportSize({ width: 375, height: 667 })
49+
await expect(page.locator('h1')).toBeVisible()
50+
const caseStudyCards = page.locator('.case-study-item, article')
51+
await expect(caseStudyCards.first()).toBeVisible()
5152
})
5253

53-
test.skip('@wip page has no console errors', async ({ page }) => {
54-
// Expected: No console errors on page load
55-
// Actual: Unknown - needs testing
56-
const errors: string[] = []
57-
page.on('console', (msg) => {
58-
if (msg.type() === 'error') errors.push(msg.text())
59-
})
54+
test('@ready page has no console errors', async ({ page }) => {
55+
const errorChecker = setupConsoleErrorChecker(page)
6056
await page.reload()
61-
expect(errors).toHaveLength(0)
57+
expect(errorChecker.getFilteredErrors()).toHaveLength(0)
6258
})
6359
})

0 commit comments

Comments
 (0)