خلصنا كل أوامر المكتبة. هذا الدرس مرجع مكتوب — مش درس جديد.
فتحه وانت تكتب، مش حتى تحفظه. وبعد لا تبلش مشروع Playwright بالقسم الثامن، سترجعله كذلك — لأنه هذه الأوامر هي هي، وبتتعمّق فيها بقسم المحددات (12) وقسم الـ Actions (13).
بنهاية هذا الدرس، ستكون قادراً على:
await page.goto('https://qacart-todo.herokuapp.com');
await page.goBack();
await page.goForward();
await page.reload();
const url = page.url();
const title = await page.title();بالترتيب من الأفضل للأقل:
page.getByRole('button', { name: 'إضافة' }) // 1. الدور والاسم
page.getByLabel('البريد الإلكتروني') // 2. عنوان الحقل
page.getByPlaceholder('كود الخصم') // 3. النص التوضيحي
page.getByTestId('cart-total') // 4. معرّف الاختبار
page.getByText('تمت الإضافة') // 5. النص
page.locator('#email') // 6. CSS
page.locator('xpath=//button[text()="حفظ"]') // 7. XPath — آخر خياروالفلترة:
page.locator('.card', { hasText: 'iPhone 15' }) // حاوية فيها نص
page.locator('.card:has(h3)') // حاوية فيها عنصر
page.locator('tr').filter({ hasText: 'ORD-4471' }) // فلترة
page.locator('li').nth(2) // بالفهرس
page.locator('li').first()
page.locator('li').last()
page.locator('.card').locator('button') // تسلسلgetByRole أول خيار دايماً — لأنه يوصف العنصر كما المستخدم يشوفه. ولو انكسر، معناها التجربة تغيّرت فعلياً — وهذا بالضبط لا تريد اختبارك يلقطه.await locator.click();
await locator.dblclick();
await locator.click({ button: 'right' });
await locator.fill('iPhone 15'); // بيمسح وبيكتب — الأفضل
await locator.clear();
await locator.press('Enter');
await locator.type('iPhone', { delay: 100 }); // حرف حرف
await locator.check(); // checkbox / radio
await locator.uncheck();
await locator.selectOption('amman'); // قائمة منسدلة
await locator.selectOption({ label: 'عمان' });
await locator.hover();
await locator.focus();
await locator.setInputFiles('./id-card.png'); // رفع ملف
await locator.dragTo(target);
await locator.scrollIntoViewIfNeeded();fill() مش type() للحقول العادية. fill تمسح وتكتب مرة واحدة وبتشعّل الأحداث صح. وtype تكتب حرف حرف — استخدمها لكن عندما تختبر بحث فوري (autocomplete) أو تحقّق أثناء الكتابة.await locator.textContent();
await locator.innerText();
await locator.inputValue(); // للحقول
await locator.getAttribute('href');
await locator.isVisible();
await locator.isEnabled();
await locator.isChecked();
await locator.count();
await locator.all();textContent مقابل innerText: الأولى بترجّع كل النص حتى المخفي، والثانية بترجّع المرئي بس. لو تفحص ما المستخدم يشوفه، استخدم innerText.// ✅ مرر الـ Locator — تعيد المحاولة تلقائياً
await expect(locator).toBeVisible();
await expect(locator).toBeHidden();
await expect(locator).toBeEnabled();
await expect(locator).toBeDisabled();
await expect(locator).toBeChecked();
await expect(locator).toHaveText('1350');
await expect(locator).toContainText('1350');
await expect(locator).toHaveValue('ahmad@test.com');
await expect(locator).toHaveCount(3);
await expect(locator).toHaveAttribute('href', '/cart');
await expect(locator).toHaveCSS('background-color', 'rgb(255, 0, 0)');
await expect(page).toHaveURL(/.*\/dashboard/);
await expect(page).toHaveTitle(/السلة/);
// مرن — بيكمّل ويجمع الأخطاء
await expect.soft(locator).toHaveText('1350');
// مع رسالة
await expect(locator, 'الإجمالي بعد خصم 10%').toHaveText('1350');
// عكس
await expect(locator).not.toBeVisible();expect، مش القيمة.
javascript // ❌ تأخذ القيمة الآن — لو السيرفر ما رد بعد، فشل const total = await page.getByTestId('total').textContent(); expect(total).toBe('1350'); // ✅ تعيد المحاولة لحد لا تنجح await expect(page.getByTestId('total')).toHaveText('1350'); // ✅ الأفضل — الـ Assertion هي الانتظار
await expect(locator).toBeVisible();
// انتظار صريح عندما تحتاجه
await locator.waitFor({ state: 'visible' });
await locator.waitFor({ state: 'hidden' });
await page.waitForURL('**/dashboard');
await page.waitForResponse(res => res.url().includes('/api/todos'));
// ❌ ممنوع
await page.waitForTimeout(2000);waitForTimeout ممنوعة بمشروع نظيف. بتضيّع وقت عندما السيرفر سريع، وبتفشل عندما يتأخر، وتخفي مشاكل أداء حقيقية.// طلب API مباشر — للتجهيز
const response = await request.post('/api/todos', {
headers: { Authorization: `Bearer ${token}` },
data: { item: 'اقرأ الدرس', isCompleted: false }
});
expect(response.status()).toBe(201);
const body = await response.json();
// محاكاة رد
await page.route('**/api/todos', route =>
route.fulfill({ status: 200, body: JSON.stringify([]) })
);
// محاكاة خطأ
await page.route('**/api/todos', route => route.fulfill({ status: 500 }));
// مراقبة الطلبات
page.on('request', req => console.log(req.method(), req.url()));await page.screenshot({ path: 'shot.png' });
await locator.screenshot({ path: 'element.png' });
await page.evaluate(() => localStorage.setItem('token', 'abc'));
await context.addCookies([{ name: 'session', value: 'abc', url: 'https://qacart.com' }]);| الخطأ | العرض | الحل |
|---|---|---|
نسيت await |
الاختبار يمر أخضر دايماً | await قبل كل عملية |
| قرأت القيمة بدل الـ Locator | فشل عشوائي | مرّر الـ Locator لـ expect |
type() بدل fill() |
بطيء وأحياناً ناقص | fill() |
waitForTimeout |
بطيء ومتذبذب | expect أو waitFor |
expect(locator).toHaveText('x') بدون await بترجّع Promise ولا أحد بينتظرها — والاختبار يمر أخضر مهما كانت النتيجة.
فعّل قاعدة no-floating-promises بـ ESLint وهي تلقطه إلك. وإذا اختبار عندك ما فشل ولا مرة أبداً — افحص الـ await أول شيء.test('applying a valid coupon reduces the total by ten percent', async ({ page }) => {
// 1. تجهيز
await page.goto('/cart');
await expect(page.getByTestId('cart-item')).toHaveCount(1);
// 2. الفعل
await page.getByTestId('coupon-input').fill('SAVE10');
await page.getByTestId('coupon-apply').click();
// 3. التحقق
await expect.soft(page.getByTestId('cart-subtotal'), 'المجموع الفرعي').toHaveText('1500');
await expect.soft(page.getByTestId('cart-discount'), 'الخصم').toHaveText('150');
await expect.soft(page.getByTestId('cart-total'), 'الإجمالي').toHaveText('1350');
});هذا مرجع مش درس — افتحه وانت تكتب، واحفظ رابطه.
ترتيب المحددات: getByRole أول، XPath آخر.
fill() للحقول العادية، type() لكن لاختبار البحث الفوري.
textContent بترجّع المخفي كذلك، innerText المرئي بس.
مرّر الـ Locator للـ expect مش القيمة — أهم قاعدة بالورقة كلها.
expect هي الانتظار — لا تحتاج انتظار صريح بمعظم الحالات.
waitForTimeout ممنوعة — وتخفي مشاكل أداء حقيقية.
page.route للمحاكاة — أخطاء وحالات فاضية وتأخير.
نسيان await أخطر خطأ — الاختبار يمر أخضر مهما صار.
واختبار ما فشل ولا مرة أبداً = افحص الـ await.
وبهيك خلصنا قسم أساسيات مكتبة QAcart! صار عندك كل الأوامر، وتعرف تكتب اختبار كامل.
في القسم الجاي: تطبيقات عملية وأفضل الممارسات — هون بتتعلّم مش بس كيف تكتب اختبار، بس كيف تكتب اختبار جيد.
يلا، نلتقي بالقسم الجاي!