mirror of
https://github.com/GoogleChrome/chrome-extensions-samples.git
synced 2026-03-27 13:29:34 +07:00
Add examples for testing service worker termination (#1078)
* Add examples for testing service worker termination * Add example of failing case to tutorial
This commit is contained in:
15
functional-samples/tutorial.terminate-sw/README.md
Normal file
15
functional-samples/tutorial.terminate-sw/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Testing service worker termination
|
||||
|
||||
## Overview
|
||||
|
||||
**Note:** The test extension is intentionally broken as part of a tutorial in
|
||||
our documentation. See [Test service worker termination with Puppeteer](https://developer.chrome.com/docs/extensions/how-to/test/test-serviceworker-termination-with-puppeteer).
|
||||
|
||||
Sample code to show how to terminate a service worker in Puppeteer or Selenium.
|
||||
|
||||
## Running the tests
|
||||
|
||||
1. Install [Node.JS](https://nodejs.org/).
|
||||
2. Change to the `puppeteer` or `selenium` directory.
|
||||
3. Run `npm install`.
|
||||
4. Run `npm start`.
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": ["../../../.eslintrc"],
|
||||
"plugins": ["jest"],
|
||||
"env": {
|
||||
"jest/globals": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const puppeteer = require('puppeteer');
|
||||
|
||||
const EXTENSION_PATH = '../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;
|
||||
});
|
||||
|
||||
/**
|
||||
* 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} page Puppeteer page that CDP session can be started from
|
||||
* @param {string} extensionId Extension ID of worker to terminate
|
||||
*/
|
||||
async function stopServiceWorker(page, extensionId) {
|
||||
const host = `chrome-extension://${extensionId}`;
|
||||
|
||||
// Create a new CDP session
|
||||
const client = await page.target().createCDPSession();
|
||||
|
||||
// Find the extension service worker
|
||||
const targets = await client.send('Target.getTargets');
|
||||
const worker = targets.targetInfos.find(
|
||||
(t) => t.type === 'service_worker' && t.url.startsWith(host)
|
||||
);
|
||||
|
||||
if (!worker) {
|
||||
throw new Error(`No worker found for ${host}`);
|
||||
}
|
||||
|
||||
// Terminate the service worker
|
||||
await client.send('Target.closeTarget', {
|
||||
targetId: worker.targetId
|
||||
});
|
||||
|
||||
// End the CDP session
|
||||
await client.detach();
|
||||
}
|
||||
|
||||
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');
|
||||
});
|
||||
9145
functional-samples/tutorial.terminate-sw/puppeteer/package-lock.json
generated
Normal file
9145
functional-samples/tutorial.terminate-sw/puppeteer/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "puppeteer-demo",
|
||||
"version": "1.0",
|
||||
"dependencies": {
|
||||
"jest": "^29.7.0",
|
||||
"puppeteer": "^21.3.6"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "jest ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/globals": "^29.7.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": ["../../../.eslintrc"],
|
||||
"plugins": ["jest"],
|
||||
"env": {
|
||||
"jest/globals": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const { Builder, Browser, By, until } = require('selenium-webdriver');
|
||||
// eslint-disable-next-line no-undef
|
||||
const { Options } = require('selenium-webdriver/chrome');
|
||||
|
||||
const EXTENSION_PATH = '../test-extension';
|
||||
const EXTENSION_ID = 'gjgkofgpcmpfpggbgjgdfaaifcmoklbl';
|
||||
|
||||
let driver;
|
||||
let cdpConnection;
|
||||
|
||||
beforeEach(async () => {
|
||||
driver = await new Builder()
|
||||
.forBrowser(Browser.CHROME)
|
||||
.setChromeOptions(
|
||||
new Options().addArguments([
|
||||
`--disable-extensions-except=${EXTENSION_PATH}`,
|
||||
`--load-extension=${EXTENSION_PATH}`
|
||||
])
|
||||
)
|
||||
.build();
|
||||
|
||||
// Create this here, since there is one connection per driver and we want to
|
||||
// avoid repeatedly recreating it.
|
||||
cdpConnection = await driver.createCDPConnection('page');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await driver.quit();
|
||||
driver = undefined;
|
||||
});
|
||||
|
||||
/**
|
||||
* 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 {Driver} driver Driver that CDP session can be started from
|
||||
* @param {string} extensionId Extension ID of worker to terminate
|
||||
*/
|
||||
async function stopServiceWorker(driver, extensionId) {
|
||||
const host = `chrome-extension://${extensionId}`;
|
||||
|
||||
// Find the extension service worker
|
||||
const response = await cdpConnection.send('Target.getTargets', {});
|
||||
const worker = response.result.targetInfos.find(
|
||||
(t) => t.type === 'service_worker' && t.url.startsWith(host)
|
||||
);
|
||||
|
||||
if (!worker) {
|
||||
throw new Error(`No worker found for ${host}`);
|
||||
}
|
||||
|
||||
// Terminate the service worker
|
||||
await cdpConnection.send('Target.closeTarget', {
|
||||
targetId: worker.targetId
|
||||
});
|
||||
}
|
||||
|
||||
test('can message service worker when terminated', async () => {
|
||||
await driver.get(`chrome-extension://${EXTENSION_ID}/page.html`);
|
||||
|
||||
// Message without terminating service worker
|
||||
await driver.wait(until.elementLocated(By.css('button'))).click();
|
||||
await driver.wait(until.elementLocated(By.css('#response-0')));
|
||||
|
||||
// Terminate service worker
|
||||
await stopServiceWorker(driver, EXTENSION_ID);
|
||||
|
||||
// Try to send another message
|
||||
await driver.wait(until.elementLocated(By.css('button'))).click();
|
||||
await driver.wait(until.elementLocated(By.css('#response-1')));
|
||||
});
|
||||
8149
functional-samples/tutorial.terminate-sw/selenium/package-lock.json
generated
Normal file
8149
functional-samples/tutorial.terminate-sw/selenium/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "puppeteer-demo",
|
||||
"version": "1.0",
|
||||
"dependencies": {
|
||||
"jest": "^29.7.0",
|
||||
"selenium-webdriver": "^4.17.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "jest ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/globals": "^29.7.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "Hello World",
|
||||
"version": "0.1",
|
||||
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr1Cssen3kE1Kzw8x2vhc0neVV3Im5HhQ28cl2zptYPZVLMkT4RuVAbSu8/CnlqyfYMoHSSUKgo/kaEOW+g9aoGjPyKYfmy5FJmIZnWfbKP+qLRcnX8XrgX6NM8XxAalzrq/a8DeaFTCtLyVEX+Xw5uzjJapXfaiFdwPhAV6TR0GPgB6pSvkcRiPTTcctqQ64/FSbNQutcVRA0bH8d8tnIDQZ9nm/9/4A0njq1Xujf/NnhldWjlKilQPLZh/2bXrThlWDLal3LJbMsvWolFbQWpGIPw4ti13bhBFp9A7jFUt89wBnwEPhViMEjatOJzx72karMqkAFEOfPiXsytrNYQIDAQAB",
|
||||
"manifest_version": 3,
|
||||
"description": "Basic Hello World Extension",
|
||||
"background": {
|
||||
"service_worker": "service-worker-broken.js"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<button id="get-response" type="button">Get Response</button>
|
||||
<script src="page.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
const GET_RESPONSE_BUTTON = document.getElementById('get-response');
|
||||
let counter = 0;
|
||||
|
||||
GET_RESPONSE_BUTTON.addEventListener('click', async () => {
|
||||
const response = await chrome.runtime.sendMessage('ping');
|
||||
|
||||
if (response) {
|
||||
const element = document.createElement('p');
|
||||
element.id = `response-${counter}`;
|
||||
element.innerText = `Response ${counter}: ${response}`;
|
||||
document.body.appendChild(element);
|
||||
|
||||
counter++;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
let data;
|
||||
|
||||
chrome.runtime.onInstalled.addListener(() => {
|
||||
data = { version: chrome.runtime.getManifest().version };
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
sendResponse(data.version);
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
sendResponse(chrome.runtime.getManifest().version);
|
||||
});
|
||||
Reference in New Issue
Block a user