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

Bu rehberde, Puppeteer kullanarak hizmet çalışanı sonlandırmasını test ederek daha sağlam uzantılar oluşturma açıklanmaktadır. Sonlandırmayı her an işleme almaya hazır olmak önemlidir. Çünkü bu işlem uyarı yapılmadan gerçekleşebilir ve hizmet çalışanındaki kalıcı olmayan durumların kaybolmasına neden olabilir. Bu nedenle, uzantılar önemli durumu kaydetmeli ve işlenecek bir etkinlik olduğunda yeniden başlatılır başlatılmaz istekleri işleyebilmelidir.

Başlamadan önce

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

Puppeteer'ın üzerinde oluşturulduğu çalışma zamanı olan Node.JS'yi de yüklemeniz gerekir.

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

Yeni bir dizinde aşağıdaki dosyaları oluşturun. Birlikte yeni bir Node.js projesi oluşturur ve test çalıştırıcı olarak Jest'i kullanarak Puppeteer test paketinin temel yapısını sağlarlar. Bu kurulum hakkında daha ayrıntılı bilgi edinmek için Test Chrome Extensions with Puppeteer (Puppeteer ile Chrome Uzantılarını Test Etme) başlıklı makaleyi inceleyin.

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

Testimizin, örnekler deposundan test-extension yüklediğini fark edin. browser.runtime.onMessage işleyicisi, browser.runtime.onInstalled etkinliğinin işleyicisinde ayarlanan duruma bağlıdır. Sonuç olarak, hizmet çalışanı sonlandırıldığında data içeriği kaybolur ve gelecekteki mesajlara yanıt verme işlemi başarısız olur. Testimizi yazdıktan sonra bu sorunu düzelteceğiz.

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

2. adım: Bağımlılıkları yükleyin

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

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

Aşağıdaki testi index.test.js alanının en altına ekleyin. Bu işlem, test uzantımızdaki test sayfasını açar, düğme öğesini tıklar ve hizmet çalışanından yanıt gelmesini 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');
});

Testinizi npm start ile çalıştırabilir ve başarıyla tamamlandığını görebilirsiniz.

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

Aşağıdaki yardımcı işlevi ekleyin. Bu işlev, hizmet çalışanınızı sonlandırır:

/**
 * 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, testinizi aşağıdaki kodla 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 çalıştırın. Testiniz başarısız olmalıdır. Bu, hizmet çalışanı 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ığını kaldırarak hizmet çalışanını düzeltin. Test uzantısını, depodaki service-worker-fixed.js içinde saklanan aşağıdaki kodu kullanacak şekilde güncelleyin.

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

Burada, hizmet çalışanı ömrü boyunca durumu korumak için sürümü genel değişken yerine browser.storage.local'ye kaydediyoruz. Depolamaya yalnızca eşzamansız olarak erişilebildiğinden, onMessage işleyicisinden de true döndürerek sendResponse geri çağırma işlevinin etkin kalmasını sağlıyoruz.

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

Testi npm start ile tekrar çalıştırın. Şimdi geçmesi gerekir.

Sonraki adımlar

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

  • Beklenmedik hizmet çalışanı sonlandırmasıyla veya sonlandırması olmadan çalışmayı desteklemek için test paketinizi oluşturun. Ardından, hataya neyin neden olduğunu daha net anlamak için her iki modu ayrı ayrı çalıştırabilirsiniz.
  • Test içinde rastgele noktalarda hizmet çalışanını sonlandıracak kod yazın. Bu, tahmin edilmesi zor olabilecek sorunları keşfetmek için iyi bir yöntem olabilir.
  • Test hatalarından ders çıkarın ve gelecekte savunma amaçlı kod yazmaya çalışın. Örneğin, genel değişkenlerin kullanılmasını önlemek için bir linting kuralı ekleyin ve verileri daha kalıcı bir duruma taşımaya çalışın.