diff --git a/package.json b/package.json index 46e1f650d8db4..8cad59e113806 100644 --- a/package.json +++ b/package.json @@ -1807,6 +1807,7 @@ "json5": "^2.2.3", "jsondiffpatch": "0.4.1", "license-checker": "^25.0.1", + "lighthouse": "^12.4.0", "listr2": "^8.2.5", "lmdb": "^2.9.2", "marge": "^1.0.1", diff --git a/src/platform/packages/shared/kbn-scout/index.ts b/src/platform/packages/shared/kbn-scout/index.ts index 019fc3832dd7a..47239a10c97b2 100644 --- a/src/platform/packages/shared/kbn-scout/index.ts +++ b/src/platform/packages/shared/kbn-scout/index.ts @@ -12,6 +12,7 @@ export { expect, test, spaceTest, + lighthouseTest, globalSetupHook, tags, createPlaywrightConfig, @@ -40,6 +41,6 @@ export type { } from './src/types'; // re-export from Playwright -export type { Locator } from 'playwright/test'; +export type { Locator, CDPSession } from 'playwright/test'; export { measurePerformance, measurePerformanceAsync } from './src/common'; diff --git a/src/platform/packages/shared/kbn-scout/src/config/utils/save_scout_test_config.test.ts b/src/platform/packages/shared/kbn-scout/src/config/utils/save_scout_test_config.test.ts index 770145c8fdf35..2de42d00d23ae 100644 --- a/src/platform/packages/shared/kbn-scout/src/config/utils/save_scout_test_config.test.ts +++ b/src/platform/packages/shared/kbn-scout/src/config/utils/save_scout_test_config.test.ts @@ -11,6 +11,7 @@ import path from 'path'; import Fs from 'fs'; import { ToolingLog } from '@kbn/tooling-log'; import { saveScoutTestConfigOnDisk } from './save_scout_test_config'; +import { ServerlessProjectType } from '@kbn/es'; const MOCKED_SCOUT_SERVERS_ROOT = '/mock/repo/root/scout/servers'; @@ -34,6 +35,7 @@ const testServersConfig = { password: 'changeme', }, serverless: true, + projectType: 'oblt' as ServerlessProjectType, isCloud: true, license: 'trial', cloudUsersFilePath: '/path/to/users', diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/config/create_config.test.ts b/src/platform/packages/shared/kbn-scout/src/playwright/config/create_config.test.ts index 7fd7bfe6f14d7..40e811bb2acd9 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/config/create_config.test.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/config/create_config.test.ts @@ -49,6 +49,8 @@ describe('createPlaywrightConfig', () => { expect(config.use).toEqual({ serversConfigDir: SCOUT_SERVERS_ROOT, [VALID_CONFIG_MARKER]: true, + actionTimeout: 10000, + navigationTimeout: 20000, screenshot: 'only-on-failure', testIdAttribute: 'data-test-subj', trace: 'on-first-retry', diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/config/create_config.ts b/src/platform/packages/shared/kbn-scout/src/playwright/config/create_config.ts index bb83c16dbf3e7..c787696ad6e3d 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/config/create_config.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/config/create_config.ts @@ -72,6 +72,8 @@ export function createPlaywrightConfig(options: ScoutPlaywrightOptions): Playwri ], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { + actionTimeout: 10000, // Shorten timeout for actions like `click()` + navigationTimeout: 20000, // Shorter timeout for page navigations // 'configName' is not defined by default to enforce using '--project' flag when running the tests testIdAttribute: 'data-test-subj', serversConfigDir: SCOUT_SERVERS_ROOT, diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/single_thread_fixtures.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/single_thread_fixtures.ts index fccf1fe5d9e4d..41683ee0c77ae 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/single_thread_fixtures.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/single_thread_fixtures.ts @@ -15,6 +15,7 @@ import { esArchiverFixture, uiSettingsFixture, synthtraceFixture, + lighthouseFixture, } from './worker'; import type { EsArchiverFixture, @@ -31,9 +32,12 @@ import { browserAuthFixture, pageObjectsFixture, validateTagsFixture, + persistentContext, + perfTrackerFixture, } from './test'; -import type { BrowserAuthFixture, ScoutPage, PageObjects } from './test'; +import type { BrowserAuthFixture, ScoutPage, PageObjects, PerfTrackerFixture } from './test'; export type { ScoutPage, PageObjects } from './test'; +export type { LighthouseAuditOptions } from './worker'; export const scoutFixtures = mergeTests( // worker scope fixtures @@ -47,13 +51,16 @@ export const scoutFixtures = mergeTests( browserAuthFixture, scoutPageFixture, pageObjectsFixture, - validateTagsFixture + validateTagsFixture, + // performance fixtures + perfTrackerFixture ); export interface ScoutTestFixtures { browserAuth: BrowserAuthFixture; page: ScoutPage; pageObjects: PageObjects; + perfTracker: PerfTrackerFixture; } export interface ScoutWorkerFixtures extends ApiFixtures { @@ -68,3 +75,5 @@ export interface ScoutWorkerFixtures extends ApiFixtures { infraSynthtraceEsClient: SynthtraceFixture['infraSynthtraceEsClient']; otelSynthtraceEsClient: SynthtraceFixture['otelSynthtraceEsClient']; } + +export const lighthouseFixtures = mergeTests(scoutFixtures, persistentContext, lighthouseFixture); diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/context/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/context/index.ts new file mode 100644 index 0000000000000..3c989f41c7549 --- /dev/null +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/context/index.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import * as os from 'os'; +import getPort from 'get-port'; +import { BrowserContext, chromium } from 'playwright/test'; +import { coreWorkerFixtures } from '../../worker'; + +/** + * Launches browser with persistent context across multiple tests / browser windows in the same test. + * E.g. Lighthouse launches a new browser window and the authentication state + * is not persisted between windows by default, so we can't do page audit without persistent context. + */ +export const persistentContext = coreWorkerFixtures.extend< + { + context: BrowserContext; + }, + { debuggingPort: number } +>({ + debuggingPort: [ + async ({ log }, use) => { + const port = await getPort({ port: [9222, 9223, 9224] }); + log.serviceLoaded(`remote debugging port [${port}]`); + use(port); + }, + { scope: 'worker' }, + ], + context: [ + async ({ log, debuggingPort }, use) => { + const userDataDir = os.tmpdir(); + const context = await chromium.launchPersistentContext(userDataDir, { + args: [`--remote-debugging-port=${debuggingPort}`], + }); + log.serviceLoaded(`persistentContext on port [${debuggingPort}]`); + await use(context); + await context.close(); + }, + { scope: 'test' }, + ], +}); diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/index.ts index f1381412b93e2..ac81eab8fc381 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/index.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/index.ts @@ -14,3 +14,6 @@ export type { ScoutPage } from './scout_page'; export { validateTagsFixture } from './validate_tags'; export { pageObjectsFixture, pageObjectsParallelFixture } from './page_objects'; export type { PageObjects } from './page_objects'; +export { persistentContext } from './context'; +export { perfTrackerFixture } from './performance'; +export type { PerfTrackerFixture } from './performance'; diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/page_objects/parallel.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/page_objects/parallel.ts index 92ae09826667e..450bb4f98d3a7 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/page_objects/parallel.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/page_objects/parallel.ts @@ -8,7 +8,7 @@ */ import { PageObjects, createCorePageObjects } from '../../../page_objects'; -import { ScoutSpaceParallelFixture } from '../../worker'; +import { ScoutSpaceParallelFixture, ScoutTestConfig } from '../../worker'; import { scoutPageParallelFixture } from '../scout_page'; /** @@ -23,10 +23,10 @@ export const pageObjectsParallelFixture = scoutPageParallelFixture.extend< { pageObjects: PageObjects; }, - { scoutSpace: ScoutSpaceParallelFixture } + { scoutSpace: ScoutSpaceParallelFixture; config: ScoutTestConfig } >({ - pageObjects: async ({ page, log }, use) => { - const corePageObjects = createCorePageObjects(page); + pageObjects: async ({ page, config, log }, use) => { + const corePageObjects = createCorePageObjects({ page, config, log }); log.serviceLoaded(`pageObjects`); await use(corePageObjects); }, diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/page_objects/single_thread.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/page_objects/single_thread.ts index b1f39c9f2336a..9682be249e23d 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/page_objects/single_thread.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/page_objects/single_thread.ts @@ -8,6 +8,7 @@ */ import { PageObjects, createCorePageObjects } from '../../../page_objects'; +import { ScoutTestConfig } from '../../worker'; import { scoutPageFixture } from '../scout_page'; /** @@ -18,11 +19,14 @@ import { scoutPageFixture } from '../scout_page'; * * Note: Page Objects are lazily instantiated on first access. */ -export const pageObjectsFixture = scoutPageFixture.extend<{ - pageObjects: PageObjects; -}>({ - pageObjects: async ({ page, log }, use) => { - const corePageObjects = createCorePageObjects(page); +export const pageObjectsFixture = scoutPageFixture.extend< + { + pageObjects: PageObjects; + }, + { config: ScoutTestConfig } +>({ + pageObjects: async ({ page, log, config }, use) => { + const corePageObjects = createCorePageObjects({ page, config, log }); log.serviceLoaded('pageObjects'); await use(corePageObjects); }, diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/README.md b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/README.md new file mode 100644 index 0000000000000..9852e03c64a79 --- /dev/null +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/README.md @@ -0,0 +1,126 @@ +## Performance Tracker Fixture + +### Overview + +`perfTrackerFixture` is a Playwright fixture designed to analyze JavaScript bundle performance and page-level performance metrics in Kibana by leveraging Chrome DevTools Protocol (CDP). It intercepts network requests, filters static bundles, and computes bundle size statistics per page load. Additionally, it collects CDP Performance Domain Metrics, allowing in-depth analysis of rendering and script execution times. + +### Key Features + +- Uses CDP session to monitor network requests in Playwright tests. +- Exposes `waitForJsLoad` to ensure all incoming bundle requests are fully resolved before proceeding. +- Exposes `captureBundleResponses` to start tracking network requests and collect JavaScript bundle responses. +- Exposes `collectJsBundleStats` to aggregate all captured responses by plugin, making validation easier in tests. +- Automatically attaches collected JS bundle stats as a JSON artifact in test reports, making them available in the `Playwright HTML report`. +- Captures `CDP Performance Domain Metrics`, including: + - JavaScript Heap Usage (jsHeapUsedSize, jsHeapTotalSize) + - CPU Execution Time (cpuTime) + - Script Execution Time (scriptTime) + - Layout & Rendering Performance (layoutTime, layoutCount, styleRecalcCount) + - Frames Per Second (FPS) (fps) + - DOM Complexity Metrics (nodesCount, documentsCount) + + +### Usage: capturing JS bundles on page + +```ts +test.describe( + 'Discover App - Performance Metrics & Bundle Analysis', + { tag: [...tags.DEPLOYMENT_AGNOSTIC, ...tags.PERFORMANCE] }, + () => { + let cdp: CDPSession; + + test.beforeEach(async ({ browserAuth, page, context, perfTracker }) => { + await browserAuth.loginAsAdmin(); + cdp = await context.newCDPSession(page); + await cdp.send('Network.enable'); + // load the starting page, e.g. '/app/home' + await perfTracker.waitForJsLoad(cdp); // Ensure JS bundles are fully loaded + }); + + test('collects and validates JS Bundles loaded on page', async ({ + page, + pageObjects, + perfTracker, + }) => { + perfTracker.captureBundleResponses(cdp); // Start tracking + + // Navigate to Discover app + await pageObjects.collapsibleNav.clickItem('Discover'); + const currentUrl = page.url(); + expect(currentUrl).toContain('app/discover#/'); + + // Ensure all JS bundles are loaded + await perfTracker.waitForJsLoad(cdp); + + // Collect and validate stats + const stats = perfTracker.collectJsBundleStats(currentUrl); + expect( + stats.totalSize, + `Total bundles size loaded on page should not exceed 3.0 MB` + ).toBeLessThan(3 * 1024 * 1024); + expect(stats.bundleCount, { + message: `Total bundle chunks count loaded on page should not exceed 100`, + }).toBeLessThan(100); + expect( + stats.plugins.map((p) => p.name), + { message: 'Unexpected plugins were loaded on page' } + ).toStrictEqual([ + 'aiops', + 'discover', + 'eventAnnotation', + 'expressionXY', + 'kbn-ui-shared-deps-npm', + 'lens', + 'maps', + 'unifiedHistogram', + 'unifiedSearch', + ]); + // Validate individual plugin bundle sizes + expect(stats.plugins.find((p) => p.name === 'discover')?.totalSize, { + message: `Total 'discover' bundles size should not exceed 625 KB`, + }).toBeLessThan(625 * 1024); + }); +``` + +### Uage: collecting CDP Performance metrics + +```ts +test.describe( + 'Discover App - Performance Metrics & Bundle Analysis', + { tag: [...tags.DEPLOYMENT_AGNOSTIC, ...tags.PERFORMANCE] }, + () => { + let cdp: CDPSession; + + test.beforeEach(async ({ browserAuth, page, context, perfTracker }) => { + await browserAuth.loginAsAdmin(); + cdp = await context.newCDPSession(page); + // load the starting page, e.g. '/app/home' and wait for loading to finish + }); + + test('measures Performance Metrics before and after Discover load', async ({ + page, + pageObjects, + perfTracker, + }) => { + const beforeMetrics = await perfTracker.capturePagePerformanceMetrics(cdp); + + // Navigate to Discover app + await pageObjects.collapsibleNav.clickItem('Discover'); + await page.waitForLoadingIndicatorHidden(); + const currentUrl = page.url(); + expect(currentUrl).toContain('app/discover#/'); + + await pageObjects.discover.waitForHistogramRendered(); + + const afterMetrics = await perfTracker.capturePagePerformanceMetrics(cdp); + const perfStats = perfTracker.collectPagePerformanceStats( + currentUrl, + beforeMetrics, + afterMetrics + ); + + expect(perfStats.cpuTime.diff).toBeLessThan(1.5); // CPU time (seconds) usage during page navigation + expect(perfStats.scriptTime.diff).toBeLessThan(0.4); // Additional time (seconds) spent executing JS scripts + expect(perfStats.layoutTime.diff).toBeLessThan(0.06); // Total layout computation time (seconds) + }); +``` diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/index.ts new file mode 100644 index 0000000000000..81572c1ed47eb --- /dev/null +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { coreWorkerFixtures } from '../../worker'; +import { PerformanceTracker } from './performance_tracker'; + +export const perfTrackerFixture = coreWorkerFixtures.extend<{ perfTracker: PerformanceTracker }>({ + perfTracker: [ + async ({ log }, use, testInfo) => { + log.serviceLoaded('perfTracker'); + + const tracker = new PerformanceTracker(testInfo); + await use(tracker); + }, + { scope: 'test' }, + ], +}); + +export type PerfTrackerFixture = ReturnType; diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/performance_tracker.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/performance_tracker.ts new file mode 100644 index 0000000000000..5dbf69230e66f --- /dev/null +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/performance_tracker.ts @@ -0,0 +1,184 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { CDPSession, TestInfo } from '@playwright/test'; +import { BundleInfo, PageInfo, PerformanceMetrics, PluginInfo } from './types'; + +export class PerformanceTracker { + private bundleResponses = new Map(); + + constructor(private testInfo: TestInfo) {} + + private getRequestData(requestId: string): BundleInfo { + if (!this.bundleResponses.has(requestId)) { + this.bundleResponses.set(requestId, { + url: '', + name: '', + plugin: '', + transferredSize: 0, + headersSize: 0, + }); + } + return this.bundleResponses.get(requestId)!; + } + + captureBundleResponses(cdp: CDPSession) { + cdp.on('Network.responseReceived', (event) => { + if (event.response.url.endsWith('.js') && event.response.url.includes('bundles')) { + const requestData = this.getRequestData(event.requestId); + requestData.url = event.response.url; + requestData.name = event.response.url.split('/').pop()!; + requestData.plugin = requestData.name.split('.')[0]; + requestData.headersSize = event.response.headersText?.length ?? 0; + } + }); + + cdp.on('Network.loadingFinished', (event) => { + if (this.bundleResponses.has(event.requestId)) { + this.bundleResponses.get(event.requestId)!.transferredSize = event.encodedDataLength; + } + }); + } + + async waitForJsLoad(cdp: CDPSession, timeout: number = 2000): Promise { + return new Promise((resolve) => { + let lastRequestTime = Date.now(); + let activeRequests = 0; + + // Track new JS requests + cdp.on('Network.requestWillBeSent', (event) => { + if (event.request.url.endsWith('.js') && event.request.url.includes('bundles')) { + activeRequests++; + lastRequestTime = Date.now(); + } + }); + + // Track when JS requests are completed + cdp.on('Network.loadingFinished', () => { + activeRequests = Math.max(0, activeRequests - 1); + }); + + // Check every 500ms if no new requests arrived + const interval = setInterval(() => { + if (Date.now() - lastRequestTime > timeout && activeRequests === 0) { + clearInterval(interval); + resolve(); + } + }, 500); + }); + } + + computeBundleStats(bundleResponses: Map): PageInfo { + const bundles = Array.from(bundleResponses.values()); + const pluginAggregates = new Map(); + + let totalSize = 0; + + for (const { plugin, transferredSize, name } of bundles) { + totalSize += transferredSize; + + if (!pluginAggregates.has(plugin)) { + pluginAggregates.set(plugin, { count: 0, totalSize: 0, bundles: [] }); + } + + const pluginInfo = pluginAggregates.get(plugin)!; + pluginInfo.count += 1; + pluginInfo.totalSize += transferredSize; + pluginInfo.bundles.push({ name, transferredSize }); + } + + // Sort plugins alphabetically and bundle names inside them + const plugins = Array.from(pluginAggregates.entries()) + .map(([pluginName, pluginInfo]) => ({ + name: pluginName, + bundlesCount: pluginInfo.count, + totalSize: pluginInfo.totalSize, + bundles: pluginInfo.bundles.sort((a, b) => a.name.localeCompare(b.name)), + })) + .sort((a, b) => a.name.localeCompare(b.name)); + + return { + bundleCount: bundles.length, + totalSize, + pluginCount: pluginAggregates.size, + plugins, + }; + } + + collectJsBundleStats(url: string) { + const stats = this.computeBundleStats(this.bundleResponses); + + this.testInfo.attach('page-bundles-report', { + body: JSON.stringify({ url, ...stats }, null, 2), + contentType: 'application/json', + }); + + return stats; + } + + // CDP Performance Domain Metrics + + async capturePagePerformanceMetrics(cdp: CDPSession) { + await cdp.send('Performance.enable'); + const { metrics } = await cdp.send('Performance.getMetrics'); + + return { + jsHeapUsedSize: metrics.find((m) => m.name === 'JSHeapUsedSize')?.value, + jsHeapTotalSize: metrics.find((m) => m.name === 'JSHeapTotalSize')?.value, + cpuTime: metrics.find((m) => m.name === 'TaskDuration')?.value, + scriptTime: metrics.find((m) => m.name === 'ScriptDuration')?.value, + layoutTime: metrics.find((m) => m.name === 'LayoutDuration')?.value, + fps: metrics.find((m) => m.name === 'FramesPerSecond')?.value, + nodesCount: metrics.find((m) => m.name === 'Nodes')?.value, + documentsCount: metrics.find((m) => m.name === 'Documents')?.value, + layoutCount: metrics.find((m) => m.name === 'LayoutCount')?.value, + styleRecalcCount: metrics.find((m) => m.name === 'RecalcStyleCount')?.value, + }; + } + + private comparePerformanceMetrics(before: PerformanceMetrics, after: PerformanceMetrics) { + const metrics: Record< + string, + { before: number; after: number; diff: number; percentage: string } + > = {}; + + for (const key of Object.keys(after)) { + const metricKey = key as keyof PerformanceMetrics; + if (after[metricKey] !== undefined && before[metricKey] !== undefined) { + const diff = after[metricKey]! - before[metricKey]!; + const percentage = + before[metricKey] !== 0 ? ((diff / before[metricKey]!) * 100).toFixed(2) + '%' : 'N/A'; + + metrics[metricKey] = { + before: before[metricKey]!, + after: after[metricKey]!, + diff, + percentage, + }; + } + } + + return metrics; + } + + collectPagePerformanceStats = ( + url: string, + before: PerformanceMetrics, + after: PerformanceMetrics + ) => { + const stats = this.comparePerformanceMetrics(before, after); + + this.testInfo.attach('perf-metrics-report', { + body: JSON.stringify({ url, stats }, null, 2), + contentType: 'application/json', + }); + + return stats; + }; +} diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/types.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/types.ts new file mode 100644 index 0000000000000..71b931214baef --- /dev/null +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/performance/types.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export interface BundleInfo { + url: string; + name: string; + plugin: string; + transferredSize: number; + headersSize: number; +} + +export interface PluginInfo { + count: number; + totalSize: number; + bundles: Array<{ name: string; transferredSize: number }>; +} + +export interface PageInfo { + bundleCount: number; + totalSize: number; + pluginCount: number; + plugins: Array<{ + name: string; + bundlesCount: number; + totalSize: number; + bundles: Array<{ name: string; transferredSize: number }>; + }>; +} + +export interface PerformanceMetrics { + jsHeapUsedSize?: number; + jsHeapTotalSize?: number; + cpuTime?: number; + scriptTime?: number; + layoutTime?: number; + fps?: number; + nodesCount?: number; + documentsCount?: number; + layoutCount?: number; + styleRecalcCount?: number; +} diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/scout_page/single_thread.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/scout_page/single_thread.ts index e76d73f66e9cd..ed0bbcb7a3611 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/scout_page/single_thread.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/scout_page/single_thread.ts @@ -7,10 +7,10 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { Page } from '@playwright/test'; +import { Page, test as base } from '@playwright/test'; import { subj } from '@kbn/test-subj-selector'; import { PathOptions } from '../../../../common/services/kibana_url'; -import { KibanaUrl, ScoutLogger, coreWorkerFixtures } from '../../worker'; +import { KibanaUrl, ScoutLogger } from '../../worker'; import { ScoutPage } from '.'; /** @@ -120,7 +120,7 @@ export function extendPlaywrightPage({ * await page.gotoApp('discover); * ``` */ -export const scoutPageFixture = coreWorkerFixtures.extend< +export const scoutPageFixture = base.extend< { page: ScoutPage; log: ScoutLogger }, { kbnUrl: KibanaUrl } >({ diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/validate_tags/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/validate_tags/index.ts index c792f905ebe9f..d46af11ccb3b3 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/validate_tags/index.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/test/validate_tags/index.ts @@ -10,7 +10,7 @@ import { test as base } from '@playwright/test'; import { tags } from '../../../tags'; -const supportedTags = tags.DEPLOYMENT_AGNOSTIC; +const supportedTags = [...tags.DEPLOYMENT_AGNOSTIC, ...tags.PERFORMANCE]; export const validateTagsFixture = base.extend<{ validateTags: void }>({ validateTags: [ diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/index.ts index ec4337117b437..c240ebff45e15 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/index.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/index.ts @@ -31,3 +31,6 @@ export type { ApiFixtures, ApiParallelWorkerFixtures } from './apis'; export { synthtraceFixture } from './synthtrace'; export type { SynthtraceFixture } from './synthtrace'; + +export { lighthouseFixture } from './lighthouse'; +export type { LighthouseFixture, LighthouseAuditOptions } from './lighthouse'; diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/lighthouse/README.md b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/lighthouse/README.md new file mode 100644 index 0000000000000..1ec3c46315e39 --- /dev/null +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/lighthouse/README.md @@ -0,0 +1,44 @@ +## Lighthouse Fixture + +### Overview + +`lighthouseFixture` integrates Lighthouse with Playwright, allowing automated performance and accessibility audits for Kibana and other web applications. It leverages persistent browser sessions to ensure authenticated audits and automatically attaches reports as artifacts in Playwright test reports. + +### How it works + +- Dynamically imports Lighthouse (ES module) +- Uses `persistentContext` fixture to launch a new browser context on the specified debugging port, preserving authentication state across sessions. +- Loads the provided Kibana URL inside this persistent context and runs the Lighthouse audit, using the same debug port and ensuring the session remains active (otherwise Lighthouse will be redirected to login page) +- Automatically attaches Lighthouse report as html artifact in test reports, making them available in the `Playwright HTML report`. + +### Usage: running report on Kibana page + +```ts +import { lighthouseTest, tags } from '@kbn/scout'; + +lighthouseTest.describe( + 'Discover App - Lighthouse Performance Audit', + { tag: [...tags.DEPLOYMENT_AGNOSTIC, ...tags.PERFORMANCE] }, + () => { + lighthouseTest.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + // loading the data + }); + + lighthouseTest.afterAll(async ({ kbnClient, uiSettings }) => { + // unloading the data + }); + + lighthouseTest( + 'runs audit on Discover Page', + async ({ browserAuth, lighthouse, page, pageObjects }) => { + await browserAuth.loginAsAdmin(); + await pageObjects.discover.goto(); + await pageObjects.discover.waitForHistogramRendered(); + const currentUrl = page.url(); + + // Run the Lighthouse audit on the current page and attach the report + await lighthouse.runAudit(currentUrl); + } + ); + } +``` diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/lighthouse/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/lighthouse/index.ts new file mode 100644 index 0000000000000..873036a2cafde --- /dev/null +++ b/src/platform/packages/shared/kbn-scout/src/playwright/fixtures/worker/lighthouse/index.ts @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { RunnerResult } from 'lighthouse'; +import { coreWorkerFixtures } from '../core_fixtures'; + +type OutputMode = 'html' | 'json' | 'csv'; +export interface LighthouseAuditOptions { + maxWaitForLoad?: number; + screenEmulation?: { + width: number; + height: number; + }; +} + +export interface LighthouseFixture { + runAudit: (url: string, options?: LighthouseAuditOptions) => Promise; +} + +/** + * Lighthouse fixture https://developer.chrome.com/docs/lighthouse/overview/ + * It allows to run Lighthouse audits on a given URL + */ +export const lighthouseFixture = coreWorkerFixtures.extend< + { lighthouse: LighthouseFixture }, + { debuggingPort: number } +>({ + lighthouse: [ + async ({ log, debuggingPort }, use, testInfo) => { + // Import Lighthouse dynamically (ES module) + const lighthouse = (await import('lighthouse')).default; + + if (!debuggingPort) { + throw new Error( + `Remote debugging port is not set: Check 'use.launchOptions.args' in Playwright configuration` + ); + } + + const DEFAULT_AUDIT_OPTIONS: Partial = { + maxWaitForLoad: 30000, + output: ['html'], + formFactor: 'desktop', + screenEmulation: { + width: 1920, + height: 1080, + mobile: false, + deviceScaleFactor: 1, + disabled: false, + }, + }; + + const runAudit = async (url: string, auditOptions?: LighthouseAuditOptions) => { + const options: import('lighthouse').Flags = { + port: debuggingPort, + maxWaitForLoad: auditOptions?.maxWaitForLoad ?? DEFAULT_AUDIT_OPTIONS.maxWaitForLoad, + output: DEFAULT_AUDIT_OPTIONS.output as OutputMode[], + formFactor: DEFAULT_AUDIT_OPTIONS.formFactor as 'desktop' | 'mobile', + screenEmulation: { + width: + auditOptions?.screenEmulation?.width ?? DEFAULT_AUDIT_OPTIONS.screenEmulation!.width, + height: + auditOptions?.screenEmulation?.height ?? + DEFAULT_AUDIT_OPTIONS.screenEmulation!.height, + mobile: DEFAULT_AUDIT_OPTIONS.screenEmulation!.mobile, + deviceScaleFactor: DEFAULT_AUDIT_OPTIONS.screenEmulation!.deviceScaleFactor, + disabled: DEFAULT_AUDIT_OPTIONS.screenEmulation!.disabled, + }, + }; + + const auditResult = await lighthouse(url, options); + + if (!auditResult?.lhr?.categories?.performance?.score) { + throw new Error('Lighthouse audit failed: No performance score found'); + } + + const perfScore = auditResult.lhr.categories.performance.score; + log.info(`✅ Lighthouse audit completed with performance score: ${perfScore}`); + + testInfo.attach('lighthouse-report', { + body: auditResult.report?.[0] ?? 'No report generated', + contentType: 'text/html', + }); + + return auditResult; + }; + + use({ runAudit }); + }, + { scope: 'test' }, + ], +}); diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/index.ts index 579596822688c..92212592740cb 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/index.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/index.ts @@ -7,11 +7,13 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { scoutFixtures, scoutParallelFixtures, globalSetup } from './fixtures'; +import { scoutFixtures, scoutParallelFixtures, lighthouseFixtures, globalSetup } from './fixtures'; // Scout core fixtures: worker & test scope export const test = scoutFixtures; +export const lighthouseTest = lighthouseFixtures; + // Scout core 'space aware' fixtures: worker & test scope export const spaceTest = scoutParallelFixtures; diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/page_objects/collapsible_nav.ts b/src/platform/packages/shared/kbn-scout/src/playwright/page_objects/collapsible_nav.ts new file mode 100644 index 0000000000000..2678211118700 --- /dev/null +++ b/src/platform/packages/shared/kbn-scout/src/playwright/page_objects/collapsible_nav.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { Locator } from 'playwright/test'; +import { ScoutPage } from '..'; +import { ScoutTestConfig } from '../../types'; + +export class CollapsibleNav { + private toggleNavButton: Locator; + + constructor(private readonly page: ScoutPage, private readonly config: ScoutTestConfig) { + this.toggleNavButton = this.page.testSubj.locator( + this.config.serverless ? 'euiCollapsibleNavButton' : 'toggleNavButton' + ); + } + + async expandNav() { + if (await this.toggleNavButton.isVisible()) { + const isExpanded = await this.toggleNavButton.getAttribute('aria-expanded'); + if (isExpanded === 'false') { + await this.toggleNavButton.click(); + } + } + } + + async clickItem(itemName: 'Discover' | 'Dashboards' | 'Maps' | 'Machine Learning') { + await this.expandNav(); + return this.config.serverless + ? this.page.testSubj.click(`*nav-item-id-${itemName.toLocaleLowerCase()}`) + : this.page.click(`[title="${itemName}"]`); + } +} diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/page_objects/dashboard_app.ts b/src/platform/packages/shared/kbn-scout/src/playwright/page_objects/dashboard_app.ts index bcc587ecee9a1..6537c5ad4fc9e 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/page_objects/dashboard_app.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/page_objects/dashboard_app.ts @@ -25,6 +25,10 @@ export class DashboardApp { await this.page.gotoApp('dashboards'); } + async waitForListingTableToLoad() { + return this.page.testSubj.waitForSelector('table-is-ready', { state: 'visible' }); + } + async openNewDashboard() { await this.page.testSubj.click('newItemButton'); await this.page.testSubj.waitForSelector('emptyDashboardWidget', { state: 'visible' }); @@ -92,4 +96,24 @@ export class DashboardApp { state: 'hidden', }); } + + async waitForPanelsToLoad( + expectedCount: number, + options: { timeout: number; selector: string } = { + timeout: 20000, + selector: '[data-test-subj="embeddablePanel"][data-render-complete="true"]', + } + ) { + const startTime = Date.now(); + + while (Date.now() - startTime < options.timeout) { + const count = await this.page.locator(options.selector).count(); + if (count === expectedCount) return; + // Short polling interval + + await this.page.waitForTimeout(100); + } + + throw new Error(`Timeout waiting for ${expectedCount} elements matching ${options.selector}`); + } } diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/page_objects/index.ts b/src/platform/packages/shared/kbn-scout/src/playwright/page_objects/index.ts index 59e7f19c96790..5131064464dba 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/page_objects/index.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/page_objects/index.ts @@ -8,6 +8,9 @@ */ import { ScoutPage } from '..'; +import { ScoutLogger } from '../../common'; +import { ScoutTestConfig } from '../../types'; +import { CollapsibleNav } from './collapsible_nav'; import { DashboardApp } from './dashboard_app'; import { DatePicker } from './date_picker'; import { DiscoverApp } from './discover_app'; @@ -16,6 +19,12 @@ import { MapsPage } from './maps_page'; import { RenderablePage } from './renderable_page'; import { createLazyPageObject } from './utils'; +export interface PageObjectsFixtures { + page: ScoutPage; + config: ScoutTestConfig; + log: ScoutLogger; +} + export interface PageObjects { datePicker: DatePicker; discover: DiscoverApp; @@ -23,6 +32,7 @@ export interface PageObjects { filterBar: FilterBar; maps: MapsPage; renderable: RenderablePage; + collapsibleNav: CollapsibleNav; } /** @@ -31,14 +41,15 @@ export interface PageObjects { * @param page - `ScoutPage` instance used for initializing page objects. * @returns An object containing lazy-loaded core page objects. */ -export function createCorePageObjects(page: ScoutPage): PageObjects { +export function createCorePageObjects(fixtures: PageObjectsFixtures): PageObjects { return { - datePicker: createLazyPageObject(DatePicker, page), - dashboard: createLazyPageObject(DashboardApp, page), - discover: createLazyPageObject(DiscoverApp, page), - filterBar: createLazyPageObject(FilterBar, page), - maps: createLazyPageObject(MapsPage, page), - renderable: createLazyPageObject(RenderablePage, page), + datePicker: createLazyPageObject(DatePicker, fixtures.page), + dashboard: createLazyPageObject(DashboardApp, fixtures.page), + discover: createLazyPageObject(DiscoverApp, fixtures.page), + filterBar: createLazyPageObject(FilterBar, fixtures.page), + maps: createLazyPageObject(MapsPage, fixtures.page), + renderable: createLazyPageObject(RenderablePage, fixtures.page), + collapsibleNav: createLazyPageObject(CollapsibleNav, fixtures.page, fixtures.config), // Add new page objects here }; } diff --git a/src/platform/packages/shared/kbn-scout/src/playwright/tags.ts b/src/platform/packages/shared/kbn-scout/src/playwright/tags.ts index a022b6afd3430..6e24d6380b773 100644 --- a/src/platform/packages/shared/kbn-scout/src/playwright/tags.ts +++ b/src/platform/packages/shared/kbn-scout/src/playwright/tags.ts @@ -10,11 +10,13 @@ const SERVERLESS_ONLY = ['@svlSecurity', '@svlOblt', '@svlSearch']; const ESS_ONLY = ['@ess']; const DEPLOYMENT_AGNOSTIC = SERVERLESS_ONLY.concat(ESS_ONLY); +const PERFORMANCE = ['@perf']; export const tags = { ESS_ONLY, SERVERLESS_ONLY, DEPLOYMENT_AGNOSTIC, + PERFORMANCE, }; export const tagsByMode = { diff --git a/x-pack/platform/plugins/private/discover_enhanced/ui_tests/tests/discover_cdp_perf.spec.ts b/x-pack/platform/plugins/private/discover_enhanced/ui_tests/tests/discover_cdp_perf.spec.ts new file mode 100644 index 0000000000000..003c12a760cbf --- /dev/null +++ b/x-pack/platform/plugins/private/discover_enhanced/ui_tests/tests/discover_cdp_perf.spec.ts @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { test, tags, expect, CDPSession } from '@kbn/scout'; +import { testData } from '../fixtures'; + +test.describe( + 'Discover App - Performance Metrics & Bundle Analysis', + { tag: [...tags.DEPLOYMENT_AGNOSTIC, ...tags.PERFORMANCE] }, + () => { + let cdp: CDPSession; + + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.LOGSTASH); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.DASHBOARD_DRILLDOWNS); + await uiSettings.set({ + defaultIndex: testData.DATA_VIEW_ID.LOGSTASH, + 'timepicker:timeDefaults': `{ "from": "${testData.LOGSTASH_DEFAULT_START_TIME}", "to": "${testData.LOGSTASH_DEFAULT_END_TIME}"}`, + }); + }); + + test.beforeEach(async ({ browserAuth, page, context, perfTracker }) => { + await browserAuth.loginAsAdmin(); + cdp = await context.newCDPSession(page); + await cdp.send('Network.enable'); + await page.gotoApp('home'); + await page.waitForLoadingIndicatorHidden(); + await perfTracker.waitForJsLoad(cdp); // Ensure JS bundles are fully loaded + }); + + test.afterAll(async ({ kbnClient, uiSettings }) => { + await uiSettings.unset('defaultIndex', 'timepicker:timeDefaults'); + await kbnClient.savedObjects.cleanStandardList(); + }); + + test('collects and validates JS Bundles loaded on page', async ({ + page, + pageObjects, + perfTracker, + }) => { + perfTracker.captureBundleResponses(cdp); // Start tracking + + // Navigate to Discover app + await pageObjects.collapsibleNav.clickItem('Discover'); + const currentUrl = page.url(); + expect(currentUrl).toContain('app/discover#/'); + + // Ensure all JS bundles are loaded + await perfTracker.waitForJsLoad(cdp); + + // Collect and validate stats + const stats = perfTracker.collectJsBundleStats(currentUrl); + expect( + stats.totalSize, + `Total bundles size loaded on page should not exceed 3.1 MB` + ).toBeLessThan(3.1 * 1024 * 1024); + expect( + stats.bundleCount, + `Total bundle chunks count loaded on page should not exceed 100` + ).toBeLessThan(100); + expect( + stats.plugins.map((p) => p.name), + 'Unexpected plugins were loaded on page' + ).toStrictEqual([ + 'aiops', + 'data', + 'discover', + 'eventAnnotation', + 'expressionXY', + 'kbn-ui-shared-deps-npm', + 'lens', + 'maps', + 'unifiedHistogram', + 'unifiedSearch', + ]); + // Validate individual plugin bundle sizes + expect( + stats.plugins.find((p) => p.name === 'discover')?.totalSize, + `Total 'discover' bundles size should not exceed 650 KB` + ).toBeLessThan(650 * 1024); + expect( + stats.plugins.find((p) => p.name === 'unifiedHistogram')?.totalSize, + `Total 'unifiedHistogram' bundles size should not exceed 150 KB` + ).toBeLessThan(150 * 1024); + expect( + stats.plugins.find((p) => p.name === 'unifiedSearch')?.totalSize, + `Total 'unifiedSearch' bundles size should not exceed 450 KB` + ).toBeLessThan(450 * 1024); + }); + + test('measures Performance Metrics before and after Discover load', async ({ + page, + pageObjects, + perfTracker, + }) => { + const beforeMetrics = await perfTracker.capturePagePerformanceMetrics(cdp); + + // Navigate to Discover app + await pageObjects.collapsibleNav.clickItem('Discover'); + await page.waitForLoadingIndicatorHidden(); + const currentUrl = page.url(); + expect(currentUrl).toContain('app/discover#/'); + + await pageObjects.discover.waitForHistogramRendered(); + + const afterMetrics = await perfTracker.capturePagePerformanceMetrics(cdp); + const perfStats = perfTracker.collectPagePerformanceStats( + currentUrl, + beforeMetrics, + afterMetrics + ); + + expect( + perfStats.cpuTime.diff, + 'CPU time (seconds) usage during page navigation should not exceed 1.5 seconds' + ).toBeLessThan(1.5); + expect( + perfStats.scriptTime.diff, + 'Additional time spent executing JS scripts should not exceed 0.5 second' + ).toBeLessThan(0.5); + expect( + perfStats.layoutTime.diff, + 'Total layout computation time should not exceed 0.1 second' + ).toBeLessThan(0.06); + }); + } +); diff --git a/x-pack/platform/plugins/private/discover_enhanced/ui_tests/tests/discover_lighthouse.spec.ts b/x-pack/platform/plugins/private/discover_enhanced/ui_tests/tests/discover_lighthouse.spec.ts new file mode 100644 index 0000000000000..c192c7aac8ab7 --- /dev/null +++ b/x-pack/platform/plugins/private/discover_enhanced/ui_tests/tests/discover_lighthouse.spec.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { lighthouseTest, tags } from '@kbn/scout'; +import { testData } from '../fixtures'; + +lighthouseTest.describe( + 'Discover App - Lighthouse Performance Audit', + { tag: [...tags.DEPLOYMENT_AGNOSTIC, ...tags.PERFORMANCE] }, + () => { + lighthouseTest.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.LOGSTASH); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.DASHBOARD_DRILLDOWNS); + await uiSettings.set({ + defaultIndex: testData.DATA_VIEW_ID.LOGSTASH, + 'timepicker:timeDefaults': `{ "from": "${testData.LOGSTASH_DEFAULT_START_TIME}", "to": "${testData.LOGSTASH_DEFAULT_END_TIME}"}`, + }); + }); + + lighthouseTest.afterAll(async ({ kbnClient, uiSettings }) => { + await uiSettings.unset('defaultIndex', 'timepicker:timeDefaults'); + await kbnClient.savedObjects.cleanStandardList(); + }); + + lighthouseTest( + 'runs audit on Discover Page', + async ({ browserAuth, lighthouse, page, pageObjects }) => { + await browserAuth.loginAsAdmin(); + await pageObjects.discover.goto(); + await pageObjects.discover.waitForHistogramRendered(); + const currentUrl = page.url(); + + // Run the Lighthouse audit on the current page and attach the report + await lighthouse.runAudit(currentUrl); + } + ); + } +); diff --git a/yarn.lock b/yarn.lock index d907d52cdb293..f865febd405fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2739,6 +2739,16 @@ "@formatjs/intl-localematcher" "0.5.4" tslib "^2.4.0" +"@formatjs/ecma402-abstract@2.3.3": + version "2.3.3" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.3.tgz#fbc7555c9e4fdd104cd5e23129fa3735be3ad0ba" + integrity sha512-pJT1OkhplSmvvr6i3CWTPvC/FGC06MbN5TNBfRO6Ox62AEz90eMq+dVvtX9Bl3jxCEkS0tATzDarRZuOLw7oFg== + dependencies: + "@formatjs/fast-memoize" "2.2.6" + "@formatjs/intl-localematcher" "0.6.0" + decimal.js "10" + tslib "2" + "@formatjs/fast-memoize@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz#33bd616d2e486c3e8ef4e68c99648c196887802b" @@ -2746,6 +2756,22 @@ dependencies: tslib "^2.4.0" +"@formatjs/fast-memoize@2.2.6": + version "2.2.6" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.6.tgz#fac0a84207a1396be1f1aa4ee2805b179e9343d1" + integrity sha512-luIXeE2LJbQnnzotY1f2U2m7xuQNj2DA8Vq4ce1BY9ebRZaoPB1+8eZ6nXpLzsxuW5spQxr7LdCg+CApZwkqkw== + dependencies: + tslib "2" + +"@formatjs/icu-messageformat-parser@2.11.1", "@formatjs/icu-messageformat-parser@^2.7.6": + version "2.11.1" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.1.tgz#59d69124b9cf3186800a576c0228947d10594347" + integrity sha512-o0AhSNaOfKoic0Sn1GkFCK4MxdRsw7mPJ5/rBpIqdvcC7MIuyUSW8WChUEvrK78HhNpYOgqCQbINxCTumJLzZA== + dependencies: + "@formatjs/ecma402-abstract" "2.3.3" + "@formatjs/icu-skeleton-parser" "1.8.13" + tslib "2" + "@formatjs/icu-messageformat-parser@2.7.6": version "2.7.6" resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.6.tgz#3d69806de056d2919d53dad895a5ff4851e4e9ff" @@ -2755,7 +2781,7 @@ "@formatjs/icu-skeleton-parser" "1.8.0" tslib "^2.4.0" -"@formatjs/icu-messageformat-parser@2.7.8", "@formatjs/icu-messageformat-parser@^2.7.6": +"@formatjs/icu-messageformat-parser@2.7.8": version "2.7.8" resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz#f6d7643001e9bb5930d812f1f9a9856f30fa0343" integrity sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA== @@ -2772,6 +2798,14 @@ "@formatjs/ecma402-abstract" "1.18.2" tslib "^2.4.0" +"@formatjs/icu-skeleton-parser@1.8.13": + version "1.8.13" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.13.tgz#5e8b1e1bb467c937735fecb4cb4b345932151a44" + integrity sha512-N/LIdTvVc1TpJmMt2jVg0Fr1F7Q1qJPdZSCs19unMskCmVQ/sa0H9L8PWt13vq+gLdLg1+pPsvBLydL1Apahjg== + dependencies: + "@formatjs/ecma402-abstract" "2.3.3" + tslib "2" + "@formatjs/icu-skeleton-parser@1.8.2": version "1.8.2" resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.2.tgz#2252c949ae84ee66930e726130ea66731a123c9f" @@ -2805,6 +2839,13 @@ dependencies: tslib "^2.4.0" +"@formatjs/intl-localematcher@0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.6.0.tgz#33cf0d33279572c990e02ab75a93122569878082" + integrity sha512-4rB4g+3hESy1bHSBG3tDFaMY2CH67iT7yne1e+0CLTsGLDcmoEWWpJjjpWVaYgYfYuohIRuo0E+N536gd2ZHZA== + dependencies: + tslib "2" + "@formatjs/intl-pluralrules@^5.2.12": version "5.2.12" resolved "https://registry.yarnpkg.com/@formatjs/intl-pluralrules/-/intl-pluralrules-5.2.12.tgz#0433202e985c7853b8737e7127253e18474eced1" @@ -8926,6 +8967,13 @@ node-addon-api "^3.2.1" node-gyp-build "^4.3.0" +"@paulirish/trace_engine@0.0.44": + version "0.0.44" + resolved "https://registry.yarnpkg.com/@paulirish/trace_engine/-/trace_engine-0.0.44.tgz#27f2188856c4800e02a68e6f51b6ade9c460cfb8" + integrity sha512-QjDv5qVaUXd5WZzE2ktKvqtGA17v4HFtj6MROCGkK57AZr9n0ZKgcx7dEFho+5EHZ6V6h1upW2eqheo8C4Y4dA== + dependencies: + third-party-web latest + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -9050,6 +9098,19 @@ unbzip2-stream "^1.4.3" yargs "^17.7.2" +"@puppeteer/browsers@2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.8.0.tgz#9d592933cbefc66c37823770844b8cbac52607dd" + integrity sha512-yTwt2KWRmCQAfhvbCRjebaSX8pV1//I0Y3g+A7f/eS7gf0l4eRJoUCvcYdVtboeU4CTOZQuqYbZNS8aBYb8ROQ== + dependencies: + debug "^4.4.0" + extract-zip "^2.0.1" + progress "^2.0.3" + proxy-agent "^6.5.0" + semver "^7.7.1" + tar-fs "^3.0.8" + yargs "^17.7.2" + "@redocly/ajv@^8.11.2": version "8.11.2" resolved "https://registry.yarnpkg.com/@redocly/ajv/-/ajv-8.11.2.tgz#46e1bf321ec0ac1e0fd31dea41a3d1fcbdcda0b5" @@ -9176,6 +9237,56 @@ agentkeepalive "^4.1.3" lodash "^4.17.21" +"@sentry-internal/tracing@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.120.3.tgz#a54e67c39d23576a72b3f349c1a3fae13e27f2f1" + integrity sha512-Ausx+Jw1pAMbIBHStoQ6ZqDZR60PsCByvHdw/jdH9AqPrNE9xlBSf9EwcycvmrzwyKspSLaB52grlje2cRIUMg== + dependencies: + "@sentry/core" "7.120.3" + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + +"@sentry/core@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.120.3.tgz#88ae2f8c242afce59e32bdee7f866d8788e86c03" + integrity sha512-vyy11fCGpkGK3qI5DSXOjgIboBZTriw0YDx/0KyX5CjIjDDNgp5AGgpgFkfZyiYiaU2Ww3iFuKo4wHmBusz1uA== + dependencies: + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + +"@sentry/integrations@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.120.3.tgz#ea6812b77dea7d0090a5cf85383f154b3bd5b073" + integrity sha512-6i/lYp0BubHPDTg91/uxHvNui427df9r17SsIEXa2eKDwQ9gW2qRx5IWgvnxs2GV/GfSbwcx4swUB3RfEWrXrQ== + dependencies: + "@sentry/core" "7.120.3" + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + localforage "^1.8.1" + +"@sentry/node@^7.0.0": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.120.3.tgz#59a54e1bfccffd28e7d502a5eefea615f07e13f5" + integrity sha512-t+QtekZedEfiZjbkRAk1QWJPnJlFBH/ti96tQhEq7wmlk3VszDXraZvLWZA0P2vXyglKzbWRGkT31aD3/kX+5Q== + dependencies: + "@sentry-internal/tracing" "7.120.3" + "@sentry/core" "7.120.3" + "@sentry/integrations" "7.120.3" + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + +"@sentry/types@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.120.3.tgz#25f69ae27f0c8430f1863ad2a9ee9cab7fccf232" + integrity sha512-C4z+3kGWNFJ303FC+FxAd4KkHvxpNFYAFN8iMIgBwJdpIl25KZ8Q/VdGn0MLLUEHNLvjob0+wvwlcRBBNLXOow== + +"@sentry/utils@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.120.3.tgz#0cc891c315d3894eb80c2e7298efd7437e939a5d" + integrity sha512-UDAOQJtJDxZHQ5Nm1olycBIsz2wdGX8SdzyGVHmD8EOQYAeDZQyIlQYohDe9nazdIOQLZCIc3fU0G9gqVLkaGQ== + dependencies: + "@sentry/types" "7.120.3" + "@sideway/address@^4.1.5": version "4.1.5" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" @@ -13199,6 +13310,11 @@ axe-core@^4.10.0: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.0.tgz#d9e56ab0147278272739a000880196cdfe113b59" integrity sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g== +axe-core@^4.10.2: + version "4.10.2" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.2.tgz#85228e3e1d8b8532a27659b332e39b7fa0e022df" + integrity sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w== + axe-core@^4.2.0, axe-core@^4.6.2: version "4.7.2" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.2.tgz#040a7342b20765cb18bb50b628394c21bccc17a0" @@ -13419,27 +13535,33 @@ bare-events@^2.0.0, bare-events@^2.2.0: resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.2.1.tgz#7b6d421f26a7a755e20bf580b727c84b807964c1" integrity sha512-9GYPpsPFvrWBkelIhOhTWtkeZxVxZOdb3VnFTCzlOo3OjvmTvzLoZFUT8kNFACx0vJej6QPney1Cf9BvzCNE/A== -bare-fs@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-2.2.1.tgz#c1985d8d3e07a178956b072d3af67cb8c1fa9391" - integrity sha512-+CjmZANQDFZWy4PGbVdmALIwmt33aJg8qTkVjClU6X4WmZkTPBDxRHiBn7fpqEWEfF3AC2io++erpViAIQbSjg== +bare-fs@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-4.0.1.tgz#85844f34da819c76754d545323a8b23ed3617c76" + integrity sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg== dependencies: bare-events "^2.0.0" - bare-os "^2.0.0" - bare-path "^2.0.0" - streamx "^2.13.0" + bare-path "^3.0.0" + bare-stream "^2.0.0" -bare-os@^2.0.0, bare-os@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-2.2.0.tgz#24364692984d0bd507621754781b31d7872736b2" - integrity sha512-hD0rOPfYWOMpVirTACt4/nK8mC55La12K5fY1ij8HAdfQakD62M+H4o4tpfKzVGLgRDTuk3vjA4GqGXXCeFbag== +bare-os@^3.0.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-3.6.0.tgz#1465dd7e1bebe0dec230097a23ad00f7db51f957" + integrity sha512-BUrFS5TqSBdA0LwHop4OjPJwisqxGy6JsWVqV6qaFoe965qqtaKfDzHY5T2YA1gUL0ZeeQeA+4BBc1FJTcHiPw== -bare-path@^2.0.0, bare-path@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-2.1.0.tgz#830f17fd39842813ca77d211ebbabe238a88cb4c" - integrity sha512-DIIg7ts8bdRKwJRJrUMy/PICEaQZaPGZ26lsSx9MJSwIhSrcdHn7/C8W+XmnG/rKi6BaRcz+JO00CjZteybDtw== +bare-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-3.0.0.tgz#b59d18130ba52a6af9276db3e96a2e3d3ea52178" + integrity sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw== dependencies: - bare-os "^2.1.0" + bare-os "^3.0.1" + +bare-stream@^2.0.0: + version "2.6.5" + resolved "https://registry.yarnpkg.com/bare-stream/-/bare-stream-2.6.5.tgz#bba8e879674c4c27f7e27805df005c15d7a2ca07" + integrity sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA== + dependencies: + streamx "^2.21.0" base64-js@1.3.1: version "1.3.1" @@ -14282,6 +14404,16 @@ chroma-js@2.4.2, chroma-js@^2.1.0, chroma-js@^2.4.2: resolved "https://registry.yarnpkg.com/chroma-js/-/chroma-js-2.4.2.tgz#dffc214ed0c11fa8eefca2c36651d8e57cbfb2b0" integrity sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A== +chrome-launcher@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-1.1.2.tgz#52eff6b3fd7f24b65192b2624a108dadbcca4b9d" + integrity sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw== + dependencies: + "@types/node" "*" + escape-string-regexp "^4.0.0" + is-wsl "^2.2.0" + lighthouse-logger "^2.0.1" + chrome-trace-event@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" @@ -14310,6 +14442,14 @@ chromium-bidi@1.1.0: mitt "3.0.1" zod "3.24.1" +chromium-bidi@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-2.1.2.tgz#b0710279f993128d4e0b41c892209ea093217d97" + integrity sha512-vtRWBK2uImo5/W2oG6/cDkkHSm+2t6VHgnj+Rcwhb0pP74OoUb4GipyRX/T/y39gYQPhioP0DPShn+A7P6CHNw== + dependencies: + mitt "^3.0.1" + zod "^3.24.1" + ci-info@^3.2.0: version "3.8.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" @@ -14844,6 +14984,18 @@ concaveman@*: robust-predicates "^2.0.4" tinyqueue "^2.0.3" +configstore@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + connect-history-api-fallback@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" @@ -15148,6 +15300,16 @@ crypto-js@^4.2.0: resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +csp_evaluator@1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/csp_evaluator/-/csp_evaluator-1.1.5.tgz#33788d695b7b539b17d5b6eba494431ce931faff" + integrity sha512-EL/iN9etCTzw/fBnp0/uj0f5BOOGvZut2mzsiiBZ/FdT6gFQCKRO/tmcKOxn5drWZ2Ndm/xBb1SI4zwWbGtmIw== + css-box-model@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" @@ -15840,7 +16002,7 @@ debounce@^1.2.1: resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -15903,10 +16065,10 @@ decamelize@^6.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-6.0.0.tgz#8cad4d916fde5c41a264a43d0ecc56fe3d31749e" integrity sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA== -decimal.js@^10.4.1: - version "10.4.1" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.1.tgz#be75eeac4a2281aace80c1a8753587c27ef053e7" - integrity sha512-F29o+vci4DodHYT9UrR5IEbfBw9pE5eSapIJdTqXK5+6hq+t8VRxwQyKlW2i+KDKFkkJQRvFyI/QXD83h8LyQw== +decimal.js@10, decimal.js@^10.4.1: + version "10.5.0" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.5.0.tgz#0f371c7cf6c4898ce0afb09836db73cd82010f22" + integrity sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw== decko@^1.2.0: version "1.2.0" @@ -16333,6 +16495,16 @@ devtools-protocol@0.0.1380148: resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1380148.tgz#7dcdad06515135b244ff05878ca8019e041c1c55" integrity sha512-1CJABgqLxbYxVI+uJY/UDUHJtJ0KZTSjNYJYKqd9FRoXT33WDakDHNxRapMEgzeJ/C3rcs01+avshMnPmKQbvA== +devtools-protocol@0.0.1413902: + version "0.0.1413902" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1413902.tgz#a0f00fe9eb25ab337a8f9656a29e0a1a69f42401" + integrity sha512-yRtvFD8Oyk7C9Os3GmnFZLu53yAfsnyw1s+mLmHHUK0GQEc9zthHWvS1r67Zqzm5t7v56PILHIVZ7kmFMaL2yQ== + +devtools-protocol@0.0.1423531: + version "0.0.1423531" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1423531.tgz#43ba906340fb8ffbda566711ead31f139b2a150a" + integrity sha512-z6cOcajZWxk80zvFnkTGa7tj3oqF+C5SnOF1KSMeAr5/WW/nLNHlEpKr7voSzMz8IaUoq5rjdI0Mqv5k/BUkhg== + dezalgo@^1.0.0, dezalgo@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" @@ -16535,6 +16707,13 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" +dot-prop@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + dotenv@^16.0.2, dotenv@^16.0.3, dotenv@^16.4.5: version "16.4.7" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26" @@ -17817,7 +17996,7 @@ fast-equals@^2.0.0: resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-2.0.0.tgz#bef2c423af3939f2c54310df54c57e64cd2adefc" integrity sha512-u6RBd8cSiLLxAiC04wVsLV6GBFDOXcTCgWkd3wEoFXgidPSoAJENqC9m7Jb2vewSvjBIfXV6icKeh3GTKfIaXA== -fast-fifo@^1.1.0, fast-fifo@^1.2.0: +fast-fifo@^1.2.0, fast-fifo@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== @@ -19610,6 +19789,11 @@ http-https@^1.0.0: resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" integrity sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs= +http-link-header@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/http-link-header/-/http-link-header-1.1.3.tgz#b367b7a0ad1cf14027953f31aa1df40bb433da2a" + integrity sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ== + http-parser-js@>=0.5.1: version "0.5.3" resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" @@ -19796,6 +19980,11 @@ ignore@^7.0.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.0.tgz#52da780b009bd0845d1f9dd4d8ae6a7569ae73c4" integrity sha512-lcX8PNQygAa22u/0BysEY8VhaFRzlOkvdlKczDPnJvrkJD1EuqzEky5VYYKM2iySIuaVIDv9N190DfSreSLw2A== +image-ssim@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/image-ssim/-/image-ssim-0.2.0.tgz#83b42c7a2e6e4b85505477fe6917f5dbc56420e5" + integrity sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg== + immediate@~3.0.5: version "3.0.6" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" @@ -19982,6 +20171,16 @@ intl-messageformat@10.5.12: "@formatjs/icu-messageformat-parser" "2.7.6" tslib "^2.4.0" +intl-messageformat@^10.5.3: + version "10.7.15" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.7.15.tgz#5cdc62139ef39ece1b083db32dae4d1c9fa5b627" + integrity sha512-LRyExsEsefQSBjU2p47oAheoKz+EOJxSLDdjOaEjdriajfHsMXOmV/EhMvYSg9bAgCUHasuAC+mcUBe/95PfIg== + dependencies: + "@formatjs/ecma402-abstract" "2.3.3" + "@formatjs/fast-memoize" "2.2.6" + "@formatjs/icu-messageformat-parser" "2.11.1" + tslib "2" + invariant@^2.1.0, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -20351,6 +20550,11 @@ is-obj@^1.0.1: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + is-odd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" @@ -21212,6 +21416,11 @@ jpeg-exif@^1.1.4: resolved "https://registry.yarnpkg.com/jpeg-exif/-/jpeg-exif-1.1.4.tgz#781a65b6cd74f62cb1c493511020f8d3577a1c2b" integrity sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ== +jpeg-js@^0.4.1, jpeg-js@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa" + integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg== + jquery@^3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.1.tgz#083ef98927c9a6a74d05a6af02806566d16274de" @@ -21227,6 +21436,11 @@ js-levenshtein@^1.1.6: resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== +js-library-detector@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/js-library-detector/-/js-library-detector-6.7.0.tgz#5075c71fcf835b71133bca13363b91509a39235a" + integrity sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA== + js-search@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/js-search/-/js-search-1.4.3.tgz#23a86d7e064ca53a473930edc48615b6b1c1954a" @@ -21815,6 +22029,13 @@ license-checker@^25.0.1: spdx-satisfies "^4.0.0" treeify "^1.1.0" +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== + dependencies: + immediate "~3.0.5" + lie@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" @@ -21822,6 +22043,53 @@ lie@~3.3.0: dependencies: immediate "~3.0.5" +lighthouse-logger@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz#48895f639b61cca89346bb6f47f7403a3895fa02" + integrity sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ== + dependencies: + debug "^2.6.9" + marky "^1.2.2" + +lighthouse-stack-packs@1.12.2: + version "1.12.2" + resolved "https://registry.yarnpkg.com/lighthouse-stack-packs/-/lighthouse-stack-packs-1.12.2.tgz#dbe0ccdbc381784ef176f4f8c2367ac5b077d6ca" + integrity sha512-Ug8feS/A+92TMTCK6yHYLwaFMuelK/hAKRMdldYkMNwv+d9PtWxjXEg6rwKtsUXTADajhdrhXyuNCJ5/sfmPFw== + +lighthouse@^12.4.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/lighthouse/-/lighthouse-12.4.0.tgz#0ca978e6b3ef2c815c132866eb83fbb21845980a" + integrity sha512-1p/YKQpMqfYVSKVOB43RG3xbnxkSUOG0zqVm/bxJHAaAHKrEACgFi8HZxD9CCTFrt+d/Q/x9gjDyeUDarm1SIg== + dependencies: + "@paulirish/trace_engine" "0.0.44" + "@sentry/node" "^7.0.0" + axe-core "^4.10.2" + chrome-launcher "^1.1.2" + configstore "^5.0.1" + csp_evaluator "1.1.5" + devtools-protocol "0.0.1423531" + enquirer "^2.3.6" + http-link-header "^1.1.1" + intl-messageformat "^10.5.3" + jpeg-js "^0.4.4" + js-library-detector "^6.7.0" + lighthouse-logger "^2.0.1" + lighthouse-stack-packs "1.12.2" + lodash-es "^4.17.21" + lookup-closest-locale "6.2.0" + metaviewport-parser "0.3.0" + open "^8.4.0" + parse-cache-control "1.0.1" + puppeteer-core "^24.3.0" + robots-parser "^3.0.1" + semver "^5.3.0" + speedline-core "^1.4.3" + third-party-web "^0.26.5" + tldts-icann "^6.1.16" + ws "^7.0.0" + yargs "^17.3.1" + yargs-parser "^21.0.0" + lilconfig@^2.0.3, lilconfig@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" @@ -21915,6 +22183,13 @@ loader-utils@^2.0.0, loader-utils@^2.0.4: emojis-list "^3.0.0" json5 "^2.1.2" +localforage@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== + dependencies: + lie "3.1.1" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -22158,6 +22433,11 @@ longest-streak@^2.0.0, longest-streak@^2.0.1: resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== +lookup-closest-locale@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/lookup-closest-locale/-/lookup-closest-locale-6.2.0.tgz#57f665e604fd26f77142d48152015402b607bcf3" + integrity sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ== + loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -22425,6 +22705,11 @@ marked@^4.3.0: resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== +marky@^1.2.2: + version "1.2.5" + resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.5.tgz#55796b688cbd72390d2d399eaaf1832c9413e3c0" + integrity sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q== + math-intrinsics@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" @@ -22690,6 +22975,11 @@ meta-png@1.0.6: resolved "https://registry.yarnpkg.com/meta-png/-/meta-png-1.0.6.tgz#34d78a403cc1c809978d3e9f89485a2700daafce" integrity sha512-eQtEi5E9axqwqA/sDK1dyhX9kYHCUe2m+45aQ3JHrozjGPs+/ab+hdhPp7A3GUNW+ZAbavrsg5xQ4r5jkGDX+A== +metaviewport-parser@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/metaviewport-parser/-/metaviewport-parser-0.3.0.tgz#6af1e99b5eaf250c049e0af1e84143a39750dea6" + integrity sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ== + methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -22906,7 +23196,7 @@ minizlib@^3.0.1: minipass "^7.0.4" rimraf "^5.0.5" -mitt@3.0.1: +mitt@3.0.1, mitt@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1" integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== @@ -24014,7 +24304,7 @@ open@^10.0.3: is-inside-container "^1.0.0" is-wsl "^3.1.0" -open@^8.0.4, open@~8.4.0: +open@^8.0.4, open@^8.4.0, open@~8.4.0: version "8.4.2" resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== @@ -24425,6 +24715,11 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.6: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" +parse-cache-control@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" + integrity sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg== + parse-entities@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" @@ -25529,6 +25824,18 @@ puppeteer-core@24.1.1: typed-query-selector "^2.12.0" ws "^8.18.0" +puppeteer-core@^24.3.0: + version "24.4.0" + resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-24.4.0.tgz#a301c58344fe939b487704593681ea9f913fe6f8" + integrity sha512-eFw66gCnWo0X8Hyf9KxxJtms7a61NJVMiSaWfItsFPzFBsjsWdmcNlBdsA1WVwln6neoHhsG+uTVesKmTREn/g== + dependencies: + "@puppeteer/browsers" "2.8.0" + chromium-bidi "2.1.2" + debug "^4.4.0" + devtools-protocol "0.0.1413902" + typed-query-selector "^2.12.0" + ws "^8.18.1" + puppeteer@24.1.1: version "24.1.1" resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-24.1.1.tgz#dadcfbe05b25a54aee7061325631145db568890b" @@ -25582,11 +25889,6 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -queue-tick@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" - integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== - quick-format-unescaped@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.3.tgz#6d6b66b8207aa2b35eef12be1421bb24c428f652" @@ -26940,6 +27242,11 @@ rison-node@1.0.2: resolved "https://registry.yarnpkg.com/rison-node/-/rison-node-1.0.2.tgz#b7b5f37f39f5ae2a51a973a33c9aa17239a33e4b" integrity sha1-t7Xzfzn1ripRqXOjPJqhcjmjPks= +robots-parser@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/robots-parser/-/robots-parser-3.0.1.tgz#3d8a3cdfa8ac240cbb062a4bd16fcc0e0fb9ed23" + integrity sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ== + robust-predicates@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-2.0.4.tgz#0a2367a93abd99676d075981707f29cfb402248b" @@ -27356,7 +27663,7 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== @@ -28119,6 +28426,15 @@ specificity@^0.4.1: resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019" integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg== +speedline-core@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/speedline-core/-/speedline-core-1.4.3.tgz#4d6e7276e2063c2d36a375cb25a523ac73475319" + integrity sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog== + dependencies: + "@types/node" "*" + image-ssim "^0.2.0" + jpeg-js "^0.4.1" + split-on-first@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" @@ -28314,13 +28630,13 @@ stream-slicer@0.0.6: resolved "https://registry.yarnpkg.com/stream-slicer/-/stream-slicer-0.0.6.tgz#f86b2ac5c2440b7a0a87b71f33665c0788046138" integrity sha1-+GsqxcJEC3oKh7cfM2ZcB4gEYTg= -streamx@^2.12.0, streamx@^2.12.5, streamx@^2.13.0, streamx@^2.13.2, streamx@^2.14.0, streamx@^2.15.0: - version "2.16.1" - resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.16.1.tgz#2b311bd34832f08aa6bb4d6a80297c9caef89614" - integrity sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ== +streamx@^2.12.0, streamx@^2.12.5, streamx@^2.13.2, streamx@^2.14.0, streamx@^2.15.0, streamx@^2.21.0: + version "2.22.0" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.22.0.tgz#cd7b5e57c95aaef0ff9b2aef7905afa62ec6e4a7" + integrity sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw== dependencies: - fast-fifo "^1.1.0" - queue-tick "^1.0.1" + fast-fifo "^1.3.2" + text-decoder "^1.1.0" optionalDependencies: bare-events "^2.2.0" @@ -28350,7 +28666,7 @@ string-replace-loader@^3.1.0: loader-utils "^2.0.0" schema-utils "^3.0.0" -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -28368,15 +28684,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -28469,7 +28776,7 @@ stringify-object@^3.2.1: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -28483,13 +28790,6 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -28928,16 +29228,16 @@ tar-fs@^2.0.0: pump "^3.0.0" tar-stream "^2.1.4" -tar-fs@^3.0.4, tar-fs@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.6.tgz#eaccd3a67d5672f09ca8e8f9c3d2b89fa173f217" - integrity sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w== +tar-fs@^3.0.4, tar-fs@^3.0.6, tar-fs@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.8.tgz#8f62012537d5ff89252d01e48690dc4ebed33ab7" + integrity sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg== dependencies: pump "^3.0.0" tar-stream "^3.1.5" optionalDependencies: - bare-fs "^2.1.1" - bare-path "^2.1.0" + bare-fs "^4.0.1" + bare-path "^3.0.0" tar-stream@^2.1.4: version "2.2.0" @@ -29041,6 +29341,13 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +text-decoder@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.2.3.tgz#b19da364d981b2326d5f43099c310cc80d770c65" + integrity sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA== + dependencies: + b4a "^1.6.4" + text-diff@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/text-diff/-/text-diff-1.0.1.tgz#6c105905435e337857375c9d2f6ca63e453ff565" @@ -29066,6 +29373,11 @@ thingies@^1.20.0: resolved "https://registry.yarnpkg.com/thingies/-/thingies-1.21.0.tgz#e80fbe58fd6fdaaab8fad9b67bd0a5c943c445c1" integrity sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g== +third-party-web@^0.26.5, third-party-web@latest: + version "0.26.5" + resolved "https://registry.yarnpkg.com/third-party-web/-/third-party-web-0.26.5.tgz#c442b2a16db66a6064e05e0f060c9ed780f31709" + integrity sha512-tDuKQJUTfjvi9Fcrs1s6YAQAB9mzhTSbBZMfNgtWNmJlHuoFeXO6dzBFdGeCWRvYL50jQGK0jPsBZYxqZQJ2SA== + thread-stream@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-2.3.0.tgz#4fc07fb39eff32ae7bad803cb7dd9598349fed33" @@ -29204,11 +29516,18 @@ tinyspy@^3.0.0: resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== -tldts-core@^6.1.46: +tldts-core@^6.1.46, tldts-core@^6.1.78: version "6.1.78" resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-6.1.78.tgz#47b477d9742870daa01dbd5ff9a598a48379728c" integrity sha512-jS0svNsB99jR6AJBmfmEWuKIgz91Haya91Z43PATaeHJ24BkMoNRb/jlaD37VYjb0mYf6gRL/HOnvS1zEnYBiw== +tldts-icann@^6.1.16: + version "6.1.78" + resolved "https://registry.yarnpkg.com/tldts-icann/-/tldts-icann-6.1.78.tgz#82909d0a1d9a278956aecaa6d49b3789bfd2130f" + integrity sha512-IaM0vesvhlEGsEOG+UQfaW6AuQPB9MHI8sz9K8T8sUjj1rKxBp8SclNqUG8a3WQGv87VOoa+ICZrGXh/tnc/VA== + dependencies: + tldts-core "^6.1.78" + tldts@^6.1.32: version "6.1.46" resolved "https://registry.yarnpkg.com/tldts/-/tldts-6.1.46.tgz#0c3c4157efe732caeddd06eee6da891b26bd8a75" @@ -29493,6 +29812,11 @@ tsd@^0.31.1: path-exists "^4.0.0" read-pkg-up "^7.0.0" +tslib@2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.2, tslib@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + tslib@2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" @@ -29513,11 +29837,6 @@ tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.2, tslib@^2.8.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" - integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - tslib@~2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" @@ -29875,6 +30194,13 @@ union-value@^1.0.0, union-value@^1.0.1: is-extendable "^0.1.1" set-value "^2.0.1" +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + unist-builder@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436" @@ -31179,7 +31505,7 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -31205,15 +31531,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" @@ -31255,15 +31572,20 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@^7.3.1, ws@^7.4.2: +ws@^7.0.0, ws@^7.3.1, ws@^7.4.2: version "7.5.10" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -ws@^8.16.0, ws@^8.18.0, ws@^8.2.3, ws@^8.9.0: - version "8.18.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" - integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== +ws@^8.16.0, ws@^8.18.0, ws@^8.18.1, ws@^8.2.3, ws@^8.9.0: + version "8.18.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" + integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== + +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== xml-crypto@^6.0.1: version "6.0.1" @@ -31319,7 +31641,7 @@ xpath@^0.0.33: resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.33.tgz#5136b6094227c5df92002e7c3a13516a5074eb07" integrity sha512-NNXnzrkDrAzalLhIUc01jO2mOzXGXh1JwPgkihcLLzw98c0WgYDmmjSh1Kl3wzaxSVWMuA+fe0WTWOBDWCBmNA== -"xstate5@npm:xstate@^5.19.2": +"xstate5@npm:xstate@^5.19.2", xstate@^5.19.2: version "5.19.2" resolved "https://registry.yarnpkg.com/xstate/-/xstate-5.19.2.tgz#db3f1ee614bbb6a49ad3f0c96ddbf98562d456ba" integrity sha512-B8fL2aP0ogn5aviAXFzI5oZseAMqN00fg/TeDa3ZtatyDcViYLIfuQl4y8qmHCiKZgGEzmnTyNtNQL9oeJE2gw== @@ -31329,11 +31651,6 @@ xstate@^4.38.3: resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.38.3.tgz#4e15e7ad3aa0ca1eea2010548a5379966d8f1075" integrity sha512-SH7nAaaPQx57dx6qvfcIgqKRXIh4L0A1iYEqim4s1u7c9VoCgzZc+63FY90AKU4ZzOC2cfJzTnpO4zK7fCUzzw== -xstate@^5.19.2: - version "5.19.2" - resolved "https://registry.yarnpkg.com/xstate/-/xstate-5.19.2.tgz#db3f1ee614bbb6a49ad3f0c96ddbf98562d456ba" - integrity sha512-B8fL2aP0ogn5aviAXFzI5oZseAMqN00fg/TeDa3ZtatyDcViYLIfuQl4y8qmHCiKZgGEzmnTyNtNQL9oeJE2gw== - "xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -31591,7 +31908,7 @@ zod-to-json-schema@^3.22.3, zod-to-json-schema@^3.22.4, zod-to-json-schema@^3.22 resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.1.tgz#f08c6725091aadabffa820ba8d50c7ab527f227a" integrity sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w== -zod@3.24.1: +zod@3.24.1, zod@^3.24.1: version "3.24.1" resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.1.tgz#27445c912738c8ad1e9de1bea0359fa44d9d35ee" integrity sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==