이 가이드에서는 테스트 서비스를 통해 더 강력한 확장 프로그램을 빌드하는 방법을 설명합니다. 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": "^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; });
테스트에서 샘플 저장소에서 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
를 사용하여 테스트를 다시 실행합니다. 이제 통과합니다.
다음 단계
이제 자체 확장 프로그램에 동일한 접근 방식을 적용할 수 있습니다. 다음 사항을 고려하세요.
- 예상치 못한 서비스 작업자 종료 여부와 관계없이 실행을 지원하도록 테스트 모음을 빌드합니다. 그런 다음 두 모드를 개별적으로 실행하여 보다 명확하게 확인할 수 있습니다. 확인할 수 있습니다
- 테스트 내 임의의 지점에서 서비스 워커를 종료하는 코드를 작성합니다. 이는 예측하기 어려운 문제를 발견하는 데 좋은 방법입니다.
- 테스트 실패에서 교훈을 얻고 향후 방어적으로 코딩해 보세요. 대상 예를 들어 전역 변수 사용을 권장하지 않는 린트 규칙을 추가하고 데이터를 보다 영구적인 상태로 이동