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 các tiện ích mạnh mẽ hơn bằng cách kiểm thử quá trình chấm dứt trình chạy dịch vụ bằng Puppeteer. Việc chuẩn bị để xử lý việc chấm dứt bất cứ lúc nào là rất quan trọng vì điều này có thể xảy ra mà không cần cảnh báo, dẫn đến mọi trạng thái không liên tục trong trình chạy dịch vụ bị mất. Do đó, 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ó 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. Tiện ích này sẽ gửi thông báo đến trình chạy dịch vụ mỗi khi người dùng nhấp vào 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 sẽ cần cài đặt Node.JS, đây là thời gian chạy mà Puppeteer được tạo trên đó.

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

Tạo các tệp sau trong thư mục mới. Họ cùng nhau tạo ra 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 của 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;
});

Xin lưu ý rằng chương trình 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 đặt trong trình xử lý cho sự kiện chrome.runtime.onInstalled. Do đó, nội dung của data sẽ bị mất khi trình chạy dịch vụ bị chấm dứt và không phản hồi bất kỳ thông báo nào trong tương lai. Chúng ta sẽ khắc phục vấn đề này sau khi viết chương trình 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 kiểm thử cơ bản

Thêm 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ừ trình chạy 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à thấy rằng kiểm thử hoàn tất thành công.

Bước 4: Chấm dứt trình chạy dịch vụ

Thêm hàm trợ giúp sau đây để chấm dứt trình chạy dịch vụ của bạn:

/**
 * 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 mã sau. Bây giờ, hãy chấm dứt trình chạy dịch vụ rồi nhấp lại vào nút để kiểm tra xem bạn đã nhận được phản hồi hay 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 kiểm thử

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

Bước 6: Sửa trình chạy dịch vụ

Tiếp theo, hãy sửa Service worker bằng cách xoá sự phụ thuộc vào trạng thái tạm thời. Cập nhật tiện ích kiểm thử để sử dụng mã sau, đượ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ể được truy cập không đồng bộ, nên chúng ta cũng trả về giá trị true từ trình nghe onMessage để đả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. Bây giờ, kết quả sẽ thành công.

Các bước tiếp theo

Giờ đây, bạn có thể áp dụng phương pháp tương tự cho tiện ích của riêng mình. Hãy cân nhắc những điều sau:

  • Xây dựng bộ kiểm thử để hỗ trợ việc chạy có hoặc không có việc chấm dứt trình chạy dịch vụ ngoài dự kiến. Sau đó, bạn có thể chạy riêng cả hai chế độ để làm rõ nguyên nhân gây ra lỗi.
  • Viết mã để chấm dứt trình chạy 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 các vấn đề khó dự đoán.
  • Rút kinh nghiệm từ các lần thất bại trong kiểm thử và cố gắng viết mã phòng vệ trong tương lai. Ví dụ: thêm quy tắc tìm lỗi mã nguồn để ngăn việc 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.