Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /fledge/tentative/service-worker-request-visibility.https.window.html?1-last - WPT Dashboard Interop Dashboard
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/common/utils.js
// META: script=resources/fledge-util.sub.js
// META: script=/common/subset-tests.js
// META: timeout=long
// META: variant=?1-last
"use strict;"
const SERVICE_WORKER_SCRIPT = "resources/service-worker-helper.js";
// List of URL fragments that uniquely identify private requests.
// These are used to detect if a service worker has inadvertently
// accessed any of these private requests, which should not be visible to it.
const PRIVATE_REQUEST_FILE_NAMES = [
'trusted-bidding-signals.py',
'update-url.py', // This requires another test, since it takes a while,
// see TODO file for more info.
'wasm-helper.py',
'bidding-logic.py',
'decision-logic.py',
'trusted-scoring-signals.py',
'trusted-bidding-signals.py',
'bidder_report',
'seller_report'
];
// List of URL fragments that uniquely identify public requests.
// These are used to verify that a service worker can correctly
// access and intercept these public requests as expected.
const PUBLIC_REQUEST_FILE_NAMES = [
'direct-from-seller-signals.py',
];
const COMPLETE_TEST_URL = 'complete-test'
const CURRENT_SCOPE = "/fledge/tentative/"
async function registerAndActivateServiceWorker(test) {
// Unregister existing service worker (if any)
const existingRegistration = await navigator.serviceWorker.getRegistration(CURRENT_SCOPE);
if (existingRegistration) {
await existingRegistration.unregister();
}
// Register new service worker
var newRegistration = await navigator.serviceWorker.register(`./${SERVICE_WORKER_SCRIPT}`, { scope: CURRENT_SCOPE });
test.add_cleanup(async () => {
await newRegistration.unregister();
});
await navigator.serviceWorker.ready;
// Wait for the page to be controlled by the service worker.
// This is needed as navigator.serviceWorker.ready does not
// guarantee that the page is being controlled.
await new Promise(resolve => {
if (navigator.serviceWorker.controller) {
resolve();
} else {
navigator.serviceWorker.addEventListener('controllerchange', resolve);
}
});
// Validate the service worker
if (!navigator.serviceWorker.controller.scriptURL.includes(SERVICE_WORKER_SCRIPT)) {
throw new Error('Failed to register service worker');
}
}
async function setUpServiceWorkerAndGetBroadcastChannel(test) {
await registerAndActivateServiceWorker(test);
return new BroadcastChannel("requests-test");
}
// Waits for a service worker to observe specific URL filenames via a BroadcastChannel.
// Resolves when all expected URL filenames are seen.
function awaitServiceWorkerURLPromise(broadcastChannel, expectedURLFileNames,
unexpectedURLFileNames) {
const seenURLs = new Set();
return new Promise((resolve, reject) => {
broadcastChannel.addEventListener('message', (event) => {
var url = event.data.url;
var fileName = url.substring(url.lastIndexOf('/') + 1);
if (expectedURLFileNames.includes(fileName)) {
seenURLs.add(fileName);
}
if (unexpectedURLFileNames.includes(fileName)) {
reject(`unexpected result: ${fileName}`);
}
// Resolve when all `expectedURLs` have been seen.
if (seenURLs.size === expectedURLFileNames.length) {
resolve();
}
});
});
}
// Tests that public requests are seen by the service worker.
// Specifically anything that contains:
// - 'direct-from-seller-signals.py'
// This test works by having the service worker send a message over
// the broadcastChannel, if it sees a request that contains any of
// the following strings above, it will send a 'passed' result and
// also change the variable 'finish_test', to true, so that guarantees
// that the request was seen before we complete the test.
subsetTest(promise_test, async test => {
const broadcastChannel = await setUpServiceWorkerAndGetBroadcastChannel(test);
let finishTest = awaitServiceWorkerURLPromise(
broadcastChannel,
PUBLIC_REQUEST_FILE_NAMES,
PRIVATE_REQUEST_FILE_NAMES);
await fetchDirectFromSellerSignals({ 'Buyer-Origin': window.location.origin });
await finishTest;
}, "Make sure service workers do see public requests.");
// Tests that private requests are not seen by the service worker.
// Specifically anything that contains:
// - 'resources/trusted-bidding-signals.py'
// - 'resources/trusted-scoring-signals.py'
// - 'wasm-helper.py'
// - 'bidding-logic.py'
// - 'decision-logic.py'
// - 'seller_report'
// - 'bidder_report'
// This test works by having the service worker send a message
// over the broadcastChannel, if it sees a request that contains
// any of the following strings above, it will send a 'failed'
// result which will cause assert_false case to fail.
subsetTest(promise_test, async test => {
const uuid = generateUuid(test);
const broadcastChannel = await setUpServiceWorkerAndGetBroadcastChannel(test);
let finishTest = awaitServiceWorkerURLPromise(
broadcastChannel,
/*expectedURLFileNames=*/[COMPLETE_TEST_URL],
PRIVATE_REQUEST_FILE_NAMES)
let interestGroupOverrides = {
biddingWasmHelperURL: `${RESOURCE_PATH}wasm-helper.py`,
trustedBiddingSignalsURL: TRUSTED_BIDDING_SIGNALS_URL,
trustedScoringSignalsURL: TRUSTED_SCORING_SIGNALS_URL,
};
await joinInterestGroup(test, uuid, interestGroupOverrides);
await runBasicFledgeAuctionAndNavigate(test, uuid);
// By verifying that these requests are observed we can assume
// none of the other requests were seen by the service-worker.
await waitForObservedRequests(
uuid,
[createBidderReportURL(uuid), createSellerReportURL(uuid)]);
// We use this fetch to complete the test.
await fetch(COMPLETE_TEST_URL);
await finishTest;
}, "Make sure service workers do not see private requests");