این راهنما نحوه ساخت افزونههای قویتر را با آزمایش خاتمه کارگر خدمات با استفاده از Puppeteer توضیح میدهد. آماده بودن برای رسیدگی به فسخ در هر زمان مهم است زیرا این می تواند بدون اخطار اتفاق بیفتد و منجر به از دست رفتن هر حالت غیرمداومی در سرویسکار شود. در نتیجه، برنامههای افزودنی باید وضعیت مهم را ذخیره کنند و بتوانند به محض راهاندازی مجدد درخواستها، زمانی که رویدادی برای رسیدگی وجود دارد، رسیدگی کنند.
قبل از شروع
مخزن chrome-extensions-samples را شبیه سازی یا دانلود کنید. ما از پسوند آزمایشی در /functional-samples/tutorial.terminate-sw/test-extension
استفاده میکنیم که هر بار که روی دکمه کلیک میشود پیامی به سرویسکار ارسال میکند و در صورت دریافت پاسخ، متنی را به صفحه اضافه میکند.
همچنین باید Node.JS را نصب کنید که زمان اجرای Puppeteer بر روی آن ساخته شده است.
مرحله 1: پروژه Node.js خود را شروع کنید
فایل های زیر را در یک دایرکتوری جدید ایجاد کنید. آنها با هم یک پروژه Node.js جدید ایجاد می کنند و ساختار اولیه یک مجموعه آزمایشی Puppeteer را با استفاده از Jest به عنوان یک آزمایش اجرا می کنند. برای آشنایی بیشتر با این راهاندازی، به آزمایش برنامههای افزودنی Chrome با Puppeteer مراجعه کنید.
package.json:
{
"name": "puppeteer-demo",
"version": "1.0",
"dependencies": {
"jest": "^29.7.0",
"puppeteer": "^22.1.0"
},
"scripts": {
"start": "jest ."
},
"devDependencies": {
"@jest/globals": "^29.7.0"
}
}
index.test.js:
const puppeteer = require('puppeteer');
const SAMPLES_REPO_PATH = 'PATH_TO_SAMPLES_REPOSITORY';
const EXTENSION_PATH = `${SAMPLES_REPO_PATH}/functional-samples/tutorial.terminate-sw/test-extension`;
const EXTENSION_ID = 'gjgkofgpcmpfpggbgjgdfaaifcmoklbl';
let browser;
beforeEach(async () => {
browser = await puppeteer.launch({
// Set to 'new' to hide Chrome if running as part of an automated build.
headless: false,
args: [
`--disable-extensions-except=${EXTENSION_PATH}`,
`--load-extension=${EXTENSION_PATH}`
]
});
});
afterEach(async () => {
await browser.close();
browser = undefined;
});
توجه داشته باشید که آزمایش ما test-extension
از مخزن نمونه بارگیری می کند. کنترل کننده chrome.runtime.onMessage
به حالت تنظیم شده در کنترل کننده برای رویداد chrome.runtime.onInstalled
متکی است. در نتیجه، محتویات data
با پایان کار سرویسدهنده از بین میرود و پاسخگویی به پیامهای بعدی با شکست مواجه میشود. ما پس از نوشتن تست خود این مشکل را برطرف خواهیم کرد.
service-worker-broken.js:
let data;
chrome.runtime.onInstalled.addListener(() => {
data = { version: chrome.runtime.getManifest().version };
});
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
sendResponse(data.version);
});
مرحله 2: وابستگی ها را نصب کنید
برای نصب وابستگی های مورد نیاز npm install
اجرا کنید.
مرحله 3: یک آزمون پایه بنویسید
تست زیر را به پایین index.test.js
اضافه کنید. این صفحه آزمایشی را از برنامه افزودنی آزمایشی ما باز می کند، روی عنصر دکمه کلیک می کند و منتظر پاسخ از طرف سرویس دهنده می ماند.
test('can message service worker', async () => {
const page = await browser.newPage();
await page.goto(`chrome-extension://${EXTENSION_ID}/page.html`);
// Message without terminating service worker
await page.click('button');
await page.waitForSelector('#response-0');
});
می توانید تست خود را با npm start
اجرا کنید و باید ببینید که با موفقیت کامل شده است.
مرحله 4: کارفرما را خاتمه دهید
تابع کمکی زیر را اضافه کنید که سرویس کار شما را خاتمه می دهد:
/**
* Stops the service worker associated with a given extension ID. This is done
* by creating a new Chrome DevTools Protocol session, finding the target ID
* associated with the worker and running the Target.closeTarget command.
*
* @param {Page} browser Browser instance
* @param {string} extensionId Extension ID of worker to terminate
*/
async function stopServiceWorker(browser, extensionId) {
const host = `chrome-extension://${extensionId}`;
const target = await browser.waitForTarget((t) => {
return t.type() === 'service_worker' && t.url().startsWith(host);
});
const worker = await target.worker();
await worker.close();
}
در نهایت تست خود را با کد زیر به روز کنید. اکنون سرویس کارگر را خاتمه دهید و دوباره روی دکمه کلیک کنید تا بررسی شود که پاسخ دریافت کرده اید.
test('can message service worker when terminated', async () => {
const page = await browser.newPage();
await page.goto(`chrome-extension://${EXTENSION_ID}/page.html`);
// Message without terminating service worker
await page.click('button');
await page.waitForSelector('#response-0');
// Terminate service worker
await stopServiceWorker(page, EXTENSION_ID);
// Try to send another message
await page.click('button');
await page.waitForSelector('#response-1');
});
مرحله 5: آزمون خود را اجرا کنید
npm start
اجرا کنید. آزمایش شما باید با شکست مواجه شود که نشان می دهد کارگر خدمات پس از پایان آن پاسخ نداده است.
مرحله 6: سرویس کار را تعمیر کنید
در مرحله بعد، سرویسکار را با حذف اتکای آن به حالت موقت تعمیر کنید. پسوند test را برای استفاده از کد زیر که در service-worker-fixed.js
در مخزن ذخیره می شود، به روز کنید.
service-worker-fixed.js:
chrome.runtime.onInstalled.addListener(() => {
chrome.storage.local.set({ version: chrome.runtime.getManifest().version });
});
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
chrome.storage.local.get('version').then((data) => {
sendResponse(data.version);
});
return true;
});
در اینجا، ما نسخه را به جای یک متغیر سراسری در chrome.storage.local
ذخیره میکنیم تا وضعیت بین طول عمر کارمند سرویس حفظ شود. از آنجایی که فضای ذخیرهسازی فقط بهصورت ناهمزمان قابل دسترسی است، ما از شنونده onMessage
نیز true را برمیگردانیم تا مطمئن شویم که پاسخ تماس sendResponse
زنده میماند.
مرحله 7: تست خود را دوباره اجرا کنید
تست را دوباره با npm start
اجرا کنید. اکنون باید بگذرد.
مراحل بعدی
اکنون می توانید همین رویکرد را برای برنامه افزودنی خود اعمال کنید. موارد زیر را در نظر بگیرید:
- مجموعه آزمایشی خود را برای پشتیبانی از اجرای با یا بدون خاتمه غیرمنتظره سرویسکار بسازید. سپس می توانید هر دو حالت را به صورت جداگانه اجرا کنید تا مشخص شود که چه چیزی باعث شکست شده است.
- کدی بنویسید تا کارگر سرویس را در نقاط تصادفی در یک آزمایش خاتمه دهد. این می تواند راه خوبی برای کشف مسائلی باشد که پیش بینی آنها ممکن است سخت باشد.
- از شکست های تست درس بگیرید و سعی کنید در آینده به صورت تدافعی کدنویسی کنید. به عنوان مثال، برای جلوگیری از استفاده از متغیرهای سراسری، یک قانون پرده اضافه کنید و سعی کنید داده ها را به حالت پایدارتر منتقل کنید.