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ử việc chấm dứt worker dịch vụ bằng Puppeteer. Việc chuẩn bị sẵn sàng để 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ó cảnh báo, dẫn đến việc mọi trạng thái không liên tục trong trình chạy dịch vụ đều bị mất. 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 được 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. Tiện ích này sẽ gửi một thông báo đến trình chạy dịch vụ mỗi khi một nút được nhấp 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à thời gian chạy mà Puppeteer được xây dựng trên đó.

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ả hai 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 một 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 phần Kiểm thử tiện ích Chrome bằng Puppeteer để tìm hiểu chi tiết hơn về chế độ thiết lập này.

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

Lưu ý rằng kiểm thử của chúng ta tải test-extension từ kho lưu trữ mẫu. Trình xử lý cho browser.runtime.onMessage dựa vào trạng thái được đặt trong trình xử lý cho sự kiện browser.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à việc phản hồi mọi thông báo trong tương lai sẽ không thành công. Chúng ta sẽ khắc phục vấn đề này sau khi viết bài kiểm thử.

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

Bước 2: Cài đặt các 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 kiểm thử cơ bản

Thêm bài 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ử của chúng tôi, nhấp vào phần tử nút và đợi 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à sẽ thấy 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ụ:

/**
 * 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 trình thực thi dịch vụ và 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. Thử nghiệm của bạn sẽ không thành công, cho thấy 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 lỗi trình chạy dịch vụ

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

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

Ở đây, chúng ta lưu phiên bản vào browser.storage.local thay vì một 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ì chỉ có thể truy cập vào bộ nhớ một cách 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 kiểm thử bằng npm start. Giờ đây, kiểm thử 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:

  • Tạo bộ kiểm thử để hỗ trợ chạy có hoặc không có trường hợp chấm dứt worker dịch vụ ngoài dự kiến. Sau đó, bạn có thể chạy từng chế độ riêng lẻ để biết rõ hơn 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 một bài kiểm thử. Đây có thể là một cách hay để khám phá những vấn đề khó dự đoán.
  • Học hỏi từ các lần kiểm thử thất bại và cố gắng viết mã một cách phòng thủ trong tương lai. Ví dụ: thêm một quy tắc linting để ngăn chặn việc sử dụng các biến toàn cục và cố gắng di chuyển dữ liệu vào trạng thái ổn định hơn.