diff --git a/lighthouse-core/gather/driver/execution-context.js b/lighthouse-core/gather/driver/execution-context.js index 00bea697bbd4..5a7214e8c075 100644 --- a/lighthouse-core/gather/driver/execution-context.js +++ b/lighthouse-core/gather/driver/execution-context.js @@ -97,7 +97,8 @@ class ExecutionContext { .catch(${pageFunctions.wrapRuntimeEvalErrorInBrowserString}) .then(resolve); }); - }())`, + }()) + //# sourceURL=_lighthouse-eval.js`, includeCommandLineAPI: true, awaitPromise: true, returnByValue: true, @@ -195,7 +196,8 @@ class ExecutionContext { ${ExecutionContext._cachedNativesPreamble}; ${depsSerialized}; (${mainFn})(${argsSerialized}); - })()`; + })() + //# sourceURL=_lighthouse-eval.js`; await this._session.sendCommand('Page.addScriptToEvaluateOnNewDocument', {source: expression}); } diff --git a/lighthouse-core/gather/gatherers/js-usage.js b/lighthouse-core/gather/gatherers/js-usage.js index 4bb0bc0298c2..2e83af257799 100644 --- a/lighthouse-core/gather/gatherers/js-usage.js +++ b/lighthouse-core/gather/gatherers/js-usage.js @@ -50,12 +50,13 @@ class JsUsage extends FRGatherer { const usageByScriptId = {}; for (const scriptUsage of this._scriptUsages) { - // If `url` is blank, that means the script was anonymous (eval, new Function, onload, ...). - // Or, it's because it was code Lighthouse over the protocol via `Runtime.evaluate`. - // We currently don't consider coverage of anonymous scripts, and we definitely don't want - // coverage of code Lighthouse ran to inspect the page, so we ignore this ScriptCoverage if - // url is blank. - if (scriptUsage.url === '') { + // If `url` is blank, that means the script was dynamically + // created (eval, new Function, onload, ...) + if (scriptUsage.url === '' || scriptUsage.url === '_lighthouse-eval.js') { + // We currently don't consider coverage of dynamic scripts, and we definitely don't want + // coverage of code Lighthouse ran to inspect the page, so we ignore this ScriptCoverage. + // Audits would work the same without this, it is only an optimization (not tracking coverage + // for scripts we don't care about). continue; } diff --git a/lighthouse-core/gather/gatherers/scripts.js b/lighthouse-core/gather/gatherers/scripts.js index a08c158e26e2..8e3be365f92c 100644 --- a/lighthouse-core/gather/gatherers/scripts.js +++ b/lighthouse-core/gather/gatherers/scripts.js @@ -28,6 +28,23 @@ async function runInSeriesOrParallel(values, promiseMapper, runInSeries) { } } +/** + * Returns true if the script was created via our own calls + * to Runtime.evaluate. + * @param {LH.Crdp.Debugger.ScriptParsedEvent} script + */ +function isLighthouseRuntimeEvaluateScript(script) { + // Scripts created by Runtime.evaluate that run on the main session/frame + // result in an empty string for the embedderName. + // Or, it means the script was dynamically created (eval, new Function, onload, ...) + if (!script.embedderName) return true; + + // Otherwise, when running our own code inside other frames, the embedderName + // is set to the frame's url. In that case, we rely on the special sourceURL that + // we set. + return script.hasSourceURL && script.url === '_lighthouse-eval.js'; +} + /** * @fileoverview Gets JavaScript file contents. */ @@ -68,8 +85,9 @@ class Scripts extends FRGatherer { // it also blocks scripts from the same origin but that happen to run in a different process, // like a worker. if (event.method === 'Debugger.scriptParsed' && !sessionId) { - // Events without an embedderName (read: a url) are for JS that we ran over the protocol. - if (event.params.embedderName) this._scriptParsedEvents.push(event.params); + if (!isLighthouseRuntimeEvaluateScript(event.params)) { + this._scriptParsedEvents.push(event.params); + } } } diff --git a/lighthouse-core/test/gather/driver/execution-context-test.js b/lighthouse-core/test/gather/driver/execution-context-test.js index 81c696b2197e..90a792fd6c7f 100644 --- a/lighthouse-core/test/gather/driver/execution-context-test.js +++ b/lighthouse-core/test/gather/driver/execution-context-test.js @@ -241,7 +241,8 @@ const fetch = globalThis.__nativeFetch || globalThis.fetch; }) .then(resolve); }); - }())`.trim(); + }()) + //# sourceURL=_lighthouse-eval.js`.trim(); expect(trimTrailingWhitespace(expression)).toBe(trimTrailingWhitespace(expected)); expect(await eval(expression)).toBe(1); });