10.9 Lighthouse תרגול
תרגול - לייטהאוס ואסטרטגיית בדיקות - Lighthouse and Testing Strategy¶
תרגיל 1 - הגדרת Lighthouse CI¶
הגדירו Lighthouse CI לפרויקט Next.js שכולל:
- קובץ
lighthouserc.jsonעם: - בדיקה של 3 דפים (בית, מוצרים, אודות)
- 5 הרצות לכל דף (לממוצע אמין)
- ציון מינימלי: Performance 90, Accessibility 95, SEO 90, Best Practices 90
-
שמירת דוחות
-
GitHub Action שמריץ את Lighthouse CI ב-PR
-
סקריפט בדיקה מקומי ב-package.json
תרגיל 2 - ניתוח ותיקון דוח Lighthouse¶
נתון דוח Lighthouse עם הציונים הבאים:
- Performance: 45
- Accessibility: 62
- Best Practices: 78
- SEO: 55
הבעיות שזוהו:
ביצועים:
- LCP: 6.2 שניות (תמונת hero של 3MB ב-JPEG)
- TBT: 1,200 מ"ש (bundle של 800KB)
- CLS: 0.35 (תמונות ללא dimensions, פונט FOUT)
- Unused JavaScript: 450KB
נגישות:
- 5 תמונות ללא alt
- 3 inputs ללא label
- ניגודיות צבעים נמוכה (2.5:1) על 4 אלמנטים
- אין lang attribute
SEO:
- אין meta description
- אין viewport meta
- קישורים עם "לחצו כאן" כ-anchor text
כתבו תוכנית תיקון מפורטת עם קוד לדוגמה לכל בעיה. סדרו לפי עדיפות.
תרגיל 3 - תכנון אסטרטגיית בדיקות¶
אתם מפתחים אפליקציית ניהול משימות (Todo App) עם הפיצ'רים הבאים:
- הרשמה והתחברות
- יצירה, עריכה, מחיקה של משימות
- סינון לפי סטטוס (הכל, פעילות, הושלמו)
- גרירה ושחרור לשינוי סדר
- תזכורות (notifications)
- שיתוף משימות עם משתמשים אחרים
- סטטיסטיקות (כמה משימות הושלמו החודש)
תכננו אסטרטגיית בדיקות מלאה:
1. רשימת בדיקות יחידה (לפחות 10)
2. רשימת בדיקות אינטגרציה (לפחות 6)
3. רשימת בדיקות E2E (לפחות 4)
4. הגדרת coverage thresholds
5. הגדרת CI pipeline
תרגיל 4 - כתיבת בדיקות לפרויקט קיים¶
נתון פרויקט עם הקבצים הבאים. כתבו בדיקות מתאימות לכל קובץ:
// utils/date.ts
export function formatDate(date: Date): string {
return new Intl.DateTimeFormat('he-IL', {
year: 'numeric',
month: 'long',
day: 'numeric',
}).format(date);
}
export function isOverdue(dueDate: Date): boolean {
return new Date() > dueDate;
}
export function daysUntil(date: Date): number {
const now = new Date();
const diff = date.getTime() - now.getTime();
return Math.ceil(diff / (1000 * 60 * 60 * 24));
}
export function getRelativeTime(date: Date): string {
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffMinutes = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (diffMinutes < 1) return 'הרגע';
if (diffMinutes < 60) return `לפני ${diffMinutes} דקות`;
if (diffHours < 24) return `לפני ${diffHours} שעות`;
if (diffDays < 30) return `לפני ${diffDays} ימים`;
return formatDate(date);
}
// components/TaskItem.tsx
interface Task {
id: string;
title: string;
completed: boolean;
dueDate: Date | null;
}
function TaskItem({
task,
onToggle,
onDelete,
onEdit,
}: {
task: Task;
onToggle: (id: string) => void;
onDelete: (id: string) => void;
onEdit: (id: string, title: string) => void;
}) {
const [editing, setEditing] = useState(false);
const [editTitle, setEditTitle] = useState(task.title);
function handleSave() {
if (editTitle.trim()) {
onEdit(task.id, editTitle);
setEditing(false);
}
}
const isOverdue = task.dueDate && !task.completed && new Date() > task.dueDate;
return (
<li className={isOverdue ? 'overdue' : ''}>
<input
type="checkbox"
checked={task.completed}
onChange={() => onToggle(task.id)}
aria-label={`סמן ${task.title} כ${task.completed ? 'לא' : ''} הושלם`}
/>
{editing ? (
<input
value={editTitle}
onChange={e => setEditTitle(e.target.value)}
onBlur={handleSave}
onKeyDown={e => e.key === 'Enter' && handleSave()}
autoFocus
/>
) : (
<span
style={{ textDecoration: task.completed ? 'line-through' : 'none' }}
onDoubleClick={() => setEditing(true)}
>
{task.title}
</span>
)}
{task.dueDate && (
<time dateTime={task.dueDate.toISOString()}>
{formatDate(task.dueDate)}
</time>
)}
<button onClick={() => onDelete(task.id)} aria-label={`מחק ${task.title}`}>
מחק
</button>
</li>
);
}
כתבו:
- בדיקות יחידה ל-date.ts (לפחות 12 בדיקות)
- בדיקות אינטגרציה ל-TaskItem (לפחות 8 בדיקות)
תרגיל 5 - CI Pipeline מלא¶
צרו GitHub Actions workflow מלא שכולל:
- שלב lint: ESLint + TypeScript type check
- שלב בדיקות יחידה: Vitest עם coverage
- שלב build: npm run build
- שלב בדיקות E2E: Playwright (רק על Chromium ב-CI)
- שלב Lighthouse: בדיקת 2 דפים עם ספים
הדרישות:
- בדיקות יחידה רצות במקביל ל-lint
- E2E רץ רק אחרי build
- Lighthouse רץ רק אחרי build
- כל השלבים מעלים artifacts
- ב-PR: הכל רץ. ב-push ל-main: רק lint + unit + build
תרגיל 6 - דוח בדיקות אוטומטי¶
כתבו סקריפט שמריץ את כל הבדיקות ומייצר דוח HTML מסכם:
הדוח צריך לכלול:
- תאריך ושעה
- תוצאות בדיקות יחידה (עברו/נכשלו/דילגו)
- אחוזי כיסוי קוד (statements, branches, functions, lines)
- תוצאות בדיקות E2E
- ציוני Lighthouse (אם זמינים)
- רשימת בדיקות שנכשלו עם פרטים
שאלות¶
- מה ההבדל בין Lab Data ל-Field Data ב-Lighthouse? למה הציונים עשויים להיות שונים?
- למה 100% code coverage אינו יעד מומלץ? מה היעד הנכון?
- כיצד מחליטים מה לבדוק בבדיקת E2E ומה בבדיקת יחידה?
- מה היתרון של הרצת Lighthouse ב-CI לעומת בדיקה ידנית?
- תארו מצב שבו בדיקות עוברות אבל האפליקציה שבורה. כיצד ניתן למנוע מצב כזה?