core(user-flow): add base flags option (#14459)

This commit is contained in:
Adam Raine 2022-10-21 16:28:08 -07:00 коммит произвёл GitHub
Родитель 872d816e17
Коммит 88cc46b1bc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 123 добавлений и 19 удалений

Просмотреть файл

@ -99,6 +99,29 @@ describe('UserFlow', () => {
]);
});
it('should merge flow flags with step flags', async () => {
const flowFlags = {maxWaitForLoad: 500, maxWaitForFcp: 500};
const flow = new UserFlow(mockPage.asPage(), {flags: flowFlags});
await flow.navigate('https://example.com/1');
const flags = {maxWaitForLoad: 1000};
await flow.navigate('https://example.com/2', flags);
expect(navigationModule.navigationGather).toHaveBeenCalledTimes(2);
/** @type {any[][]} */
const [[,, call1], [,, call2]] =
navigationModule.navigationGather.mock.calls;
expect(call1.flags.maxWaitForLoad).toBe(500);
expect(call1.flags.maxWaitForFcp).toBe(500);
expect(call2.flags.maxWaitForLoad).toBe(1000);
expect(call2.flags.maxWaitForFcp).toBe(500);
// Check that we didn't mutate the original objects.
expect(flowFlags).toEqual({maxWaitForLoad: 500, maxWaitForFcp: 500});
expect(flags).toEqual({maxWaitForLoad: 1000});
});
it('should disable storage reset on subsequent navigations', async () => {
const flow = new UserFlow(mockPage.asPage());
await flow.navigate('https://example.com/1');
@ -114,22 +137,30 @@ describe('UserFlow', () => {
const flagsExplicit = {disableStorageReset: false};
await flow.navigate('https://example.com/4', flagsExplicit);
// Try once when we explicitly set it on the flow.
const flowFlagsExplicit = {disableStorageReset: false};
const flow2 = new UserFlow(mockPage.asPage(), {flags: flowFlagsExplicit});
await flow2.navigate('https://example.com/5');
// Check that we have the property set.
expect(navigationModule.navigationGather).toHaveBeenCalledTimes(4);
expect(navigationModule.navigationGather).toHaveBeenCalledTimes(5);
/** @type {any[][]} */
const [[,, call1], [,, call2], [,, call3], [,, call4]] =
const [[,, call1], [,, call2], [,, call3], [,, call4], [,, call5]] =
navigationModule.navigationGather.mock.calls;
expect(call1).not.toHaveProperty('flags.disableStorageReset');
expect(call2).toHaveProperty('flags.disableStorageReset');
expect(call3).toHaveProperty('flags.disableStorageReset');
expect(call4).toHaveProperty('flags.disableStorageReset');
expect(call5).toHaveProperty('flags.disableStorageReset');
expect(call2.flags.disableStorageReset).toBe(true);
expect(call3.flags.disableStorageReset).toBe(true);
expect(call4.flags.disableStorageReset).toBe(false);
expect(call5.flags.disableStorageReset).toBe(false);
// Check that we didn't mutate the original objects.
expect(flags).toEqual({maxWaitForLoad: 1000});
expect(flagsExplicit).toEqual({disableStorageReset: false});
expect(flowFlagsExplicit).toEqual({disableStorageReset: false});
});
it('should disable about:blank jumps by default', async () => {
@ -144,20 +175,29 @@ describe('UserFlow', () => {
const flagsExplicit = {skipAboutBlank: false};
await flow.navigate('https://example.com/3', flagsExplicit);
// Try once when we explicitly set it on the flow.
const flowFlagsExplicit = {skipAboutBlank: false};
const flow2 = new UserFlow(mockPage.asPage(), {flags: flowFlagsExplicit});
await flow2.navigate('https://example.com/5');
// Check that we have the property set.
expect(navigationModule.navigationGather).toHaveBeenCalledTimes(3);
expect(navigationModule.navigationGather).toHaveBeenCalledTimes(4);
/** @type {any[][]} */
const [[,, call1], [,, call2], [,, call3]] = navigationModule.navigationGather.mock.calls;
const [[,, call1], [,, call2], [,, call3], [,, call4]] =
navigationModule.navigationGather.mock.calls;
expect(call1).toHaveProperty('flags.skipAboutBlank');
expect(call2).toHaveProperty('flags.skipAboutBlank');
expect(call3).toHaveProperty('flags.skipAboutBlank');
expect(call4).toHaveProperty('flags.skipAboutBlank');
expect(call1.flags.skipAboutBlank).toBe(true);
expect(call2.flags.skipAboutBlank).toBe(true);
expect(call3.flags.skipAboutBlank).toBe(false);
expect(call4.flags.skipAboutBlank).toBe(false);
// Check that we didn't mutate the original objects.
expect(flags).toEqual({maxWaitForLoad: 1000});
expect(flagsExplicit).toEqual({skipAboutBlank: false});
expect(flowFlagsExplicit).toEqual({skipAboutBlank: false});
});
});
@ -235,6 +275,31 @@ describe('UserFlow', () => {
{flags: undefined},
]);
});
it('should merge flow flags with step flags', async () => {
const flowFlags = {maxWaitForLoad: 500, maxWaitForFcp: 500};
const flow = new UserFlow(mockPage.asPage(), {flags: flowFlags});
await flow.startTimespan();
await flow.endTimespan();
const flags = {maxWaitForLoad: 1000};
await flow.startTimespan(flags);
await flow.endTimespan();
expect(timespanModule.startTimespanGather).toHaveBeenCalledTimes(2);
/** @type {any[][]} */
const [[, call1], [, call2]] =
timespanModule.startTimespanGather.mock.calls;
expect(call1.flags.maxWaitForLoad).toBe(500);
expect(call1.flags.maxWaitForFcp).toBe(500);
expect(call2.flags.maxWaitForLoad).toBe(1000);
expect(call2.flags.maxWaitForFcp).toBe(500);
// Check that we didn't mutate the original objects.
expect(flowFlags).toEqual({maxWaitForLoad: 500, maxWaitForFcp: 500});
expect(flags).toEqual({maxWaitForLoad: 1000});
});
});
describe('.endTimespan()', () => {
@ -263,6 +328,29 @@ describe('UserFlow', () => {
{flags: undefined},
]);
});
it('should merge flow flags with step flags', async () => {
const flowFlags = {maxWaitForLoad: 500, maxWaitForFcp: 500};
const flow = new UserFlow(mockPage.asPage(), {flags: flowFlags});
await flow.snapshot();
const flags = {maxWaitForLoad: 1000};
await flow.snapshot(flags);
expect(snapshotModule.snapshotGather).toHaveBeenCalledTimes(2);
/** @type {any[][]} */
const [[, call1], [, call2]] =
snapshotModule.snapshotGather.mock.calls;
expect(call1.flags.maxWaitForLoad).toBe(500);
expect(call1.flags.maxWaitForFcp).toBe(500);
expect(call2.flags.maxWaitForLoad).toBe(1000);
expect(call2.flags.maxWaitForFcp).toBe(500);
// Check that we didn't mutate the original objects.
expect(flowFlags).toEqual({maxWaitForLoad: 500, maxWaitForFcp: 500});
expect(flags).toEqual({maxWaitForLoad: 1000});
});
});
describe('.getFlowResult', () => {

Просмотреть файл

@ -11,6 +11,7 @@ import {navigationGather} from './gather/navigation-runner.js';
import {Runner} from './runner.js';
import {initializeConfig} from './config/config.js';
import {getFormatted} from '../shared/localization/format.js';
import {mergeConfigFragment, deepClone} from './config/config-helpers.js';
import * as i18n from './lib/i18n/i18n.js';
/** @typedef {WeakMap<LH.UserFlow.GatherStep, LH.Gatherer.FRGatherResult['runnerOptions']>} GatherStepRunnerOptions */
@ -67,30 +68,39 @@ class UserFlow {
}
/**
* @param {LH.UserFlow.StepFlags} [flags]
* @param {LH.UserFlow.StepFlags|undefined} flags
* @return {LH.UserFlow.StepFlags|undefined}
*/
_getNextFlags(flags) {
const clonedFlowFlags = this._options?.flags && deepClone(this._options?.flags);
if (!flags) return clonedFlowFlags;
return mergeConfigFragment(clonedFlowFlags || {}, flags, true);
}
/**
* @param {LH.UserFlow.StepFlags|undefined} flags
* @return {LH.UserFlow.StepFlags}
*/
_getNextNavigationFlags(flags) {
const newStepFlags = {...flags};
const nextFlags = this._getNextFlags(flags) || {};
if (newStepFlags.skipAboutBlank === undefined) {
newStepFlags.skipAboutBlank = true;
if (nextFlags.skipAboutBlank === undefined) {
nextFlags.skipAboutBlank = true;
}
// On repeat navigations, we want to disable storage reset by default (i.e. it's not a cold load).
const isSubsequentNavigation = this._gatherSteps
.some(step => step.artifacts.GatherContext.gatherMode === 'navigation');
if (isSubsequentNavigation) {
if (newStepFlags.disableStorageReset === undefined) {
newStepFlags.disableStorageReset = true;
if (nextFlags.disableStorageReset === undefined) {
nextFlags.disableStorageReset = true;
}
}
return newStepFlags;
return nextFlags;
}
/**
*
* @param {LH.Gatherer.FRGatherResult} gatherResult
* @param {LH.UserFlow.StepFlags} [flags]
*/
@ -111,13 +121,13 @@ class UserFlow {
if (this.currentTimespan) throw new Error('Timespan already in progress');
if (this.currentNavigation) throw new Error('Navigation already in progress');
const newStepFlags = this._getNextNavigationFlags(flags);
const nextFlags = this._getNextNavigationFlags(flags);
const gatherResult = await navigationGather(this._page, requestor, {
config: this._options?.config,
flags: newStepFlags,
flags: nextFlags,
});
this._addGatherStep(gatherResult, newStepFlags);
this._addGatherStep(gatherResult, nextFlags);
}
/**
@ -179,11 +189,13 @@ class UserFlow {
if (this.currentTimespan) throw new Error('Timespan already in progress');
if (this.currentNavigation) throw new Error('Navigation already in progress');
const nextFlags = this._getNextFlags(flags);
const timespan = await startTimespanGather(this._page, {
config: this._options?.config,
flags: flags,
flags: nextFlags,
});
this.currentTimespan = {timespan, flags};
this.currentTimespan = {timespan, flags: nextFlags};
}
async endTimespan() {
@ -204,12 +216,14 @@ class UserFlow {
if (this.currentTimespan) throw new Error('Timespan already in progress');
if (this.currentNavigation) throw new Error('Navigation already in progress');
const nextFlags = this._getNextFlags(flags);
const gatherResult = await snapshotGather(this._page, {
config: this._options?.config,
flags: flags,
flags: nextFlags,
});
this._addGatherStep(gatherResult, flags);
this._addGatherStep(gatherResult, nextFlags);
}
/**

2
types/user-flow.d.ts поставляемый
Просмотреть файл

@ -9,6 +9,8 @@ declare module UserFlow {
export interface Options {
/** Config to use for each flow step. */
config?: LH.Config.Json;
/** Base flags to use for each flow step. Step specific flags will override these flags. */
flags?: LH.Flags;
/** Display name for this user flow. */
name?: string;
}