اختبار النماذج وتدفقات المستخدم من البداية إلى النهاية
أتمت عمليات إرسال النماذج متعددة الخطوات وتدفقات التنقل باستخدام كائنات صفحات Playwright.
اختبار النماذج وتدفقات المستخدم من البداية إلى النهاية درس مجاني في React Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في React Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة React Academy 4 دروس في المجموع.
استراتيجية اختبار النماذج من طرف إلى طرف
تحاكي اختبارات النماذج من طرف إلى طرف رحلة المستخدم الكاملة: فتح الصفحة، وملء الحقول، والإرسال، ومعالجة أخطاء التحقق، والتحقق من نتيجة النجاح.
نمط كائن الصفحة
يغلّف نمط كائن الصفحة (POM) المحدّدات والتفاعلات الخاصة بصفحة داخل فئة، مما يجعل الاختبارات سهلة القراءة ويقلل التكرار.
class LoginPage {
constructor(private page: Page) {}
async goto() { await this.page.goto('/login'); }
async fillEmail(email: string) { await this.page.getByLabel('Email').fill(email); }
async fillPassword(pw: string) { await this.page.getByLabel('Password').fill(pw); }
async submit() { await this.page.getByRole('button', { name: /log in/i }).click(); }
async getError() { return this.page.getByRole('alert').textContent(); }
}استخدام كائن الصفحة في الاختبارات
تتحول الاختبارات عند استخدام كائنات الصفحات إلى أوصاف للإجراءات التي ينوي المستخدم تنفيذها، فتسهل قراءتها وصيانتها.
test('successful login redirects to dashboard', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.fillEmail('alice@example.com');
await loginPage.fillPassword('password123');
await loginPage.submit();
await expect(page).toHaveURL('/dashboard');
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});اختبار أخطاء التحقق
أرسل بيانات غير صالحة أو فارغة، وتحقّق من رسائل الخطأ التي تعرضها واجهة المستخدم.
test('shows validation errors on empty submit', async ({ page }) => {
await page.goto('/register');
await page.getByRole('button', { name: 'Create account' }).click();
await expect(page.getByText('Email is required')).toBeVisible();
await expect(page.getByText('Password must be at least 8 characters')).toBeVisible();
});اختبار النماذج متعددة الخطوات
في المعالجات متعددة الخطوات، تقدّم عبر كل خطوة، وتحقّق من انتقال النموذج واحتفاظه بالإدخال السابق.
test('completes 3-step signup', async ({ page }) => {
await page.goto('/signup');
// Step 1
await page.getByLabel('First Name').fill('Alice');
await page.getByRole('button', { name: 'Next' }).click();
// Step 2
await page.getByLabel('Plan').selectOption('pro');
await page.getByRole('button', { name: 'Next' }).click();
// Step 3
await page.getByLabel('Card Number').fill('4242424242424242');
await page.getByRole('button', { name: 'Complete' }).click();
await expect(page.getByText('Welcome, Alice!')).toBeVisible();
});محاكاة API في Playwright
استخدم page.route() لاعتراض استدعاءات API وإرجاع استجابات وهمية، وهو أمر مفيد لاختبار الحالات الحدّية من دون خادم خلفي حقيقي.
await page.route('/api/register', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ token: 'fake-token' }),
});
});
await page.goto('/register');
// ...fill and submit form
await expect(page).toHaveURL('/dashboard');اختبار تحميل الملفات
استخدم setInputFiles() لمحاكاة تحميل ملف في Playwright.
test('uploads a profile photo', async ({ page }) => {
await page.goto('/profile');
const fileInput = page.getByLabel('Profile photo');
await fileInput.setInputFiles('./fixtures/avatar.png');
await page.getByRole('button', { name: 'Upload' }).click();
await expect(page.getByAltText('Profile photo')).toBeVisible();
});إعادة استخدام حالة المصادقة
سجّل الدخول مرة واحدة، واحفظ حالة تخزين المتصفح، وأعد استخدامها عبر الاختبارات لتجاوز عمليات تسجيل الدخول المتكررة.
// auth.setup.ts
test('authenticate', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('alice@example.com');
await page.getByLabel('Password').fill('password');
await page.getByRole('button', { name: 'Log in' }).click();
await page.context().storageState({ path: 'e2e/.auth/user.json' });
});
// playwright.config.ts — use storageState in other tests
use: { storageState: 'e2e/.auth/user.json' }اختبار استرداد الأخطاء
حاكِ حالات فشل الشبكة، وتحقّق من قدرة المستخدم على إعادة المحاولة أو رؤيته رسالة خطأ مفيدة.
await page.route('/api/submit', route => route.abort());
await page.getByRole('button', { name: 'Submit' }).click();
await expect(page.getByText('Network error. Please try again.')).toBeVisible();
await page.unroute('/api/submit');
// Now the real request goes through
await page.getByRole('button', { name: 'Retry' }).click();اختبار التنقّل باستخدام لوحة المفاتيح
اختبر أن النماذج متاحة بالكامل باستخدام لوحة المفاتيح، وذلك بالتنقّل بين الحقول باستخدام Tab والإرسال باستخدام Enter.
test('submits form with keyboard only', async ({ page }) => {
await page.goto('/contact');
await page.keyboard.press('Tab'); // focus name
await page.keyboard.type('Alice');
await page.keyboard.press('Tab'); // focus email
await page.keyboard.type('alice@example.com');
await page.keyboard.press('Tab'); // focus submit
await page.keyboard.press('Enter');
await expect(page.getByText('Message sent!')).toBeVisible();
});مصانع بيانات الاختبار
استخدم مصانع Playwright لمشاركة منطق الإعداد، مثل إنشاء مستخدم للاختبار، بين اختبارات متعددة بطريقة منظمة.
// fixtures.ts
const test = base.extend<{ testUser: User }>({
testUser: async ({}, use) => {
const user = await createTestUser();
await use(user);
await deleteTestUser(user.id);
},
});
// In a test file:
test('edits profile', async ({ page, testUser }) => {
await page.goto(`/users/${testUser.id}/edit`);
});التنفيذ المتوازي للاختبارات
يشغّل Playwright الاختبارات بالتوازي افتراضيًا عبر عمال متعددين. استخدم test.describe.serial فقط للاختبارات التي يجب تشغيلها بالترتيب.
تحقق سريع
ما الفائدة الأساسية من نمط كائن الصفحة (POM) في اختبار E2E؟
خلاصة
تستخدم اختبارات النماذج من طرف إلى طرف كائنات الصفحات لتحسين قابلية الصيانة، وpage.route() لمحاكاة API، وsetInputFiles() لتحميل الملفات، وحالة التخزين لإعادة استخدام جلسات المصادقة. اختبر التحقق والتدفقات متعددة الخطوات والتنقّل باستخدام لوحة المفاتيح لتغطية رحلات المستخدم الحقيقية.
الأسئلة الشائعة
هل درس «اختبار النماذج وتدفقات المستخدم من البداية إلى النهاية» مجاني؟
نعم — نص درس «اختبار النماذج وتدفقات المستخدم من البداية إلى النهاية» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة React Academy، انتقل إلى CoddyKit PRO. تتضمن دورة React Academy 4 دروس في المجموع.
ماذا ستتعلم في «اختبار النماذج وتدفقات المستخدم من البداية إلى النهاية»؟
أتمت عمليات إرسال النماذج متعددة الخطوات وتدفقات التنقل باستخدام كائنات صفحات Playwright. تتمرن على React Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ React Academy؟
لا تُشترط خبرة سابقة. React Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «اختبار النماذج وتدفقات المستخدم من البداية إلى النهاية»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس React Academy هذا؟
نعم. كل درس في React Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- اختبار التكامل باستخدام React Testing Library
- اختبار الواجهة غير المتزامنة واستدعاءات API باستخدام MSW
- البدء باستخدام Playwright لتطبيقات React
- اختبار النماذج وتدفقات المستخدم من البداية إلى النهاية