From a550a86c37c221ae59ec930ddc9492b2e05c0deb Mon Sep 17 00:00:00 2001 From: alexzurbonsen Date: Sun, 27 Oct 2024 19:48:05 +0100 Subject: [PATCH] feature(webpage-impact): add support for custom user interactions Signed-off-by: alexzurbonsen --- example-manifests/measure-webpage.yml | 3 +- src/lib/webpage-impact/README.md | 27 +++++++++++++++++ src/lib/webpage-impact/index.ts | 43 ++++++++++++++++++++++++--- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/example-manifests/measure-webpage.yml b/example-manifests/measure-webpage.yml index b5eb302..144c82f 100644 --- a/example-manifests/measure-webpage.yml +++ b/example-manifests/measure-webpage.yml @@ -13,7 +13,8 @@ initialize: path: '@tngtech/if-webpage-plugins' config: scrollToBottom: true - url: https://www.tngtech.com + url: https://www.sueddeutsche.de + customUserInteraction: '/absolute/path/to/your/script.js' 'co2js': method: Co2js path: '@tngtech/if-webpage-plugins' diff --git a/src/lib/webpage-impact/README.md b/src/lib/webpage-impact/README.md index 702f58c..7ffaa4b 100644 --- a/src/lib/webpage-impact/README.md +++ b/src/lib/webpage-impact/README.md @@ -24,6 +24,10 @@ The follwing config parameters are optional: - `accept`: string https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept - `accept-encoding`: array of allowed encodings (a single encoding can also be passed as a string) https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding +Experimental: + +- `customUserInteraction`: absolute path to a Javascript Common JS module, that exports a function with the signature `userInteraction: (page: Page) => Promise`. For an example see below. Setting `customUserInteraction` cannot be set together with `scrollToBottom`. + ### Returns - `network/data/bytes`: page weight in bytes @@ -80,3 +84,26 @@ tree: - webpage-impact inputs: ``` + +## Experimental: Custom user interactions + +Example script: + +```js +const userInteraction = async page => { + // on tngtech.com click on the "Leistungen" link + await page.locator('#menu > ul > li:nth-child(1) > a').click(); + await page.waitForNavigation(); + + // for debugging purposes + await page.screenshot({ + path: '/absolute/path/image.png', + }); +}; + +exports.userInteraction = userInteraction; +``` + +Puppeteer docs on page interactions: https://pptr.dev/guides/page-interactions + +TODO: How to deal with the reload option? diff --git a/src/lib/webpage-impact/index.ts b/src/lib/webpage-impact/index.ts index fc733b6..f12e861 100644 --- a/src/lib/webpage-impact/index.ts +++ b/src/lib/webpage-impact/index.ts @@ -24,6 +24,7 @@ type WebpageImpactOptions = { reload: boolean; cacheEnabled: boolean; scrollToBottom?: boolean; + customUserInteraction?: string; }; type ResourceBase = { @@ -36,6 +37,10 @@ type Resource = ResourceBase & {transferSize: number}; type Device = keyof typeof KnownDevices; +interface CustomUserInteraction { + userInteraction: (page: Page) => Promise; +} + const LOGGER_PREFIX = 'WebpageImpact'; const ALLOWED_ENCODINGS = [ @@ -180,6 +185,7 @@ const WebpageImpactUtils = () => { reload: false, cacheEnabled: false, scrollToBottom: config?.scrollToBottom, + customUserInteraction: config?.customUserInteraction, }); let reloadedResources: Resource[] | undefined; @@ -207,7 +213,12 @@ const WebpageImpactUtils = () => { const loadPageResources = async ( page: Page, url: string, - {reload, cacheEnabled, scrollToBottom}: WebpageImpactOptions + { + reload, + cacheEnabled, + scrollToBottom, + customUserInteraction, + }: WebpageImpactOptions ): Promise => { try { await page.setCacheEnabled(cacheEnabled); @@ -258,14 +269,19 @@ const WebpageImpactUtils = () => { if (!reload) { await page.goto(url, {waitUntil: 'networkidle0'}); + if (customUserInteraction) { + const module = await import(customUserInteraction); + if (iscustomUserInteraction(module)) { + await module.userInteraction(page); + } + } } else { + console.log('before reload'); await page.reload({waitUntil: 'networkidle0'}); } - if (scrollToBottom) { - // await page.screenshot({path: './TOP.png'}); + if (!customUserInteraction && scrollToBottom) { await page.evaluate(scrollToBottomOfPage); - // await page.screenshot({path: './BOTTOM.png'}); } await cdpSession.detach(); @@ -278,6 +294,15 @@ const WebpageImpactUtils = () => { } }; + const iscustomUserInteraction = ( + customUserInteraction: any + ): customUserInteraction is CustomUserInteraction => { + return ( + 'userInteraction' in customUserInteraction && + typeof customUserInteraction['userInteraction'] === 'function' + ); + }; + const mergeCdpData = ( cdpResponses: Record, cdpTransferSizes: Record @@ -378,6 +403,7 @@ const WebpageImpactUtils = () => { mobileDevice: z.string().optional(), emulateNetworkConditions: z.string().optional(), scrollToBottom: z.boolean().optional(), + customUserInteraction: z.string().optional(), headers: z .object({ accept: z.string().optional(), @@ -425,6 +451,15 @@ const WebpageImpactUtils = () => { PredefinedNetworkConditions ).join(', ')}.`, } + ) + .refine( + data => { + return !(data?.scrollToBottom && data?.customUserInteraction); + }, + { + message: + '`scrollToBottom: true` and `customUserInteraction` cannot be provided together.', + } ); return validate>(configSchema, config);