چرا تست بلاکهای وردپرس با Jest و Playwright ضروری است؟
بدون تست خودکار، بلاکهای وردپرس با هر تغییر در وردپرس یا افزونهها میشکنند. چرا Jest و Playwright استاندارد تست بلاکهای حرفهای شدهاند؟
اولین باری که یک بلاک سفارشی گوتنبرگ را بدون هیچ تستی روی یک سایت Production مستقر کردم، دو هفته بعد، پس از یک بهروزرسانی جزئی در پکیج @wordpress/block-editor، ویرایشگر آن سایت کامل از کار افتاد. کنسول مرورگر پر از خطاهای TypeError: Cannot read property 'blocks' of undefined بود و تیم محتوا نمیتوانست حتی یک نوشته جدید ذخیره کند. آن تجربه، هزینه واقعی نداشتن تست را برای همیشه در ذهنم حک کرد.
چرا تست بلاکهای وردپرس ضروری است؟
بلاکهای گوتنبرگ (Gutenberg Blocks) تنها قطعه کد ساده نیستند. هر بلاک یک اپلیکیشن کوچک React است که در سه محیط مختلف اجرا میشود: ویرایشگر (Editor)، فرانتاند (Front-end)، و ذخیرهساز (Serializer). این سه محیط، هرکدام چرخه حیات متفاوتی دارند و یک بلاک که در ویرایشگر کار میکند، ممکن است در فرانتاند ناقص رندر شود یا در Serializer دادههای نادرستی تولید کند. اگر با آموزش ساخت بلاک سفارشی گوتنبرگ آشنا باشید، میدانید که پیچیدگی این چرخه سهگانه، تنها با تست قابل مدیریت است.
فرض کنید یک بلاک نمایش قیمت محصول را میسازید. در ویرایشگر، کاربر قیمت را وارد میکند. در فرانتاند، قیمت باید با فرمت صحیح و واحد پول نمایش داده شود. در Serializer، قیمت باید بهصورت Attribute معتبر ذخیره شود تا در ویرایشهای بعدی قابل بازیابی باشد. اگر فقط یکی از این سه لایه نادرست باشد، تجربه کاربری بهطور کامل مختل میشود.
«یک بلاک بدون تست، شبیه یک پل بدون بازرسی فنی است: ممکن است سالها کار کند، اما یک روز، بدون هشدار، فرو میریزد.»
مشکل دوم، Dependency Drift (انحراف وابستگی) است. بلاکهای گوتنبرگ به دهها پکیج npm وابسته هستند: @wordpress/blocks، @wordpress/block-editor، @wordpress/components، @wordpress/data، @wordpress/i18n و دهها پکیج دیگر. هر بهروزرسانی در این پکیجها میتواند رفتار بلاک را تغییر دهد. بدون تست، این تغییرات تا زمانی که در Production فاجعه ایجاد نکنند، کشف نمیشوند.
مشکل سوم، Regression (پسرفت) است. در پروژههای تیمی، هر توسعهدهنده ممکن است بخشی از منطق بلاک را تغییر دهد و بدون اینکه بداند، رفتار بخش دیگری را خراب کند. تستها بهعنوان یک شبکه ایمنی عمل میکنند: اگر تغییری باعث پسرفت شود، در محیط CI/CD قبل از Merge کشف میشود. اگر با تست و دیباگ پروژههای توسعه وردپرس آشنا شده باشید، این موضوع را بهعنوان یک اصل بنیادین مهندسی میشناسید.
مشکل چهارم، Backward Compatibility است. بلاکهای گوتنبرگ نه فقط باید در نسخه فعلی وردپرس کار کنند، بلکه باید با نسخههای قبلی نیز سازگار باشند. هر بلاک میتواند چندین deprecated داشته باشد که رفتار نسخههای قبلی را شبیهسازی میکنند. تست این Deprecationها بدون اتوماسیون تقریباً غیرممکن است.
Jest و Playwright: دو لایه مکمل تست
Jest و Playwright دو ابزار متفاوت با دو هدف متفاوت هستند. Jest یک Test Runner است که برای تست منطق JavaScript در محیط Node.js طراحی شده. Playwright یک Browser Automation Framework است که مرورگر واقعی را کنترل میکند و تعامل کاربر را شبیهسازی مینماید. ترکیب این دو، یک هرم تست (Testing Pyramid) کامل میسازد.
| معیار | Jest | Playwright |
|---|---|---|
| محیط اجرا | Node.js (بدون مرورگر) | مرورگر واقعی (Chromium, Firefox, WebKit) |
| سرعت | بسیار سریع (میلیثانیه) | کندتر (ثانیه) |
| نوع تست | Unit، Integration، Snapshot | End-to-End، Visual Regression |
| پوشش | منطق بلاک، Attributeها، Deprecated | تعامل کاربر، رندر نهایی، ذخیره محتوا |
| هزینه نگهداری | پایین | متوسط تا بالا |
| زمان اجرا در CI | چند ثانیه | چند دقیقه |
Jest برای تستهایی که به مرورگر نیازی ندارند ایدهآل است: تست توابع Helper، تست اعتبارسنجی Attributeها، تست منطق تبدیل داده، و تست Deprecated Blockها. Playwright برای تستهایی که باید مرورگر واقعی را کنترل کنند: تست درج بلاک در ویرایشگر، تست تغییر تنظیمات، تست ذخیره نوشته، و تست رندر فرانتاند.
«هر تستی که میتواند در Jest نوشته شود، نباید در Playwright نوشته شود. Playwright گرانتر است، کندتر است، و شکنندهتر. Jest را بهعنوان خط اول دفاع و Playwright را بهعنوان خط آخر در نظر بگیرید.»
این اصل، به Testing Trophy معروف است که توسط Kent C. Dodds مطرح شد: بیشترین تست باید در سطح Integration باشد (نه Unit، نه E2E)، و E2E فقط برای Critical Pathها نوشته شود. در بلاکهای وردپرس، این یعنی تستهای Jest برای منطق و Attributeها، تستهای Playwright برای Workflowهای کاربر.
راهاندازی محیط تست با wp-env و @wordpress/scripts
وردپرس یک اکوسیستم رسمی برای تست بلاکها فراهم میکند که شامل دو ابزار اصلی است: @wordpress/env برای راهاندازی محیط توسعه و @wordpress/scripts برای Build و Test. این دو ابزار، استاندارد رسمی تیم Gutenberg هستند.
نصب @wordpress/env
ابزار wp-env یک محیط وردپرس کامل با Docker راهاندازی میکند:
npm install --save-dev @wordpress/env
npx wp-env start
پس از اجرا، دو محیط ایجاد میشود: یک محیط Development در http://localhost:8888 و یک محیط Test در http://localhost:8889. محیط Test برای اجرای تستهای Playwright استفاده میشود. اگر با توسعه وردپرس با محیط لوکال آشنا باشید، این ابزار را بهعنوان نسخه رسمی و استاندارد آن میشناسید.
پیکربندی @wordpress/scripts
پکیج @wordpress/scripts تمام تنظیمات Webpack، Babel، ESLint و Jest را بهصورت از پیشپیکربندیشده فراهم میکند:
npm install --save-dev @wordpress/scripts
سپس در فایل package.json اسکریپتهای تست تعریف میشوند:
{
"scripts": {
"test:unit": "wp-scripts test-unit-js",
"test:e2e": "wp-scripts test-playwright",
"test:unit:watch": "wp-scripts test-unit-js --watch"
}
}
پکیج @wordpress/scripts بهطور خودکار فایلهای .test.js و .spec.js در پوشه src/ را شناسایی میکند و تنظیمات Jest را بدون نیاز به پیکربندی دستی اعمال مینماید. این ابزار، بخش عمدهای از پیچیدگی راهاندازی تست را حذف میکند و به توسعهدهنده اجازه میدهد روی منطق تست تمرکز کند.
ساختار پوشه پیشنهادی
ساختار استاندارد برای یک پروژه بلاک با تست:
my-block/
├── src/
│ ├── index.js
│ ├── edit.js
│ ├── save.js
│ ├── utils.js
│ └── __tests__/
│ ├── utils.test.js
│ └── save.test.js
├── tests/
│ └── e2e/
│ └── block.spec.js
├── package.json
└── playwright.config.js
این ساختار، جداسازی تستهای واحد و E2E را تضمین میکند و با ساختار فایلهای یک افزونه استاندارد وردپرس همخوانی دارد.
تست واحد با Jest: منطق بلاک
تست واحد در Jest برای بررسی منطق بلاک بدون نیاز به مرورگر استفاده میشود. این تستها سریع، پایدار و ارزان هستند و باید بخش عمده هرم تست را تشکیل دهند.
تست توابع Helper
فرض کنید یک بلاک نمایش قیمت دارید که تابعی بهنام formatPrice در فایل utils.js دارد:
// src/utils.js
export function formatPrice(amount, currency = "USD") {
if (typeof amount !== "number" || isNaN(amount)) {
return "";
}
const formatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency,
});
return formatter.format(amount);
}
تست این تابع در Jest:
// src/__tests__/utils.test.js
import { formatPrice } from "../utils";
describe("formatPrice", () => {
it("should format USD correctly", () => {
expect(formatPrice(1234.5, "USD")).toBe("$1,234.50");
});
it("should handle zero", () => {
expect(formatPrice(0, "USD")).toBe("$0.00");
});
it("should return empty string for invalid input", () => {
expect(formatPrice("abc")).toBe("");
expect(formatPrice(null)).toBe("");
expect(formatPrice(undefined)).toBe("");
});
it("should support EUR currency", () => {
expect(formatPrice(100, "EUR")).toContain("100");
});
});
این تستها در کمتر از ۵۰ میلیثانیه اجرا میشوند و تمام Edge Caseها را پوشش میدهند. اگر تابع formatPrice تغییر کند و یکی از این رفتارها بشکند، تست در CI/CD شکست میخورد. اگر با اصول کدنویسی تمیز در پروژههای وردپرس آشنا باشید، جداسازی منطق در توابع Helper را بهعنوان یک الگوی بنیادین میشناسید.
تست Attribute Validation
هر بلاک گوتنبرگ یک Schema از Attributeها دارد که در block.json یا در فراخوانی registerBlockType تعریف میشود. این Schema، اعتبارسنجی دادهها را تضمین میکند:
// src/index.js
import { registerBlockType } from "@wordpress/blocks";
registerBlockType("my-plugin/price-block", {
attributes: {
amount: { type: "number", default: 0 },
currency: { type: "string", default: "USD" },
showSymbol: { type: "boolean", default: true },
},
// ...
});
برای تست این Schema، میتوان از getBlockType استفاده کرد:
// src/__tests__/block-registration.test.js
import { getBlockType } from "@wordpress/blocks";
import "../index";
describe("price-block registration", () => {
it("should register with correct attributes", () => {
const blockType = getBlockType("my-plugin/price-block");
expect(blockType).toBeDefined();
expect(blockType.attributes.amount.type).toBe("number");
expect(blockType.attributes.currency.default).toBe("USD");
});
});
این تست، ثبت صحیح بلاک و Schema آن را تضمین میکند. اگر کسی بهاشتباه نوع amount را از number به string تغییر دهد، تست شکست میخورد.
Snapshot Testing و Attribute Validation
Snapshot Testing یکی از ویژگیهای قدرتمند Jest است که خروجی یک تابع را با یک نسخه ذخیرهشده مقایسه میکند. در بلاکهای وردپرس، این تکنیک برای تست save.js ایدهآل است.
// src/__tests__/save.test.js
import { render } from "@testing-library/react";
import Save from "../save";
describe("Save component", () => {
it("should render price correctly", () => {
const attributes = { amount: 99.99, currency: "USD" };
const { container } = render( );
expect(container.firstChild).toMatchSnapshot();
});
it("should handle empty price", () => {
const attributes = { amount: 0, currency: "USD" };
const { container } = render( );
expect(container.firstChild).toMatchSnapshot();
});
});
بار اول که این تست اجرا میشود، Jest یک فایل .snap در پوشه __snapshots__ ایجاد میکند. بارهای بعدی، خروجی فعلی با این فایل مقایسه میشود. اگر خروجی تغییر کند، تست شکست میخورد و توسعهدهنده باید تصمیم بگیرد که آیا تغییر عمدی است (و Snapshot را بهروزرسانی کند) یا یک Regression است (و کد را اصلاح کند).
«Snapshot Testing یک شمشیر دو لبه است: از یک سو، پسرفتهای ناخواسته در رندر را فوراً کشف میکند. از سوی دیگر، اگر بدون بازبینی بهروزرسانی شود، به یک تست بیارزش تبدیل میشود.»
برای بلاکهای با Attribute پیچیده، توصیه میشود که Snapshot را با Assertionهای صریح ترکیب کنید. Snapshot بهتنهایی نمیتواند تضمین کند که یک Attribute خاص در DOM وجود دارد؛ این کار نیازمند تستهای هدفمند است:
import { render } from "@testing-library/react";
import Save from "../save";
it("should include currency class on wrapper", () => {
const attributes = { amount: 100, currency: "EUR" };
const { container } = render( );
expect(container.querySelector(".currency-eur")).toBeInTheDocument();
});
این ترکیب، هم ساختار کلی را تضمین میکند و هم Attributeهای حیاتی را. اگر با ساخت بلاک سفارشی گوتنبرگ از صفر آشنا شده باشید، این الگو را بهعنوان بخشی از فرآیند توسعه حرفهای میشناسید.
تست Deprecated Blockها
بلاکهای گوتنبرگ میتوانند چندین deprecated داشته باشند که رفتار نسخههای قبلی را شبیهسازی میکنند. تست این Deprecationها حیاتی است چون اگر نادرست باشند، محتوای قدیمی سایت از کار میافتد:
// src/__tests__/deprecated.test.js
import { getBlockType } from "@wordpress/blocks";
import "../index";
describe("deprecated versions", () => {
it("should have a deprecated version for old schema", () => {
const blockType = getBlockType("my-plugin/price-block");
expect(blockType.deprecated).toBeDefined();
expect(blockType.deprecated.length).toBeGreaterThan(0);
});
it("old attribute should migrate to new", () => {
const blockType = getBlockType("my-plugin/price-block");
const oldDeprecated = blockType.deprecated[0];
expect(oldDeprecated.attributes.oldPrice).toBeDefined();
expect(oldDeprecated.migrate).toBeInstanceOf(Function);
});
});
این تست تضمین میکند که Deprecation بهدرستی تعریف شده و تابع migrate وجود دارد. اگر با گوتنبرگ و آینده ویرایش محتوا در وردپرس آشنا باشید، میدانید که Deprecation یکی از پیچیدهترین بخشهای نگهداری بلاک است.
تست E2E با Playwright: تعامل واقعی کاربر
Playwright یک فریمورک اتوماسیون مرورگر است که توسط Microsoft توسعه یافته و از Chromium، Firefox و WebKit پشتیبانی میکند. در بلاکهای وردپرس، Playwright برای تست Workflowهایی استفاده میشود که Jest نمیتواند پوشش دهد: درج بلاک در ویرایشگر، تغییر تنظیمات، ذخیره نوشته، و بررسی رندر فرانتاند.
راهاندازی Playwright در پروژه بلاک
اگر از @wordpress/scripts استفاده میکنید، Playwright بهطور خودکار پیکربندی میشود. در غیر این صورت، باید بهصورت دستی نصب و پیکربندی شود:
npm install --save-dev @playwright/test
npx playwright install
فایل playwright.config.js در ریشه پروژه:
import { defineConfig } from "@playwright/test";
export default defineConfig({
testDir: "./tests/e2e",
timeout: 60000,
use: {
baseURL: "http://localhost:8889",
trace: "on-first-retry",
screenshot: "only-on-failure",
},
projects: [
{ name: "chromium", use: { browserName: "chromium" } },
{ name: "firefox", use: { browserName: "firefox" } },
],
});
پارامتر baseURL به محیط Test اشاره میکند که توسط wp-env راهاندازی شده است. پارامترهای trace و screenshot برای دیباگ تستهای شکستخورده حیاتی هستند.
نوشتن اولین تست E2E
// tests/e2e/block.spec.js
import { test, expect } from "@playwright/test";
test.describe("Price Block", () => {
test.beforeEach(async ({ page }) => {
// Login
await page.goto("/wp-login.php");
await page.fill("#user_login", "admin");
await page.fill("#user_pass", "password");
await page.click("#wp-submit");
await page.waitForURL(/wp-admin/);
});
test("should insert block and save post", async ({ page }) => {
await page.goto("/wp-admin/post-new.php");
// Open block inserter
await page.click('button[aria-label="Add block"]');
await page.fill('input[placeholder="Search"]', "Price Block");
// Insert block
await page.click('button:has-text("Price Block")');
// Fill price
const amountInput = page.locator('input[type="number"]').first();
await amountInput.fill("99.99");
// Save post
await page.click('button:has-text("Publish")');
await page.waitForSelector('.editor-post-publish-panel__header');
await page.click('button:has-text("Publish")');
// Verify saved
await expect(page.locator('.components-notice')).toContainText("Post published");
});
});
این تست، یک Workflow کامل را شبیهسازی میکند: ورود به پنل، ایجاد نوشته جدید، درج بلاک، پر کردن قیمت، و انتشار. اگر هر مرحله شکست بخورد، تست با جزئیات کامل (Trace، Screenshot، Console Log) گزارش میدهد.
تست رندر فرانتاند
بعد از ذخیره نوشته، باید رندر فرانتاند نیز بررسی شود:
test("should render price on frontend", async ({ page }) => {
// Assuming post ID 1 exists with price block
await page.goto("/?p=1");
const priceElement = page.locator(".wp-block-my-plugin-price");
await expect(priceElement).toBeVisible();
await expect(priceElement).toContainText("$99.99");
});
این تست تضمین میکند که بلاک در فرانتاند با فرمت صحیح رندر میشود. اگر با ویرایشگر گوتنبرگ و تحول ویرایش محتوا آشنا باشید، این جداسازی بین Editor و Front-end را بهعنوان یکی از چالشهای اصلی بلاکنویسی میشناسید.
ابزارهای Playwright برای وردپرس
تیم Gutenberg یک پکیج اختصاصی بهنام @wordpress/e2e-test-utils-playwright منتشر کرده که توابع Helper برای تست وردپرس فراهم میکند:
import { test, expect } from "@wordpress/e2e-test-utils-playwright";
test("should create post with block", async ({ page, admin, editor }) => {
await admin.createNewPost();
await editor.insertBlock({ name: "my-plugin/price-block" });
await editor.canvas.getByLabel("Amount").fill("49.99");
const postId = await editor.publishPost();
expect(postId).toBeGreaterThan(0);
});
این Helperها، جزئیات پیچیده تعامل با ویرایشگر گوتنبرگ را پنهان میکنند و تست را پایدارتر میسازند. توابع مهم عبارتند از:
admin.createNewPost(): ایجاد نوشته جدید و انتقال به ویرایشگرadmin.visitAdminPage(path): بازدید از یک صفحه مدیریتیeditor.insertBlock({ name }): درج بلاک با نام مشخصeditor.publishPost(): انتشار نوشته و بازگشت شناسهeditor.canvas: دسترسی به iframe ویرایشگرpageUtils.waitForNetworkIdle(): انتظار برای اتمام درخواستهای شبکه
استفاده از این Helperها، تستها را کوتاهتر، پایدارتر و قابلخوانتر میکند. اگر با مقایسه ابزارهای توسعه وردپرس آشنا شده باشید، این پکیج را بهعنوان استاندارد رسمی تست بلاکهای گوتنبرگ میشناسید.
یکپارچهسازی با CI/CD و GitHub Actions
تستها تنها زمانی ارزش کامل خود را نشان میدهند که بهصورت خودکار در CI/CD اجرا شوند. GitHub Actions یک بستر عالی برای این کار فراهم میکند:
# .github/workflows/test.yml
name: Test
on: [push, pull_request]
jobs:
unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run test:unit
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx wp-env start
- run: npx playwright install --with-deps
- run: npm run test:e2e
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-traces
path: test-results/
این Workflow دو Job مجزا دارد: یکی برای تستهای واحد که سریع اجرا میشوند، و یکی برای تستهای E2E که کندتر هستند. اگر تستهای E2E شکست بخورند، Trace و Screenshot بهعنوان Artifact ذخیره میشود تا دیباگ آسانتر باشد.
نکته مهم در CI/CD، اجرای تستها بهصورت موازی است. Jest بهصورت پیشفرض تستها را موازی اجرا میکند. Playwright نیز با تنظیم workers میتواند چند مرورگر را همزمان اجرا کند:
export default defineConfig({
workers: process.env.CI ? 2 : undefined,
retries: process.env.CI ? 2 : 0,
});
پارامتر retries باعث میشود تستهای شکستخورده در CI دو بار دیگر تلاش شوند. این کار، شکنندگی تستهای E2E را کاهش میدهد. اگر با ساختاربندی پروژه توسعه وردپرس آشنا باشید، این سطح از اتوماسیون را بهعنوان بلوغ تیم مهندسی میشناسید.
اشتباهات رایج در تست بلاکهای وردپرس
اشتباه اول: نوشتن تست E2E برای همهچیز. Playwright کند و شکننده است. هر تستی که میتواند در Jest نوشته شود، باید در Jest نوشته شود. نسبت ایدهآل، ۷۰٪ Jest و ۳۰٪ Playwright است.
اشتباه دوم: استفاده از Selectorهای شکننده در Playwright. انتخاب بر اساس Class CSS یا ساختار DOM، با هر تغییر در گوتنبرگ میشکند. بهجای آن، از Selectorهای معنایی استفاده کنید:
// ❌ شکننده
await page.click('.components-button.is-primary');
// ✅ پایدار
await page.getByRole('button', { name: 'Publish' }).click();
اشتباه سوم: نادیده گرفتن waitFor. گوتنبرگ یک اپلیکیشن React است و تعاملات آن آسنکرون هستند. اگر بدون انتظار کلیک کنید، تست ممکن است قبل از آماده شدن UI اجرا شود و شکست بخورد. از waitForSelector، waitForLoadState، یا Helperهای @wordpress/e2e-test-utils-playwright استفاده کنید.
اشتباه چهارم: بهروزرسانی کور Snapshotها. اگر یک Snapshot شکست خورد، هرگز بدون بازبینی با --updateSnapshot آن را بهروز نکنید. Snapshot یک قرارداد است؛ اگر تغییر عمدی است، در Commit Message توضیح دهید. اگر تغییر ناخواسته است، کد را اصلاح کنید. اگر با اشتباهات رایج در توسعه قالب و افزونه وردپرس آشنا شده باشید، این اصل را در همه لایههای توسعه میشناسید.
اشتباه پنجم: تست نکردن Deprecationها. اگر بلاک شما چند نسخه دارد، هر نسخه باید تست جداگانه داشته باشد. بدون این تستها، محتوای قدیمی سایت ممکن است در بهروزرسانی بعدی از کار بیفتد.
اشتباه ششم: نادیده گرفتن تست Accessibility. بلاکهای گوتنبرگ باید استانداردهای ARIA را رعایت کنند. Playwright میتواند با @axe-core/playwright تستهای Accessibility را نیز اجرا کند:
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
test("block should have no accessibility violations", async ({ page }) => {
await page.goto("/?p=1");
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
اگر با استانداردهای دسترسپذیری وب آشنا باشید، این نوع تست را بهعنوان بخشی از مسئولیت مهندسی میشناسید، نه یک ویژگی اضافی.
پرسشهای پرتکرار درباره تست بلاکهای وردپرس
آیا تست بلاکهای وردپرس برای پروژههای کوچک هم ضروری است؟
بله، اما با شدت کمتر. برای یک پروژه کوچک با یک یا دو بلاک سفارشی، حداقل تستهای Jest برای منطق و Attributeها کافی است. تستهای E2E را میتوان به Critical Pathها محدود کرد. هرچه پروژه بزرگتر و تیم بزرگتر، ارزش تست بیشتر میشود.
تفاوت Jest و Playwright در تست بلاکهای وردپرس چیست؟
Jest در محیط Node.js بدون مرورگر اجرا میشود و برای تست منطق، توابع Helper، اعتبارسنجی Attributeها و Snapshotهای رندر مناسب است. Playwright یک مرورگر واقعی را کنترل میکند و برای تست Workflowهای کاربر، درج بلاک در ویرایشگر، ذخیره نوشته و رندر فرانتاند استفاده میشود. این دو مکمل یکدیگرند، نه جانشین.
چگونه تستهای Playwright را پایدارتر کنیم؟
سه اصل: اول، از Selectorهای معنایی (Role، Label، Text) بهجای Class CSS استفاده کنید. دوم، از Helperهای @wordpress/e2e-test-utils-playwright بهره ببرید. سوم، در CI از retries و در پیکربندی از trace و screenshot برای دیباگ استفاده کنید.
آیا تست بلاکها با wp-env کند است؟
wp-env از Docker استفاده میکند و راهاندازی اولیه آن ممکن است چند دقیقه طول بکشد. اما پس از راهاندازی، اجرای تستها سریع است. برای CI، میتوان از کش Docker و اجرای موازی استفاده کرد تا زمان کل کاهش یابد.
چگونه تستها را در CI/CD اجرا کنیم؟
در GitHub Actions، دو Job جداگانه تعریف کنید: یکی برای npm run test:unit (سریع) و یکی برای npm run test:e2e (کند). برای E2E، باید wp-env و Playwright نصب شوند. Trace و Screenshot را در صورت شکست بهعنوان Artifact ذخیره کنید.
آیا Jest جایگزین تستهای PHPUnit میشود؟
خیر. Jest برای تست JavaScript بلاکهاست و PHPUnit برای تست کد PHP وردپرس. اگر بلاک شما یک Endpoint REST یا یک تابع PHP دارد، باید آن را با PHPUnit تست کنید. این دو ابزار، دو لایه متفاوت از یک هرم تست را پوشش میدهند. اگر با دیباگ کردن کدهای سفارشی وردپرس آشنا شده باشید، این جداسازی را بهعنوان یک اصل میشناسید.
آیا تست بلاکها برای همه نسخههای وردپرس ضروری است؟
بلاکهای گوتنبرگ از وردپرس ۵.۰ وجود دارند، اما API آنها در نسخههای مختلف تغییر کرده. توصیه میشود تستها در حداقل دو نسخه وردپرس اجرا شوند: نسخه فعلی و نسخه قبلی. اگر با بررسی سازگاری افزونههای وردپرس آشنا باشید، این موضوع را بهعنوان بخشی از استراتژی سازگاری میشناسید.
نگاه مهندسی سطح بالا
از منظر معماری نرمافزار، تست بلاکهای گوتنبرگ یک نمونه جالب از Layered Testing در یک محیط Runtime چندگانه است. بلاکها در سه محیط (Editor، Front-end، Serializer) اجرا میشوند و هر محیط چرخه حیات، وابستگیها و APIهای متفاوتی دارد. Jest لایههای Editor و Serializer را در محیط Node.js شبیهسازی میکند، در حالی که Playwright لایه Front-end را در مرورگر واقعی. این جداسازی، نه فقط یک انتخاب فنی، بلکه یک تصمیم معمارانه است: تستهایی که میتوانند مستقل از مرورگر اجرا شوند، باید در Jest نوشته شوند تا هزینه CI پایین بماند و بازخورد سریعتر باشد.
چالش اصلی در تست بلاکهای گوتنبرگ، State Synchronization است. گوتنبرگ یک اپلیکیشن React با State Management پیچیده (بر پایه @wordpress/data) است که در آن، State بین ویرایشگر، Store و Server همگامسازی میشود. تست این همگامسازی در Jest نیازمند Mock کردن @wordpress/data است که خود یک لایه پیچیدگی دارد. Playwright این مشکل را با اجرای مرورگر واقعی حل میکند، اما هزینه آن کندی و شکنندگی است. تعادل بهینه، استفاده از Mock Store در Jest برای تستهای واحد و استفاده از Playwright فقط برای Workflowهای Critical است. اگر با استفاده از استانداردهای کدنویسی وردپرس در پروژهها آشنا باشید، این سطح از انضباط مهندسی را بهعنوان بلوغ تیم میشناسید. در نهایت، تست بلاکهای گوتنبرگ یک سرمایهگذاری است: زمان اولیه بیشتر، اما هزینه نگهداری بلندمدت بهشدت کمتر. تیمهایی که این سرمایهگذاری را انجام میدهند، در برابر تغییرات سریع اکوسیستم گوتنبرگ مقاومتر هستند و تجربه کاربری پایدارتری به کاربران نهایی ارائه میدهند.
اگر این تجربه را در یک پروژه واقعی داشتهاید، جالب است بدانید کدام بخش آن بیشترین زمان را از شما گرفت. تجربه خودتان را در دیدگاهها بنویسید؛ بهخصوص اگر راهحل دیگری پیدا کردهاید که میتواند برای خواننده بعدی مفید باشد. 🧪
همچنین اگر میخواهید در مورد پیادهسازی عملی بلاکهای گوتنبرگ و تست آنها بیشتر بدانید، ساخت بلاک سفارشی گوتنبرگ از صفر و مقایسه ویرایشگر Classic و گوتنبرگ میتوانند نقاط شروع خوبی باشند.