اختبار تطبيقات Next.js
نلقي نظرة في هذه الصفحة على طرق اختبار تطبيقات Next.js باستخدادم أدوات مثل Cypress و Playwright و Jest مع مكتبة اختبار React.
اختبار تطبيقات Next.js باستخدام Cypress
تُستخدم المكتبة في تنفيذ اختبارات مشتركة للواجهتين الأمامية و الخلفية End-to-End واختبارات التكامل 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
وتضيفها إلى حقل السكربتات في ملف package.json
كالتالي:
"test": "start-server-and-test start http://localhost:3000 cypress"
وذلك كي تُشغّل خادم إنتاج إلى جوار, وتذكرأن تعيد بناء التطبيق بعد إجراء تعديلات جديدة.
التحضير لعملية التكامل المتواصل CI في تطبيقات Next.js
ربما ستلاحظ أن تشغل متصفحًا تفاعليًا ليس نموذجيًا لبيئة التكامل المتواصل 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 والتتكامل المتواصل من خلال المصادر التالية:
- توثيق التكامل المتواصل في Cypress
- دليل استخدام Cypress مع أفعال GitHub
- دليل استخدام Cypress مع أفعال GitHub
اختبار تطبيقات Next.js باستخدام Playwright
Playwright هو إطار عمل للاختبارات يتيح لك أتمتة Chromium و Firefox و WebKit من خلال واجهة برمجية واحدة. يُمكنك استخدام في تنفيذ الاختبارات المشتركة للواجهتين واختبارات التكامل عبر جميع المنصات.
بدلية سريعة
بإمكانك استخدام 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 قبل أن تبدأ Cypress. ننصحك بتطبيق اختباراتك على شيفرة الإنتاج لتقف بشكل أوضح على سلوك تطبيقك.
نفّذ الأمر npm run build
ثم npm run start
وبعد ذلك الأمر npm run test:e2e
في نافذة جديدة للطرفية لتشغيل Playwright.
ملاحظة: بإمكانك كحل بديل استخدام الميزة webServer
لكي تسمح للمكتبة Playwright بتشغيل خادم التطوير ومن ثم تنتظر حتى يجهز تمامًا
تشغيل Playwright في وشع التكامل المتواصل
تُنفَّذ Playwright اختباراتك دون ترويسات افتراضيًا. ولتثبيت كل اعتماديات Playwright نفّذ الأمر npx playwright install-deps
بإمكانك الاطلاع أكثر على Playwright والتكامل المتواصل من خلال المصادر التالية:
- تجهّز للعمل مع Playwright.
- استخدام خادم التطوير.
- استخدام Playwright مع مزوّد التكامل المتواصل الخاص بك.
استخدام Jest ومكتبة اختبار React لاختبار تطبيقات Next.js
تُستسخدم هاتين المكتبتين مرارًا في إجراء اختبار الوحدات Unit Testing. وهنالك ثلاث طرق لكي تستخدم Jest في تطبيق Next.js:
- استخدام أحد أمثلة الإقلاع السريع.
- مع مُصرَّف Rust الخاص بتطبيقات .
- باستخدام 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'],
// مع عناوين جذرية ستحتاج إلى مايلي لإخفاء العمل 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 مع Babel
إن أردت الاستغناء عن مُصرِّف Rust، لا بد من ضبط إعدادات يدويًا وتثبيت babel-jest
و identity-obj-proxy
بالإضافة إلى الحزم التي ثبتها سابقًا.
إليك الخيارات المستحسنة لتهيئة Jest من أجل تطبيقات Next.js:
// jest.config.js
module.exports = {
collectCoverageFrom: [
'**/*.{js,jsx,ts,tsx}',
'!**/*.d.ts',
'!**/node_modules/**',
],
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.
إدراج الصور و صفحات التسيق الموّرثة
لا تُستخدم الصور و التنسيقات الموَّرثة في الاختبارات لكن إدراجها قد يقود إلى أخطاء، وبالتالي لا بد من تقليدها. انشئ ملفات التقليد 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 = {}
لمعلومات أكثر عن التعامل مع الموجودات الساكنة راجع توثيق 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.
المصادر
- الصفحة Testing من توثيق Next.js الرسمي.