इस गाइड में, Puppeteer का इस्तेमाल करके, सर्विस वर्कर को बंद करने की सुविधा की जांच करके, ज़्यादा भरोसेमंद एक्सटेंशन बनाने का तरीका बताया गया है. किसी भी समय बंद होने की स्थिति को मैनेज करने के लिए तैयार रहना ज़रूरी है, क्योंकि ऐसा बिना किसी चेतावनी के हो सकता है. इससे सर्विस वर्कर में मौजूद कोई भी नॉन-परसिस्टेंट स्टेट मिट सकती है. इसलिए, एक्सटेंशन को ज़रूरी स्थिति सेव करनी चाहिए. साथ ही, किसी इवेंट को मैनेज करने के लिए, एक्सटेंशन को फिर से शुरू करने पर, अनुरोधों को मैनेज करने में सक्षम होना चाहिए.
शुरू करने से पहले
chrome-extensions-samples रिपॉज़िटरी को क्लोन करें या डाउनलोड करें.
हम /functional-samples/tutorial.terminate-sw/test-extension में टेस्ट एक्सटेंशन का इस्तेमाल करेंगे. यह एक्सटेंशन, बटन पर हर बार क्लिक किए जाने पर सर्विस वर्कर को एक मैसेज भेजता है. साथ ही, अगर कोई जवाब मिलता है, तो पेज में टेक्स्ट जोड़ता है.
आपको Node.JS भी इंस्टॉल करना होगा. यह वह रनटाइम है जिस पर Puppeteer बनाया गया है.
पहला चरण: Node.js प्रोजेक्ट शुरू करना
नई डायरेक्ट्री में ये फ़ाइलें बनाएं. ये दोनों मिलकर एक नया Node.js प्रोजेक्ट बनाते हैं. साथ ही, Jest को टेस्ट रनर के तौर पर इस्तेमाल करके, Puppeteer टेस्ट सुइट का बुनियादी स्ट्रक्चर उपलब्ध कराते हैं. इस सेटअप के बारे में ज़्यादा जानने के लिए, Puppeteer की मदद से Chrome एक्सटेंशन टेस्ट करना लेख पढ़ें.
package.json:
{
"name": "puppeteer-demo",
"version": "1.0",
"dependencies": {
"jest": "^29.7.0",
"puppeteer": "^24.8.1"
},
"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,
pipe: true,
enableExtensions: [EXTENSION_PATH]
});
});
afterEach(async () => {
await browser.close();
browser = undefined;
});
ध्यान दें कि हमारा टेस्ट, सैंपल रिपॉज़िटरी से test-extension लोड करता है.
browser.runtime.onMessage इवेंट का हैंडलर, browser.runtime.onInstalled इवेंट के हैंडलर में सेट की गई स्थिति पर निर्भर करता है. इस वजह से, सर्विस वर्कर के बंद होने पर data का कॉन्टेंट मिट जाएगा. साथ ही, आने वाले समय में किसी भी मैसेज का जवाब नहीं दिया जा सकेगा. हम टेस्ट लिखने के बाद, इस समस्या को ठीक करेंगे.
service-worker-broken.js:
let data;
browser.runtime.onInstalled.addListener(() => {
data = { version: browser.runtime.getManifest().version };
});
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
sendResponse(data.version);
});
दूसरा चरण: डिपेंडेंसी इंस्टॉल करना
ज़रूरी डिपेंडेंसी इंस्टॉल करने के लिए, npm install चलाएं.
तीसरा चरण: बुनियादी टेस्ट लिखना
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 की मदद से टेस्ट चलाएं. आपको दिखेगा कि यह टेस्ट पूरा हो गया है.
चौथा चरण: सर्विस वर्कर को बंद करना
नीचे दिए गए हेल्पर फ़ंक्शन को जोड़ें. इससे आपका सर्विस वर्कर बंद हो जाएगा:
/**
* 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');
});
पांचवां चरण: टेस्ट चलाना
रन npm start. आपका टेस्ट फ़ेल होना चाहिए. इससे पता चलता है कि सर्विस वर्कर के बंद होने के बाद, उसने कोई जवाब नहीं दिया.
छठा चरण: सर्विस वर्कर से जुड़ी समस्या ठीक करना
इसके बाद, सर्विस वर्कर को ठीक करें. इसके लिए, उसे कुछ समय के लिए सेव किए गए डेटा पर निर्भर न रहने दें. टेस्ट-एक्सटेंशन को अपडेट करें, ताकि इस कोड का इस्तेमाल किया जा सके. यह कोड, रिपॉज़िटरी में service-worker-fixed.js में सेव किया गया है.
service-worker-fixed.js:
browser.runtime.onInstalled.addListener(() => {
browser.storage.local.set({ version: browser.runtime.getManifest().version });
});
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
browser.storage.local.get('version').then((data) => {
sendResponse(data.version);
});
return true;
});
यहां हम वर्शन को ग्लोबल वैरिएबल के बजाय browser.storage.local में सेव करते हैं, ताकि सर्विस वर्कर के लाइफ़टाइम के बीच स्थिति बनी रहे. स्टोरेज को सिर्फ़ एसिंक्रोनस तरीके से ऐक्सेस किया जा सकता है. इसलिए, हम onMessage लिसनर से true वैल्यू भी दिखाते हैं, ताकि यह पक्का किया जा सके कि sendResponse कॉलबैक चालू रहे.
सातवां चरण: फिर से टेस्ट करें
npm start के साथ फिर से टेस्ट चलाएं. अब यह पास हो जाना चाहिए.
अगले चरण
अब इसी तरीके का इस्तेमाल करके, अपने एक्सटेंशन को भी बेहतर बनाया जा सकता है. इन बातों का ध्यान रखें:
- अपनी टेस्ट सुइट बनाएं, ताकि सर्विस वर्कर के अचानक बंद होने पर भी टेस्ट चल सकें. इसके बाद, दोनों मोड को अलग-अलग तौर पर चलाया जा सकता है, ताकि यह पता चल सके कि किस वजह से टेस्ट पूरा नहीं हो सका.
- किसी टेस्ट में अलग-अलग जगहों पर सर्विस वर्कर को बंद करने के लिए कोड लिखो. इससे ऐसी समस्याओं का पता लगाया जा सकता है जिनका अनुमान लगाना मुश्किल होता है.
- टेस्ट फ़ेल होने से सीखें और आने वाले समय में, डिफ़ेंसिव कोडिंग करने की कोशिश करें. उदाहरण के लिए, ग्लोबल वैरिएबल के इस्तेमाल को रोकने के लिए, लिंटिंग का नियम जोड़ें. साथ ही, डेटा को ज़्यादा समय तक सेव रखने की कोशिश करें.