Questa guida spiega come creare estensioni più affidabili utilizzando il servizio di test risoluzione dei lavoratori tramite Puppeteer. Essere preparati a gestire la risoluzione in qualsiasi l'ora è importante perché ciò può verificarsi senza preavviso, generando uno stato non persistente del Service worker che viene perso. Di conseguenza, le estensioni devono salvare lo stato importante e essere in grado di gestire le richieste non appena vengono riavviate quando c'è un evento da gestire.
Prima di iniziare
Clona o scarica il repository chrome-extensions-samples.
Utilizzeremo l'estensione di test in
/functional-samples/tutorial.terminate-sw/test-extension
che invia un messaggio
al service worker ogni volta che viene fatto clic su un pulsante e aggiunge del testo alla pagina
se viene ricevuta una risposta.
Dovrai anche installare Node.JS, che è il runtime su cui è basato Puppeteer.
Passaggio 1: avvia il progetto Node.js
Crea i seguenti file in una nuova directory. Insieme creano un nuovo progetto Node.js e forniscono la struttura di base di una suite di test Puppeteer utilizzando Jest come test runner. Consulta Testa le estensioni di Chrome con Puppeteer per scoprire di più su questa configurazione in modo più dettagliato.
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;
});
Tieni presente che il nostro test carica test-extension
dal repository di esempi.
Il gestore per chrome.runtime.onMessage
si basa sullo stato impostato nel gestore
per l'evento chrome.runtime.onInstalled
. Di conseguenza, i contenuti di data
andranno persi quando il servizio worker verrà terminato e la risposta a eventuali messaggi futuri
non andrà a buon fine. Lo risolveremo dopo aver scritto il test.
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);
});
Passaggio 2: installa le dipendenze
Esegui npm install
per installare le dipendenze richieste.
Passaggio 3: scrivi un test di base
Aggiungi il seguente test in fondo a index.test.js
. Si apre la pagina di test della nostra estensione di test, fa clic sull'elemento del pulsante e attende una risposta dal 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');
});
Puoi eseguire il test con npm start
e dovresti vedere che viene completato
correttamente.
Passaggio 4: termina il service worker
Aggiungi la seguente funzione helper che termina il tuo 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();
}
Infine, aggiorna il test con il codice seguente. Ora termina il servizio worker e fai di nuovo clic sul pulsante per verificare di aver ricevuto una risposta.
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');
});
Passaggio 5: esegui il test
Esegui npm start
. Il test dovrebbe avere esito negativo, il che indica che il service worker
non ha risposto dopo la chiusura.
Passaggio 6: correggi il service worker
Poi, correggi il worker del servizio rimuovendo la dipendenza dallo stato temporaneo. Aggiorna
l'estensione di test in modo da utilizzare il seguente codice, memorizzato in
service-worker-fixed.js
nel repository.
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;
});
Qui salviamo la versione in chrome.storage.local
anziché in una variabile globale
per mantenere lo stato tra le durate dei service worker. Poiché l'archiviazione può
accessibile in modo asincrono, viene restituito anche true dal listener onMessage
a
assicurati che il callback sendResponse
rimanga attivo.
Passaggio 7: esegui di nuovo il test
Esegui di nuovo il test con npm start
. Ora dovrebbe passare.
Passaggi successivi
Ora puoi applicare lo stesso approccio alla tua estensione. Considera le seguenti:
- Crea la suite di test in modo che supporti l'esecuzione con o senza interruzione imprevista dei worker di servizio. Puoi quindi eseguire entrambe le modalità singolarmente per renderlo più chiaro cosa ha causato l'errore.
- Scrivi codice per terminare il servizio worker in punti casuali all'interno di un test. Questo può essere un buon modo per scoprire problemi difficili da prevedere.
- Impara dagli errori di test e prova a scrivere codice in modo più sicuro in futuro. Ad esempio, aggiungi una regola di linting per scoraggiare l'uso di variabili globali e prova a spostare i dati in uno stato più persistente.