Kiểm thử quá trình chấm dứt trình chạy dịch vụ bằng Puppeteer

Hướng dẫn này giải thích cách tạo tiện ích mạnh mẽ hơn bằng cách kiểm thử dịch vụ chấm dứt worker bằng Puppeteer. Chuẩn bị sẵn sàng để xử lý việc chấm dứt vào bất kỳ trường hợp nào là rất quan trọng vì điều này có thể xảy ra mà không có cảnh báo dẫn đến bất kỳ trạng thái không ổn định nào trong bị mất trình chạy dịch vụ. Do đó, các tiện ích phải lưu trạng thái quan trọng và có thể xử lý các yêu cầu ngay khi khởi động lại khi có một sự kiện cần xử lý.

Trước khi bắt đầu

Sao chép hoặc tải kho lưu trữ chrome-extensions-samples xuống. Chúng ta sẽ sử dụng tiện ích kiểm thử trong /functional-samples/tutorial.terminate-sw/test-extension để gửi thông báo đến worker dịch vụ mỗi khi người dùng nhấp vào một nút và thêm văn bản vào trang nếu nhận được phản hồi.

Bạn cũng cần cài đặt Node.JS, đây là môi trường thời gian chạy mà Puppeteer được xây dựng.

Bước 1: Bắt đầu dự án Node.js

Tạo các tệp sau trong một thư mục mới. Các thành phần này cùng nhau tạo một dự án Node.js mới và cung cấp cấu trúc cơ bản của bộ kiểm thử Puppeteer bằng cách sử dụng Jest làm trình chạy kiểm thử. Hãy xem bài viết Kiểm thử tiện ích Chrome bằng Puppeteer để tìm hiểu thêm về cách thiết lập này.

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

Lưu ý rằng kiểm thử của chúng ta sẽ tải test-extension từ kho lưu trữ mẫu. Trình xử lý cho chrome.runtime.onMessage dựa vào trạng thái được thiết lập trong trình xử lý cho sự kiện chrome.runtime.onInstalled. Do đó, nội dung của data sẽ bị mất khi worker dịch vụ bị chấm dứt và việc phản hồi bất kỳ thông báo nào trong tương lai sẽ không thành công. Chúng tôi sẽ khắc phục vấn đề này sau khi viết mã kiểm thử.

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

Bước 2: Cài đặt phần phụ thuộc

Chạy npm install để cài đặt các phần phụ thuộc bắt buộc.

Bước 3: Viết một chương trình kiểm thử cơ bản

Thêm kiểm thử sau vào cuối index.test.js. Thao tác này sẽ mở trang kiểm thử từ tiện ích kiểm thử, nhấp vào phần tử nút và chờ phản hồi từ worker dịch vụ.

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

Bạn có thể chạy kiểm thử bằng npm start và sẽ thấy kiểm thử hoàn tất thành công.

Bước 4: Chấm dứt worker dịch vụ

Thêm hàm trợ giúp sau đây để chấm dứt worker dịch vụ:

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

Cuối cùng, hãy cập nhật kiểm thử bằng đoạn mã sau. Bây giờ, hãy chấm dứt dịch vụ worker và nhấp lại vào nút đó để kiểm tra xem bạn đã nhận được phản hồi chưa.

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

Bước 5: Chạy chương trình kiểm thử

Chạy npm start. Kiểm thử của bạn sẽ không đạt, cho biết rằng worker dịch vụ không phản hồi sau khi bị chấm dứt.

Bước 6: Khắc phục trình chạy dịch vụ

Tiếp theo, hãy khắc phục trình chạy dịch vụ bằng cách loại bỏ sự phụ thuộc của trình chạy dịch vụ vào trạng thái tạm thời. Cập nhật phần mở rộng kiểm thử để sử dụng mã sau đây, được lưu trữ trong service-worker-fixed.js trong kho lưu trữ.

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

Ở đây, chúng ta lưu phiên bản vào chrome.storage.local thay vì biến toàn cục để duy trì trạng thái giữa các vòng đời của trình chạy dịch vụ. Vì bộ nhớ chỉ có thể truy cập không đồng bộ, chúng ta cũng sẽ trả về giá trị true từ trình nghe onMessage đến đảm bảo lệnh gọi lại sendResponse vẫn hoạt động.

Bước 7: Chạy lại kiểm thử

Chạy lại chương trình kiểm thử bằng npm start. Giờ thì bạn đã vượt qua.

Các bước tiếp theo

Giờ đây, bạn có thể áp dụng phương pháp tương tự cho phần mở rộng của riêng mình. Cân nhắc sau:

  • Xây dựng bộ kiểm thử để hỗ trợ chạy có hoặc không có dịch vụ không mong muốn chấm dứt worker. Sau đó, bạn có thể chạy cả hai chế độ riêng lẻ để làm cho dữ liệu rõ ràng hơn nguyên nhân gây ra lỗi.
  • Viết mã để chấm dứt worker dịch vụ tại các điểm ngẫu nhiên trong quá trình kiểm thử. Đây có thể là một cách hay để phát hiện những vấn đề khó dự đoán.
  • Học hỏi từ những lần thất bại trong kiểm thử và cố gắng viết mã theo cách phòng thủ trong tương lai. Ví dụ: thêm quy tắc tìm lỗi mã nguồn để hạn chế sử dụng biến toàn cục và cố gắng chuyển dữ liệu sang trạng thái ổn định hơn.