In deze handleiding wordt uitgelegd hoe u robuustere extensies kunt bouwen door de beëindiging van servicemedewerkers te testen met behulp van Puppeteer. Het is belangrijk dat u op elk moment voorbereid kunt zijn op beëindiging, omdat dit zonder waarschuwing kan gebeuren, waardoor een niet-persistente toestand van de servicemedewerker verloren gaat. Bijgevolg moeten extensies belangrijke statussen opslaan en verzoeken kunnen afhandelen zodra ze opnieuw worden opgestart als er een gebeurtenis moet worden afgehandeld.
Voordat je begint
Kloon of download de chrome-extensions-samples- repository. We gebruiken de testextensie in /functional-samples/tutorial.terminate-sw/test-extension
, die elke keer dat er op een knop wordt geklikt een bericht naar de servicemedewerker stuurt en tekst aan de pagina toevoegt als er een antwoord wordt ontvangen.
Je moet ook Node.JS installeren, de runtime waarop Puppeteer is gebouwd.
Stap 1: Start uw Node.js-project
Maak de volgende bestanden in een nieuwe map. Samen creëren ze een nieuw Node.js-project en bieden ze de basisstructuur van een Puppeteer-testsuite met Jest als testrunner. Zie Chrome-extensies testen met Puppeteer voor meer informatie over deze configuratie.
pakket.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;
});
Merk op dat onze test de test-extension
uit de voorbeeldrepository laadt. De handler voor chrome.runtime.onMessage
is afhankelijk van de status die is ingesteld in de handler voor de gebeurtenis chrome.runtime.onInstalled
. Als gevolg hiervan gaat de inhoud van data
verloren wanneer de servicemedewerker wordt beëindigd en zal het reageren op toekomstige berichten mislukken. We zullen dit oplossen na het schrijven van onze test.
service-werker-broken.js:
let data;
chrome.runtime.onInstalled.addListener(() => {
data = { version: chrome.runtime.getManifest().version };
});
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
sendResponse(data.version);
});
Stap 2: Afhankelijkheden installeren
Voer npm install
om de vereiste afhankelijkheden te installeren.
Stap 3: Schrijf een basistest
Voeg de volgende test toe aan de onderkant van index.test.js
. Deze opent de testpagina van onze testextensie, klikt op het knopelement en wacht op een reactie van de servicemedewerker.
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');
});
U kunt uw test uitvoeren met npm start
en u zult zien dat deze met succes wordt voltooid.
Stap 4: Beëindig de servicemedewerker
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_worker' && t.url().startsWith(host);
});
const worker = await target.worker();
await worker.close();
}
Werk ten slotte uw test bij met de volgende code. Beëindig nu de servicemedewerker en klik nogmaals op de knop om te controleren of u een reactie heeft ontvangen.
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');
});
Stap 5: Voer uw test uit
Voer npm start
. Uw test zou moeten mislukken, wat aangeeft dat de servicemedewerker niet heeft gereageerd nadat deze was beëindigd.
Stap 6: Repareer de servicemedewerker
Corrigeer vervolgens de servicemedewerker door zijn afhankelijkheid van de tijdelijke status weg te nemen. Werk de testextensie bij om de volgende code te gebruiken, die is opgeslagen in service-worker-fixed.js
in de repository.
service-werker-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;
});
Hier slaan we de versie op in chrome.storage.local
in plaats van een globale variabele om de status tussen de levens van servicemedewerkers te behouden. Omdat opslag alleen asynchroon toegankelijk is, retourneren we ook true van de onMessage
listener om ervoor te zorgen dat de sendResponse
callback actief blijft.
Stap 7: Voer uw test opnieuw uit
Voer de test opnieuw uit met npm start
. Het zou nu voorbij moeten gaan.
Volgende stappen
U kunt nu dezelfde aanpak toepassen op uw eigen extensie. Overweeg het volgende:
- Bouw uw testsuite ter ondersteuning van uitvoering met of zonder onverwachte beëindiging van de servicemedewerker. Vervolgens kunt u beide modi afzonderlijk uitvoeren om duidelijker te maken wat de oorzaak van een fout is.
- Schrijf code om de servicemedewerker op willekeurige punten binnen een test te beëindigen. Dit kan een goede manier zijn om problemen te ontdekken die misschien moeilijk te voorspellen zijn.
- Leer van testfouten en probeer in de toekomst defensief te coderen. Voeg bijvoorbeeld een lintingregel toe om het gebruik van globale variabelen te ontmoedigen en te proberen gegevens in een meer persistente staat te brengen.