Puppeteer를 사용하여 서비스 워커 종료 테스트

이 가이드에서는 테스트 서비스를 통해 더 강력한 확장 프로그램을 빌드하는 방법을 설명합니다. Puppeteer를 사용하여 작업자 종료를 실행합니다. 종료는 경고 없이 발생할 수 있으며, 이로 인해 서비스 워커의 비지속성 상태가 손실될 수 있으므로 언제든지 종료를 처리할 준비가 되어 있어야 합니다. 따라서 확장 프로그램은 중요한 상태를 저장하고 다시 시작되는 즉시 요청을 처리할 수 있어야 이벤트를 처리합니다.

시작하기 전에

chrome-extensions-samples 저장소를 클론하거나 다운로드합니다. /functional-samples/tutorial.terminate-sw/test-extension에서 테스트 확장 프로그램을 사용합니다. 이 확장 프로그램은 버튼을 클릭할 때마다 서비스 워커에 메시지를 전송하고 응답을 수신하면 페이지에 텍스트를 추가합니다.

Puppeteer가 빌드되는 런타임인 Node.JS도 설치해야 합니다.

1단계: Node.js 프로젝트 시작

새 디렉터리에 다음 파일을 만듭니다. 이들이 함께 어우러져 새로운 Node.js 프로젝트를 설명하고 Puppeteer 테스트 모음의 기본 구조를 제공합니다. Jest를 테스트 실행기로 사용 이 설정에 관해 자세히 알아보려면 Puppeteer로 Chrome 확장 프로그램 테스트를 참고하세요.

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

테스트에서 샘플 저장소에서 test-extension를 로드합니다. chrome.runtime.onMessage의 핸들러는 chrome.runtime.onInstalled 이벤트의 핸들러에 설정된 상태를 사용합니다. 따라서 data의 콘텐츠는 서비스 워커가 종료되고 향후 메시지가 실패합니다 테스트를 작성한 후 이 문제를 수정할 예정입니다.

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단계: 종속 항목 설치

npm install을 실행하여 필수 종속 항목을 설치합니다.

3단계: 기본 테스트 작성

index.test.js 하단에 다음 테스트를 추가합니다. 테스트가 열립니다. 버튼 요소를 클릭하고 응답을 기다립니다. 서비스 워커에서 시작됩니다

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로 테스트를 실행하면 테스트가 성공적으로 완료되는 것을 확인할 수 있습니다.

4단계: 서비스 워커 종료

서비스 워커를 종료하는 다음 도우미 함수를 추가합니다.

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

마지막으로 다음 코드로 테스트를 업데이트합니다. 이제 서비스 작업자를 종료하고 버튼을 다시 클릭하여 응답을 받았는지 확인합니다.

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단계: 테스트 실행

npm start을 실행합니다. 테스트가 실패하여 서비스 워커가 응답이 없습니다.

6단계: 서비스 워커 수정

그런 다음 임시 상태에 대한 의존성을 삭제하여 서비스 워커를 수정합니다. 저장소의 service-worker-fixed.js에 저장된 다음 코드를 사용하도록 test-extension을 업데이트합니다.

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

여기에서는 버전을 전역 변수 대신 chrome.storage.local에 저장합니다. 서비스 워커 수명 주기 사이에 상태를 유지합니다 저장소에는 비동기식으로만 액세스할 수 있으므로 sendResponse 콜백이 계속 실행되도록 onMessage 리스너에서 true도 반환합니다.

7단계: 테스트 다시 실행

npm start를 사용하여 테스트를 다시 실행합니다. 이제 통과합니다.

다음 단계

이제 자체 확장 프로그램에 동일한 접근 방식을 적용할 수 있습니다. 다음 사항을 고려하세요.

  • 예상치 못한 서비스 작업자 종료 여부와 관계없이 실행을 지원하도록 테스트 모음을 빌드합니다. 그런 다음 두 모드를 개별적으로 실행하여 보다 명확하게 확인할 수 있습니다. 확인할 수 있습니다
  • 테스트 내 임의의 지점에서 서비스 워커를 종료하는 코드를 작성합니다. 이는 예측하기 어려운 문제를 발견하는 데 좋은 방법입니다.
  • 테스트 실패에서 교훈을 얻고 향후 방어적으로 코딩해 보세요. 대상 예를 들어 전역 변수 사용을 권장하지 않는 린트 규칙을 추가하고 데이터를 보다 영구적인 상태로 이동