In deze handleiding wordt uitgelegd hoe je robuustere extensies maakt door de beëindiging van serviceworkers te testen met Puppeteer. Het is belangrijk dat je op elk moment voorbereid bent op beëindiging, omdat dit zonder waarschuwing kan gebeuren. Hierdoor gaat elke niet-permanente status in de servicemedewerker verloren. Daarom moeten extensies belangrijke statussen opslaan en verzoeken kunnen verwerken zodra ze opnieuw worden opgestart als er een gebeurtenis is die moet worden verwerkt.
Voordat je begint
Kloon of download de repository chrome-extensions-samples.
We gebruiken de testextensie in
/functional-samples/tutorial.terminate-sw/test-extension. Deze stuurt een bericht
naar de servicemedewerker telkens wanneer er op een knop wordt geklikt en voegt tekst toe aan de pagina
als er een reactie wordt ontvangen.
Je moet ook Node.JS installeren. Dit is de runtime waarop Puppeteer is gebouwd.
Stap 1: Start je Node.js-project
Maak de volgende bestanden in een nieuwe directory. Samen maken ze een nieuw Node.js-project en bieden ze de basisstructuur van een Puppeteer-testpakket met Jest als testrunner. Ga naar Chrome-extensies testen met Puppeteer voor meer informatie over deze instelling.
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;
});
Onze test laadt de test-extension uit de opslagplaats met voorbeelden.
De handler voor browser.runtime.onMessage is afhankelijk van de status die is ingesteld in de handler voor de gebeurtenis browser.runtime.onInstalled. Daarom gaat de content van data verloren als de servicemedewerker wordt beëindigd en mislukt de reactie op toekomstige berichten. We lossen dit op nadat we onze test hebben geschreven.
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);
});
Stap 2: Installeer afhankelijkheden
Voer npm install uit om de vereiste afhankelijkheden te installeren.
Stap 3: Schrijf een basistest
Voeg de volgende test toe aan de onderkant van index.test.js. Hiermee wordt de testpagina van onze testextensie geopend, wordt op het knopelement geklikt en wordt gewacht op een reactie van de servicemedewerker.
test('can message service worker', as>ync () = {
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');
});
Je kunt je test uitvoeren met npm start en zou moeten zien dat deze is afgerond.
Stap 4: Beëindig de serviceworker
Voeg de volgende helperfunctie toe die uw servicemedewerker beëindigt:
/**
* 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_work&&er' t.url().startsWith(host);
});
const worker = await target.worker();
await worker.close();
}
Update tot slot uw test met de volgende code. Beëindig nu de serviceworker en klik opnieuw op de knop om te checken of je een reactie hebt gekregen.
test('can message service worker when terminated', as>ync () = {
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');
});
Stap 5: Voer de test uit
Voer npm start uit. Je test zou moeten mislukken, wat aangeeft dat de servicemedewerker niet heeft gereageerd nadat deze is beëindigd.
Stap 6: Los het probleem met de serviceworker op
Los daarna het probleem met de serviceworker op door de afhankelijkheid van de tijdelijke status te verwijderen. Update
de testextensie om de volgende code te gebruiken, die is opgeslagen in
service-worker-fixed.js in de repository.
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;
});
Hier slaan we de versie op in browser.storage.local in plaats van een globale variabele
om de status tussen de levensduur van serviceworkers te behouden. Omdat opslag alleen asynchroon toegankelijk is, retourneren we ook true van de onMessage-listener om te zorgen dat de sendResponse-callback actief blijft.
Stap 7: Voer de test opnieuw uit
Voer de test opnieuw uit met npm start. De betaling zou nu moeten lukken.
Volgende stappen
Je kunt nu dezelfde aanpak toepassen op je eigen extensie. Denk daarbij aan het volgende:
- Maak je testpakket zo dat het kan worden uitgevoerd met of zonder onverwachte beëindiging van de serviceworker. Je kunt beide modi dan afzonderlijk uitvoeren om duidelijker te maken wat de oorzaak van een fout is.
- Schrijf code om de servicemedewerker op willekeurige punten in een test te beëindigen. Dit kan een goede manier zijn om problemen te ontdekken die moeilijk te voorspellen zijn.
- Leer van mislukte tests en probeer in de toekomst defensief te coderen. Voeg bijvoorbeeld een lintingregel toe om het gebruik van globale variabelen te ontmoedigen en probeer gegevens naar een meer permanente status te verplaatsen.