Ce guide explique comment créer des extensions plus robustes en testant l'arrêt des workers de service à l'aide de Puppeteer. Être prêt à gérer un licenciement le temps est important, car cela peut se produire sans avertissement, ce qui entraîne un état non persistant dans le la perte d'un service worker. Par conséquent, les extensions doivent enregistrer l'état important traiter les requêtes dès qu'elles sont redémarrées, en cas de à gérer.
Avant de commencer
Clonez ou téléchargez le dépôt chrome-extensions-samples.
Nous utiliserons l'extension
de test dans
/functional-samples/tutorial.terminate-sw/test-extension
qui envoie un message
au service worker chaque fois qu'un utilisateur clique sur un bouton et ajoute du texte à la page
si une réponse est reçue.
Vous devez également installer Node.js, l'environnement d'exécution sur lequel Puppeteer est basé.
Étape 1 : Démarrez votre projet Node.js
Créez les fichiers suivants dans un nouveau répertoire. Ensemble, ils créent Projet Node.js et fournir la structure de base d'une suite de tests Puppeteer en utilisant Jest en tant que lanceur de test ; Pour en savoir plus sur cette configuration, consultez Tester les extensions Chrome avec 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;
});
Notez que notre test charge test-extension
à partir du dépôt d'exemples.
Le gestionnaire de chrome.runtime.onMessage
s'appuie sur l'état défini dans le gestionnaire pour l'événement chrome.runtime.onInstalled
. Par conséquent, le contenu de data
sera perdu lorsque le service worker sera arrêté, et la réponse à tout message futur échouera. Nous allons corriger ce problème après avoir écrit notre 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);
});
Étape 2 : Installer les dépendances
Exécutez npm install
pour installer les dépendances requises.
Étape 3 : Écrire un test de base
Ajoutez le test suivant en bas de index.test.js
. Cela ouvre le test
de notre extension de test, clique sur l'élément "bouton" et attend une réponse.
à partir du 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');
});
Vous pouvez exécuter votre test avec npm start
. Il devrait s'exécuter correctement.
Étape 4 : Arrêter le service worker
Ajoutez la fonction d'assistance suivante, qui met fin à votre 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();
}
Enfin, mettez à jour votre test avec le code suivant. Mettre fin au service et cliquez à nouveau sur le bouton pour vérifier si vous avez reçu une réponse.
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');
});
Étape 5: Exécutez le test
Exécutez npm start
. Votre test devrait échouer, ce qui indique que le service worker n'a pas répondu après avoir été arrêté.
Étape 6: Corrigez le service worker
Ensuite, corrigez le service worker en supprimant sa dépendance à l'état temporaire. Mettre à jour
l'extension de test d'utiliser le code suivant, qui est stocké dans
service-worker-fixed.js
dans le dépôt.
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;
});
Ici, nous enregistrons la version dans chrome.storage.local
au lieu d'une variable globale.
la persistance de l'état entre les durées de vie des service workers. Comme le stockage ne peut
accessibles de manière asynchrone, nous renvoyons également la valeur "true" à partir de l'écouteur onMessage
pour
assurez-vous que le rappel sendResponse
reste actif.
Étape 7: Exécutez à nouveau le test
Exécutez à nouveau le test avec npm start
. Il devrait maintenant réussir.
Étapes suivantes
Vous pouvez maintenant appliquer la même approche à votre propre extension. Réfléchissez aux éléments suivants :
- Créez votre suite de tests pour qu'elle puisse s'exécuter avec ou sans arrêt inattendu du service worker. Vous pouvez ensuite exécuter les deux modes individuellement pour plus de clarté ce qui a causé une défaillance.
- Écrire du code pour arrêter le service worker à des points aléatoires d'un test Cela peut être un bon moyen de découvrir des problèmes qui peuvent être difficiles à prévoir.
- tirer des enseignements des échecs des tests et essayer de coder de manière défensive à l'avenir. Par exemple, ajoutez une règle de linting pour décourager l'utilisation de variables globales et essayez de déplacer les données vers un état plus persistant.