Puppeteer ile hizmet çalışanı feshini test etme

Bu kılavuzda, Puppeteer kullanarak hizmet çalışanı fesihlerini test ederek nasıl daha sağlam uzantılar oluşturulacağı açıklanmaktadır. Herhangi bir uyarı almadan hizmet çalışanının kalıcı olmayan durumlarının kaybedilmesine neden olabilecek bu işlem sonucunda gerçekleşebileceği için herhangi bir zamanda fesih işlemine hazırlıklı olmak önemlidir. Sonuç olarak, uzantılar önemli durumu kaydetmeli ve ele alınacak bir etkinlik olduğunda istekleri yeniden başlatıldıklarında işleyebilmelidir.

Başlamadan önce

chrome-extensions-samples deposunu klonlayın veya indirin. /functional-samples/tutorial.terminate-sw/test-extension içindeki test uzantısını kullanacağız. Bu uzantı, düğme her tıklandığında hizmet çalışanına bir mesaj gönderir ve yanıt alındığında sayfaya metin ekler.

Ayrıca, Puppeteer'ın temel aldığı çalışma zamanı olan Node.JS'yi de yüklemeniz gerekir.

1. Adım: Node.js projenizi başlatın

Aşağıdaki dosyaları yeni bir dizinde oluşturun. Birlikte yeni bir Node.js projesi oluşturur ve Jest'i test yürütücüsü olarak kullanan bir Puppeteer test paketinin temel yapısını sağlarlar. Bu ayar hakkında daha ayrıntılı bilgi edinmek için Chrome Uzantılarını Puppeteer ile Test Etme bölümüne bakın.

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;
});

Testimizin, örnekler deposundan test-extension öğesini yüklediğine dikkat edin. chrome.runtime.onMessage işleyicisi, chrome.runtime.onInstalled etkinliği için işleyicide ayarlanan duruma dayanır. Sonuç olarak, hizmet çalışanı feshedildiğinde data içeriği kaybolur ve gelecekteki mesajlara yanıt vermek başarısız olur. Testinizi yazdıktan sonra bu sorunu düzelteceğiz.

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);
});

2. Adım: Bağımlılıkları yükleme

Gerekli bağımlılıkları yüklemek için npm install komutunu çalıştırın.

3. Adım: Temel bir test yazın

index.test.js etiketinin altına aşağıdaki testi ekleyin. Bu işlem, test uzantımızdan test sayfasını açar, düğme öğesini tıklar ve Service Worker'dan yanıt bekler.

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 ile test ederseniz testin başarıyla tamamlandığını görürsünüz.

4. Adım: Hizmet çalışanını sonlandırın

Service Worker'ınızı sonlandıran aşağıdaki yardımcı işlevi ekleyin:

/**
 * 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();
}

Son olarak, aşağıdaki kodu kullanarak testinizi güncelleyin. Şimdi hizmet çalışanını sonlandırın ve yanıt alıp almadığınızı kontrol etmek için düğmeyi tekrar tıklayın.

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');
});

5. Adım: Testinizi çalıştırın

npm start komutunu çalıştırın. Testiniz başarısız olur. Bu, hizmet çalışanının sonlandırıldıktan sonra yanıt vermediğini gösterir.

6. Adım: Hizmet çalışanını düzeltin

Ardından, geçici duruma bağımlılığı kaldırarak Service Worker'ı düzeltin. test-uzantısını, kod deposundaki service-worker-fixed.js içinde saklanan aşağıdaki kodu kullanacak şekilde güncelleyin.

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;
});

Hizmet çalışanı ömürleri arasındaki durumu korumak için burada sürümü genel değişken yerine chrome.storage.local konumuna kaydediyoruz. Depolama alanına yalnızca eşzamansız olarak erişilebildiğinden, sendResponse geri çağırma işlevinin kullanımda kalmasını sağlamak için onMessage dinleyicisinden true değerini de döndürürüz.

7. Adım: Testinizi tekrar çalıştırın

npm start ile testi tekrar çalıştırın. Artık başarılı olacaktır.

Sonraki adımlar

Artık aynı yaklaşımı kendi uzantınıza da uygulayabilirsiniz. Aşağıdakileri göz önünde bulundurun:

  • Hizmet çalışanının beklenmedik şekilde sonlandırılmasıyla veya bu fesihler olmadan çalışmayı desteklemek için test paketinizi oluşturun. Daha sonra, hatanın nedenini daha açık şekilde göstermek için her iki modu da ayrı ayrı çalıştırabilirsiniz.
  • Hizmet çalışanını testteki rastgele noktalarda sonlandırmak için kod yazın. Bu, tahmin edilmesi zor olabilecek sorunları keşfetmek için iyi bir yol olabilir.
  • Test başarısızlıklarından ders çıkarın ve gelecekte savunmaya yönelik bir şekilde kodlamaya çalışın. Örneğin, genel değişkenlerin kullanılmasını önlemek ve verileri daha kalıcı bir duruma taşımaya çalışmak için hata analizi kuralı ekleyin.