UNPKG

reportage

Version:

Scenarist-wrapped mocha sessions on browsers to any reporters

220 lines (217 loc) 9.58 kB
/* @license https://github.com/t2ym/reportage/blob/master/LICENSE.md Copyright (c) 2023 Tetsuya Mori <t2y3141592@gmail.com>. All rights reserved. */ const NAVIGATION_PREFIX = 'navigation-'; const SCREENSHOT_PREFIX = 'screenshot-'; chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { switch (message.type) { case 'setup-injection': { chrome.storage.session.set({ injectionParameters: message.injectionParameters }).then(() => { console.log(`background.js: injectionParameters`, message.injectionParameters); sendResponse({ type: 'setup-injection-finished', injectionParameters: message.injectionParameters }); }); } break; case 'get-injection-parameters': { chrome.storage.session.get(['injectionParameters']).then((result) => { console.log(`background.js: get-injection-parameters`, result.injectionParameters); sendResponse({ type: 'injection-parameters', injectionParameters: result.injectionParameters }); }); } break; case 'cleanup': { const filterableTargets = { // filterable by origins/hostnames cookies: true, // The browser's cookies. cache: true, // The browser's cache. fileSystems: true, // Websites' file systems.; not on Firefox indexedDB: true, // Websites' IndexedDB data. localStorage: true, // Websites' local storage data. cacheStorage: true, // Cache storage serviceWorkers: true, // Service Workers. webSQL: true, // [DEPRECATED FEATURE] Websites' WebSQL data. }; const nonFilterableTargets = { // non-filterable by origins/hostnames - Be aware that other apps with the same user profile are affected as well appcache: true, // [DEPRECATED FEATURE] Websites' appcaches. downloads: true, // [BASICALLY IRRELEVANT TO WEB TESTS] The browser's download list. history: true, // [Session history is reset on navigating to cleanup.html] The browser's history, which is different from window.history object formData: true, // [Autofill feature should be disabled in the browser settings] The browser's stored form data. passwords: true, // [Autofill feature should be disabled in the browser settings] Stored passwords. }; const dataToRemove = message.parameters.dataToRemove; console.log(`dataToRemove: ${JSON.stringify(dataToRemove,null,0)}`); const filterableDataToRemove = {}; const nonFilterableDataToRemove = {}; for (let target in dataToRemove) { if (filterableTargets[target]) { filterableDataToRemove[target] = dataToRemove[target]; } if (nonFilterableTargets[target]) { nonFilterableDataToRemove[target] = dataToRemove[target]; } } chrome.browsingData.remove( { since: message.parameters.removalOptions.since || 0, }, nonFilterableDataToRemove, () => { console.log(`chrome.browsingData.remove: done for non-filterable browsing data ${JSON.stringify(nonFilterableDataToRemove, null, 0)}`); chrome.browsingData.remove( message.parameters.removalOptions, filterableDataToRemove, () => { console.log(`chrome.browsingData.remove: done for filterable browsing data ${JSON.stringify(filterableDataToRemove, null, 0)} for origins ${JSON.stringify(message.parameters.removalOptions.origins,null,0)}`); sendResponse({ type: 'cleanup-finished', origins: message.parameters.removalOptions.origins }); } ); } ); } break; case 'navigation': { const origin = new URL(message.url).origin; chrome.storage.session.set({ [`${NAVIGATION_PREFIX}${origin}`]: { url: message.url, timestamp: message.timestamp } }).then(() => { console.log(`background.js: navigation origin: ${origin} url: ${message.url} timestamp: ${message.timestamp}`); sendResponse({ type: 'navigation-url-stored', values: { [origin]: { url: message.url, timestamp: message.timestamp } } }); }); } break; case 'get-navigation': { const origin = message.origin; chrome.storage.session.get([`${NAVIGATION_PREFIX}${origin}`]).then((result) => { const value = result[`${NAVIGATION_PREFIX}${origin}`]; console.log(`background.js: get-navigation for origin: ${origin}`, value); sendResponse({ type: 'navigation-url', values: value ? { [origin]: value } : {} }); }); } break; case 'clear-navigation': { const origin = message.origin; if (origin === '*') { chrome.storage.session.get(null).then((result) => { let targetOrigins = []; let targetResults = {}; for (let origin in result) { if (origin.startsWith(NAVIGATION_PREFIX)) { targetOrigins.push(origin); targetResults[origin.substring(NAVIGATION_PREFIX.length)] = result[origin]; } } chrome.storage.session.remove(targetOrigins).then(() => { console.log(`background.js: clear-navigation for origins: ${JSON.stringify(targetOrigins.map(value => value.substring(NAVIGATION_PREFIX.length)))}`); sendResponse({ type: 'navigation-url-cleared', values: targetResults }); }); }); } else { chrome.storage.session.get([`${NAVIGATION_PREFIX}${origin}`]).then((result) => { if (result[`${NAVIGATION_PREFIX}${origin}`]) { chrome.storage.session.remove(`${NAVIGATION_PREFIX}${origin}`).then(() => { console.log(`background.js: clear-navigation for origin: ${origin}`, result[`${NAVIGATION_PREFIX}${origin}`]); sendResponse({ type: 'navigation-url-cleared', values: { [origin]: result[`${NAVIGATION_PREFIX}${origin}`] } }); }); } else { console.log(`background.js: clear-navigation for origin: ${origin} failed as the value is missing`); sendResponse({ type: 'navigation-url-cleared', values: {} }); } }); } } break; /* case 'screenshot': (async () => { let tab; try { const [ _tab ] = await chrome.tabs.query({ currentWindow: true, url: message.url }); tab = _tab; await chrome.debugger.attach({ tabId: tab.id }, '1.3'); const result = { type: 'screenshot-finished', err: null, tabId: tab.id, url: tab.url }; Object.assign(result, await chrome.debugger.sendCommand({ tabId: tab.id }, 'Page.getLayoutMetrics', {})); let { data } = await chrome.debugger.sendCommand({ tabId: tab.id }, 'Page.captureScreenshot', { format: message.format, quality: message.quality, clip: { x: 0, y: 0, width: result.cssContentSize.width, height: result.cssContentSize.height, scale: 1 }, captureBeyondViewport: true, }); await chrome.debugger.detach({ tabId: tab.id }); data = `data:image/${message.format};base64,` + data; result.dataSize = data.length; console.log(`background.js: screenshot-finished result: ${JSON.stringify(result, null, 2)} `); await chrome.storage.session.set({ [`${SCREENSHOT_PREFIX}${message.testURL}`]: { data } }); console.log(`background.js: screenshot saved as ${SCREENSHOT_PREFIX}${message.testURL}`); sendResponse(result); } catch (err) { if (tab) { await chrome.debugger.detach({ tabId: tab.id }); } console.log(`background.js: screenshot-finished err: ${err.message} for ${message.url}`, err); await chrome.storage.session.remove(`${SCREENSHOT_PREFIX}${message.testURL}`); sendResponse({ type: 'screenshot-finished', err: err.message, stack: err.stack }); } })(); break; */ case 'coverage': (async () => { //console.log(message); const randomUUID = (() => { // emulate crypto.randomUUID() const hex = Array.prototype.map.call( crypto.getRandomValues(new Uint16Array(8)), (v) => v.toString(16).padStart(4, '0')); return `${hex[0]}${hex[1]}-${hex[2]}-${hex[3]}-${hex[4]}-${hex[5]}${hex[6]}${hex[7]}` })(); /* { "coverage-${RandomUUID}": [{},...], ... } */ if (message.__coverage__) { await chrome.storage.local.set({ [`coverage-${randomUUID}`]: message.__coverage__ }); // no need to send a response as the coverage has been sent on a beforeunload event of a page } else { const rawResult = await chrome.storage.local.get(null); // get all results in the local storage // merge all covarage data const result = []; const keys = []; for (let key in rawResult) { if (key.startsWith('coverage-')) { // filter out coverage data result.splice(result.length, 0, ...rawResult[key]); keys.push(key); } } // merge globalThis.__coverage__ of background.js itself if (globalThis.__coverage__) { result.push(globalThis.__coverage__); } // remove all stored coverage data in chrome.storage.local await chrome.storage.local.remove(keys); sendResponse({ type: 'coverage', __coverage__: result }); } })(); break; default: sendResponse({ type: 'unknown-message' }); break; } return true; });