الفرق بين المراجعتين لصفحة: «Next.js/testing»
لا ملخص تعديل |
جميل-بيلوني (نقاش | مساهمات) طلا ملخص تعديل |
||
(3 مراجعات متوسطة بواسطة مستخدمين اثنين آخرين غير معروضة) | |||
سطر 3: | سطر 3: | ||
== اختبار تطبيقات Next.js باستخدام Cypress == | == اختبار تطبيقات Next.js باستخدام Cypress == | ||
تُستخدم المكتبة في تنفيذ اختبارات | تُستخدم المكتبة Cypress في تنفيذ اختبارات شاملة End-to-End Testing -أو E2E اختصارًا- واختبارات التكامل Integration Testing. | ||
=== بداية سريعة === | === بداية سريعة === | ||
سطر 20: | سطر 20: | ||
"cypress": "cypress open", | "cypress": "cypress open", | ||
} | } | ||
</syntaxhighlight>شغّل Cypress للمرة الأولى لكي تولِّد أمثلة تستخدم | </syntaxhighlight>شغّل Cypress للمرة الأولى لكي تولِّد أمثلة تستخدم الهيكلية المفضّلة للمجلد الخاص بها:<syntaxhighlight lang="bash"> | ||
npm run cypress | npm run cypress | ||
</syntaxhighlight>يمكنك الاطلاع على الأمثلة الموّلدة [https://docs.cypress.io/guides/getting-started وتوثيق Cypress] لتألف التعامل مع هذ المكتبة. | </syntaxhighlight>يمكنك الاطلاع على الأمثلة الموّلدة [https://docs.cypress.io/guides/getting-started وتوثيق Cypress] لتألف التعامل مع هذ المكتبة. | ||
سطر 38: | سطر 38: | ||
) | ) | ||
} | } | ||
</syntaxhighlight><syntaxhighlight lang="javascript"> | |||
// pages/about.js | // pages/about.js | ||
export default function About() { | export default function About() { | ||
سطر 51: | سطر 52: | ||
describe('Navigation', () => { | describe('Navigation', () => { | ||
it('should navigate to the about page', () => { | it('should navigate to the about page', () => { | ||
// index | // index ابدأ بالصفحة | ||
cy.visit('http://localhost:3000/') | cy.visit('http://localhost:3000/') | ||
سطر 64: | سطر 65: | ||
}) | }) | ||
}) | }) | ||
</syntaxhighlight>بإمكانك استخدام | </syntaxhighlight>بإمكانك استخدام <code>("/")cy.visit</code> بدلًا من <code>cy.visit("<nowiki>http://localhost:3000/</nowiki>")</code>، إن أضفت <code>"baseUrl": "<nowiki>http://localhost:3000</nowiki>"</code> إلى ملف التهيئة <code>cypress.json</code>. | ||
=== تنفيذ اختبارات Cypress === | === تنفيذ اختبارات Cypress === | ||
سطر 71: | سطر 72: | ||
نفّذ الأمر <code>npm run build</code> ثم <code>npm run start</code> وبعد ذلك الأمر <code>npm run cypress</code> في نافذة جديدة للطرفية لتشغيل Cypress. | نفّذ الأمر <code>npm run build</code> ثم <code>npm run start</code> وبعد ذلك الأمر <code>npm run cypress</code> في نافذة جديدة للطرفية لتشغيل Cypress. | ||
'''ملاحظة''': بإمكانك كحل بديل أن تُثبِّت الحزمة <code>start-server-and-test</code> وتضيفها إلى حقل السكربتات في ملف <code>package.json</code> كالتالي:<syntaxhighlight lang="json"> | '''ملاحظة''': بإمكانك كحل بديل أن تُثبِّت الحزمة <code>start-server-and-test</code> وتضيفها إلى حقل السكربتات "scripts" في ملف <code>package.json</code> كالتالي:<syntaxhighlight lang="json"> | ||
"test": "start-server-and-test start http://localhost:3000 cypress" | "test": "start-server-and-test start http://localhost:3000 cypress" | ||
</syntaxhighlight>وذلك كي تُشغّل خادم إنتاج إلى جوار | </syntaxhighlight>وذلك كي تُشغّل خادم إنتاج Next.js إلى جوار Cypress، وتذكرأن تعيد بناء التطبيق بعد إجراء تعديلات جديدة. | ||
=== التحضير لعملية التكامل المتواصل CI في تطبيقات Next.js === | === التحضير لعملية التكامل المتواصل CI في تطبيقات Next.js === | ||
ربما ستلاحظ أن تشغل متصفحًا تفاعليًا ليس نموذجيًا لبيئة التكامل المتواصل | ربما ستلاحظ أن Cypress تشغل متصفحًا تفاعليًا ليس نموذجيًا لبيئة التكامل المتواصل Continuous Integration. بإمكانك أن تُشغّل Cypress أيضًا دون واجهة المتصفح تلك بتنفيذ الأمر <code>cypress run</code>:<syntaxhighlight lang="json"> | ||
// package.json | // package.json | ||
سطر 89: | سطر 90: | ||
* [https://docs.cypress.io/guides/continuous-integration/introduction توثيق التكامل المتواصل في Cypress] | * [https://docs.cypress.io/guides/continuous-integration/introduction توثيق التكامل المتواصل في Cypress] | ||
* [https://on.cypress.io/github-actions دليل استخدام Cypress مع أفعال GitHub] | * [https://on.cypress.io/github-actions دليل استخدام Cypress مع أفعال GitHub] | ||
== اختبار تطبيقات Next.js باستخدام Playwright == | == اختبار تطبيقات Next.js باستخدام Playwright == | ||
Playwright هو إطار عمل للاختبارات يتيح لك أتمتة Chromium و Firefox و WebKit من خلال واجهة برمجية واحدة. يُمكنك استخدام في تنفيذ الاختبارات | Playwright هو إطار عمل للاختبارات يتيح لك أتمتة Chromium و Firefox و WebKit من خلال واجهة برمجية واحدة. يُمكنك استخدام Playwright في تنفيذ الاختبارات الشاملة End-to-End واختبارات التكامل Integration عبر جميع المنصات. | ||
=== | === بداية سريعة === | ||
بإمكانك استخدام <code>create-next-app</code> مع المثال [https://github.com/vercel/next.js/tree/canary/examples/with-playwright with-playwright] لتبدأ العمل بسرعة. سيُنشئ ذلك | بإمكانك استخدام <code>create-next-app</code> مع المثال [https://github.com/vercel/next.js/tree/canary/examples/with-playwright with-playwright] لتبدأ العمل بسرعة. سيُنشئ ذلك مشروعًا جديدًا أعدت فيه Next.js بشكل كامل.<syntaxhighlight lang="bash"> | ||
npx create-next-app@latest --example with-playwright with-playwright-app | npx create-next-app@latest --example with-playwright with-playwright-app | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== الإعداد اليدوي == | === الإعداد اليدوي === | ||
بإمكانك أن تستخدم <code>npm init playwright</code> أيضًا لإضافة Playwright إلى مشروع <code>NPM</code> موجود مسبقًا. ثبِّت الحزمة <code>playwright/test@</code> لكي تبدأ يدويًا العمل مع Playwright. <syntaxhighlight lang="bash"> | بإمكانك أن تستخدم <code>npm init playwright</code> أيضًا لإضافة Playwright إلى مشروع <code>NPM</code> موجود مسبقًا. ثبِّت الحزمة <code>playwright/test@</code> لكي تبدأ يدويًا العمل مع Playwright. <syntaxhighlight lang="bash"> | ||
npm install --save-dev @playwright/test | npm install --save-dev @playwright/test | ||
سطر 126: | سطر 127: | ||
) | ) | ||
} | } | ||
</syntaxhighlight><syntaxhighlight lang="javascript"> | |||
// pages/about.js | // pages/about.js | ||
export default function About() { | export default function About() { | ||
سطر 150: | سطر 152: | ||
await expect(page.locator('h1')).toContainText('About Page') | await expect(page.locator('h1')).toContainText('About Page') | ||
}) | }) | ||
</syntaxhighlight>بإمكانك استخدام | </syntaxhighlight>بإمكانك استخدام <code>("/")page.goto</code> بدلًا من <code>page.goto("<nowiki>http://localhost:3000/</nowiki>")</code>، إن أضفت <code>"baseUrl": "<nowiki>http://localhost:3000</nowiki>"</code> إلى ملف التهيئة <code>playwright.config.ts</code>. | ||
=== تنفيذ اختبارات Playwright === | === تنفيذ اختبارات Playwright === | ||
تختبر Playwright تطبيقات Next.js حقيقية لذلك لا بد أن يعمل خادم Next.js قبل أن تبدأ | تختبر Playwright تطبيقات Next.js حقيقية لذلك لا بد أن يعمل خادم Next.js قبل أن تبدأ Playwright. ننصحك بتطبيق اختباراتك على شيفرة الإنتاج لتقف بشكل أوضح على سلوك تطبيقك. | ||
نفّذ الأمر <code>npm run build</code> ثم <code>npm run start</code> وبعد ذلك الأمر <code>npm run test:e2e</code> في نافذة جديدة للطرفية لتشغيل Playwright. | نفّذ الأمر <code>npm run build</code> ثم <code>npm run start</code> وبعد ذلك الأمر <code>npm run test:e2e</code> في نافذة جديدة للطرفية لتشغيل Playwright. | ||
'''ملاحظة''': بإمكانك كحل بديل استخدام الميزة <code>[https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests webServer]</code> لكي تسمح للمكتبة Playwright بتشغيل خادم التطوير ومن ثم تنتظر حتى يجهز تمامًا | '''ملاحظة''': بإمكانك كحل بديل استخدام الميزة <code>[https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests webServer]</code> لكي تسمح للمكتبة Playwright بتشغيل خادم التطوير ومن ثم تنتظر حتى يجهز تمامًا. | ||
=== تشغيل Playwright في | === تشغيل Playwright في وضع التكامل المتواصل === | ||
تُنفَّذ Playwright اختباراتك دون | تُنفَّذ Playwright اختباراتك دون واجهة [https://playwright.dev/docs/ci#running-headed headless mode] افتراضيًا. ولتثبيت كل اعتماديات Playwright نفّذ الأمر <code>npx playwright install-deps</code> | ||
بإمكانك الاطلاع أكثر على Playwright والتكامل المتواصل من خلال المصادر التالية: | بإمكانك الاطلاع أكثر على Playwright والتكامل المتواصل من خلال المصادر التالية: | ||
سطر 168: | سطر 170: | ||
* [https://playwright.dev/docs/ci استخدام Playwright مع مزوّد التكامل المتواصل الخاص بك]. | * [https://playwright.dev/docs/ci استخدام Playwright مع مزوّد التكامل المتواصل الخاص بك]. | ||
== | == اختبار تطبيقات Next.js باستخدام Jest ومكتبة اختبار React == | ||
تُستسخدم هاتين المكتبتين مرارًا في إجراء اختبار الوحدات Unit Testing. وهنالك ثلاث طرق لكي تستخدم Jest في تطبيق Next.js: | تُستسخدم هاتين المكتبتين مرارًا في إجراء اختبار الوحدات Unit Testing. وهنالك ثلاث طرق لكي تستخدم Jest في تطبيق Next.js: | ||
# استخدام أحد أمثلة الإقلاع السريع. | # استخدام أحد أمثلة الإقلاع السريع. | ||
# مع مُصرَّف Rust الخاص بتطبيقات . | # مع مُصرَّف Rust الخاص بتطبيقات Next.js. | ||
# باستخدام Babel. | # باستخدام Babel. | ||
سطر 181: | سطر 183: | ||
=== إعداد المكتبة Jest (مع مُصرّف Rust) === | === إعداد المكتبة Jest (مع مُصرّف Rust) === | ||
تتمتع Next.js ابتداءً من النسخة 12 بدعم مدمج للمكتبة Jest. ولإعداد Jest، ثبِّت الاعتماديات التالية <code>jest</code> و <code>@testing-library/react</code> و <code>@testing-library/jest-dom</code>:<syntaxhighlight lang="bash"> | تتمتع Next.js ابتداءً من النسخة 12 بدعم مدمج للمكتبة Jest. ولإعداد Jest، ثبِّت الاعتماديات التالية <code>jest</code> و <code>@testing-library/react</code> و <code>@testing-library/jest-dom</code>:<syntaxhighlight lang="bash"> | ||
npm install --save-dev jest @testing-library/react @testing-library/jest-dom | npm install --save-dev jest @testing-library/react @testing-library/jest-dom | ||
</syntaxhighlight>أنشئ الملف <code>jest.config.js</code> في | </syntaxhighlight>أنشئ الملف <code>jest.config.js</code> في جذر مجلد مشروعك وأضف الشيفرة التالية:<syntaxhighlight lang="javascript"> | ||
// jest.config.js | // jest.config.js | ||
const nextJest = require('next/jest') | const nextJest = require('next/jest') | ||
سطر 196: | سطر 198: | ||
// أضف أية خيارات إعداد أخرى قبل تنفيذ كل اختبار | // أضف أية خيارات إعداد أخرى قبل تنفيذ كل اختبار | ||
// setupFilesAfterEnv: ['<rootDir>/jest.setup.js'], | // setupFilesAfterEnv: ['<rootDir>/jest.setup.js'], | ||
// | // ستحتاج إلى مايلي لإخفاء العمل baseUrl مع عناوين جذرية TypeScript إن كنت تستخدم | ||
moduleDirectories: ['node_modules', '<rootDir>/'], | moduleDirectories: ['node_modules', '<rootDir>/'], | ||
testEnvironment: 'jest-environment-jsdom', | testEnvironment: 'jest-environment-jsdom', | ||
} | } | ||
//قادر على next/jest بهذا الشكل | //قادر على next/jest بهذا الشكل للتأكد من أن createJestConfig تُصدّر | ||
//بشكل غير متزامن Next.js تحميل إعدادات | //بشكل غير متزامن Next.js تحميل إعدادات | ||
module.exports = createJestConfig(customJestConfig) | module.exports = createJestConfig(customJestConfig) | ||
</syntaxhighlight>تهيئ <code>next/jest</code> | </syntaxhighlight>تهيئ <code>next/jest</code> المكتبة Jest خلف الستار نيابة عنك بما في ذلك: | ||
* إعداد <code>transform</code> باستخدام [[Next.js/compiler|SWC]]. | * إعداد <code>transform</code> باستخدام [[Next.js/compiler|SWC]]. | ||
* التقليد التلقائي | * التقليد التلقائي للتنسيقات (<code>css.</code> و <code>module.css.</code> وما يماثلها من تنسيقات <code>SCSS</code>). | ||
* تحميل <code>env.</code> (وكل ما يماثلها) ضمن <code>process.env</code>. | * تحميل <code>env.</code> (وكل ما يماثلها) ضمن <code>process.env</code>. | ||
* تجاهل <code>node_modules</code> عند تحليل وتنفيذ الاختبارات | * تجاهل <code>node_modules</code> عند تحليل وتنفيذ الاختبارات والتحويلات transforms. | ||
* تجاهل <code>next.</code> عند تحليل الاختبار. | * تجاهل <code>next.</code> عند تحليل الاختبار. | ||
* تحميل <code>next.config.js</code> من أجل الرايات التي تفعّل تحويلات SWC. | * تحميل <code>next.config.js</code> من أجل الرايات التي تفعّل تحويلات SWC. | ||
'''ملاحظة''': إن أردت اختبار متغيرات البيئة مباشرةً، فحملهم يدويًا في سكربت تهيئة منفصل أو في ملف jest.config.js، ولمزيد من التفاصيل، ارجع إلى قسم [[Next.js/environment variables#.D8.A7.D8.AE.D8.AA.D8.A8.D8.A7.D8.B1 .D9.85.D8.AA.D8.BA.D9.8A.D8.B1.D8.A7.D8.AA .D8.A7.D9.84.D8.A8.D9.8A.D8.A6.D8.A9 .D9.81.D9.8A Next.js|اختبار متغيرات البيئة]]. | |||
=== ضبط إعدادات Jest مع Babel === | === ضبط إعدادات Jest مع Babel === | ||
إن أردت الاستغناء عن [[Next.js/compiler|مُصرِّف Rust]]، لا بد من ضبط إعدادات يدويًا وتثبيت <code>babel-jest</code> و <code>identity-obj-proxy</code> بالإضافة إلى الحزم التي ثبتها سابقًا. | إن أردت الاستغناء عن [[Next.js/compiler|مُصرِّف Rust]]، لا بد من ضبط إعدادات Babel يدويًا وتثبيت <code>babel-jest</code> و <code>identity-obj-proxy</code> بالإضافة إلى الحزم التي ثبتها سابقًا. | ||
إليك الخيارات المستحسنة لتهيئة Jest من أجل تطبيقات Next.js:<syntaxhighlight lang="javascript"> | إليك الخيارات المستحسنة لتهيئة Jest من أجل تطبيقات Next.js:<syntaxhighlight lang="javascript"> | ||
// jest.config.js | // jest.config.js | ||
module.exports = { | module.exports = { | ||
collectCoverage: true, | |||
coverageProvider: 'v8', | |||
collectCoverageFrom: [ | collectCoverageFrom: [ | ||
'**/*.{js,jsx,ts,tsx}', | '**/*.{js,jsx,ts,tsx}', | ||
'!**/*.d.ts', | '!**/*.d.ts', | ||
'!**/node_modules/**', | '!**/node_modules/**', | ||
'!<rootDir>/out/**', | |||
'!<rootDir>/.next/**', | |||
'!<rootDir>/*.config.js', | |||
'!<rootDir>/coverage/**', | |||
], | ], | ||
moduleNameMapper: { | moduleNameMapper: { | ||
سطر 255: | سطر 264: | ||
</syntaxhighlight>بإمكانك الاطلاع على كل خيار من خيارات الإعداد في [https://jestjs.io/docs/configuration توثيق Jest.] | </syntaxhighlight>بإمكانك الاطلاع على كل خيار من خيارات الإعداد في [https://jestjs.io/docs/configuration توثيق Jest.] | ||
==== إدراج الصور | ==== إدراج الصور وصفحات التسيق CSS ==== | ||
لا تُستخدم الصور | لا تُستخدم الصور والتنسيقات في الاختبارات لكن إدراجها قد يقود إلى أخطاء، وبالتالي لا بد من تقليدها. انشئ ملفات التقليد mock files المُشار إليها في الإعدادات السابقة (<code>fileMock.js</code> و <code>styleMock.js</code>) ضمن المجلد <code>__mocks__</code>:<syntaxhighlight lang="javascript"> | ||
// __mocks__/fileMock.js | // __mocks__/fileMock.js | ||
module.exports = { | module.exports = { | ||
سطر 266: | سطر 275: | ||
// __mocks__/styleMock.js | // __mocks__/styleMock.js | ||
module.exports = {} | module.exports = {} | ||
</syntaxhighlight>لمعلومات أكثر عن التعامل مع الموجودات | </syntaxhighlight>لمعلومات أكثر عن التعامل مع الموجودات أو الأصول الثابتة static assets راجع [https://jestjs.io/docs/webpack#handling-static-assets توثيق Jest]. | ||
==== توسعة Jest بمطابقات مخصصة (اختياري) ==== | ==== توسعة Jest بمطابقات مخصصة (اختياري) ==== | ||
تتضمن | تتضمن <code>testing-library/jest-dom@</code> مجموعة من المُطابِقات المخصصة [https://github.com/testing-library/jest-dom#custom-matchers custom matchers] التي تُسهَّل كتابة الاختبارات مثل <code>()toBeInTheDocument.</code>. بإمكانك إدراج المُطابق المخصص في كل اختبار بإضافة الخيار التالي إلى ملف تهيئة Jest:<syntaxhighlight lang="javascript"> | ||
// jest.config.js | // jest.config.js | ||
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'] | setupFilesAfterEnv: ['<rootDir>/jest.setup.js'] | ||
سطر 277: | سطر 286: | ||
</syntaxhighlight>إن أردت إضافة المزيد من خيارات الإعداد قبل كل اختبار، فمن الشائع إضافتها داخل الملف <code>jest.setup.js</code>. | </syntaxhighlight>إن أردت إضافة المزيد من خيارات الإعداد قبل كل اختبار، فمن الشائع إضافتها داخل الملف <code>jest.setup.js</code>. | ||
==== الإدراجات ذات المسارات المطلقة | ==== الإدراجات ذات المسارات المطلقة والبديلة ==== | ||
إن استخدمت [[Next.js/module | إن استخدمت [[Next.js/module path aliases|بدائل مسار الوحدة البرمجية]] Module Path Aliases، فلا بد من تهيئة Jest ليحلل هذه الإدراجات بمطابقة الخيار "paths" (المسارات) في الملف <code>jsconfig.json</code> مع الخيار <code>moduleNameMapper</code> في الملف <code>jest.config.js</code>. إليك مثالًا:<syntaxhighlight lang="javascript"> | ||
// tsconfig.json or jsconfig.json | // tsconfig.json or jsconfig.json | ||
{ | { | ||
سطر 288: | سطر 297: | ||
} | } | ||
} | } | ||
</syntaxhighlight><syntaxhighlight lang="javascript"> | |||
// jest.config.js | // jest.config.js | ||
moduleNameMapper: { | moduleNameMapper: { | ||
سطر 296: | سطر 306: | ||
=== إنشاء الاختبارات الخاصة بك === | === إنشاء الاختبارات الخاصة بك === | ||
* '''إضافة سكربت الاختبار إلى الملف package.json''': أضف خيار تنفيذ اختبارات Jest إلى سكربتات | * '''إضافة سكربت الاختبار إلى الملف package.json''': أضف خيار تنفيذ اختبارات Jest إلى سكربتات <code>package.json</code> ، إذ يعيد الخيار تشغيل الاختبار عندما يتغير الملف: | ||
<syntaxhighlight lang="json"> | <syntaxhighlight lang="json"> | ||
"scripts": { | "scripts": { | ||
سطر 306: | سطر 316: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* '''إنشاء أول اختباراتك''': أصبح مشروعك | * '''إنشاء أول اختباراتك''': أصبح مشروعك الآن جاهزًا لتنفيذ الاختبارات. اتبع تقاليد Jest بإضافة الاختبارات إلى المجلد <code>__tests__</code> في جذر مجلد مشروعك. يمكنك مثلًا إضافة اختبار يتحقق من تصيير المكوّن <code></ Home></code> لعنوان بشكل صحيح: | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
// __tests__/index.test.jsx | // __tests__/index.test.jsx | ||
سطر 337: | سطر 347: | ||
</syntaxhighlight>'''ملاحظة''': لا ينبغي وضع ملفات الاختبار مباشرة ضمن مجلد الصفحات لأن كل ملف في هذا المجلد يُعدّث وجهة route. | </syntaxhighlight>'''ملاحظة''': لا ينبغي وضع ملفات الاختبار مباشرة ضمن مجلد الصفحات لأن كل ملف في هذا المجلد يُعدّث وجهة route. | ||
* '''تشغيل مجموعة الاختبارات''': نفّذ ببساطة الأمر <code>npm run test</code> | * '''تشغيل مجموعة الاختبارات''': نفّذ ببساطة الأمر <code>npm run test</code> وستلاحظ مجموعة من الأوامر التفاعلية يولّدها Jest سواء أخفق أو نجح الاختبار، ولهذا فائدته عند إضافة اختبارات أكثر. | ||
لمعلومات أكثر، يمكنك الاطلاع على المصادر التالية: | لمعلومات أكثر، يمكنك الاطلاع على المصادر التالية: | ||
* توثيق Jest | * [https://jestjs.io/docs/getting-started توثيق Jest] | ||
* [https://testing-library.com/docs/react-testing-library/intro/ توثيق مكتبة اختبارت React] | * [https://testing-library.com/docs/react-testing-library/intro/ توثيق مكتبة اختبارت React] | ||
* [https://testing-playground.com/ Testing Playground]: وهي منصة تدرّبك على إجراء الاختبارات ومطابقة العناصر. | * [https://testing-playground.com/ Testing Playground]: وهي منصة تدرّبك على إجراء الاختبارات ومطابقة العناصر. | ||
== حزم طوّرها مجتمع Next.js | == حزم طوّرها مجتمع Next.js وأمثلة متنوعة == | ||
طوّر مجتمع Next.js حزمًا قد تجدها مفيدة منها: | طوّر مجتمع Next.js حزمًا قد تجدها مفيدة منها: | ||
* [https://github.com/toomuchdesign/next-page-tester next-page-tester]: لمكاملة شجرة DOM مع الاختبارات. | * [https://github.com/toomuchdesign/next-page-tester next-page-tester]: لمكاملة شجرة DOM مع الاختبارات. | ||
* [https://github.com/scottrippey/next-router-mock next-router-mock]: من أجل Storybook. | * [https://github.com/scottrippey/next-router-mock next-router-mock]: من أجل Storybook. | ||
== أمثلة == | |||
* [https://github.com/vercel/next.js/tree/canary/examples/with-cypress Next.js with Cypress] | |||
* [https://github.com/vercel/next.js/tree/canary/examples/with-playwright Next.js with Playwright] | |||
* [https://github.com/vercel/next.js/tree/canary/examples/with-jest Next.js with Jest and React Testing Library] | |||
* [https://github.com/vercel/next.js/tree/canary/examples/with-vitest Next.js with Vitest] | |||
== المصادر == | == المصادر == | ||
* الصفحة [https://nextjs.org/docs/testing Testing] من توثيق Next.js الرسمي. | * الصفحة [https://nextjs.org/docs/testing Testing] من توثيق Next.js الرسمي. | ||
[[تصنيف:Next.js|{{SUBPAGENAME}}]] |
المراجعة الحالية بتاريخ 17:16، 3 يناير 2023
نلقي نظرة في هذه الصفحة على طرق اختبار تطبيقات Next.js باستخدادم أدوات مثل Cypress و Playwright و Jest مع مكتبة اختبار React.
اختبار تطبيقات Next.js باستخدام Cypress
تُستخدم المكتبة Cypress في تنفيذ اختبارات شاملة End-to-End Testing -أو E2E اختصارًا- واختبارات التكامل Integration Testing.
بداية سريعة
بإمكانك استخدام create-next-app
مع المثال with-cypress لتبدأ العمل بسرعة:
npx create-next-app@latest --example with-cypress with-cypress-app
الإعداد اليدوي
ثبّت حزمة cypress
كالتالي:
npm install --save-dev cypress
أضف Cypress إلى حقل السكربتات "scripts" في ملف package.json
:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"cypress": "cypress open",
}
شغّل Cypress للمرة الأولى لكي تولِّد أمثلة تستخدم الهيكلية المفضّلة للمجلد الخاص بها:
npm run cypress
يمكنك الاطلاع على الأمثلة الموّلدة وتوثيق Cypress لتألف التعامل مع هذ المكتبة.
إنشاء أول اختبار تكامل باستخدام Cypress
لنفترض وجود صفحتي Next.js التاليتين:
// pages/index.js
import Link from 'next/link'
export default function Home() {
return (
<nav>
<Link href="/about">
<a>About</a>
</Link>
</nav>
)
}
// pages/about.js
export default function About() {
return (
<div>
<h1>About Page</h1>
</div>
)
}
أضف اختبارًا للتحقق من إمكانية التنقل بينهما:
// cypress/integration/app.spec.js
describe('Navigation', () => {
it('should navigate to the about page', () => {
// index ابدأ بالصفحة
cy.visit('http://localhost:3000/')
//ثم انقر عليها "about" التي تضم href جد رابطًا له السمة
cy.get('a[href*="about"]').click()
//"/about" ينبغي أن يضم العنوان الجدبد
cy.url().should('include', '/about')
//"About page" مع h1 ينبغي أن تضم الصفحة الجديدة العنصر
cy.get('h1').contains('About Page')
})
})
بإمكانك استخدام ("/")cy.visit
بدلًا من cy.visit("http://localhost:3000/")
، إن أضفت "baseUrl": "http://localhost:3000"
إلى ملف التهيئة cypress.json
.
تنفيذ اختبارات Cypress
تختبر Cypress تطبيقات Next.js حقيقية لذلك لا بد أن يعمل خادم Next.js قبل أن تبدأ Cypress. ننصحك بتطبيق اختباراتك على شيفرة الإنتاج لتقف بشكل أوضح على سلوك تطبيقك.
نفّذ الأمر npm run build
ثم npm run start
وبعد ذلك الأمر npm run cypress
في نافذة جديدة للطرفية لتشغيل Cypress.
ملاحظة: بإمكانك كحل بديل أن تُثبِّت الحزمة start-server-and-test
وتضيفها إلى حقل السكربتات "scripts" في ملف package.json
كالتالي:
"test": "start-server-and-test start http://localhost:3000 cypress"
وذلك كي تُشغّل خادم إنتاج Next.js إلى جوار Cypress، وتذكرأن تعيد بناء التطبيق بعد إجراء تعديلات جديدة.
التحضير لعملية التكامل المتواصل CI في تطبيقات Next.js
ربما ستلاحظ أن Cypress تشغل متصفحًا تفاعليًا ليس نموذجيًا لبيئة التكامل المتواصل Continuous Integration. بإمكانك أن تُشغّل Cypress أيضًا دون واجهة المتصفح تلك بتنفيذ الأمر cypress run
:
// package.json
"scripts": {
//...
"cypress": "cypress open",
"cypress:headless": "cypress run",
"e2e": "start-server-and-test start http://localhost:3000 cypress",
"e2e:headless": "start-server-and-test start http://localhost:3000 cypress:headless"
}
يمكنك الاطلاع على المزيد من المعلومات حول Cypress والتتكامل المتواصل من خلال المصادر التالية:
اختبار تطبيقات Next.js باستخدام Playwright
Playwright هو إطار عمل للاختبارات يتيح لك أتمتة Chromium و Firefox و WebKit من خلال واجهة برمجية واحدة. يُمكنك استخدام Playwright في تنفيذ الاختبارات الشاملة End-to-End واختبارات التكامل Integration عبر جميع المنصات.
بداية سريعة
بإمكانك استخدام create-next-app
مع المثال with-playwright لتبدأ العمل بسرعة. سيُنشئ ذلك مشروعًا جديدًا أعدت فيه Next.js بشكل كامل.
npx create-next-app@latest --example with-playwright with-playwright-app
الإعداد اليدوي
بإمكانك أن تستخدم npm init playwright
أيضًا لإضافة Playwright إلى مشروع NPM
موجود مسبقًا. ثبِّت الحزمة playwright/test@
لكي تبدأ يدويًا العمل مع Playwright.
npm install --save-dev @playwright/test
أضف Playwright إلى حقل "scripts" في الملف package.json
:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test:e2e": "playwright test",
}
إنشاء أول اختبار مشترك للواجهتين باستخدام Playwright
افترض وجود صفحتي Next.js التاليتين:
// pages/index.js
import Link from 'next/link'
export default function Home() {
return (
<nav>
<Link href="/about">
<a>About</a>
</Link>
</nav>
)
}
// pages/about.js
export default function About() {
return (
<div>
<h1>About Page</h1>
</div>
)
}
أضف اختبارًا يتحقق من إمكانية التنقل بين الصفحتين:
// e2e/example.spec.ts
import { test, expect } from '@playwright/test'
test('should navigate to the about page', async ({ page }) => {
// يُحدد العنوان الجذري من قبل خادم ويب وفقًا للملف) index ابدأ من الصفحة
// the playwright.config.ts)
await page.goto('http://localhost:3000/')
//وانقر عليه 'About Page' جد عنصرًا يحمل النص
await page.click('text=About Page')
//(باستخدام العنوان الجذري) "/about" الجديد هو URL ينبغي أن يكون عنوان
await expect(page).toHaveURL('http://localhost:3000/about')
//"About page" مع h1 ينبغي أن تضم الصفحة الجديدة العنصر
await expect(page.locator('h1')).toContainText('About Page')
})
بإمكانك استخدام ("/")page.goto
بدلًا من page.goto("http://localhost:3000/")
، إن أضفت "baseUrl": "http://localhost:3000"
إلى ملف التهيئة playwright.config.ts
.
تنفيذ اختبارات Playwright
تختبر Playwright تطبيقات Next.js حقيقية لذلك لا بد أن يعمل خادم Next.js قبل أن تبدأ Playwright. ننصحك بتطبيق اختباراتك على شيفرة الإنتاج لتقف بشكل أوضح على سلوك تطبيقك.
نفّذ الأمر npm run build
ثم npm run start
وبعد ذلك الأمر npm run test:e2e
في نافذة جديدة للطرفية لتشغيل Playwright.
ملاحظة: بإمكانك كحل بديل استخدام الميزة webServer
لكي تسمح للمكتبة Playwright بتشغيل خادم التطوير ومن ثم تنتظر حتى يجهز تمامًا.
تشغيل Playwright في وضع التكامل المتواصل
تُنفَّذ Playwright اختباراتك دون واجهة headless mode افتراضيًا. ولتثبيت كل اعتماديات Playwright نفّذ الأمر npx playwright install-deps
بإمكانك الاطلاع أكثر على Playwright والتكامل المتواصل من خلال المصادر التالية:
- تجهّز للعمل مع Playwright.
- استخدام خادم التطوير.
- استخدام Playwright مع مزوّد التكامل المتواصل الخاص بك.
اختبار تطبيقات Next.js باستخدام Jest ومكتبة اختبار React
تُستسخدم هاتين المكتبتين مرارًا في إجراء اختبار الوحدات Unit Testing. وهنالك ثلاث طرق لكي تستخدم Jest في تطبيق Next.js:
- استخدام أحد أمثلة الإقلاع السريع.
- مع مُصرَّف Rust الخاص بتطبيقات Next.js.
- باستخدام Babel.
بداية سريعة
بإمكانك استخدام create-next-app
مع المثال with-jest لتبدأ العمل بسرعة:
npx create-next-app@latest --example with-jest with-jest-app
إعداد المكتبة Jest (مع مُصرّف Rust)
تتمتع Next.js ابتداءً من النسخة 12 بدعم مدمج للمكتبة Jest. ولإعداد Jest، ثبِّت الاعتماديات التالية jest
و @testing-library/react
و @testing-library/jest-dom
:
npm install --save-dev jest @testing-library/react @testing-library/jest-dom
أنشئ الملف jest.config.js
في جذر مجلد مشروعك وأضف الشيفرة التالية:
// jest.config.js
const nextJest = require('next/jest')
const createJestConfig = nextJest({
//في بيئة التطوير .env وملفات next.config.js ضع مسار تطبيقك لتحميل
dir: './',
})
// Jest أضف أية إعدادات أخرى تنوي تمريرها إلى
const customJestConfig = {
// أضف أية خيارات إعداد أخرى قبل تنفيذ كل اختبار
// setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
// ستحتاج إلى مايلي لإخفاء العمل baseUrl مع عناوين جذرية TypeScript إن كنت تستخدم
moduleDirectories: ['node_modules', '<rootDir>/'],
testEnvironment: 'jest-environment-jsdom',
}
//قادر على next/jest بهذا الشكل للتأكد من أن createJestConfig تُصدّر
//بشكل غير متزامن Next.js تحميل إعدادات
module.exports = createJestConfig(customJestConfig)
تهيئ next/jest
المكتبة Jest خلف الستار نيابة عنك بما في ذلك:
- إعداد
transform
باستخدام SWC. - التقليد التلقائي للتنسيقات (
css.
وmodule.css.
وما يماثلها من تنسيقاتSCSS
). - تحميل
env.
(وكل ما يماثلها) ضمنprocess.env
. - تجاهل
node_modules
عند تحليل وتنفيذ الاختبارات والتحويلات transforms. - تجاهل
next.
عند تحليل الاختبار. - تحميل
next.config.js
من أجل الرايات التي تفعّل تحويلات SWC.
ملاحظة: إن أردت اختبار متغيرات البيئة مباشرةً، فحملهم يدويًا في سكربت تهيئة منفصل أو في ملف jest.config.js، ولمزيد من التفاصيل، ارجع إلى قسم اختبار متغيرات البيئة.
ضبط إعدادات Jest مع Babel
إن أردت الاستغناء عن مُصرِّف Rust، لا بد من ضبط إعدادات Babel يدويًا وتثبيت babel-jest
و identity-obj-proxy
بالإضافة إلى الحزم التي ثبتها سابقًا.
إليك الخيارات المستحسنة لتهيئة Jest من أجل تطبيقات Next.js:
// jest.config.js
module.exports = {
collectCoverage: true,
coverageProvider: 'v8',
collectCoverageFrom: [
'**/*.{js,jsx,ts,tsx}',
'!**/*.d.ts',
'!**/node_modules/**',
'!<rootDir>/out/**',
'!<rootDir>/.next/**',
'!<rootDir>/*.config.js',
'!<rootDir>/coverage/**',
],
moduleNameMapper: {
// (CSS مع وحدات) المُدرج CSS التعامل مع تنسيقات
// https://jestjs.io/docs/webpack#mocking-css-modules
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
//(CSS دون وحدات) المُدرج CSS التعامل مع تنسيقات
// Handle CSS imports (without CSS modules)
'^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
// التعامل مع إدراج الصور
// https://jestjs.io/docs/webpack#handling-static-assets
'^.+\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i': `<rootDir>/__mocks__/fileMock.js`,
// التعامل مع الوحدات البديلة (المقنعة أو المخفية)
'^@/components/(.*)$': '<rootDir>/components/$1',
},
// أضف أية خيارات إعداد أخرى قبل تنفيذ كل اختبار
// setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'],
testEnvironment: 'jsdom',
transform: {
//next/babel لنقل شيفرة الاختبارات باستخدام babel-jest استخدام
// https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
},
transformIgnorePatterns: [
'/node_modules/',
'^.+\\.module\\.(css|sass|scss)$',
],
}
بإمكانك الاطلاع على كل خيار من خيارات الإعداد في توثيق Jest.
إدراج الصور وصفحات التسيق CSS
لا تُستخدم الصور والتنسيقات في الاختبارات لكن إدراجها قد يقود إلى أخطاء، وبالتالي لا بد من تقليدها. انشئ ملفات التقليد mock files المُشار إليها في الإعدادات السابقة (fileMock.js
و styleMock.js
) ضمن المجلد __mocks__
:
// __mocks__/fileMock.js
module.exports = {
src: '/img.jpg',
height: 24,
width: 24,
blurDataURL: 'data:image/png;base64,imagedata',
}
// __mocks__/styleMock.js
module.exports = {}
لمعلومات أكثر عن التعامل مع الموجودات أو الأصول الثابتة static assets راجع توثيق Jest.
توسعة Jest بمطابقات مخصصة (اختياري)
تتضمن testing-library/jest-dom@
مجموعة من المُطابِقات المخصصة custom matchers التي تُسهَّل كتابة الاختبارات مثل ()toBeInTheDocument.
. بإمكانك إدراج المُطابق المخصص في كل اختبار بإضافة الخيار التالي إلى ملف تهيئة Jest:
// jest.config.js
setupFilesAfterEnv: ['<rootDir>/jest.setup.js']
ثم أدرج ما يلي داخل الملف jest.setup.js
:
// jest.setup.js
import '@testing-library/jest-dom/extend-expect'
إن أردت إضافة المزيد من خيارات الإعداد قبل كل اختبار، فمن الشائع إضافتها داخل الملف jest.setup.js
.
الإدراجات ذات المسارات المطلقة والبديلة
إن استخدمت بدائل مسار الوحدة البرمجية Module Path Aliases، فلا بد من تهيئة Jest ليحلل هذه الإدراجات بمطابقة الخيار "paths" (المسارات) في الملف jsconfig.json
مع الخيار moduleNameMapper
في الملف jest.config.js
. إليك مثالًا:
// tsconfig.json or jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/components/*": ["components/*"]
}
}
}
// jest.config.js
moduleNameMapper: {
'^@/components/(.*)$': '<rootDir>/components/$1',
}
إنشاء الاختبارات الخاصة بك
- إضافة سكربت الاختبار إلى الملف package.json: أضف خيار تنفيذ اختبارات Jest إلى سكربتات
package.json
، إذ يعيد الخيار تشغيل الاختبار عندما يتغير الملف:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest --watch"
}
- إنشاء أول اختباراتك: أصبح مشروعك الآن جاهزًا لتنفيذ الاختبارات. اتبع تقاليد Jest بإضافة الاختبارات إلى المجلد
__tests__
في جذر مجلد مشروعك. يمكنك مثلًا إضافة اختبار يتحقق من تصيير المكوّن</ Home>
لعنوان بشكل صحيح:
// __tests__/index.test.jsx
import { render, screen } from '@testing-library/react'
import Home from '../pages/index'
import '@testing-library/jest-dom'
describe('Home', () => {
it('renders a heading', () => {
render(<Home />)
const heading = screen.getByRole('heading', {
name: /welcome to next\.js!/i,
})
expect(heading).toBeInTheDocument()
})
})
وكخيار آخر، أضف اختبار اللقطات snapshot test لتعقب التغيرات غير المتوقعة في المكوّن </ Home>
// __tests__/snapshot.js
import { render } from '@testing-library/react'
import Home from '../pages/index'
it('renders homepage unchanged', () => {
const { container } = render(<Home />)
expect(container).toMatchSnapshot()
})
ملاحظة: لا ينبغي وضع ملفات الاختبار مباشرة ضمن مجلد الصفحات لأن كل ملف في هذا المجلد يُعدّث وجهة route.
- تشغيل مجموعة الاختبارات: نفّذ ببساطة الأمر
npm run test
وستلاحظ مجموعة من الأوامر التفاعلية يولّدها Jest سواء أخفق أو نجح الاختبار، ولهذا فائدته عند إضافة اختبارات أكثر.
لمعلومات أكثر، يمكنك الاطلاع على المصادر التالية:
- توثيق Jest
- توثيق مكتبة اختبارت React
- Testing Playground: وهي منصة تدرّبك على إجراء الاختبارات ومطابقة العناصر.
حزم طوّرها مجتمع Next.js وأمثلة متنوعة
طوّر مجتمع Next.js حزمًا قد تجدها مفيدة منها:
- next-page-tester: لمكاملة شجرة DOM مع الاختبارات.
- next-router-mock: من أجل Storybook.
أمثلة
- Next.js with Cypress
- Next.js with Playwright
- Next.js with Jest and React Testing Library
- Next.js with Vitest
المصادر
- الصفحة Testing من توثيق Next.js الرسمي.