คู่มือนี้จะอธิบายวิธีสร้างส่วนขยายที่มีประสิทธิภาพมากขึ้นโดยการทดสอบการสิ้นสุดการทำงานของ Service Worker โดยใช้ Puppeteer การเตรียมตัวรับมือกับการสิ้นสุด เป็นสิ่งสำคัญ เนื่องจากกรณีนี้อาจเกิดขึ้นโดยไม่มีการเตือน ซึ่งส่งผลให้เกิดสถานะที่ไม่ถาวรใน Service Worker หาย ด้วยเหตุนี้ ส่วนขยายจึงต้องบันทึกสถานะที่สำคัญ สามารถจัดการคำขอต่างๆ ได้ทันทีที่คำขอนั้นเริ่มต้นขึ้นอีกครั้งเมื่อมี เหตุการณ์ที่ต้องจัดการ
ก่อนจะเริ่ม
โคลนหรือดาวน์โหลดที่เก็บ chrome-extensions-samples
เราจะใช้ส่วนขยายทดสอบใน
/functional-samples/tutorial.terminate-sw/test-extension
ซึ่งส่งข้อความ
ให้กับ Service Worker ทุกครั้งที่มีการคลิกปุ่มและเพิ่มข้อความลงในหน้าเว็บ
ในกรณีที่ได้รับการตอบกลับ
นอกจากนี้ คุณยังต้องติดตั้ง 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
ซึ่งจะเปิดหน้าทดสอบจากส่วนขยายทดสอบ คลิกองค์ประกอบปุ่ม และรอการตอบกลับจาก Service Worker
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: สิ้นสุดโปรแกรมทำงานของบริการ
เพิ่มฟังก์ชันตัวช่วยต่อไปนี้ซึ่งจะสิ้นสุดการทำงานของ Service Worker
/**
* 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: แก้ไข Service Worker
ขั้นตอนต่อไป ให้แก้ไข Service Worker โดยนำการพึ่งพาสถานะชั่วคราวออก อัปเดตส่วนขยายทดสอบให้ใช้โค้ดต่อไปนี้ ซึ่งจัดเก็บไว้ใน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
แทนตัวแปรร่วม
เพื่อคงสถานะไว้ระหว่างอายุการใช้งานของ Service Worker เนื่องจากพื้นที่เก็บข้อมูลใช้ได้เฉพาะ
แบบไม่พร้อมกันและเราจะแสดงผล true จาก Listener onMessage
เป็น
ตรวจสอบให้แน่ใจว่า Callback ของ sendResponse
ยังทำงานอยู่
ขั้นตอนที่ 7: ทำการทดสอบอีกครั้ง
ทำการทดสอบอีกครั้งด้วย npm start
เท่านี้ก็เรียบร้อย
ขั้นตอนถัดไป
ตอนนี้คุณใช้แนวทางเดียวกันกับส่วนขยายของคุณเองได้แล้ว ลองพิจารณาสิ่งต่อไปนี้
- สร้างชุดทดสอบเพื่อรองรับการใช้งานที่มีหรือไม่มีบริการที่ไม่คาดคิด การสิ้นสุดการดำเนินงานของพนักงาน จากนั้นคุณจะเรียกใช้ทั้ง 2 โหมดแยกกันได้เพื่อให้เห็นชัดเจนยิ่งขึ้น ที่ทำให้ธุรกิจล้มเหลว
- เขียนโค้ดเพื่อสิ้นสุด Service Worker ณ จุดใดก็ได้แบบสุ่มภายในการทดสอบ ซึ่งอาจเป็นวิธีที่ดีในการค้นพบปัญหาที่อาจคาดการณ์ได้ยาก
- เรียนรู้จากการทดสอบที่ล้มเหลวและพยายามเขียนโค้ดเพื่อป้องกันในอนาคต สำหรับ เช่น เพิ่มกฎ Linting เพื่อไม่สนับสนุนให้ใช้ตัวแปรร่วมและลอง ย้ายข้อมูลไปไว้ในสถานะที่ถาวรมากขึ้น