الفرق بين المراجعتين لصفحة: «Next.js/testing»

من موسوعة حسوب
لا ملخص تعديل
طلا ملخص تعديل
 
(3 مراجعات متوسطة بواسطة مستخدمين اثنين آخرين غير معروضة)
سطر 3: سطر 3:


== اختبار تطبيقات Next.js باستخدام Cypress ==
== اختبار تطبيقات Next.js باستخدام Cypress ==
تُستخدم المكتبة في تنفيذ اختبارات مشتركة للواجهتين الأمامية و الخلفية End-to-End واختبارات التكامل Integration Testing.  
تُستخدم المكتبة Cypress في تنفيذ اختبارات شاملة End-to-End Testing -أو E2E اختصارًا- واختبارات التكامل Integration Testing.  


=== بداية سريعة ===
=== بداية سريعة ===
سطر 20: سطر 20:
   "cypress": "cypress open",
   "cypress": "cypress open",
}
}
</syntaxhighlight>شغّل Cypress للمرة الأولى لكي تولِّد أمثلة تستخدم البنية المستحسنة للمجلد الخاص بها:<syntaxhighlight lang="bash">
</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>بإمكانك استخدام <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>.  
</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 ===
ربما ستلاحظ أن تشغل متصفحًا تفاعليًا ليس نموذجيًا لبيئة التكامل المتواصل Continuous Integration. بإمكانك أن تُشغّل Cypress أيضًا دون ترويسة بتنفيذ الأمر <code>cypress run</code>:<syntaxhighlight lang="json">
ربما ستلاحظ أن 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]
* [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] لتبدأ العمل بسرعة. سيُنشئ ذلك مشروع  جديد أعد فيه Next.js بشكل كامل.<syntaxhighlight lang="bash">
بإمكانك استخدام <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>بإمكانك استخدام <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>.  
</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 قبل أن تبدأ Cypress. ننصحك بتطبيق اختباراتك على شيفرة الإنتاج لتقف بشكل أوضح على سلوك تطبيقك.
تختبر 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 نفّذ الأمر <code>npx playwright install-deps</code>
تُنفَّذ 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 مع مزوّد التكامل المتواصل الخاص بك].


== استخدام Jest ومكتبة اختبار React لاختبار تطبيقات Next.js ==
== اختبار تطبيقات 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 lang="javascript">
</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'],
   // مع عناوين جذرية ستحتاج إلى مايلي لإخفاء العمل TypeScript إن كنت تستخدم  
   // ستحتاج إلى مايلي لإخفاء العمل baseUrl مع عناوين جذرية TypeScript إن كنت تستخدم  
   moduleDirectories: ['node_modules', '<rootDir>/'],
   moduleDirectories: ['node_modules', '<rootDir>/'],
   testEnvironment: 'jest-environment-jsdom',
   testEnvironment: 'jest-environment-jsdom',
}
}
//قادر على  next/jest بهذا الشكل للتاكد من أن createJestConfig تُصدّر  
//قادر على  next/jest بهذا الشكل للتأكد من أن createJestConfig تُصدّر  
//بشكل غير متزامن Next.js تحميل إعدادات  
//بشكل غير متزامن Next.js تحميل إعدادات  
module.exports = createJestConfig(customJestConfig)
module.exports = createJestConfig(customJestConfig)
</syntaxhighlight>تهيئ <code>next/jest</code> تحت الستار Jest نيابة عنك بما في ذلك:
</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>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> عند تحليل وتنفيذ الاختبارات و التحويلات transforms.
* تجاهل <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">
لا تُستخدم الصور والتنسيقات في الاختبارات لكن إدراجها قد يقود إلى أخطاء، وبالتالي لا بد من تقليدها. انشئ ملفات التقليد 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>لمعلومات أكثر عن التعامل مع الموجودات الساكنة راجع [https://jestjs.io/docs/webpack#handling-static-assets توثيق Jest].
</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">
تتضمن <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-path-aliases|بدائل مسار الوحدة البرمجية]] Module Path Aliases، فلا بد من تهيئة Jest ليحلل هذه الإدراجات بمطابقة الخيار "paths" (المسارات) في الملف <code>jsconfig.json</code> مع الخيار <code>moduleNameMapper</code> في الملف <code>jest.config.js</code>. إليك مثالًا:<syntaxhighlight lang="javascript">
إن استخدمت [[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 إلى سكربتات <code>package.json</code> حيث يعيد الخيار تشغيل الاختبار عندما يتغير الملف:
* '''إضافة سكربت الاختبار إلى الملف 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> لعنوان بشكل صحيح:
* '''إنشاء أول اختباراتك''': أصبح مشروعك الآن جاهزًا لتنفيذ الاختبارات. اتبع تقاليد 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>. ستلاحظ مجموعة من الأوامر التفاعلية يولّدها Jest سواء أخفق أو نجح الاختبار ولهذا فائدته عند إضافة اختبارات أكثر.
* '''تشغيل مجموعة الاختبارات''': نفّذ ببساطة الأمر <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 والتكامل المتواصل من خلال المصادر التالية:

اختبار تطبيقات Next.js باستخدام Jest ومكتبة اختبار React

تُستسخدم هاتين المكتبتين مرارًا في إجراء اختبار الوحدات Unit Testing. وهنالك ثلاث طرق لكي تستخدم Jest في تطبيق Next.js:

  1. استخدام أحد أمثلة الإقلاع السريع.
  2. مع مُصرَّف Rust الخاص بتطبيقات Next.js.
  3. باستخدام 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 سواء أخفق أو نجح الاختبار، ولهذا فائدته عند إضافة اختبارات أكثر.

لمعلومات أكثر، يمكنك الاطلاع على المصادر التالية:

حزم طوّرها مجتمع Next.js وأمثلة متنوعة

طوّر مجتمع Next.js حزمًا قد تجدها مفيدة منها:

أمثلة

المصادر

  • الصفحة Testing من توثيق Next.js الرسمي.