From 9fd24a35e97dbfa012ddec1b1ed7811b1d4d1deb Mon Sep 17 00:00:00 2001 From: Adam Raine <6752989+adamraine@users.noreply.github.com> Date: Thu, 6 Jul 2023 21:56:25 -0700 Subject: [PATCH] tests: remove usages of legacy driver (#15230) --- .../gather/driver/execution-context-test.js | 78 +++++++------------ core/test/gather/driver/navigation-test.js | 19 ++--- .../gather/driver/wait-for-condition-test.js | 21 +---- .../gather/gatherers/global-listeners-test.js | 15 ++-- core/test/gather/gatherers/js-usage-test.js | 15 +--- .../test/gather/gatherers/source-maps-test.js | 24 ++---- .../gather/gatherers/trace-elements-test.js | 49 +++++------- core/test/gather/mock-driver.js | 7 +- core/test/lib/emulation-test.js | 60 +++++++------- 9 files changed, 102 insertions(+), 186 deletions(-) diff --git a/core/test/gather/driver/execution-context-test.js b/core/test/gather/driver/execution-context-test.js index c8e2d5bdc904..3f1c3593af76 100644 --- a/core/test/gather/driver/execution-context-test.js +++ b/core/test/gather/driver/execution-context-test.js @@ -6,25 +6,12 @@ import {ExecutionContext} from '../../../gather/driver/execution-context.js'; import { - mockCommands, makePromiseInspectable, flushAllTimersAndMicrotasks, fnAny, timers, } from '../../test-utils.js'; - -// This can be removed when FR becomes the default. -const createMockSendCommandFn = - mockCommands.createMockSendCommandFn.bind(null, {useSessionId: false}); - -/** @return {LH.Gatherer.FRProtocolSession} */ -function createMockSession() { - /** @type {any} */ - const session = {}; - session.hasNextProtocolTimeout = fnAny().mockReturnValue(false); - session.setNextProtocolTimeout = fnAny(); - return session; -} +import {createMockSession} from '../mock-driver.js'; /** @param {string} s */ function trimTrailingWhitespace(s) { @@ -32,8 +19,7 @@ function trimTrailingWhitespace(s) { } describe('ExecutionContext', () => { - /** @type {LH.Gatherer.FRProtocolSession} */ - let sessionMock; + let sessionMock = createMockSession(); /** @type {(executionContext: ExecutionContext, id: number) => Promise} */ let forceNewContextId; @@ -41,7 +27,7 @@ describe('ExecutionContext', () => { sessionMock = createMockSession(); forceNewContextId = async (executionContext, executionContextId) => { - executionContext._session.sendCommand = createMockSendCommandFn() + sessionMock.sendCommand .mockResponse('Page.enable') .mockResponse('Runtime.enable') .mockResponse('Page.getFrameTree', {frameTree: {frame: {id: '1337'}}}) @@ -53,11 +39,9 @@ describe('ExecutionContext', () => { }); it('should clear context on frame navigations', async () => { - const onMock = sessionMock.on = fnAny(); - const executionContext = new ExecutionContext(sessionMock); - const frameListener = onMock.mock.calls.find(call => call[0] === 'Page.frameNavigated'); + const frameListener = sessionMock.on.mock.calls.find(call => call[0] === 'Page.frameNavigated'); expect(frameListener).toBeDefined(); await forceNewContextId(executionContext, 42); @@ -67,11 +51,9 @@ describe('ExecutionContext', () => { }); it('should clear context on execution context destroyed', async () => { - const onMock = sessionMock.on = fnAny(); - const executionContext = new ExecutionContext(sessionMock); - const executionDestroyed = onMock.mock.calls + const executionDestroyed = sessionMock.on.mock.calls .find(call => call[0] === 'Runtime.executionContextDestroyed'); expect(executionDestroyed).toBeDefined(); @@ -90,19 +72,17 @@ describe('.evaluateAsync', () => { before(() => timers.useFakeTimers()); after(() => timers.dispose()); - /** @type {LH.Gatherer.FRProtocolSession} */ - let sessionMock; + let sessionMock = createMockSession(); /** @type {ExecutionContext} */ let executionContext; beforeEach(() => { sessionMock = createMockSession(); - sessionMock.on = fnAny(); - executionContext = new ExecutionContext(sessionMock); + executionContext = new ExecutionContext(sessionMock.asSession()); }); it('evaluates an expression', async () => { - const sendCommand = (sessionMock.sendCommand = createMockSendCommandFn().mockResponse( + const sendCommand = (sessionMock.sendCommand.mockResponse( 'Runtime.evaluate', {result: {value: 2}} )); @@ -115,7 +95,7 @@ describe('.evaluateAsync', () => { it('uses a high default timeout', async () => { const setNextProtocolTimeout = sessionMock.setNextProtocolTimeout = fnAny(); sessionMock.hasNextProtocolTimeout = fnAny().mockReturnValue(false); - sessionMock.sendCommand = createMockSendCommandFn().mockRejectedValue(new Error('Timeout')); + sessionMock.sendCommand.mockRejectedValue(new Error('Timeout')); const evaluatePromise = makePromiseInspectable(executionContext.evaluateAsync('1 + 1')); @@ -130,7 +110,7 @@ describe('.evaluateAsync', () => { const setNextProtocolTimeout = sessionMock.setNextProtocolTimeout = fnAny(); sessionMock.hasNextProtocolTimeout = fnAny().mockReturnValue(true); sessionMock.getNextProtocolTimeout = fnAny().mockReturnValue(expectedTimeout); - sessionMock.sendCommand = createMockSendCommandFn().mockRejectedValue(new Error('Timeout')); + sessionMock.sendCommand.mockRejectedValue(new Error('Timeout')); const evaluatePromise = makePromiseInspectable(executionContext.evaluateAsync('1 + 1')); @@ -141,38 +121,38 @@ describe('.evaluateAsync', () => { }); it('evaluates an expression in isolation', async () => { - let sendCommand = (sessionMock.sendCommand = createMockSendCommandFn() + sessionMock.sendCommand .mockResponse('Page.enable') .mockResponse('Runtime.enable') .mockResponse('Page.getFrameTree', {frameTree: {frame: {id: '1337'}}}) .mockResponse('Page.createIsolatedWorld', {executionContextId: 1}) - .mockResponse('Runtime.evaluate', {result: {value: 2}})); + .mockResponse('Runtime.evaluate', {result: {value: 2}}) + .mockResponse('Runtime.evaluate', {result: {value: 2}}); const value = await executionContext.evaluateAsync('1 + 1', {useIsolation: true}); expect(value).toEqual(2); // Check that we used the correct frame when creating the isolated context - const createWorldArgs = sendCommand.findInvocation('Page.createIsolatedWorld'); - expect(createWorldArgs).toMatchObject({frameId: '1337'}); + let createWorldInvocations = + sessionMock.sendCommand.findAllInvocations('Page.createIsolatedWorld'); + expect(createWorldInvocations[0]).toMatchObject({frameId: '1337'}); // Check that we used the isolated context when evaluating - const evaluateArgs = sendCommand.findInvocation('Runtime.evaluate'); + const evaluateArgs = sessionMock.sendCommand.findInvocation('Runtime.evaluate'); expect(evaluateArgs).toMatchObject({contextId: 1}); // Make sure we cached the isolated context from last time - sendCommand = sessionMock.sendCommand = createMockSendCommandFn().mockResponse( - 'Runtime.evaluate', - {result: {value: 2}} - ); + createWorldInvocations = sessionMock.sendCommand.findAllInvocations('Page.createIsolatedWorld'); + expect(createWorldInvocations).toHaveLength(1); + await executionContext.evaluateAsync('1 + 1', {useIsolation: true}); - expect(sessionMock.sendCommand).not.toHaveBeenCalledWith( - 'Page.createIsolatedWorld', - expect.anything() - ); + + createWorldInvocations = sessionMock.sendCommand.findAllInvocations('Page.createIsolatedWorld'); + expect(createWorldInvocations).toHaveLength(1); }); it('recovers from isolation failures', async () => { - sessionMock.sendCommand = createMockSendCommandFn() + sessionMock.sendCommand .mockResponse('Page.enable') .mockResponse('Runtime.enable') .mockResponse('Page.getFrameTree', {frameTree: {frame: {id: '1337'}}}) @@ -205,7 +185,7 @@ describe('.evaluateAsync', () => { ' at _lighthouse-eval.js:83:8', }, }; - sessionMock.sendCommand = createMockSendCommandFn() + sessionMock.sendCommand .mockResponse('Page.enable') .mockResponse('Runtime.enable') .mockResponse('Page.getResourceTree', {frameTree: {frame: {id: '1337'}}}) @@ -221,19 +201,17 @@ describe('.evaluateAsync', () => { }); describe('.evaluate', () => { - /** @type {LH.Gatherer.FRProtocolSession} */ - let sessionMock; + let sessionMock = createMockSession(); /** @type {ExecutionContext} */ let executionContext; beforeEach(() => { sessionMock = createMockSession(); - sessionMock.on = fnAny(); - executionContext = new ExecutionContext(sessionMock); + executionContext = new ExecutionContext(sessionMock.asSession()); }); it('transforms parameters into an expression given to Runtime.evaluate', async () => { - const mockFn = sessionMock.sendCommand = createMockSendCommandFn() + const mockFn = sessionMock.sendCommand .mockResponse('Runtime.evaluate', {result: {value: 1}}); /** @param {number} value */ diff --git a/core/test/gather/driver/navigation-test.js b/core/test/gather/driver/navigation-test.js index 6d403b89da12..fcbae45ae3c0 100644 --- a/core/test/gather/driver/navigation-test.js +++ b/core/test/gather/driver/navigation-test.js @@ -6,14 +6,11 @@ import {createMockDriver} from '../mock-driver.js'; import { - mockCommands, makePromiseInspectable, flushAllTimersAndMicrotasks, timers, } from '../../test-utils.js'; -const {createMockOnceFn} = mockCommands; - // Some imports needs to be done dynamically, so that their dependencies will be mocked. // https://github.com/GoogleChrome/lighthouse/blob/main/docs/hacking-tips.md#mocking-modules-with-testdouble const {gotoURL, getNavigationWarnings} = await import('../../../gather/driver/navigation.js'); @@ -41,7 +38,7 @@ describe('.gotoURL', () => { }); it('will track redirects through gotoURL load with warning', async () => { - mockDriver.defaultSession.on = mockDriver.defaultSession.once = createMockOnceFn(); + mockDriver.defaultSession.on = mockDriver.defaultSession.once; const url = 'http://example.com'; @@ -93,7 +90,7 @@ describe('.gotoURL', () => { }); it('backfills requestedUrl when using a callback requestor', async () => { - mockDriver.defaultSession.on = mockDriver.defaultSession.once = createMockOnceFn(); + mockDriver.defaultSession.on = mockDriver.defaultSession.once; const requestor = () => Promise.resolve(); @@ -112,7 +109,7 @@ describe('.gotoURL', () => { }); it('throws if no navigations found using a callback requestor', async () => { - mockDriver.defaultSession.on = mockDriver.defaultSession.once = createMockOnceFn(); + mockDriver.defaultSession.on = mockDriver.defaultSession.once; const requestor = () => Promise.resolve(); @@ -131,7 +128,7 @@ describe('.gotoURL', () => { }); it('does not add warnings when URLs are equal', async () => { - mockDriver.defaultSession.on = mockDriver.defaultSession.once = createMockOnceFn(); + mockDriver.defaultSession.on = mockDriver.defaultSession.once; const url = 'https://www.example.com'; @@ -147,7 +144,7 @@ describe('.gotoURL', () => { }); it('waits for Page.frameNavigated', async () => { - mockDriver.defaultSession.on = mockDriver.defaultSession.once = createMockOnceFn(); + mockDriver.defaultSession.on = mockDriver.defaultSession.once; const url = 'https://www.example.com'; @@ -165,7 +162,7 @@ describe('.gotoURL', () => { }); it('waits for page load', async () => { - mockDriver.defaultSession.on = mockDriver.defaultSession.once = createMockOnceFn(); + mockDriver.defaultSession.on = mockDriver.defaultSession.once; const url = 'https://www.example.com'; @@ -194,7 +191,7 @@ describe('.gotoURL', () => { }); it('waits for page FCP', async () => { - mockDriver.defaultSession.on = mockDriver.defaultSession.once = createMockOnceFn(); + mockDriver.defaultSession.on = mockDriver.defaultSession.once; const url = 'https://www.example.com'; @@ -228,7 +225,7 @@ describe('.gotoURL', () => { }); it('throws when asked to wait for FCP without waiting for load', async () => { - mockDriver.defaultSession.on = mockDriver.defaultSession.once = createMockOnceFn(); + mockDriver.defaultSession.on = mockDriver.defaultSession.once; const url = 'https://www.example.com'; diff --git a/core/test/gather/driver/wait-for-condition-test.js b/core/test/gather/driver/wait-for-condition-test.js index 5e190d74998d..c60da33d6945 100644 --- a/core/test/gather/driver/wait-for-condition-test.js +++ b/core/test/gather/driver/wait-for-condition-test.js @@ -8,16 +8,13 @@ import log from 'lighthouse-logger'; import * as wait from '../../../gather/driver/wait-for-condition.js'; import { - mockCommands, makePromiseInspectable, flushAllTimersAndMicrotasks, createDecomposedPromise, fnAny, timers, } from '../../test-utils.js'; - -const {createMockOnceFn} = mockCommands; - +import {createMockSession} from '../mock-driver.js'; function createMockWaitForFn() { const {promise, resolve, reject} = createDecomposedPromise(); @@ -256,18 +253,11 @@ describe('waitForFcp()', () => { let session; beforeEach(() => { - session = { - on: fnAny(), - once: fnAny(), - off: fnAny(), - sendCommand: fnAny(), - }; + session = createMockSession(); }); it('should not resolve until FCP fires', async () => { - session.on = session.once = createMockOnceFn(); - const waitPromise = makePromiseInspectable(wait.waitForFcp(session, 0, 60 * 1000).promise); const listener = session.on.findListener('Page.lifecycleEvent'); @@ -285,8 +275,6 @@ describe('waitForFcp()', () => { }); it('should wait for pauseAfterFcpMs after FCP', async () => { - session.on = session.once = createMockOnceFn(); - const waitPromise = makePromiseInspectable(wait.waitForFcp(session, 5000, 60 * 1000).promise); const listener = session.on.findListener('Page.lifecycleEvent'); @@ -305,8 +293,6 @@ describe('waitForFcp()', () => { }); it('should timeout', async () => { - session.on = session.once = createMockOnceFn(); - const waitPromise = makePromiseInspectable(wait.waitForFcp(session, 0, 5000).promise); await flushAllTimersAndMicrotasks(); @@ -319,9 +305,6 @@ describe('waitForFcp()', () => { }); it('should be cancellable', async () => { - session.on = session.once = createMockOnceFn(); - session.off = fnAny(); - const {promise: rawPromise, cancel} = wait.waitForFcp(session, 0, 5000); const waitPromise = makePromiseInspectable(rawPromise); diff --git a/core/test/gather/gatherers/global-listeners-test.js b/core/test/gather/gatherers/global-listeners-test.js index 9dc32f331032..132750e3e9bb 100644 --- a/core/test/gather/gatherers/global-listeners-test.js +++ b/core/test/gather/gatherers/global-listeners-test.js @@ -5,9 +5,7 @@ */ import GlobalListenerGatherer from '../../../gather/gatherers/global-listeners.js'; -import {createMockSendCommandFn} from '../mock-commands.js'; -import {Connection} from '../../../legacy/gather/connections/connection.js'; -import {Driver} from '../../../legacy/gather/driver.js'; +import {createMockDriver} from '../mock-driver.js'; describe('Global Listener Gatherer', () => { it('remove duplicate listeners from artifacts', async () => { @@ -39,19 +37,16 @@ describe('Global Listener Gatherer', () => { }, ]; - const sendCommandMock = createMockSendCommandFn() - .mockResponse('Runtime.evaluate', {result: {objectId: 10}}) - .mockResponse('DOMDebugger.getEventListeners', {listeners: mockListeners.slice(0)}); - const expectedOutput = [ mockListeners[0], mockListeners[2], mockListeners[3], ]; - const connectionStub = new Connection(); - connectionStub.sendCommand = sendCommandMock; - const driver = new Driver(connectionStub); + const driver = createMockDriver(); + driver._session.sendCommand + .mockResponse('Runtime.evaluate', {result: {objectId: 10}}) + .mockResponse('DOMDebugger.getEventListeners', {listeners: mockListeners.slice(0)}); const globalListeners = await globalListenerGatherer.getArtifact({driver}); return expect(globalListeners).toMatchObject(expectedOutput); diff --git a/core/test/gather/gatherers/js-usage-test.js b/core/test/gather/gatherers/js-usage-test.js index 498865cd3ace..fe37052e4a09 100644 --- a/core/test/gather/gatherers/js-usage-test.js +++ b/core/test/gather/gatherers/js-usage-test.js @@ -4,11 +4,8 @@ * 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. */ -import {Driver} from '../../../legacy/gather/driver.js'; -import {Connection} from '../../../legacy/gather/connections/connection.js'; import JsUsage from '../../../gather/gatherers/js-usage.js'; -import {createMockSendCommandFn, createMockOnFn} from '../mock-commands.js'; -import {createMockContext} from '../../gather/mock-driver.js'; +import {createMockContext, createMockDriver} from '../../gather/mock-driver.js'; import {flushAllTimersAndMicrotasks, timers} from '../../test-utils.js'; describe('JsUsage gatherer', () => { @@ -22,20 +19,14 @@ describe('JsUsage gatherer', () => { * @return {Promise} */ async function runJsUsage({coverage}) { - const onMock = createMockOnFn(); - const sendCommandMock = createMockSendCommandFn() + const driver = createMockDriver(); + driver._session.sendCommand .mockResponse('Profiler.enable', {}) .mockResponse('Profiler.disable', {}) .mockResponse('Profiler.startPreciseCoverage', {}) .mockResponse('Profiler.takePreciseCoverage', {result: coverage}) .mockResponse('Profiler.stopPreciseCoverage', {}); - const connectionStub = new Connection(); - connectionStub.sendCommand = sendCommandMock; - connectionStub.on = onMock; - - const driver = new Driver(connectionStub); - const gatherer = new JsUsage(); await gatherer.startInstrumentation({driver}); await gatherer.startSensitiveInstrumentation({driver}); diff --git a/core/test/gather/gatherers/source-maps-test.js b/core/test/gather/gatherers/source-maps-test.js index 04f36f9044e1..3a8bcd3184d8 100644 --- a/core/test/gather/gatherers/source-maps-test.js +++ b/core/test/gather/gatherers/source-maps-test.js @@ -4,11 +4,9 @@ * 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. */ -import {Driver} from '../../../legacy/gather/driver.js'; -import {Connection} from '../../../legacy/gather/connections/connection.js'; import SourceMaps from '../../../gather/gatherers/source-maps.js'; -import {createMockSendCommandFn, createMockOnFn} from '../mock-commands.js'; -import {flushAllTimersAndMicrotasks, fnAny, timers} from '../../test-utils.js'; +import {flushAllTimersAndMicrotasks, timers} from '../../test-utils.js'; +import {createMockDriver} from '../mock-driver.js'; const mapJson = JSON.stringify({ version: 3, @@ -40,12 +38,11 @@ describe('SourceMaps gatherer', () => { } } - const onMock = createMockOnFn(); - const sendCommandMock = createMockSendCommandFn() + const driver = createMockDriver(); + driver._session.sendCommand .mockResponse('Debugger.enable', {}) .mockResponse('Debugger.disable', {}) .mockResponse('Network.enable', {}); - const fetchMock = fnAny(); for (const mapAndEvents of mapsAndEvents) { const { @@ -55,17 +52,14 @@ describe('SourceMaps gatherer', () => { resolvedSourceMapUrl, fetchError, } = mapAndEvents; - onMock.mockEvent('protocolevent', { - method: 'Debugger.scriptParsed', - params: scriptParsedEvent, - }); + driver._session.on.mockEvent('Debugger.scriptParsed', scriptParsedEvent); if (scriptParsedEvent.sourceMapURL.startsWith('data:')) { // Only the source maps that need to be fetched use the `fetchMock` code path. continue; } - fetchMock.mockImplementationOnce(async (sourceMapUrl) => { + driver.fetcher.fetchResource.mockImplementationOnce(async (sourceMapUrl) => { // Check that the source map url was resolved correctly. if (resolvedSourceMapUrl) { expect(sourceMapUrl).toBe(resolvedSourceMapUrl); @@ -78,12 +72,6 @@ describe('SourceMaps gatherer', () => { return {content: map, status}; }); } - const connectionStub = new Connection(); - connectionStub.sendCommand = sendCommandMock; - connectionStub.on = onMock; - - const driver = new Driver(connectionStub); - driver.fetcher.fetchResource = fetchMock; const sourceMaps = new SourceMaps(); diff --git a/core/test/gather/gatherers/trace-elements-test.js b/core/test/gather/gatherers/trace-elements-test.js index be0ae1418613..ed86942dfb65 100644 --- a/core/test/gather/gatherers/trace-elements-test.js +++ b/core/test/gather/gatherers/trace-elements-test.js @@ -5,12 +5,10 @@ */ import TraceElementsGatherer from '../../../gather/gatherers/trace-elements.js'; -import {Driver} from '../../../legacy/gather/driver.js'; -import {Connection} from '../../../legacy/gather/connections/connection.js'; import {createTestTrace, rootFrame} from '../../create-test-trace.js'; -import {createMockSendCommandFn, createMockOnFn} from '../mock-commands.js'; import {flushAllTimersAndMicrotasks, fnAny, readJson, timers} from '../../test-utils.js'; import {ProcessedTrace} from '../../../computed/processed-trace.js'; +import {createMockDriver} from '../mock-driver.js'; const animationTrace = readJson('../../fixtures/artifacts/animation/trace.json', import.meta); @@ -464,8 +462,9 @@ describe('Trace Elements gatherer - Animated Elements', () => { }, type: 'text', }; - const connectionStub = new Connection(); - connectionStub.sendCommand = createMockSendCommandFn() + + const driver = createMockDriver(); + driver._session.sendCommand // nodeId: 6 .mockResponse('DOM.resolveNode', {object: {objectId: 1}}) .mockResponse('Runtime.callFunctionOn', {result: {value: LCPNodeData}}) @@ -479,7 +478,6 @@ describe('Trace Elements gatherer - Animated Elements', () => { // nodeId: 5 .mockResponse('DOM.resolveNode', {object: {objectId: 3}}) .mockResponse('Runtime.callFunctionOn', {result: {value: animationNodeData}}); - const driver = new Driver(connectionStub); const trace = createTestTrace({timeOrigin: 0, traceEnd: 2000}); trace.traceEvents.push( @@ -576,8 +574,8 @@ describe('Trace Elements gatherer - Animated Elements', () => { height: 100, }, }; - const connectionStub = new Connection(); - connectionStub.sendCommand = createMockSendCommandFn() + const driver = createMockDriver(); + driver._session.sendCommand // LCP node .mockResponse('DOM.resolveNode', {object: {objectId: 1}}) .mockResponse('Runtime.callFunctionOn', {result: {value: LCPNodeData}}) @@ -588,7 +586,6 @@ describe('Trace Elements gatherer - Animated Elements', () => { .mockResponse('DOM.resolveNode', {object: {objectId: 7}}) .mockResponse('Runtime.callFunctionOn', {result: {value: compositedNodeData}}); - const driver = new Driver(connectionStub); const gatherer = new TraceElementsGatherer(); gatherer.animationIdToName.set('2', 'alpha'); gatherer.animationIdToName.set('3', 'beta'); @@ -640,8 +637,8 @@ describe('Trace Elements gatherer - Animated Elements', () => { }, type: 'text', }; - const connectionStub = new Connection(); - connectionStub.sendCommand = createMockSendCommandFn() + const driver = createMockDriver(); + driver._session.sendCommand .mockResponse('DOM.resolveNode', {object: {objectId: 1}}) .mockResponse('Runtime.callFunctionOn', {result: {value: LCPNodeData}}) // Animation 1 @@ -651,7 +648,6 @@ describe('Trace Elements gatherer - Animated Elements', () => { // Animation 2 .mockResponse('DOM.resolveNode', {object: {objectId: 5}}) .mockResponse('Runtime.callFunctionOn', {result: {value: animationNodeData}}); - const driver = new Driver(connectionStub); const trace = createTestTrace({timeOrigin: 0, traceEnd: 2000}); trace.traceEvents.push(makeAnimationTraceEvent('0x363db876c8', 'b', {id: '1', nodeId: 5})); @@ -704,12 +700,11 @@ describe('Trace Elements gatherer - Animated Elements', () => { height: 140, }, }; - const connectionStub = new Connection(); - connectionStub.sendCommand = createMockSendCommandFn() + const driver = createMockDriver(); + driver._session.sendCommand // Animation 1 .mockResponse('DOM.resolveNode', {object: {objectId: 5}}) .mockResponse('Runtime.callFunctionOn', {result: {value: animationNodeData}}); - const driver = new Driver(connectionStub); const trace = createTestTrace({timeOrigin: 0, traceEnd: 2000}); trace.traceEvents = trace.traceEvents.filter(event => event.name !== 'firstContentfulPaint'); @@ -745,16 +740,12 @@ describe('instrumentation', () => { after(() => timers.dispose()); it('resolves animation name', async () => { - const connectionStub = new Connection(); - connectionStub.on = createMockOnFn() - .mockEvent('protocolevent', { - method: 'Animation.animationStarted', - params: {animation: {id: '1', name: 'example'}}, - }); - connectionStub.sendCommand = createMockSendCommandFn() + const driver = createMockDriver(); + driver._session.on + .mockEvent('Animation.animationStarted', {animation: {id: '1', name: 'example'}}); + driver._session.sendCommand .mockResponse('Animation.enable') .mockResponse('Animation.disable'); - const driver = new Driver(connectionStub); const gatherer = new TraceElementsGatherer(); await gatherer.startInstrumentation({driver, computedCache: new Map()}); @@ -767,16 +758,12 @@ describe('instrumentation', () => { }); it('ignores empty name', async () => { - const connectionStub = new Connection(); - connectionStub.on = createMockOnFn() - .mockEvent('protocolevent', { - method: 'Animation.animationStarted', - params: {animation: {id: '1', name: ''}}, - }); - connectionStub.sendCommand = createMockSendCommandFn() + const driver = createMockDriver(); + driver._session.on + .mockEvent('Animation.animationStarted', {animation: {id: '1', name: ''}}); + driver._session.sendCommand .mockResponse('Animation.enable') .mockResponse('Animation.disable'); - const driver = new Driver(connectionStub); const gatherer = new TraceElementsGatherer(); await gatherer.startInstrumentation({driver, computedCache: new Map()}); diff --git a/core/test/gather/mock-driver.js b/core/test/gather/mock-driver.js index d2e6f02b2cb7..dc3fc9dc8645 100644 --- a/core/test/gather/mock-driver.js +++ b/core/test/gather/mock-driver.js @@ -27,6 +27,8 @@ function createMockSession() { setTargetInfo: fnAny(), sendCommand: createMockSendCommandFn({useSessionId: false}), setNextProtocolTimeout: fnAny(), + hasNextProtocolTimeout: fnAny(), + getNextProtocolTimeout: fnAny(), once: createMockOnceFn(), on: createMockOnFn(), off: fnAny(), @@ -36,7 +38,6 @@ function createMockSession() { /** @return {LH.Gatherer.FRProtocolSession} */ asSession() { - // @ts-expect-error - We'll rely on the tests passing to know this matches. return this; }, }; @@ -135,6 +136,7 @@ function createMockExecutionContext() { function createMockTargetManager(session) { return { rootSession: () => session, + mainFrameExecutionContexts: () => [{uniqueId: 'EXECUTION_CTX_ID'}], enable: fnAny(), disable: fnAny(), on: createMockOnFn(), @@ -164,6 +166,9 @@ function createMockDriver() { disconnect: fnAny(), executionContext: context.asExecutionContext(), targetManager: targetManager.asTargetManager(), + fetcher: { + fetchResource: fnAny(), + }, /** @return {Driver} */ asDriver() { diff --git a/core/test/lib/emulation-test.js b/core/test/lib/emulation-test.js index 81a5925dcd46..a2600eab30ed 100644 --- a/core/test/lib/emulation-test.js +++ b/core/test/lib/emulation-test.js @@ -5,24 +5,16 @@ */ import * as emulation from '../../lib/emulation.js'; -import {Driver} from '../../legacy/gather/driver.js'; import * as constants from '../../config/constants.js'; -import {Connection} from '../../legacy/gather/connections/connection.js'; -import {createMockSendCommandFn} from '../gather/mock-commands.js'; +import {createMockSession} from '../gather/mock-driver.js'; describe('emulation', () => { describe('emulate', () => { - let driver; - let connectionStub; + let session; beforeEach(() => { - connectionStub = new Connection(); - connectionStub.sendCommand = cmd => { - throw new Error(`${cmd} not implemented`); - }; - driver = new Driver(connectionStub); - - connectionStub.sendCommand = createMockSendCommandFn() + session = createMockSession(); + session.sendCommand .mockResponse('Network.setUserAgentOverride') .mockResponse('Emulation.setDeviceMetricsOverride') .mockResponse('Emulation.setTouchEmulationEnabled'); @@ -42,9 +34,9 @@ describe('emulation', () => { const metrics = constants.screenEmulationMetrics; it('default: mobile w/ screenEmulation', async () => { - await emulation.emulate(driver, getSettings('mobile', metrics.mobile)); + await emulation.emulate(session, getSettings('mobile', metrics.mobile)); - const uaArgs = connectionStub.sendCommand.findInvocation('Network.setUserAgentOverride'); + const uaArgs = session.sendCommand.findInvocation('Network.setUserAgentOverride'); expect(uaArgs).toMatchObject({ userAgent: constants.userAgents.mobile, userAgentMetadata: { @@ -53,16 +45,16 @@ describe('emulation', () => { }, }); - const emulateArgs = connectionStub.sendCommand.findInvocation( + const emulateArgs = session.sendCommand.findInvocation( 'Emulation.setDeviceMetricsOverride' ); expect(emulateArgs).toMatchObject({mobile: true}); }); it('default desktop: w/ desktop screen emu', async () => { - await emulation.emulate(driver, getSettings('desktop', metrics.desktop)); + await emulation.emulate(session, getSettings('desktop', metrics.desktop)); - const uaArgs = connectionStub.sendCommand.findInvocation('Network.setUserAgentOverride'); + const uaArgs = session.sendCommand.findInvocation('Network.setUserAgentOverride'); expect(uaArgs).toMatchObject({ userAgent: constants.userAgents.desktop, userAgentMetadata: { @@ -71,7 +63,7 @@ describe('emulation', () => { }, }); - const emulateArgs = connectionStub.sendCommand.findInvocation( + const emulateArgs = session.sendCommand.findInvocation( 'Emulation.setDeviceMetricsOverride' ); expect(emulateArgs).toMatchObject({ @@ -84,36 +76,36 @@ describe('emulation', () => { }); it('mobile but screenEmu disabled (scenarios: on-device or external emu applied)', async () => { - await emulation.emulate(driver, getSettings('mobile', false)); - const uaArgs = connectionStub.sendCommand.findInvocation('Network.setUserAgentOverride'); + await emulation.emulate(session, getSettings('mobile', {disabled: true})); + const uaArgs = session.sendCommand.findInvocation('Network.setUserAgentOverride'); expect(uaArgs).toMatchObject({userAgent: constants.userAgents.mobile}); - expect(connectionStub.sendCommand).not.toHaveBeenCalledWith( + expect(session.sendCommand).not.toHaveBeenCalledWith( 'Emulation.setDeviceMetricsOverride', expect.anything() ); }); it('desktop but screenEmu disabled (scenario: DevTools or external emu applied)', async () => { - await emulation.emulate(driver, getSettings('desktop', false)); - const uaArgs = connectionStub.sendCommand.findInvocation('Network.setUserAgentOverride'); + await emulation.emulate(session, getSettings('desktop', {disabled: true})); + const uaArgs = session.sendCommand.findInvocation('Network.setUserAgentOverride'); expect(uaArgs).toMatchObject({userAgent: constants.userAgents.desktop}); - expect(connectionStub.sendCommand).not.toHaveBeenCalledWith( + expect(session.sendCommand).not.toHaveBeenCalledWith( 'Emulation.setDeviceMetricsOverride', expect.anything() ); }); it('mobile but UA emu disabled', async () => { - await emulation.emulate(driver, getSettings('mobile', metrics.mobile, false)); + await emulation.emulate(session, getSettings('mobile', metrics.mobile, false)); - expect(connectionStub.sendCommand).not.toHaveBeenCalledWith( + expect(session.sendCommand).not.toHaveBeenCalledWith( 'Network.setUserAgentOverride', expect.anything() ); - const emulateArgs = connectionStub.sendCommand.findInvocation( + const emulateArgs = session.sendCommand.findInvocation( 'Emulation.setDeviceMetricsOverride' ); expect(emulateArgs).toMatchObject({ @@ -126,14 +118,14 @@ describe('emulation', () => { }); it('desktop but UA emu disabled', async () => { - await emulation.emulate(driver, getSettings('desktop', metrics.desktop, false)); + await emulation.emulate(session, getSettings('desktop', metrics.desktop, false)); - expect(connectionStub.sendCommand).not.toHaveBeenCalledWith( + expect(session.sendCommand).not.toHaveBeenCalledWith( 'Network.setUserAgentOverride', expect.anything() ); - const emulateArgs = connectionStub.sendCommand.findInvocation( + const emulateArgs = session.sendCommand.findInvocation( 'Emulation.setDeviceMetricsOverride' ); expect(emulateArgs).toMatchObject({ @@ -149,9 +141,9 @@ describe('emulation', () => { const settings = getSettings('desktop', metrics.desktop, false); const chromeTablet = 'Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36'; // eslint-disable-line max-len settings.emulatedUserAgent = chromeTablet; - await emulation.emulate(driver, settings); + await emulation.emulate(session, settings); - const uaArgs = connectionStub.sendCommand.findInvocation('Network.setUserAgentOverride'); + const uaArgs = session.sendCommand.findInvocation('Network.setUserAgentOverride'); expect(uaArgs).toMatchObject({ userAgent: chromeTablet, userAgentMetadata: { @@ -168,9 +160,9 @@ describe('emulation', () => { const settings = getSettings('desktop', metrics.desktop, false); const FFdesktopUA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0'; // eslint-disable-line max-len settings.emulatedUserAgent = FFdesktopUA; - await emulation.emulate(driver, settings); + await emulation.emulate(session, settings); - const uaArgs = connectionStub.sendCommand.findInvocation('Network.setUserAgentOverride'); + const uaArgs = session.sendCommand.findInvocation('Network.setUserAgentOverride'); expect(uaArgs).toMatchObject({ userAgent: FFdesktopUA, userAgentMetadata: {