From 1a2073f558ad8f58787e4c1ae38f5c00a9522eb1 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Fri, 12 Sep 2025 09:33:09 +0200 Subject: [PATCH 1/2] [Jest] Lazily instantiate mocks --- package.json | 1 + packages/kbn-babel-preset/common_preset.js | 2 +- .../src/analytics_service.test.mocks.ts | 5 +- .../analytics/browser-internal/tsconfig.json | 3 +- .../src/analytics_service.mock.ts | 13 +- .../analytics/browser-mocks/tsconfig.json | 3 +- .../src/analytics_service.test.mocks.ts | 5 +- .../analytics/server-internal/tsconfig.json | 3 +- .../src/analytics_service.mock.ts | 17 +- .../analytics/server-mocks/tsconfig.json | 3 +- .../src/application_service.mock.ts | 46 +++-- .../browser-mocks/src/scoped_history.mock.ts | 5 +- .../application/browser-mocks/tsconfig.json | 1 + .../browser-mocks/src/core_context.mock.ts | 5 +- .../packages/base/browser-mocks/tsconfig.json | 3 +- .../server-mocks/src/core_context.mock.ts | 8 +- .../packages/base/server-mocks/tsconfig.json | 1 + .../browser-mocks/src/chrome_service.mock.ts | 71 +++---- .../chrome/browser-mocks/tsconfig.json | 3 +- .../custom_branding_service.mock.ts | 9 +- .../browser-mocks/service_contract.mock.ts | 6 +- .../browser-mocks/tsconfig.json | 1 + .../src/custom_branding_service.mock.ts | 5 +- .../server-mocks/src/service_contract.mock.ts | 5 +- .../server-mocks/tsconfig.json | 1 + .../data-streams/server-mocks/index.ts | 15 +- .../data-streams/server-mocks/tsconfig.json | 1 + .../src/deprecations_service.mock.ts | 24 +-- .../deprecations/browser-mocks/tsconfig.json | 3 +- .../src/deprecations_service.mock.ts | 24 +-- .../deprecations/server-mocks/tsconfig.json | 3 +- .../packages/di/mocks/src/service.mock.ts | 13 +- src/core/packages/di/mocks/tsconfig.json | 1 + .../src/doc_links_service.mock.ts | 10 +- .../doc-links/browser-mocks/tsconfig.json | 3 +- .../src/agent_manager.mocks.ts | 8 +- .../client-server-mocks/src/mocks.ts | 24 +-- .../client-server-mocks/tsconfig.json | 3 +- .../src/elasticsearch_service.mock.ts | 37 ++-- .../elasticsearch/server-mocks/tsconfig.json | 3 +- .../src/environment_service.mock.ts | 19 +- .../environment/server-mocks/tsconfig.json | 3 +- .../src/execution_context_service.mock.ts | 29 +-- .../browser-mocks/tsconfig.json | 3 +- .../src/fatal_errors_service.mock.ts | 15 +- .../fatal-errors/browser-mocks/tsconfig.json | 3 +- .../feature-flags/browser-mocks/index.ts | 13 +- .../feature-flags/browser-mocks/tsconfig.json | 1 + .../http/browser-mocks/src/base_path.mock.ts | 5 +- .../browser-mocks/src/http_service.mock.ts | 68 +++---- .../packages/http/browser-mocks/tsconfig.json | 3 +- .../src/context_container.mock.ts | 24 ++- .../src/context_service.mock.ts | 20 +- .../http/context-server-mocks/tsconfig.json | 3 +- .../src/http_resources_server.mock.ts | 20 +- .../http/resources-server-mocks/tsconfig.json | 3 +- .../router-server-mocks/src/router.mock.ts | 42 ++-- .../http/router-server-mocks/tsconfig.json | 1 + .../src/cookie_session_storage.mocks.ts | 19 +- .../server-mocks/src/http_server.mocks.ts | 26 +-- .../server-mocks/src/http_service.mock.ts | 97 ++++----- .../http/server-mocks/src/test_utils.ts | 14 +- .../packages/http/server-mocks/tsconfig.json | 1 + .../browser-mocks/src/i18n_service.mock.ts | 16 +- .../packages/i18n/browser-mocks/tsconfig.json | 1 + .../server-mocks/src/i18n_service.mock.ts | 27 +-- .../packages/i18n/server-mocks/tsconfig.json | 3 +- .../src/injected_metadata_service.mock.ts | 87 ++++---- .../browser-mocks/tsconfig.json | 3 +- .../src/integrations_service.mock.ts | 12 +- .../integrations/browser-mocks/tsconfig.json | 3 +- .../browser-mocks/src/core_setup.mock.ts | 9 +- .../browser-mocks/src/core_start.mock.ts | 9 +- .../lifecycle/browser-mocks/tsconfig.json | 1 + .../server-mocks/src/core_preboot.mock.ts | 5 +- .../server-mocks/src/core_setup.mock.ts | 21 +- .../server-mocks/src/core_start.mock.ts | 9 +- .../src/internal_core_preboot.mock.ts | 5 +- .../src/internal_core_setup.mock.ts | 5 +- .../src/internal_core_start.mock.ts | 5 +- .../lifecycle/server-mocks/tsconfig.json | 1 + .../browser-mocks/src/logging_system.mock.ts | 14 +- .../logging/browser-mocks/tsconfig.json | 3 +- .../server-mocks/src/logging_service.mock.ts | 33 +-- .../server-mocks/src/logging_system.mock.ts | 7 +- .../logging/server-mocks/tsconfig.json | 3 +- .../src/collector.mock.ts | 5 +- .../collectors-server-mocks/src/mocks.ts | 18 +- .../collectors-server-mocks/tsconfig.json | 3 +- .../server-mocks/src/metrics_service.mock.ts | 50 ++--- .../metrics/server-mocks/tsconfig.json | 3 +- .../server-mocks/src/node_service.mock.ts | 20 +- .../packages/node/server-mocks/tsconfig.json | 1 + .../src/notifications_service.mock.ts | 18 +- .../notifications/browser-mocks/tsconfig.json | 3 +- .../browser-mocks/src/banners_service.mock.ts | 14 +- .../browser-mocks/src/flyout_service.mock.ts | 12 +- .../browser-mocks/src/modal_service.mock.ts | 12 +- .../browser-mocks/src/overlay_service.mock.ts | 12 +- .../overlays/browser-mocks/tsconfig.json | 3 +- .../browser-mocks/src/plugins_service.mock.ts | 23 +-- .../plugins/browser-mocks/tsconfig.json | 1 + .../server-mocks/src/plugins_service.mock.ts | 46 +++-- .../plugins/server-mocks/tsconfig.json | 3 +- .../server-mocks/src/preboot_service.mock.ts | 17 +- .../preboot/server-mocks/tsconfig.json | 3 +- .../browser-mocks/src/pricing_service.mock.ts | 21 +- .../pricing/browser-mocks/tsconfig.json | 1 + .../server-mocks/src/pricing_service.mock.ts | 13 +- .../pricing/server-mocks/tsconfig.json | 1 + .../src/rendering_service.mock.tsx | 9 +- .../rendering/browser-mocks/tsconfig.json | 3 +- .../api-server-mocks/src/repository.mock.ts | 5 +- .../src/saved_objects_client.mock.ts | 5 +- .../src/saved_objects_extensions.mock.ts | 85 ++++---- .../src/scoped_client_provider.mock.ts | 12 +- .../api-server-mocks/tsconfig.json | 1 + .../src/document_migrator.mock.ts | 5 +- .../src/saved_objects_type_registry.mock.ts | 51 ++--- .../base-server-mocks/src/serializer.mock.ts | 5 +- .../base-server-mocks/tsconfig.json | 3 +- .../src/saved_objects_exporter.mock.ts | 5 +- .../src/saved_objects_importer.mock.ts | 5 +- .../import-export-server-mocks/tsconfig.json | 3 +- .../src/kibana_migrator.mock.ts | 16 +- .../src/migration.mocks.ts | 9 +- .../migration-server-mocks/tsconfig.json | 3 +- .../src/saved_objects_service.mock.ts | 68 +++---- .../saved-objects/server-mocks/tsconfig.json | 3 +- .../src/security_service.mock.ts | 29 +-- .../security/browser-mocks/tsconfig.json | 1 + .../server-mocks/src/api_keys.mock.ts | 22 +- .../security/server-mocks/src/audit.mock.ts | 9 +- .../server-mocks/src/security_service.mock.ts | 49 ++--- .../security/server-mocks/tsconfig.json | 1 + .../server-mocks/src/status_service.mock.ts | 17 +- .../status/server-mocks/tsconfig.json | 1 + .../browser-mocks/src/theme_service.mock.ts | 16 +- .../theme/browser-mocks/tsconfig.json | 3 +- .../browser-mocks/src/client.mock.ts | 18 +- .../src/service_contract.mock.ts | 6 +- .../src/settings_service.mock.ts | 12 +- .../ui-settings/browser-mocks/tsconfig.json | 3 +- .../src/ui_settings_service.mock.ts | 44 ++-- .../ui-settings/server-mocks/tsconfig.json | 3 +- .../src/core_usage_data_service.mock.ts | 13 +- .../src/core_usage_stats_client.mock.ts | 3 +- .../usage-data/server-mocks/tsconfig.json | 3 +- .../src/user_profile_service.mock.ts | 21 +- .../user-profile/browser-mocks/tsconfig.json | 1 + .../src/user_settings_service.mock.ts | 8 +- .../user-settings/server-mocks/tsconfig.json | 1 + src/core/public/mocks.ts | 9 +- src/core/tsconfig.json | 1 + .../kbn-config-mocks/src/config.mock.ts | 16 +- .../src/config_service.mock.ts | 34 ++-- .../private/kbn-config-mocks/src/env.mock.ts | 5 +- .../src/raw_config_service.mock.ts | 5 +- .../private/kbn-config-mocks/tsconfig.json | 1 + .../shared/kbn-babel-register/index.js | 2 + .../packages/shared/kbn-lazy-object/README.md | 3 + .../packages/shared/kbn-lazy-object/index.ts | 16 ++ .../shared/kbn-lazy-object/jest.config.js | 14 ++ .../shared/kbn-lazy-object/kibana.jsonc | 8 + .../shared/kbn-lazy-object/package.json | 6 + .../create_lazy_object_from_annotations.ts | 85 ++++++++ .../src/create_lazy_object_from_factories.ts | 40 ++++ .../shared/kbn-lazy-object/src/is_disabled.ts | 12 ++ .../shared/kbn-lazy-object/src/lazy_object.ts | 15 ++ .../shared/kbn-lazy-object/src/metrics.ts | 29 +++ .../src/plugin/lazy_babel_plugin.js | 176 ++++++++++++++++ .../src/plugin/lazy_babel_plugin.test.ts | 188 ++++++++++++++++++ .../shared/kbn-lazy-object/tsconfig.json | 17 ++ .../kbn-logging-mocks/src/logger.mock.ts | 14 +- .../shared/kbn-logging-mocks/tsconfig.json | 3 +- .../packages/shared/kbn-test/jest-preset.js | 32 ++- .../plugins/shared/files/server/mocks.ts | 53 ++--- .../plugins/shared/files/tsconfig.json | 1 + .../shared/usage_collection/server/mocks.ts | 10 +- .../shared/usage_collection/tsconfig.json | 1 + tsconfig.base.json | 2 + .../plugins/shared/actions/server/mocks.ts | 18 +- .../plugins/shared/actions/tsconfig.json | 1 + .../plugins/shared/alerting/server/mocks.ts | 54 ++--- .../server/rules_client_factory.test.ts | 106 ++++++---- .../plugins/shared/alerting/tsconfig.json | 3 +- .../common/lib/kibana/kibana_react.mock.tsx | 24 ++- .../public/common/mock/test_providers.tsx | 15 +- .../shared/cases/server/client/mocks.ts | 33 +-- .../shared/cases/server/services/mocks.ts | 41 ++-- .../plugins/shared/cases/tsconfig.json | 3 +- .../plugins/shared/features/server/mocks.ts | 9 +- .../plugins/shared/features/tsconfig.json | 1 + .../plugins/shared/licensing/public/mocks.ts | 15 +- .../plugins/shared/licensing/server/mocks.ts | 34 ++-- .../plugins/shared/licensing/tsconfig.json | 1 + .../shared/notifications/server/mocks.ts | 13 +- .../shared/notifications/tsconfig.json | 1 + .../public/authentication/index.mock.ts | 73 +++---- .../plugins/shared/security/public/mocks.ts | 13 +- .../shared/security/server/audit/mocks.ts | 10 +- .../plugins/shared/security/server/mocks.ts | 37 ++-- .../plugins/shared/security/tsconfig.json | 1 + .../shared/task_manager/server/mocks.ts | 11 +- .../plugins/shared/task_manager/tsconfig.json | 1 + .../metric_threshold_executor.test.ts | 2 +- yarn.lock | 4 + 207 files changed, 2045 insertions(+), 1271 deletions(-) create mode 100644 src/platform/packages/shared/kbn-lazy-object/README.md create mode 100644 src/platform/packages/shared/kbn-lazy-object/index.ts create mode 100644 src/platform/packages/shared/kbn-lazy-object/jest.config.js create mode 100644 src/platform/packages/shared/kbn-lazy-object/kibana.jsonc create mode 100644 src/platform/packages/shared/kbn-lazy-object/package.json create mode 100644 src/platform/packages/shared/kbn-lazy-object/src/create_lazy_object_from_annotations.ts create mode 100644 src/platform/packages/shared/kbn-lazy-object/src/create_lazy_object_from_factories.ts create mode 100644 src/platform/packages/shared/kbn-lazy-object/src/is_disabled.ts create mode 100644 src/platform/packages/shared/kbn-lazy-object/src/lazy_object.ts create mode 100644 src/platform/packages/shared/kbn-lazy-object/src/metrics.ts create mode 100644 src/platform/packages/shared/kbn-lazy-object/src/plugin/lazy_babel_plugin.js create mode 100644 src/platform/packages/shared/kbn-lazy-object/src/plugin/lazy_babel_plugin.test.ts create mode 100644 src/platform/packages/shared/kbn-lazy-object/tsconfig.json diff --git a/package.json b/package.json index 5912f8df34ed2..8106bf33ba46d 100644 --- a/package.json +++ b/package.json @@ -1587,6 +1587,7 @@ "@kbn/json-ast": "link:packages/kbn-json-ast", "@kbn/kbn-genai-cli": "link:x-pack/solutions/observability/packages/kbn-genai-cli", "@kbn/kibana-manifest-schema": "link:packages/kbn-kibana-manifest-schema", + "@kbn/lazy-object": "link:src/platform/packages/shared/kbn-lazy-object", "@kbn/lint-packages-cli": "link:packages/kbn-lint-packages-cli", "@kbn/lint-ts-projects-cli": "link:packages/kbn-lint-ts-projects-cli", "@kbn/managed-vscode-config": "link:packages/kbn-managed-vscode-config", diff --git a/packages/kbn-babel-preset/common_preset.js b/packages/kbn-babel-preset/common_preset.js index d45135c074460..aafaf57e3437b 100644 --- a/packages/kbn-babel-preset/common_preset.js +++ b/packages/kbn-babel-preset/common_preset.js @@ -14,8 +14,8 @@ module.exports = (api) => ({ // our explicit plugin configs to a sub-preset { plugins: [ + require.resolve('@kbn/lazy-object/src/plugin/lazy_babel_plugin'), require.resolve('babel-plugin-add-module-exports'), - // The class properties proposal was merged with the private fields proposal // into the "class fields" proposal. Babel doesn't support this combined // proposal yet, which includes private field, so this transform is diff --git a/src/core/packages/analytics/browser-internal/src/analytics_service.test.mocks.ts b/src/core/packages/analytics/browser-internal/src/analytics_service.test.mocks.ts index 82898c01c7df1..85fe4d2c69ac4 100644 --- a/src/core/packages/analytics/browser-internal/src/analytics_service.test.mocks.ts +++ b/src/core/packages/analytics/browser-internal/src/analytics_service.test.mocks.ts @@ -9,8 +9,9 @@ import type { AnalyticsClient } from '@elastic/ebt/client'; import { Subject } from 'rxjs'; +import { lazyObject } from '@kbn/lazy-object'; -export const analyticsClientMock: jest.Mocked = { +export const analyticsClientMock: jest.Mocked = lazyObject({ optIn: jest.fn(), reportEvent: jest.fn(), registerEventType: jest.fn(), @@ -20,7 +21,7 @@ export const analyticsClientMock: jest.Mocked = { telemetryCounter$: new Subject(), flush: jest.fn(), shutdown: jest.fn(), -}; +}); jest.doMock('@elastic/ebt/client', () => ({ createAnalytics: () => analyticsClientMock, diff --git a/src/core/packages/analytics/browser-internal/tsconfig.json b/src/core/packages/analytics/browser-internal/tsconfig.json index 9dc1d2c37c791..d34580f1e71f4 100644 --- a/src/core/packages/analytics/browser-internal/tsconfig.json +++ b/src/core/packages/analytics/browser-internal/tsconfig.json @@ -11,7 +11,8 @@ "@kbn/core-injected-metadata-browser-internal", "@kbn/core-analytics-browser", "@kbn/core-base-browser-mocks", - "@kbn/core-injected-metadata-browser-mocks" + "@kbn/core-injected-metadata-browser-mocks", + "@kbn/lazy-object" ], "exclude": ["target/**/*"] } diff --git a/src/core/packages/analytics/browser-mocks/src/analytics_service.mock.ts b/src/core/packages/analytics/browser-mocks/src/analytics_service.mock.ts index e09ec49b779a2..39dac92c4c876 100644 --- a/src/core/packages/analytics/browser-mocks/src/analytics_service.mock.ts +++ b/src/core/packages/analytics/browser-mocks/src/analytics_service.mock.ts @@ -11,11 +11,12 @@ import { Subject } from 'rxjs'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { AnalyticsServiceSetup, AnalyticsServiceStart } from '@kbn/core-analytics-browser'; import type { AnalyticsService } from '@kbn/core-analytics-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; type AnalyticsServiceContract = PublicMethodsOf; const createAnalyticsServiceSetup = (): jest.Mocked => { - return { + return lazyObject({ optIn: jest.fn(), reportEvent: jest.fn(), registerEventType: jest.fn(), @@ -23,23 +24,23 @@ const createAnalyticsServiceSetup = (): jest.Mocked => { removeContextProvider: jest.fn(), registerShipper: jest.fn(), telemetryCounter$: new Subject(), - }; + }); }; const createAnalyticsServiceStart = (): jest.Mocked => { - return { + return lazyObject({ optIn: jest.fn(), reportEvent: jest.fn(), telemetryCounter$: new Subject(), - }; + }); }; const createAnalyticsServiceMock = (): jest.Mocked => { - return { + return lazyObject({ setup: jest.fn().mockImplementation(createAnalyticsServiceSetup), start: jest.fn().mockImplementation(createAnalyticsServiceStart), stop: jest.fn(), - }; + }); }; export const analyticsServiceMock = { diff --git a/src/core/packages/analytics/browser-mocks/tsconfig.json b/src/core/packages/analytics/browser-mocks/tsconfig.json index b811574edd906..2780e9dc08ff5 100644 --- a/src/core/packages/analytics/browser-mocks/tsconfig.json +++ b/src/core/packages/analytics/browser-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-analytics-browser", - "@kbn/core-analytics-browser-internal" + "@kbn/core-analytics-browser-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/analytics/server-internal/src/analytics_service.test.mocks.ts b/src/core/packages/analytics/server-internal/src/analytics_service.test.mocks.ts index 6cc36e4c836ba..a5a1bd8515bd8 100644 --- a/src/core/packages/analytics/server-internal/src/analytics_service.test.mocks.ts +++ b/src/core/packages/analytics/server-internal/src/analytics_service.test.mocks.ts @@ -9,8 +9,9 @@ import type { AnalyticsClient } from '@elastic/ebt/client'; import { Subject } from 'rxjs'; +import { lazyObject } from '@kbn/lazy-object'; -export const analyticsClientMock: jest.Mocked = { +export const analyticsClientMock: jest.Mocked = lazyObject({ optIn: jest.fn(), reportEvent: jest.fn(), registerEventType: jest.fn(), @@ -20,7 +21,7 @@ export const analyticsClientMock: jest.Mocked = { telemetryCounter$: new Subject(), shutdown: jest.fn(), flush: jest.fn(), -}; +}); jest.doMock('@elastic/ebt/client', () => ({ createAnalytics: () => analyticsClientMock, diff --git a/src/core/packages/analytics/server-internal/tsconfig.json b/src/core/packages/analytics/server-internal/tsconfig.json index d62b5cf6aea65..89c4550371b0a 100644 --- a/src/core/packages/analytics/server-internal/tsconfig.json +++ b/src/core/packages/analytics/server-internal/tsconfig.json @@ -15,7 +15,8 @@ "@kbn/core-base-server-internal", "@kbn/core-analytics-server", "@kbn/config-mocks", - "@kbn/core-base-server-mocks" + "@kbn/core-base-server-mocks", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/analytics/server-mocks/src/analytics_service.mock.ts b/src/core/packages/analytics/server-mocks/src/analytics_service.mock.ts index 2ad3d09237239..d1169167a1485 100644 --- a/src/core/packages/analytics/server-mocks/src/analytics_service.mock.ts +++ b/src/core/packages/analytics/server-mocks/src/analytics_service.mock.ts @@ -15,11 +15,12 @@ import type { AnalyticsServicePreboot, } from '@kbn/core-analytics-server'; import type { AnalyticsService } from '@kbn/core-analytics-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; type AnalyticsServiceContract = PublicMethodsOf; const createAnalyticsServicePreboot = (): jest.Mocked => { - return { + return lazyObject({ optIn: jest.fn(), reportEvent: jest.fn(), registerEventType: jest.fn(), @@ -27,11 +28,11 @@ const createAnalyticsServicePreboot = (): jest.Mocked = removeContextProvider: jest.fn(), registerShipper: jest.fn(), telemetryCounter$: new Subject(), - }; + }); }; const createAnalyticsServiceSetup = (): jest.Mocked => { - return { + return lazyObject({ optIn: jest.fn(), reportEvent: jest.fn(), registerEventType: jest.fn(), @@ -39,24 +40,24 @@ const createAnalyticsServiceSetup = (): jest.Mocked => { removeContextProvider: jest.fn(), registerShipper: jest.fn(), telemetryCounter$: new Subject(), - }; + }); }; const createAnalyticsServiceStart = (): jest.Mocked => { - return { + return lazyObject({ optIn: jest.fn(), reportEvent: jest.fn(), telemetryCounter$: new Subject(), - }; + }); }; const createAnalyticsServiceMock = (): jest.Mocked => { - return { + return lazyObject({ preboot: jest.fn().mockImplementation(createAnalyticsServicePreboot), setup: jest.fn().mockImplementation(createAnalyticsServiceSetup), start: jest.fn().mockImplementation(createAnalyticsServiceStart), stop: jest.fn(), - }; + }); }; export const analyticsServiceMock = { diff --git a/src/core/packages/analytics/server-mocks/tsconfig.json b/src/core/packages/analytics/server-mocks/tsconfig.json index cfe405ad4fc2f..45fe3f3895912 100644 --- a/src/core/packages/analytics/server-mocks/tsconfig.json +++ b/src/core/packages/analytics/server-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-analytics-server", - "@kbn/core-analytics-server-internal" + "@kbn/core-analytics-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/application/browser-mocks/src/application_service.mock.ts b/src/core/packages/application/browser-mocks/src/application_service.mock.ts index 0d8e918f88824..31951853011e6 100644 --- a/src/core/packages/application/browser-mocks/src/application_service.mock.ts +++ b/src/core/packages/application/browser-mocks/src/application_service.mock.ts @@ -26,24 +26,27 @@ import type { InternalApplicationStart, InternalApplicationSetup, } from '@kbn/core-application-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; type ApplicationServiceContract = PublicMethodsOf; -const createSetupContractMock = (): jest.Mocked => ({ - register: jest.fn(), - registerAppUpdater: jest.fn(), -}); +const createSetupContractMock = (): jest.Mocked => + lazyObject({ + register: jest.fn(), + registerAppUpdater: jest.fn(), + }); -const createInternalSetupContractMock = (): jest.Mocked => ({ - register: jest.fn(), - registerAppUpdater: jest.fn(), -}); +const createInternalSetupContractMock = (): jest.Mocked => + lazyObject({ + register: jest.fn(), + registerAppUpdater: jest.fn(), + }); const createStartContractMock = (): jest.Mocked => { const currentAppId$ = new Subject(); const currentLocation$ = new Subject(); - return { + return lazyObject({ applications$: new BehaviorSubject>(new Map()), currentAppId$: currentAppId$.asObservable(), currentLocation$: currentLocation$.asObservable(), @@ -52,11 +55,11 @@ const createStartContractMock = (): jest.Mocked => { navigateToUrl: jest.fn(), getUrlForApp: jest.fn(), isAppRegistered: jest.fn(), - }; + }); }; const createHistoryMock = (): jest.Mocked => { - return { + return lazyObject({ block: jest.fn(), createHref: jest.fn(), go: jest.fn(), @@ -74,7 +77,7 @@ const createHistoryMock = (): jest.Mocked => { key: '', state: undefined, }, - }; + }); }; const createInternalStartContractMock = ( @@ -85,7 +88,7 @@ const createInternalStartContractMock = ( : new Subject(); const currentLocation$ = new Subject(); - return { + return lazyObject({ applications$: new BehaviorSubject>(new Map()), capabilities: capabilitiesServiceMock.createStartContract().capabilities, currentAppId$: currentAppId$.asObservable(), @@ -97,11 +100,11 @@ const createInternalStartContractMock = ( navigateToApp: jest.fn().mockImplementation((appId) => currentAppId$.next(appId)), navigateToUrl: jest.fn(), history: createHistoryMock(), - }; + }); }; const createAppMountParametersMock = (parts: Partial = {}) => { - const mock: AppMountParameters = { + const mock: AppMountParameters = lazyObject({ element: document.createElement('div'), history: scopedHistoryMock.create(), appBasePath: '/app', @@ -109,15 +112,16 @@ const createAppMountParametersMock = (parts: Partial = {}) = setHeaderActionMenu: jest.fn(), theme$: themeServiceMock.createTheme$(), ...parts, - }; + }); return mock; }; -const createMock = (): jest.Mocked => ({ - setup: jest.fn().mockReturnValue(createInternalSetupContractMock()), - start: jest.fn().mockReturnValue(createInternalStartContractMock()), - stop: jest.fn(), -}); +const createMock = (): jest.Mocked => + lazyObject({ + setup: jest.fn().mockReturnValue(createInternalSetupContractMock()), + start: jest.fn().mockReturnValue(createInternalStartContractMock()), + stop: jest.fn(), + }); export const applicationServiceMock = { create: createMock, diff --git a/src/core/packages/application/browser-mocks/src/scoped_history.mock.ts b/src/core/packages/application/browser-mocks/src/scoped_history.mock.ts index 5110de7bd72b3..930db5bb583ef 100644 --- a/src/core/packages/application/browser-mocks/src/scoped_history.mock.ts +++ b/src/core/packages/application/browser-mocks/src/scoped_history.mock.ts @@ -9,6 +9,7 @@ import type { Location } from 'history'; import type { ScopedHistory } from '@kbn/core-application-browser'; +import { lazyObject } from '@kbn/lazy-object'; export type ScopedHistoryMock = jest.Mocked; @@ -19,7 +20,7 @@ const createMock = ({ key, state, }: Partial = {}) => { - const mock: ScopedHistoryMock = { + const mock: ScopedHistoryMock = lazyObject({ block: jest.fn(), createHref: jest.fn(), createSubHistory: jest.fn(), @@ -38,7 +39,7 @@ const createMock = ({ hash, key, }, - }; + }); return mock; }; diff --git a/src/core/packages/application/browser-mocks/tsconfig.json b/src/core/packages/application/browser-mocks/tsconfig.json index bacadccc2ae35..244e3bb72fbbf 100644 --- a/src/core/packages/application/browser-mocks/tsconfig.json +++ b/src/core/packages/application/browser-mocks/tsconfig.json @@ -19,6 +19,7 @@ "@kbn/core-capabilities-browser-mocks", "@kbn/core-theme-browser-mocks", "@kbn/utility-types", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/core/packages/base/browser-mocks/src/core_context.mock.ts b/src/core/packages/base/browser-mocks/src/core_context.mock.ts index 092c18bfb62f6..7e237081c6ee7 100644 --- a/src/core/packages/base/browser-mocks/src/core_context.mock.ts +++ b/src/core/packages/base/browser-mocks/src/core_context.mock.ts @@ -10,11 +10,12 @@ import type { MockedLogger } from '@kbn/logging-mocks'; import { loggerMock } from '@kbn/logging-mocks'; import type { CoreContext } from '@kbn/core-base-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; function createCoreContext({ production = false }: { production?: boolean } = {}): CoreContext & { logger: MockedLogger; } { - return { + return lazyObject({ coreId: Symbol('core context mock'), logger: loggerMock.create(), env: { @@ -34,7 +35,7 @@ function createCoreContext({ production = false }: { production?: boolean } = {} buildFlavor: 'traditional', }, }, - }; + }); } export const coreContextMock = { diff --git a/src/core/packages/base/browser-mocks/tsconfig.json b/src/core/packages/base/browser-mocks/tsconfig.json index 4dcfe54fc12f5..2c41a94851790 100644 --- a/src/core/packages/base/browser-mocks/tsconfig.json +++ b/src/core/packages/base/browser-mocks/tsconfig.json @@ -12,7 +12,8 @@ ], "kbn_references": [ "@kbn/logging-mocks", - "@kbn/core-base-browser-internal" + "@kbn/core-base-browser-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/base/server-mocks/src/core_context.mock.ts b/src/core/packages/base/server-mocks/src/core_context.mock.ts index fea1e27e08f7b..5a6560068845d 100644 --- a/src/core/packages/base/server-mocks/src/core_context.mock.ts +++ b/src/core/packages/base/server-mocks/src/core_context.mock.ts @@ -13,6 +13,7 @@ import type { LoggerFactory } from '@kbn/logging'; import { loggerMock } from '@kbn/logging-mocks'; import { configServiceMock, createTestEnv } from '@kbn/config-mocks'; import type { CoreContext } from '@kbn/core-base-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; function create({ env = createTestEnv(), @@ -23,7 +24,12 @@ function create({ logger?: jest.Mocked; configService?: jest.Mocked; } = {}): DeeplyMockedKeys { - return { coreId: Symbol(), env: env as DeeplyMockedKeys, logger, configService }; + return lazyObject({ + coreId: Symbol(), + env: env as DeeplyMockedKeys, + logger, + configService, + }); } export const mockCoreContext = { diff --git a/src/core/packages/base/server-mocks/tsconfig.json b/src/core/packages/base/server-mocks/tsconfig.json index 3a197f23863ba..8446c5ddcfa96 100644 --- a/src/core/packages/base/server-mocks/tsconfig.json +++ b/src/core/packages/base/server-mocks/tsconfig.json @@ -17,6 +17,7 @@ "@kbn/logging", "@kbn/logging-mocks", "@kbn/core-base-server-internal", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/core/packages/chrome/browser-mocks/src/chrome_service.mock.ts b/src/core/packages/chrome/browser-mocks/src/chrome_service.mock.ts index f399f01151d22..1555682d6f5a4 100644 --- a/src/core/packages/chrome/browser-mocks/src/chrome_service.mock.ts +++ b/src/core/packages/chrome/browser-mocks/src/chrome_service.mock.ts @@ -12,9 +12,10 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; import type { ChromeBadge, ChromeBreadcrumb } from '@kbn/core-chrome-browser'; import type { ChromeService, InternalChromeStart } from '@kbn/core-chrome-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createStartContractMock = () => { - const startContract: DeeplyMockedKeys = { + const startContract: DeeplyMockedKeys = lazyObject({ getLegacyHeaderComponentForFixedLayout: jest.fn(), getClassicHeaderComponentForGridLayout: jest.fn(), getChromelessHeader: jest.fn(), @@ -22,24 +23,24 @@ const createStartContractMock = () => { getProjectAppMenuComponent: jest.fn(), getProjectHeaderComponentForGridLayout: jest.fn(), getProjectSideNavV2ComponentForGridLayout: jest.fn(), - navLinks: { + navLinks: lazyObject({ getNavLinks$: jest.fn(), has: jest.fn(), get: jest.fn(), - getAll: jest.fn(), + getAll: jest.fn().mockReturnValue([]), enableForcedAppSwitcherNavigation: jest.fn(), getForceAppSwitcherNavigation$: jest.fn(), - }, - recentlyAccessed: { + }), + recentlyAccessed: lazyObject({ add: jest.fn(), get: jest.fn(), get$: jest.fn(), - }, - docTitle: { + }), + docTitle: lazyObject({ change: jest.fn(), reset: jest.fn(), - }, - navControls: { + }), + navControls: lazyObject({ registerLeft: jest.fn(), registerCenter: jest.fn(), registerRight: jest.fn(), @@ -50,39 +51,39 @@ const createStartContractMock = () => { getExtension$: jest.fn(), setHelpMenuLinks: jest.fn(), getHelpMenuLinks$: jest.fn(), - }, + }), setIsVisible: jest.fn(), - getIsVisible$: jest.fn(), - getBadge$: jest.fn(), + getIsVisible$: jest.fn().mockReturnValue(new BehaviorSubject(false)), + getBadge$: jest.fn().mockReturnValue(new BehaviorSubject({} as ChromeBadge)), setBadge: jest.fn(), - getBreadcrumbs$: jest.fn(), + getBreadcrumbs$: jest.fn().mockReturnValue(new BehaviorSubject([{} as ChromeBreadcrumb])), setBreadcrumbs: jest.fn(), - sideNav: { - getIsCollapsed$: jest.fn(), + sideNav: lazyObject({ + getIsCollapsed$: jest.fn().mockReturnValue(new BehaviorSubject(false)), setIsCollapsed: jest.fn(), getPanelSelectedNode$: jest.fn(), setPanelSelectedNode: jest.fn(), getIsFeedbackBtnVisible$: jest.fn(), setIsFeedbackBtnVisible: jest.fn(), - }, - getBreadcrumbsAppendExtensions$: jest.fn(), + }), + getBreadcrumbsAppendExtensions$: jest.fn().mockReturnValue(new BehaviorSubject([])), setBreadcrumbsAppendExtension: jest.fn(), - getGlobalHelpExtensionMenuLinks$: jest.fn(), + getGlobalHelpExtensionMenuLinks$: jest.fn().mockReturnValue(new BehaviorSubject([])), registerGlobalHelpExtensionMenuLink: jest.fn(), - getHelpExtension$: jest.fn(), + getHelpExtension$: jest.fn().mockReturnValue(new BehaviorSubject(undefined)), setHelpExtension: jest.fn(), setHelpMenuLinks: jest.fn(), setHelpSupportUrl: jest.fn(), getHelpSupportUrl$: jest.fn(() => of('https://www.elastic.co/support')), - getCustomNavLink$: jest.fn(), + getCustomNavLink$: jest.fn().mockReturnValue(new BehaviorSubject(undefined)), setCustomNavLink: jest.fn(), setHeaderBanner: jest.fn(), - hasHeaderBanner$: jest.fn(), - getBodyClasses$: jest.fn(), + hasHeaderBanner$: jest.fn().mockReturnValue(new BehaviorSubject(false)), + getBodyClasses$: jest.fn().mockReturnValue(new BehaviorSubject([])), getChromeStyle$: jest.fn(), setChromeStyle: jest.fn(), getActiveSolutionNavId$: jest.fn(), - project: { + project: lazyObject({ setHome: jest.fn(), setCloudUrls: jest.fn(), setProjectName: jest.fn(), @@ -93,30 +94,20 @@ const createStartContractMock = () => { getNavigationTreeUi$: jest.fn(), changeActiveSolutionNavigation: jest.fn(), updateSolutionNavigations: jest.fn(), - }, - }; - startContract.navLinks.getAll.mockReturnValue([]); - startContract.getIsVisible$.mockReturnValue(new BehaviorSubject(false)); - startContract.getBadge$.mockReturnValue(new BehaviorSubject({} as ChromeBadge)); - startContract.getBreadcrumbs$.mockReturnValue(new BehaviorSubject([{} as ChromeBreadcrumb])); - startContract.getBreadcrumbsAppendExtensions$.mockReturnValue(new BehaviorSubject([])); - startContract.getCustomNavLink$.mockReturnValue(new BehaviorSubject(undefined)); - startContract.getGlobalHelpExtensionMenuLinks$.mockReturnValue(new BehaviorSubject([])); - startContract.getHelpExtension$.mockReturnValue(new BehaviorSubject(undefined)); - startContract.getBodyClasses$.mockReturnValue(new BehaviorSubject([])); - startContract.hasHeaderBanner$.mockReturnValue(new BehaviorSubject(false)); - startContract.sideNav.getIsCollapsed$.mockReturnValue(new BehaviorSubject(false)); + }), + }); + return startContract; }; type ChromeServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ setup: jest.fn(), - start: jest.fn(), + start: jest.fn().mockResolvedValue(createStartContractMock()), stop: jest.fn(), - }; - mocked.start.mockResolvedValue(createStartContractMock()); + }); + return mocked; }; diff --git a/src/core/packages/chrome/browser-mocks/tsconfig.json b/src/core/packages/chrome/browser-mocks/tsconfig.json index 2060efb16745f..a7a4826adb74c 100644 --- a/src/core/packages/chrome/browser-mocks/tsconfig.json +++ b/src/core/packages/chrome/browser-mocks/tsconfig.json @@ -15,7 +15,8 @@ "@kbn/utility-types", "@kbn/utility-types-jest", "@kbn/core-chrome-browser", - "@kbn/core-chrome-browser-internal" + "@kbn/core-chrome-browser-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/custom-branding/browser-mocks/custom_branding_service.mock.ts b/src/core/packages/custom-branding/browser-mocks/custom_branding_service.mock.ts index dc05074f476e7..b3ea8f113c5fd 100644 --- a/src/core/packages/custom-branding/browser-mocks/custom_branding_service.mock.ts +++ b/src/core/packages/custom-branding/browser-mocks/custom_branding_service.mock.ts @@ -10,6 +10,7 @@ import { of } from 'rxjs'; import type { CustomBranding } from '@kbn/core-custom-branding-common'; import { serviceContractMock } from './service_contract.mock'; +import { lazyObject } from '@kbn/lazy-object'; const mockCustomBranding: CustomBranding = { logo: 'img.jpg', @@ -20,17 +21,17 @@ const createCustomBrandingMock = (): CustomBranding => { }; const createSetupContractMock = () => { - return { + return lazyObject({ customBranding$: of(createCustomBrandingMock()), hasCustomBranding$: of(false), - }; + }); }; const createStartContractMock = () => { - return { + return lazyObject({ customBranding$: of(createCustomBrandingMock()), hasCustomBranding$: of(false), - }; + }); }; const createMock = () => { diff --git a/src/core/packages/custom-branding/browser-mocks/service_contract.mock.ts b/src/core/packages/custom-branding/browser-mocks/service_contract.mock.ts index 5d638a3fc8eb0..a76eb695204a5 100644 --- a/src/core/packages/custom-branding/browser-mocks/service_contract.mock.ts +++ b/src/core/packages/custom-branding/browser-mocks/service_contract.mock.ts @@ -7,10 +7,12 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { lazyObject } from '@kbn/lazy-object'; + export const serviceContractMock = (): jest.Mocked => { - return { + return lazyObject({ setup: jest.fn(), start: jest.fn(), stop: jest.fn(), - }; + }); }; diff --git a/src/core/packages/custom-branding/browser-mocks/tsconfig.json b/src/core/packages/custom-branding/browser-mocks/tsconfig.json index d422554872c69..d28beef1e4c02 100644 --- a/src/core/packages/custom-branding/browser-mocks/tsconfig.json +++ b/src/core/packages/custom-branding/browser-mocks/tsconfig.json @@ -9,6 +9,7 @@ }, "kbn_references": [ "@kbn/core-custom-branding-common", + "@kbn/lazy-object", ], "include": [ "**/*.ts", diff --git a/src/core/packages/custom-branding/server-mocks/src/custom_branding_service.mock.ts b/src/core/packages/custom-branding/server-mocks/src/custom_branding_service.mock.ts index ca3454be308d3..8394e4a7a61cb 100644 --- a/src/core/packages/custom-branding/server-mocks/src/custom_branding_service.mock.ts +++ b/src/core/packages/custom-branding/server-mocks/src/custom_branding_service.mock.ts @@ -8,12 +8,13 @@ */ import { serviceContractMock } from './service_contract.mock'; +import { lazyObject } from '@kbn/lazy-object'; const createSetupContractMock = () => { - return { + return lazyObject({ register: jest.fn(), getBrandingFor: jest.fn(), - }; + }); }; const createStartContractMock = () => { diff --git a/src/core/packages/custom-branding/server-mocks/src/service_contract.mock.ts b/src/core/packages/custom-branding/server-mocks/src/service_contract.mock.ts index 03b1e0014d32d..4994c5b5538d1 100644 --- a/src/core/packages/custom-branding/server-mocks/src/service_contract.mock.ts +++ b/src/core/packages/custom-branding/server-mocks/src/service_contract.mock.ts @@ -8,11 +8,12 @@ */ import type { CustomBrandingService } from '@kbn/core-custom-branding-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; export const serviceContractMock = (): jest.Mocked => { - return { + return lazyObject({ setup: jest.fn(), start: jest.fn(), stop: jest.fn(), - } as unknown as jest.Mocked; + }) as unknown as jest.Mocked; }; diff --git a/src/core/packages/custom-branding/server-mocks/tsconfig.json b/src/core/packages/custom-branding/server-mocks/tsconfig.json index 23b5924ecb761..50819a6b8b32c 100644 --- a/src/core/packages/custom-branding/server-mocks/tsconfig.json +++ b/src/core/packages/custom-branding/server-mocks/tsconfig.json @@ -9,6 +9,7 @@ }, "kbn_references": [ "@kbn/core-custom-branding-server-internal", + "@kbn/lazy-object", ], "include": [ "**/*.ts", diff --git a/src/core/packages/data-streams/server-mocks/index.ts b/src/core/packages/data-streams/server-mocks/index.ts index f34b8e90dd890..436bd67b89d90 100644 --- a/src/core/packages/data-streams/server-mocks/index.ts +++ b/src/core/packages/data-streams/server-mocks/index.ts @@ -8,13 +8,16 @@ */ import type { DataStreamsStart, DataStreamsSetup } from '@kbn/core-data-streams-server'; +import { lazyObject } from '@kbn/lazy-object'; export const dataStreamServiceMock = { - createSetupContract: (): jest.Mocked => ({ - registerDataStream: jest.fn(), - }), + createSetupContract: (): jest.Mocked => + lazyObject({ + registerDataStream: jest.fn(), + }), - createStartContract: (): jest.Mocked => ({ - getClient: jest.fn(), // TODO improve this - }), + createStartContract: (): jest.Mocked => + lazyObject({ + getClient: jest.fn(), // TODO improve this + }), }; diff --git a/src/core/packages/data-streams/server-mocks/tsconfig.json b/src/core/packages/data-streams/server-mocks/tsconfig.json index e7492d9dccc4c..155c128f0f700 100644 --- a/src/core/packages/data-streams/server-mocks/tsconfig.json +++ b/src/core/packages/data-streams/server-mocks/tsconfig.json @@ -15,5 +15,6 @@ ], "kbn_references": [ "@kbn/core-data-streams-server", + "@kbn/lazy-object", ] } diff --git a/src/core/packages/deprecations/browser-mocks/src/deprecations_service.mock.ts b/src/core/packages/deprecations/browser-mocks/src/deprecations_service.mock.ts index 3f73eef971a73..f88fc4a8c2623 100644 --- a/src/core/packages/deprecations/browser-mocks/src/deprecations_service.mock.ts +++ b/src/core/packages/deprecations/browser-mocks/src/deprecations_service.mock.ts @@ -10,23 +10,23 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import type { DeprecationsService } from '@kbn/core-deprecations-browser-internal'; import type { DeprecationsServiceStart } from '@kbn/core-deprecations-browser'; +import { lazyObject } from '@kbn/lazy-object'; -const createServiceMock = (): jest.Mocked => ({ - getAllDeprecations: jest.fn().mockResolvedValue([]), - getDeprecations: jest.fn().mockResolvedValue([]), - isDeprecationResolvable: jest.fn().mockReturnValue(false), - resolveDeprecation: jest.fn().mockResolvedValue({ status: 'ok', payload: {} }), -}); +const createServiceMock = (): jest.Mocked => + lazyObject({ + getAllDeprecations: jest.fn().mockResolvedValue([]), + getDeprecations: jest.fn().mockResolvedValue([]), + isDeprecationResolvable: jest.fn().mockReturnValue(false), + resolveDeprecation: jest.fn().mockResolvedValue({ status: 'ok', payload: {} }), + }); const createMock = () => { - const mocked: jest.Mocked> = { - setup: jest.fn(), - start: jest.fn(), + const mocked: jest.Mocked> = lazyObject({ + setup: jest.fn().mockReturnValue(void 0), + start: jest.fn().mockReturnValue(createServiceMock()), stop: jest.fn(), - }; + }); - mocked.setup.mockReturnValue(void 0); - mocked.start.mockReturnValue(createServiceMock()); return mocked; }; diff --git a/src/core/packages/deprecations/browser-mocks/tsconfig.json b/src/core/packages/deprecations/browser-mocks/tsconfig.json index 7a0a872036228..31b3755196b54 100644 --- a/src/core/packages/deprecations/browser-mocks/tsconfig.json +++ b/src/core/packages/deprecations/browser-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-deprecations-browser", - "@kbn/core-deprecations-browser-internal" + "@kbn/core-deprecations-browser-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/deprecations/server-mocks/src/deprecations_service.mock.ts b/src/core/packages/deprecations/server-mocks/src/deprecations_service.mock.ts index 3ce14545752c9..6118b4f199ae7 100644 --- a/src/core/packages/deprecations/server-mocks/src/deprecations_service.mock.ts +++ b/src/core/packages/deprecations/server-mocks/src/deprecations_service.mock.ts @@ -14,21 +14,22 @@ import type { InternalDeprecationsServiceSetup, InternalDeprecationsServiceStart, } from '@kbn/core-deprecations-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; type DeprecationsServiceContract = PublicMethodsOf; const createSetupContractMock = () => { - const setupContract: jest.Mocked = { + const setupContract: jest.Mocked = lazyObject({ registerDeprecations: jest.fn(), - }; + }); return setupContract; }; const createStartContractMock = () => { - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ asScopedToClient: jest.fn(), - }; + }); mocked.asScopedToClient.mockReturnValue(createClientMock()); @@ -36,30 +37,29 @@ const createStartContractMock = () => { }; const createInternalSetupContractMock = () => { - const internalSetupContract: jest.Mocked = { + const internalSetupContract: jest.Mocked = lazyObject({ getRegistry: jest.fn(), - }; + }); internalSetupContract.getRegistry.mockReturnValue(createSetupContractMock()); return internalSetupContract; }; const createDeprecationsServiceMock = () => { - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ setup: jest.fn(), start: jest.fn(), stop: jest.fn(), - }; + }); mocked.setup.mockResolvedValue(createInternalSetupContractMock()); return mocked; }; const createClientMock = () => { - const mocked: jest.Mocked = { - getAllDeprecations: jest.fn(), - }; - mocked.getAllDeprecations.mockResolvedValue([]); + const mocked: jest.Mocked = lazyObject({ + getAllDeprecations: jest.fn().mockResolvedValue([]), + }); return mocked; }; diff --git a/src/core/packages/deprecations/server-mocks/tsconfig.json b/src/core/packages/deprecations/server-mocks/tsconfig.json index ff5f16e5a0be4..428b8d5e24f59 100644 --- a/src/core/packages/deprecations/server-mocks/tsconfig.json +++ b/src/core/packages/deprecations/server-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-deprecations-server", - "@kbn/core-deprecations-server-internal" + "@kbn/core-deprecations-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/di/mocks/src/service.mock.ts b/src/core/packages/di/mocks/src/service.mock.ts index f565c3272dd67..7c942489cf84a 100644 --- a/src/core/packages/di/mocks/src/service.mock.ts +++ b/src/core/packages/di/mocks/src/service.mock.ts @@ -16,12 +16,13 @@ import type { InternalCoreDiServiceStart, } from '@kbn/core-di-internal'; import type { MethodKeysOf, PublicMethodsOf } from '@kbn/utility-types'; +import { lazyObject } from '@kbn/lazy-object'; function create(): jest.Mocked> { - return { + return lazyObject({ setup: jest.fn(createInternalSetupContract), start: jest.fn(createInternalStartContract), - }; + }); } function createContainer() { @@ -36,15 +37,15 @@ function createContainer() { } function createSetupContract(): jest.MockedObjectDeep { - return { + return lazyObject({ getContainer: jest.fn().mockImplementation(once(createContainer)), - }; + }); } function createStartContract(): jest.MockedObjectDeep { const getContainer = once(createContainer); - return { + return lazyObject({ fork: jest.fn().mockImplementation( once(() => { const container = new Container({ defaultScope: 'Singleton', parent: getContainer() }); @@ -54,7 +55,7 @@ function createStartContract(): jest.MockedObjectDeep { }) ), getContainer: jest.fn().mockImplementation(getContainer), - }; + }); } function createInternalSetupContract(): jest.MockedObjectDeep { diff --git a/src/core/packages/di/mocks/tsconfig.json b/src/core/packages/di/mocks/tsconfig.json index 7aa060e602c85..87e30d20b9b63 100644 --- a/src/core/packages/di/mocks/tsconfig.json +++ b/src/core/packages/di/mocks/tsconfig.json @@ -17,5 +17,6 @@ "@kbn/core-di", "@kbn/core-di-internal", "@kbn/utility-types", + "@kbn/lazy-object", ] } diff --git a/src/core/packages/doc-links/browser-mocks/src/doc_links_service.mock.ts b/src/core/packages/doc-links/browser-mocks/src/doc_links_service.mock.ts index fabc7c57e3cc6..6293fac871e68 100644 --- a/src/core/packages/doc-links/browser-mocks/src/doc_links_service.mock.ts +++ b/src/core/packages/doc-links/browser-mocks/src/doc_links_service.mock.ts @@ -12,6 +12,7 @@ import { coreContextMock } from '@kbn/core-base-browser-mocks'; import { injectedMetadataServiceMock } from '@kbn/core-injected-metadata-browser-mocks'; import type { DocLinksStart } from '@kbn/core-doc-links-browser'; import { DocLinksService } from '@kbn/core-doc-links-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createStartContractMock = (): DocLinksStart => { // This service is so simple that we actually use the real implementation @@ -21,10 +22,11 @@ const createStartContractMock = (): DocLinksStart => { }; type DocLinksServiceContract = PublicMethodsOf; -const createMock = (): jest.Mocked => ({ - setup: jest.fn().mockReturnValue(undefined), - start: jest.fn().mockReturnValue(createStartContractMock()), -}); +const createMock = (): jest.Mocked => + lazyObject({ + setup: jest.fn().mockReturnValue(undefined), + start: jest.fn().mockReturnValue(createStartContractMock()), + }); export const docLinksServiceMock = { create: createMock, diff --git a/src/core/packages/doc-links/browser-mocks/tsconfig.json b/src/core/packages/doc-links/browser-mocks/tsconfig.json index b046866d6ee95..d917a4ce15ed6 100644 --- a/src/core/packages/doc-links/browser-mocks/tsconfig.json +++ b/src/core/packages/doc-links/browser-mocks/tsconfig.json @@ -15,7 +15,8 @@ "@kbn/core-injected-metadata-browser-mocks", "@kbn/core-doc-links-browser", "@kbn/core-doc-links-browser-internal", - "@kbn/core-base-browser-mocks" + "@kbn/core-base-browser-mocks", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/elasticsearch/client-server-mocks/src/agent_manager.mocks.ts b/src/core/packages/elasticsearch/client-server-mocks/src/agent_manager.mocks.ts index 7cf5c13d74bee..ba5e38c6bacd9 100644 --- a/src/core/packages/elasticsearch/client-server-mocks/src/agent_manager.mocks.ts +++ b/src/core/packages/elasticsearch/client-server-mocks/src/agent_manager.mocks.ts @@ -8,7 +8,9 @@ */ import type { AgentStatsProvider } from '@kbn/core-elasticsearch-client-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; -export const createAgentStatsProviderMock = (): jest.Mocked => ({ - getAgentsStats: jest.fn(), -}); +export const createAgentStatsProviderMock = (): jest.Mocked => + lazyObject({ + getAgentsStats: jest.fn(), + }); diff --git a/src/core/packages/elasticsearch/client-server-mocks/src/mocks.ts b/src/core/packages/elasticsearch/client-server-mocks/src/mocks.ts index a14c32a436a26..587c93396c09b 100644 --- a/src/core/packages/elasticsearch/client-server-mocks/src/mocks.ts +++ b/src/core/packages/elasticsearch/client-server-mocks/src/mocks.ts @@ -11,6 +11,7 @@ import type { Client, TransportResult, TransportRequestOptions } from '@elastic/ import type { PublicKeys } from '@kbn/utility-types'; import type { ElasticsearchClient, ICustomClusterClient } from '@kbn/core-elasticsearch-server'; import { PRODUCT_RESPONSE_HEADER } from '@kbn/core-elasticsearch-client-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; const omittedProps = [ 'diagnostic', @@ -196,11 +197,11 @@ export interface ScopedClusterClientMock { } const createScopedClusterClientMock = () => { - const mock: ScopedClusterClientMock = { + const mock: ScopedClusterClientMock = lazyObject({ asInternalUser: createClientMock(), asCurrentUser: createClientMock(), asSecondaryAuthUser: createClientMock(), - }; + }); return mock; }; @@ -211,12 +212,10 @@ export interface ClusterClientMock { } const createClusterClientMock = () => { - const mock: ClusterClientMock = { + const mock: ClusterClientMock = lazyObject({ asInternalUser: createClientMock(), - asScoped: jest.fn(), - }; - - mock.asScoped.mockReturnValue(createScopedClusterClientMock()); + asScoped: jest.fn().mockReturnValue(createScopedClusterClientMock()), + }); return mock; }; @@ -224,14 +223,11 @@ const createClusterClientMock = () => { export type CustomClusterClientMock = jest.Mocked & ClusterClientMock; const createCustomClusterClientMock = () => { - const mock: CustomClusterClientMock = { + const mock: CustomClusterClientMock = lazyObject({ asInternalUser: createClientMock(), - asScoped: jest.fn(), - close: jest.fn(), - }; - - mock.asScoped.mockReturnValue(createScopedClusterClientMock()); - mock.close.mockReturnValue(Promise.resolve()); + asScoped: jest.fn().mockReturnValue(createScopedClusterClientMock()), + close: jest.fn().mockResolvedValue(Promise.resolve()), + }); return mock; }; diff --git a/src/core/packages/elasticsearch/client-server-mocks/tsconfig.json b/src/core/packages/elasticsearch/client-server-mocks/tsconfig.json index 61799067833c0..057e590b0cf7d 100644 --- a/src/core/packages/elasticsearch/client-server-mocks/tsconfig.json +++ b/src/core/packages/elasticsearch/client-server-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-elasticsearch-server", - "@kbn/core-elasticsearch-client-server-internal" + "@kbn/core-elasticsearch-client-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/elasticsearch/server-mocks/src/elasticsearch_service.mock.ts b/src/core/packages/elasticsearch/server-mocks/src/elasticsearch_service.mock.ts index 50dbd26b585e8..b1256939f7f9b 100644 --- a/src/core/packages/elasticsearch/server-mocks/src/elasticsearch_service.mock.ts +++ b/src/core/packages/elasticsearch/server-mocks/src/elasticsearch_service.mock.ts @@ -33,6 +33,7 @@ import type { ClusterInfo, } from '@kbn/core-elasticsearch-server-internal'; import { type ServiceStatus, ServiceStatusLevels } from '@kbn/core-status-common'; +import { lazyObject } from '@kbn/lazy-object'; type MockedElasticSearchServicePreboot = jest.Mocked; @@ -54,29 +55,29 @@ export type MockedElasticSearchServiceStart = jest.Mocked< }; const createPrebootContractMock = () => { - const prebootContract: MockedElasticSearchServicePreboot = { + const prebootContract: MockedElasticSearchServicePreboot = lazyObject({ config: { hosts: [], credentialsSpecified: false }, createClient: jest.fn((type: string) => elasticsearchClientMock.createCustomClusterClient()), - }; + }); return prebootContract; }; const createSetupContractMock = () => { - const setupContract: MockedElasticSearchServiceSetup = { + const setupContract: MockedElasticSearchServiceSetup = lazyObject({ setUnauthorizedErrorHandler: jest.fn(), legacy: { config$: new BehaviorSubject({} as ElasticsearchConfig), }, - }; + }); return setupContract; }; const createStartContractMock = () => { - const startContract: MockedElasticSearchServiceStart = { + const startContract: MockedElasticSearchServiceStart = lazyObject({ client: elasticsearchClientMock.createClusterClient(), createClient: jest.fn((type: string) => elasticsearchClientMock.createCustomClusterClient()), getCapabilities: jest.fn().mockReturnValue(createCapabilities()), - }; + }); return startContract; }; @@ -85,7 +86,7 @@ const createInternalPrebootContractMock = createPrebootContractMock; type MockedInternalElasticSearchServiceSetup = jest.Mocked; const createInternalSetupContractMock = () => { const setupContract = createSetupContractMock(); - const internalSetupContract: MockedInternalElasticSearchServiceSetup = { + const internalSetupContract: MockedInternalElasticSearchServiceSetup = lazyObject({ ...setupContract, esNodesCompatibility$: new BehaviorSubject({ isCompatible: true, @@ -104,7 +105,7 @@ const createInternalSetupContractMock = () => { summary: 'Elasticsearch is available', }), agentStatsProvider: createAgentStatsProviderMock(), - }; + }); return internalSetupContract; }; @@ -115,27 +116,23 @@ type MockedInternalElasticsearchServiceStart = jest.Mocked< const createInternalStartContractMock = () => { const startContract = createStartContractMock(); - const internalStartContractMock: MockedInternalElasticsearchServiceStart = { + const internalStartContractMock: MockedInternalElasticsearchServiceStart = lazyObject({ ...startContract, metrics: { elasticsearchWaitTime: 0, }, - }; + }); return internalStartContractMock; }; type ElasticsearchServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { - preboot: jest.fn(), - setup: jest.fn(), - start: jest.fn(), - stop: jest.fn(), - }; - mocked.preboot.mockResolvedValue(createInternalPrebootContractMock()); - mocked.setup.mockResolvedValue(createInternalSetupContractMock()); - mocked.start.mockResolvedValueOnce(createInternalStartContractMock()); - mocked.stop.mockResolvedValue(); + const mocked: jest.Mocked = lazyObject({ + preboot: jest.fn().mockResolvedValue(createInternalPrebootContractMock()), + setup: jest.fn().mockResolvedValue(createInternalSetupContractMock()), + start: jest.fn().mockResolvedValue(createInternalStartContractMock()), + stop: jest.fn().mockResolvedValue(void 0), + }); return mocked; }; diff --git a/src/core/packages/elasticsearch/server-mocks/tsconfig.json b/src/core/packages/elasticsearch/server-mocks/tsconfig.json index 4eca61039c1d0..98d69f5e0d74a 100644 --- a/src/core/packages/elasticsearch/server-mocks/tsconfig.json +++ b/src/core/packages/elasticsearch/server-mocks/tsconfig.json @@ -15,7 +15,8 @@ "@kbn/core-status-common", "@kbn/core-elasticsearch-server", "@kbn/core-elasticsearch-client-server-mocks", - "@kbn/core-elasticsearch-server-internal" + "@kbn/core-elasticsearch-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/environment/server-mocks/src/environment_service.mock.ts b/src/core/packages/environment/server-mocks/src/environment_service.mock.ts index 2fd18d40b3fd6..002f1cb2692a3 100644 --- a/src/core/packages/environment/server-mocks/src/environment_service.mock.ts +++ b/src/core/packages/environment/server-mocks/src/environment_service.mock.ts @@ -13,29 +13,28 @@ import type { InternalEnvironmentServicePreboot, InternalEnvironmentServiceSetup, } from '@kbn/core-environment-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createPrebootContractMock = () => { - const prebootContract: jest.Mocked = { + const prebootContract: jest.Mocked = lazyObject({ instanceUuid: 'uuid', - }; + }); return prebootContract; }; const createSetupContractMock = () => { - const prebootContract: jest.Mocked = { + const prebootContract: jest.Mocked = lazyObject({ instanceUuid: 'uuid', - }; + }); return prebootContract; }; type EnvironmentServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { - preboot: jest.fn(), - setup: jest.fn(), - }; - mocked.preboot.mockResolvedValue(createPrebootContractMock()); - mocked.setup.mockReturnValue(createSetupContractMock()); + const mocked: jest.Mocked = lazyObject({ + preboot: jest.fn().mockResolvedValue(createPrebootContractMock()), + setup: jest.fn().mockReturnValue(createSetupContractMock()), + }); return mocked; }; diff --git a/src/core/packages/environment/server-mocks/tsconfig.json b/src/core/packages/environment/server-mocks/tsconfig.json index 0e378151035bf..4029af8ea4171 100644 --- a/src/core/packages/environment/server-mocks/tsconfig.json +++ b/src/core/packages/environment/server-mocks/tsconfig.json @@ -12,7 +12,8 @@ ], "kbn_references": [ "@kbn/utility-types", - "@kbn/core-environment-server-internal" + "@kbn/core-environment-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/execution-context/browser-mocks/src/execution_context_service.mock.ts b/src/core/packages/execution-context/browser-mocks/src/execution_context_service.mock.ts index aea9c9ee1497d..98e4411871ecb 100644 --- a/src/core/packages/execution-context/browser-mocks/src/execution_context_service.mock.ts +++ b/src/core/packages/execution-context/browser-mocks/src/execution_context_service.mock.ts @@ -11,21 +11,24 @@ import { BehaviorSubject } from 'rxjs'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { ExecutionContextSetup } from '@kbn/core-execution-context-browser'; import type { ExecutionContextService } from '@kbn/core-execution-context-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; -const createContractMock = (): jest.Mocked => ({ - context$: new BehaviorSubject({}), - clear: jest.fn(), - set: jest.fn(), - get: jest.fn(), - getAsLabels: jest.fn(), - withGlobalContext: jest.fn(), -}); +const createContractMock = (): jest.Mocked => + lazyObject({ + context$: new BehaviorSubject({}), + clear: jest.fn(), + set: jest.fn(), + get: jest.fn(), + getAsLabels: jest.fn(), + withGlobalContext: jest.fn(), + }); -const createMock = (): jest.Mocked> => ({ - setup: jest.fn().mockReturnValue(createContractMock()), - start: jest.fn().mockReturnValue(createContractMock()), - stop: jest.fn(), -}); +const createMock = (): jest.Mocked> => + lazyObject({ + setup: jest.fn().mockReturnValue(createContractMock()), + start: jest.fn().mockReturnValue(createContractMock()), + stop: jest.fn(), + }); export const executionContextServiceMock = { create: createMock, diff --git a/src/core/packages/execution-context/browser-mocks/tsconfig.json b/src/core/packages/execution-context/browser-mocks/tsconfig.json index 3eca1997ce4c6..3ec1ac9789f37 100644 --- a/src/core/packages/execution-context/browser-mocks/tsconfig.json +++ b/src/core/packages/execution-context/browser-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-execution-context-browser", - "@kbn/core-execution-context-browser-internal" + "@kbn/core-execution-context-browser-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/fatal-errors/browser-mocks/src/fatal_errors_service.mock.ts b/src/core/packages/fatal-errors/browser-mocks/src/fatal_errors_service.mock.ts index a0dfdfdd938dd..dedd1cdb6edd1 100644 --- a/src/core/packages/fatal-errors/browser-mocks/src/fatal_errors_service.mock.ts +++ b/src/core/packages/fatal-errors/browser-mocks/src/fatal_errors_service.mock.ts @@ -10,12 +10,13 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import type { FatalErrorsSetup } from '@kbn/core-fatal-errors-browser'; import type { FatalErrorsService } from '@kbn/core-fatal-errors-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createSetupContractMock = () => { - const setupContract: jest.Mocked = { + const setupContract: jest.Mocked = lazyObject({ add: jest.fn(), catch: jest.fn(), - }; + }); return setupContract; }; @@ -23,13 +24,11 @@ const createStartContractMock = createSetupContractMock; type FatalErrorsServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { - setup: jest.fn(), - start: jest.fn(), - }; + const mocked: jest.Mocked = lazyObject({ + setup: jest.fn().mockReturnValue(createSetupContractMock()), + start: jest.fn().mockReturnValue(createStartContractMock()), + }); - mocked.setup.mockReturnValue(createSetupContractMock()); - mocked.start.mockReturnValue(createStartContractMock()); return mocked; }; diff --git a/src/core/packages/fatal-errors/browser-mocks/tsconfig.json b/src/core/packages/fatal-errors/browser-mocks/tsconfig.json index e131d23d28c28..62a77fb006f98 100644 --- a/src/core/packages/fatal-errors/browser-mocks/tsconfig.json +++ b/src/core/packages/fatal-errors/browser-mocks/tsconfig.json @@ -14,7 +14,8 @@ "kbn_references": [ "@kbn/core-fatal-errors-browser", "@kbn/core-fatal-errors-browser-internal", - "@kbn/utility-types" + "@kbn/utility-types", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/feature-flags/browser-mocks/index.ts b/src/core/packages/feature-flags/browser-mocks/index.ts index 715fa7237416e..78a6227e5c503 100644 --- a/src/core/packages/feature-flags/browser-mocks/index.ts +++ b/src/core/packages/feature-flags/browser-mocks/index.ts @@ -11,17 +11,18 @@ import type { FeatureFlagsSetup, FeatureFlagsStart } from '@kbn/core-feature-fla import type { FeatureFlagsService } from '@kbn/core-feature-flags-browser-internal'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { of } from 'rxjs'; +import { lazyObject } from '@kbn/lazy-object'; const createFeatureFlagsSetup = (): jest.Mocked => { - return { + return lazyObject({ getInitialFeatureFlags: jest.fn().mockImplementation(() => ({})), setProvider: jest.fn(), appendContext: jest.fn().mockImplementation(Promise.resolve), - }; + }); }; const createFeatureFlagsStart = (): jest.Mocked => { - return { + return lazyObject({ appendContext: jest.fn().mockImplementation(Promise.resolve), getBooleanValue: jest.fn().mockImplementation((_, fallback) => fallback), getNumberValue: jest.fn().mockImplementation((_, fallback) => fallback), @@ -29,15 +30,15 @@ const createFeatureFlagsStart = (): jest.Mocked => { getBooleanValue$: jest.fn().mockImplementation((_, fallback) => of(fallback)), getStringValue$: jest.fn().mockImplementation((_, fallback) => of(fallback)), getNumberValue$: jest.fn().mockImplementation((_, fallback) => of(fallback)), - }; + }); }; const createFeatureFlagsServiceMock = (): jest.Mocked> => { - return { + return lazyObject({ setup: jest.fn().mockImplementation(createFeatureFlagsSetup), start: jest.fn().mockImplementation(async () => createFeatureFlagsStart()), stop: jest.fn().mockImplementation(Promise.resolve), - }; + }); }; /** diff --git a/src/core/packages/feature-flags/browser-mocks/tsconfig.json b/src/core/packages/feature-flags/browser-mocks/tsconfig.json index d1c8f6d2b668e..3af66adce1ebd 100644 --- a/src/core/packages/feature-flags/browser-mocks/tsconfig.json +++ b/src/core/packages/feature-flags/browser-mocks/tsconfig.json @@ -19,5 +19,6 @@ "@kbn/core-feature-flags-browser", "@kbn/core-feature-flags-browser-internal", "@kbn/utility-types", + "@kbn/lazy-object", ] } diff --git a/src/core/packages/http/browser-mocks/src/base_path.mock.ts b/src/core/packages/http/browser-mocks/src/base_path.mock.ts index c835e4d40d742..9f3385a5359af 100644 --- a/src/core/packages/http/browser-mocks/src/base_path.mock.ts +++ b/src/core/packages/http/browser-mocks/src/base_path.mock.ts @@ -8,20 +8,21 @@ */ import type { IBasePath } from '@kbn/core-http-browser'; +import { lazyObject } from '@kbn/lazy-object'; const createBasePathMock = ({ publicBaseUrl = '/', serverBasePath = '/', assetsHrefBase = '/', }: { publicBaseUrl?: string; serverBasePath?: string; assetsHrefBase?: string } = {}) => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ prepend: jest.fn(), get: jest.fn(), remove: jest.fn(), publicBaseUrl, serverBasePath, assetsHrefBase, - }; + }); return mock; }; diff --git a/src/core/packages/http/browser-mocks/src/http_service.mock.ts b/src/core/packages/http/browser-mocks/src/http_service.mock.ts index ee30572ddeca7..a61dd4069f76d 100644 --- a/src/core/packages/http/browser-mocks/src/http_service.mock.ts +++ b/src/core/packages/http/browser-mocks/src/http_service.mock.ts @@ -12,6 +12,7 @@ import { type HttpService, BasePath } from '@kbn/core-http-browser-internal'; import type { HttpSetup } from '@kbn/core-http-browser'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { basePathMock } from './base_path.mock'; +import { lazyObject } from '@kbn/lazy-object'; export type HttpSetupMock = jest.Mocked & { basePath: BasePath; @@ -21,43 +22,42 @@ export type HttpSetupMock = jest.Mocked & { const createServiceMock = ({ basePath = '', publicBaseUrl, -}: { basePath?: string; publicBaseUrl?: string } = {}): HttpSetupMock => ({ - fetch: jest.fn(), - get: jest.fn(), - head: jest.fn(), - post: jest.fn(), - put: jest.fn(), - patch: jest.fn(), - delete: jest.fn(), - options: jest.fn(), - basePath: new BasePath({ - basePath, - publicBaseUrl, - }), - anonymousPaths: { - register: jest.fn(), - isAnonymous: jest.fn(), - }, - externalUrl: { - isInternalUrl: jest.fn(), - validateUrl: jest.fn(), - }, - staticAssets: { - getPluginAssetHref: jest.fn(), - }, - addLoadingCountSource: jest.fn(), - getLoadingCount$: jest.fn().mockReturnValue(new BehaviorSubject(0)), - intercept: jest.fn(), -}); +}: { basePath?: string; publicBaseUrl?: string } = {}): HttpSetupMock => + lazyObject({ + fetch: jest.fn(), + get: jest.fn(), + head: jest.fn(), + post: jest.fn(), + put: jest.fn(), + patch: jest.fn(), + delete: jest.fn(), + options: jest.fn(), + basePath: new BasePath({ + basePath, + publicBaseUrl, + }), + anonymousPaths: lazyObject({ + register: jest.fn(), + isAnonymous: jest.fn(), + }), + externalUrl: lazyObject({ + isInternalUrl: jest.fn(), + validateUrl: jest.fn(), + }), + staticAssets: lazyObject({ + getPluginAssetHref: jest.fn(), + }), + addLoadingCountSource: jest.fn(), + getLoadingCount$: jest.fn().mockReturnValue(new BehaviorSubject(0)), + intercept: jest.fn(), + }); const createMock = ({ basePath = '' } = {}) => { - const mocked: jest.Mocked> = { - setup: jest.fn(), - start: jest.fn(), + const mocked: jest.Mocked> = lazyObject({ + setup: jest.fn().mockReturnValue(createServiceMock({ basePath })), + start: jest.fn().mockReturnValue(createServiceMock({ basePath })), stop: jest.fn(), - }; - mocked.setup.mockReturnValue(createServiceMock({ basePath })); - mocked.start.mockReturnValue(createServiceMock({ basePath })); + }); return mocked; }; diff --git a/src/core/packages/http/browser-mocks/tsconfig.json b/src/core/packages/http/browser-mocks/tsconfig.json index fb7bfee7db8cc..7812c298b2966 100644 --- a/src/core/packages/http/browser-mocks/tsconfig.json +++ b/src/core/packages/http/browser-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-http-browser-internal", - "@kbn/core-http-browser" + "@kbn/core-http-browser", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/http/context-server-mocks/src/context_container.mock.ts b/src/core/packages/http/context-server-mocks/src/context_container.mock.ts index b44785abcb2fd..e7cfcef754d76 100644 --- a/src/core/packages/http/context-server-mocks/src/context_container.mock.ts +++ b/src/core/packages/http/context-server-mocks/src/context_container.mock.ts @@ -7,20 +7,26 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { IContextContainer } from '@kbn/core-http-server'; +import type { + IContextContainer, + KibanaRequest, + KibanaResponseFactory, +} from '@kbn/core-http-server'; +import { lazyObject } from '@kbn/lazy-object'; export type ContextContainerMock = jest.Mocked; const createContextMock = (mockContext: any = {}) => { - const contextMock: ContextContainerMock = { + const contextMock: ContextContainerMock = lazyObject({ registerContext: jest.fn(), - createHandler: jest.fn(), - }; - contextMock.createHandler.mockImplementation( - (pluginId, handler) => - (...args) => - Promise.resolve(handler(mockContext, ...args)) - ); + createHandler: jest.fn().mockImplementation( + (pluginId, handler) => + ( + ...args: [KibanaRequest, response: KibanaResponseFactory] + ) => + Promise.resolve(handler(mockContext, ...args)) + ), + }); return contextMock; }; diff --git a/src/core/packages/http/context-server-mocks/src/context_service.mock.ts b/src/core/packages/http/context-server-mocks/src/context_service.mock.ts index 435fb20a576af..3294b3a8949fb 100644 --- a/src/core/packages/http/context-server-mocks/src/context_service.mock.ts +++ b/src/core/packages/http/context-server-mocks/src/context_service.mock.ts @@ -14,29 +14,29 @@ import type { InternalContextPreboot, } from '@kbn/core-http-context-server-internal'; import { contextMock } from './context_container.mock'; +import { lazyObject } from '@kbn/lazy-object'; const createPrebootContractMock = (mockContext = {}) => { - const prebootContract: jest.Mocked = { + const prebootContract: jest.Mocked = lazyObject({ createContextContainer: jest.fn().mockImplementation(() => contextMock.create(mockContext)), - }; + }); return prebootContract; }; const createSetupContractMock = (mockContext = {}) => { - const setupContract: jest.Mocked = { + const setupContract: jest.Mocked = lazyObject({ createContextContainer: jest.fn().mockImplementation(() => contextMock.create(mockContext)), - }; + }); return setupContract; }; type ContextServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { - preboot: jest.fn(), - setup: jest.fn(), - }; - mocked.preboot.mockReturnValue(createPrebootContractMock()); - mocked.setup.mockReturnValue(createSetupContractMock()); + const mocked: jest.Mocked = lazyObject({ + preboot: jest.fn().mockReturnValue(createPrebootContractMock()), + setup: jest.fn().mockReturnValue(createSetupContractMock()), + }); + return mocked; }; diff --git a/src/core/packages/http/context-server-mocks/tsconfig.json b/src/core/packages/http/context-server-mocks/tsconfig.json index 7c27c8fe6b352..5590de3bf8335 100644 --- a/src/core/packages/http/context-server-mocks/tsconfig.json +++ b/src/core/packages/http/context-server-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-http-server", - "@kbn/core-http-context-server-internal" + "@kbn/core-http-context-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/http/resources-server-mocks/src/http_resources_server.mock.ts b/src/core/packages/http/resources-server-mocks/src/http_resources_server.mock.ts index c839ff57c250d..74a291ab25a25 100644 --- a/src/core/packages/http/resources-server-mocks/src/http_resources_server.mock.ts +++ b/src/core/packages/http/resources-server-mocks/src/http_resources_server.mock.ts @@ -11,16 +11,17 @@ import { httpServerMock } from '@kbn/core-http-server-mocks'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { HttpResourcesService } from '@kbn/core-http-resources-server-internal'; import type { HttpResources, HttpResourcesServiceToolkit } from '@kbn/core-http-resources-server'; +import { lazyObject } from '@kbn/lazy-object'; export type HttpResourcesMock = jest.Mocked>; function createHttpResourcesService() { - const mock: HttpResourcesMock = { + const mock: HttpResourcesMock = lazyObject({ preboot: jest.fn(), setup: jest.fn(), start: jest.fn(), stop: jest.fn(), - }; + }); mock.preboot.mockReturnValue(createInternalHttpResourcesPreboot()); mock.setup.mockReturnValue(createInternalHttpResourcesSetup()); @@ -28,14 +29,15 @@ function createHttpResourcesService() { return mock; } -const createHttpResourcesMock = (): jest.Mocked => ({ - register: jest.fn(), -}); +const createHttpResourcesMock = (): jest.Mocked => + lazyObject({ + register: jest.fn(), + }); function createInternalHttpResourcesPreboot() { - return { + return lazyObject({ createRegistrar: jest.fn(() => createHttpResourcesMock()), - }; + }); } function createInternalHttpResourcesSetup() { @@ -43,13 +45,13 @@ function createInternalHttpResourcesSetup() { } function createHttpResourcesResponseFactory() { - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ renderCoreApp: jest.fn(), renderAnonymousCoreApp: jest.fn(), renderHtml: jest.fn(), renderJs: jest.fn(), renderCss: jest.fn(), - }; + }); return { ...httpServerMock.createResponseFactory(), diff --git a/src/core/packages/http/resources-server-mocks/tsconfig.json b/src/core/packages/http/resources-server-mocks/tsconfig.json index 1b4861573b32b..151a12c3f7c1d 100644 --- a/src/core/packages/http/resources-server-mocks/tsconfig.json +++ b/src/core/packages/http/resources-server-mocks/tsconfig.json @@ -14,7 +14,8 @@ "@kbn/utility-types", "@kbn/core-http-server-mocks", "@kbn/core-http-resources-server", - "@kbn/core-http-resources-server-internal" + "@kbn/core-http-resources-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/http/router-server-mocks/src/router.mock.ts b/src/core/packages/http/router-server-mocks/src/router.mock.ts index 3592f74114cd4..50d2cff3fbcc4 100644 --- a/src/core/packages/http/router-server-mocks/src/router.mock.ts +++ b/src/core/packages/http/router-server-mocks/src/router.mock.ts @@ -23,11 +23,12 @@ import { } from '@kbn/core-http-server'; import { kibanaRequestFactory } from '@kbn/core-http-server-utils'; import { createVersionedRouterMock, type MockedVersionedRouter } from './versioned_router.mock'; +import { lazyObject } from '@kbn/lazy-object'; export type RouterMock = jest.Mocked> & { versioned: MockedVersionedRouter }; function createRouterMock({ routerPath = '' }: { routerPath?: string } = {}): RouterMock { - return { + return lazyObject({ routerPath, get: jest.fn(), post: jest.fn(), @@ -37,7 +38,7 @@ function createRouterMock({ routerPath = '' }: { routerPath?: string } = {}): Ro getRoutes: jest.fn(), handleLegacyErrors: jest.fn().mockImplementation((handler) => handler), versioned: createVersionedRouterMock(), - }; + }); } /** @@ -132,24 +133,25 @@ function createFakeKibanaRequestMock({ return kibanaRequestFactory(fakeRequest); } -const createResponseFactoryMock = (): jest.Mocked => ({ - ok: jest.fn(), - created: jest.fn(), - accepted: jest.fn(), - noContent: jest.fn(), - multiStatus: jest.fn(), - notModified: jest.fn(), - custom: jest.fn(), - redirected: jest.fn(), - badRequest: jest.fn(), - unauthorized: jest.fn(), - forbidden: jest.fn(), - notFound: jest.fn(), - conflict: jest.fn(), - unprocessableContent: jest.fn(), - customError: jest.fn(), - file: jest.fn(), -}); +const createResponseFactoryMock = (): jest.Mocked => + lazyObject({ + ok: jest.fn(), + created: jest.fn(), + accepted: jest.fn(), + noContent: jest.fn(), + multiStatus: jest.fn(), + notModified: jest.fn(), + custom: jest.fn(), + redirected: jest.fn(), + badRequest: jest.fn(), + unauthorized: jest.fn(), + forbidden: jest.fn(), + notFound: jest.fn(), + conflict: jest.fn(), + unprocessableContent: jest.fn(), + customError: jest.fn(), + file: jest.fn(), + }); export const mockRouter = { create: createRouterMock, diff --git a/src/core/packages/http/router-server-mocks/tsconfig.json b/src/core/packages/http/router-server-mocks/tsconfig.json index 13d8d78388faa..fa27c9c44cb55 100644 --- a/src/core/packages/http/router-server-mocks/tsconfig.json +++ b/src/core/packages/http/router-server-mocks/tsconfig.json @@ -15,6 +15,7 @@ "@kbn/config-schema", "@kbn/core-http-server", "@kbn/core-http-server-utils", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/core/packages/http/server-mocks/src/cookie_session_storage.mocks.ts b/src/core/packages/http/server-mocks/src/cookie_session_storage.mocks.ts index a1ca229e907a3..36cf3a76100e9 100644 --- a/src/core/packages/http/server-mocks/src/cookie_session_storage.mocks.ts +++ b/src/core/packages/http/server-mocks/src/cookie_session_storage.mocks.ts @@ -8,12 +8,14 @@ */ import type { SessionStorageFactory, SessionStorage } from '@kbn/core-http-server'; +import { lazyObject } from '@kbn/lazy-object'; -const createSessionStorageMock = (): jest.Mocked> => ({ - get: jest.fn().mockResolvedValue({}), - set: jest.fn(), - clear: jest.fn(), -}); +const createSessionStorageMock = (): jest.Mocked> => + lazyObject({ + get: jest.fn().mockResolvedValue({}), + set: jest.fn(), + clear: jest.fn(), + }); type ReturnMocked = { [K in keyof T]: T[K] extends (...args: any[]) => infer U @@ -24,10 +26,9 @@ type ReturnMocked = { type DeepMocked = jest.Mocked>; const creatSessionStorageFactoryMock = () => { - const mocked: DeepMocked> = { - asScoped: jest.fn(), - }; - mocked.asScoped.mockImplementation(createSessionStorageMock); + const mocked: DeepMocked> = lazyObject({ + asScoped: jest.fn().mockImplementation(createSessionStorageMock), + }); return mocked; }; diff --git a/src/core/packages/http/server-mocks/src/http_server.mocks.ts b/src/core/packages/http/server-mocks/src/http_server.mocks.ts index d1db523108667..7bb111437b181 100644 --- a/src/core/packages/http/server-mocks/src/http_server.mocks.ts +++ b/src/core/packages/http/server-mocks/src/http_server.mocks.ts @@ -16,29 +16,31 @@ import type { OnPreRoutingToolkit, } from '@kbn/core-http-server'; import { mockRouter } from '@kbn/core-http-router-server-mocks'; +import { lazyObject } from '@kbn/lazy-object'; -const createLifecycleResponseFactoryMock = (): jest.Mocked => ({ - redirected: jest.fn(), - badRequest: jest.fn(), - unauthorized: jest.fn(), - forbidden: jest.fn(), - notFound: jest.fn(), - conflict: jest.fn(), - unprocessableContent: jest.fn(), - customError: jest.fn(), -}); +const createLifecycleResponseFactoryMock = (): jest.Mocked => + lazyObject({ + redirected: jest.fn(), + badRequest: jest.fn(), + unauthorized: jest.fn(), + forbidden: jest.fn(), + notFound: jest.fn(), + conflict: jest.fn(), + unprocessableContent: jest.fn(), + customError: jest.fn(), + }); type ToolkitMock = jest.Mocked< OnPreAuthToolkit & OnPreResponseToolkit & OnPostAuthToolkit & OnPreRoutingToolkit >; const createToolkitMock = (): ToolkitMock => { - return { + return lazyObject({ render: jest.fn(), next: jest.fn(), rewriteUrl: jest.fn(), authzResultNext: jest.fn(), - }; + }); }; export const httpServerMock = { diff --git a/src/core/packages/http/server-mocks/src/http_service.mock.ts b/src/core/packages/http/server-mocks/src/http_service.mock.ts index be94de585eb14..17211dfb94646 100644 --- a/src/core/packages/http/server-mocks/src/http_service.mock.ts +++ b/src/core/packages/http/server-mocks/src/http_service.mock.ts @@ -35,6 +35,7 @@ import type { InternalHttpServiceStart, } from '@kbn/core-http-server-internal'; import { sessionStorageMock } from './cookie_session_storage.mocks'; +import { lazyObject } from '@kbn/lazy-object'; type BasePathMocked = jest.Mocked; type InternalStaticAssetsMocked = jest.Mocked; @@ -76,42 +77,42 @@ export type InternalHttpServiceStartMock = jest.Mocked const createBasePathMock = ( serverBasePath = '/mock-server-basepath', publicBaseUrl = 'http://myhost.com/mock-server-basepath' -): BasePathMocked => ({ - serverBasePath, - publicBaseUrl, - get: jest.fn().mockReturnValue(serverBasePath), - set: jest.fn(), - prepend: jest.fn(), - remove: jest.fn(), -}); +): BasePathMocked => + lazyObject({ + serverBasePath, + publicBaseUrl, + get: jest.fn().mockReturnValue(serverBasePath), + set: jest.fn(), + prepend: jest.fn(), + remove: jest.fn(), + }); const createInternalStaticAssetsMock = ( basePath: BasePathMocked, cdnUrl: undefined | string = undefined -): InternalStaticAssetsMocked => ({ - isUsingCdn: jest.fn().mockReturnValue(!!cdnUrl), - getHrefBase: jest.fn().mockReturnValue(cdnUrl ?? basePath.serverBasePath), - getPluginAssetHref: jest.fn().mockReturnValue(cdnUrl ?? basePath.serverBasePath), - getPluginServerPath: jest.fn((v, _) => v), - prependServerPath: jest.fn((v) => v), - prependPublicUrl: jest.fn((v) => v), -}); +): InternalStaticAssetsMocked => + lazyObject({ + isUsingCdn: jest.fn().mockReturnValue(!!cdnUrl), + getHrefBase: jest.fn().mockReturnValue(cdnUrl ?? basePath.serverBasePath), + getPluginAssetHref: jest.fn().mockReturnValue(cdnUrl ?? basePath.serverBasePath), + getPluginServerPath: jest.fn((v, _) => v), + prependServerPath: jest.fn((v) => v), + prependPublicUrl: jest.fn((v) => v), + }); const createAuthMock = () => { - const mock: AuthMocked = { - get: jest.fn(), - isAuthenticated: jest.fn(), - }; - mock.get.mockReturnValue({ status: AuthStatus.authenticated, state: {} }); - mock.isAuthenticated.mockReturnValue(true); + const mock: AuthMocked = lazyObject({ + get: jest.fn().mockReturnValue({ status: AuthStatus.authenticated, state: {} }), + isAuthenticated: jest.fn().mockReturnValue(true), + }); return mock; }; const createAuthHeaderStorageMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ set: jest.fn(), get: jest.fn(), - }; + }); return mock; }; @@ -121,7 +122,7 @@ interface CreateMockArgs { const createInternalPrebootContractMock = (args: CreateMockArgs = {}) => { const basePath = createBasePathMock(); - const mock: InternalHttpServicePrebootMock = { + const mock: InternalHttpServicePrebootMock = lazyObject({ registerRoutes: jest.fn(), registerRouteHandlerContext: jest.fn(), registerStaticDir: jest.fn(), @@ -132,7 +133,7 @@ const createInternalPrebootContractMock = (args: CreateMockArgs = {}) => { externalUrl: ExternalUrlConfig.DEFAULT, auth: createAuthMock(), getServerInfo: jest.fn(), - server: { + server: lazyObject({ name: 'http-preboot-server-test', version: 'kibana', route: jest.fn(), @@ -140,28 +141,28 @@ const createInternalPrebootContractMock = (args: CreateMockArgs = {}) => { stop: jest.fn(), config: jest.fn().mockReturnValue(configMock.create()), // @ts-expect-error somehow it thinks that `Server` isn't a `Construtable` - } as unknown as jest.MockedClass, - }; + }) as unknown as jest.MockedClass, + }); return mock; }; const createPrebootContractMock = () => { const internalMock = createInternalPrebootContractMock(); - const mock: HttpServicePrebootMock = { + const mock: HttpServicePrebootMock = lazyObject({ registerRoutes: internalMock.registerRoutes, basePath: createBasePathMock(), getServerInfo: jest.fn(), - }; + }); return mock; }; const createInternalSetupContractMock = () => { const basePath = createBasePathMock(); - const mock: InternalHttpServiceSetupMock = { + const mock: InternalHttpServiceSetupMock = lazyObject({ // we can mock other hapi server methods when we need it - server: { + server: lazyObject({ name: 'http-server-test', version: 'kibana', route: jest.fn(), @@ -169,8 +170,10 @@ const createInternalSetupContractMock = () => { stop: jest.fn(), config: jest.fn().mockReturnValue(configMock.create()), // @ts-expect-error somehow it thinks that `Server` isn't a `Construtable` - } as unknown as jest.MockedClass, - createCookieSessionStorageFactory: jest.fn(), + }) as unknown as jest.MockedClass, + createCookieSessionStorageFactory: jest + .fn() + .mockResolvedValue(sessionStorageMock.createFactory()), registerOnPreRouting: jest.fn(), registerOnPreAuth: jest.fn(), getDeprecatedRoutes: jest.fn(), @@ -189,19 +192,17 @@ const createInternalSetupContractMock = () => { externalUrl: ExternalUrlConfig.DEFAULT, auth: createAuthMock(), authRequestHeaders: createAuthHeaderStorageMock(), - getServerInfo: jest.fn(), + getServerInfo: jest.fn().mockReturnValue({ + hostname: 'localhost', + name: 'kibana', + port: 80, + protocol: 'http', + }), registerRouterAfterListening: jest.fn(), rateLimiter: config.schema.getSchema().extract('rateLimiter').validate({}).value, - }; - mock.createCookieSessionStorageFactory.mockResolvedValue(sessionStorageMock.createFactory()); - mock.createRouter.mockImplementation(() => mockRouter.create()); - mock.authRequestHeaders.get.mockReturnValue({ authorization: 'authorization-header' }); - mock.getServerInfo.mockReturnValue({ - hostname: 'localhost', - name: 'kibana', - port: 80, - protocol: 'http', }); + + mock.authRequestHeaders.get.mockReturnValue({ authorization: 'authorization-header' }); return mock; }; @@ -210,7 +211,7 @@ const createSetupContractMock = < >() => { const internalMock = createInternalSetupContractMock(); - const mock: HttpServiceSetupMock = { + const mock: HttpServiceSetupMock = lazyObject({ createCookieSessionStorageFactory: internalMock.createCookieSessionStorageFactory, registerOnPreRouting: internalMock.registerOnPreRouting, registerOnPreAuth: jest.fn(), @@ -223,11 +224,11 @@ const createSetupContractMock = < createRouter: jest.fn(), registerRouteHandlerContext: jest.fn(), getServerInfo: internalMock.getServerInfo, - staticAssets: { + staticAssets: lazyObject({ getPluginAssetHref: jest.fn().mockImplementation((assetPath: string) => assetPath), prependPublicUrl: jest.fn().mockImplementation((pathname: string) => pathname), - }, - }; + }), + }); mock.createRouter.mockImplementation(() => internalMock.createRouter('')); diff --git a/src/core/packages/http/server-mocks/src/test_utils.ts b/src/core/packages/http/server-mocks/src/test_utils.ts index 62ba902c56d71..640a6edddc5d3 100644 --- a/src/core/packages/http/server-mocks/src/test_utils.ts +++ b/src/core/packages/http/server-mocks/src/test_utils.ts @@ -25,6 +25,7 @@ import { HttpService, config, } from '@kbn/core-http-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; const coreId = Symbol('core'); const env = Env.createDefault(REPO_ROOT, getEnvOptions()); @@ -114,18 +115,19 @@ export const createConfigService = ({ }; const createDefaultContext = (): CoreContext => { - return { + return lazyObject({ coreId, env, logger, configService: createConfigService(), - }; + }); }; -export const createCoreContext = (overrides: Partial = {}): CoreContext => ({ - ...createDefaultContext(), - ...overrides, -}); +export const createCoreContext = (overrides: Partial = {}): CoreContext => + lazyObject({ + ...createDefaultContext(), + ...overrides, + }); /** * A mock of the HttpService that can be used in tests. diff --git a/src/core/packages/http/server-mocks/tsconfig.json b/src/core/packages/http/server-mocks/tsconfig.json index 03125f02e351c..6ba214f7da156 100644 --- a/src/core/packages/http/server-mocks/tsconfig.json +++ b/src/core/packages/http/server-mocks/tsconfig.json @@ -24,6 +24,7 @@ "@kbn/core-base-server-internal", "@kbn/core-http-context-server-mocks", "@kbn/core-execution-context-server-mocks", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/core/packages/i18n/browser-mocks/src/i18n_service.mock.ts b/src/core/packages/i18n/browser-mocks/src/i18n_service.mock.ts index eaee22f6d86f8..dec7f949c4ac1 100644 --- a/src/core/packages/i18n/browser-mocks/src/i18n_service.mock.ts +++ b/src/core/packages/i18n/browser-mocks/src/i18n_service.mock.ts @@ -11,24 +11,24 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import type { I18nService } from '@kbn/core-i18n-browser-internal'; import type { I18nStart } from '@kbn/core-i18n-browser'; import { I18nProviderMock } from './i18n_context_mock'; +import { lazyObject } from '@kbn/lazy-object'; const createStartContractMock = () => { - const setupContract: jest.Mocked = { + const setupContract: jest.Mocked = lazyObject({ // Stubbed provider returning the default message or id Context: jest.fn().mockImplementation(I18nProviderMock), - }; + }); return setupContract; }; type I18nServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { - getContext: jest.fn(), - start: jest.fn(), + const mocked: jest.Mocked = lazyObject({ + getContext: jest.fn().mockReturnValue(createStartContractMock()), + start: jest.fn().mockReturnValue(createStartContractMock()), stop: jest.fn(), - }; - mocked.getContext.mockReturnValue(createStartContractMock()); - mocked.start.mockReturnValue(createStartContractMock()); + }); + return mocked; }; diff --git a/src/core/packages/i18n/browser-mocks/tsconfig.json b/src/core/packages/i18n/browser-mocks/tsconfig.json index 935512990f29e..009526fca9f79 100644 --- a/src/core/packages/i18n/browser-mocks/tsconfig.json +++ b/src/core/packages/i18n/browser-mocks/tsconfig.json @@ -16,6 +16,7 @@ "@kbn/core-i18n-browser", "@kbn/core-i18n-browser-internal", "@kbn/i18n-react", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/core/packages/i18n/server-mocks/src/i18n_service.mock.ts b/src/core/packages/i18n/server-mocks/src/i18n_service.mock.ts index 5aeee2e9a8ab3..85bda3921c715 100644 --- a/src/core/packages/i18n/server-mocks/src/i18n_service.mock.ts +++ b/src/core/packages/i18n/server-mocks/src/i18n_service.mock.ts @@ -10,25 +10,22 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import type { I18nService, InternalI18nServicePreboot } from '@kbn/core-i18n-server-internal'; import type { I18nServiceSetup } from '@kbn/core-i18n-server'; +import { lazyObject } from '@kbn/lazy-object'; const createSetupContractMock = () => { - const mock: jest.Mocked = { - getLocale: jest.fn(), - getTranslationFiles: jest.fn(), - getTranslationHash: jest.fn(), - }; - - mock.getLocale.mockReturnValue('en'); - mock.getTranslationFiles.mockReturnValue([]); - mock.getTranslationHash.mockReturnValue('MOCK_HASH'); + const mock: jest.Mocked = lazyObject({ + getLocale: jest.fn().mockReturnValue('en'), + getTranslationFiles: jest.fn().mockReturnValue([]), + getTranslationHash: jest.fn().mockReturnValue('MOCK_HASH'), + }); return mock; }; const createInternalPrebootMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ getTranslationHash: jest.fn(), - }; + }); mock.getTranslationHash.mockReturnValue('MOCK_HASH'); @@ -38,12 +35,10 @@ const createInternalPrebootMock = () => { type I18nServiceContract = PublicMethodsOf; const createMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ preboot: jest.fn(), - setup: jest.fn(), - }; - - mock.setup.mockResolvedValue(createSetupContractMock()); + setup: jest.fn().mockResolvedValue(createSetupContractMock()), + }); return mock; }; diff --git a/src/core/packages/i18n/server-mocks/tsconfig.json b/src/core/packages/i18n/server-mocks/tsconfig.json index e9ad46c0ec83d..3c9bf773c438c 100644 --- a/src/core/packages/i18n/server-mocks/tsconfig.json +++ b/src/core/packages/i18n/server-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-i18n-server", - "@kbn/core-i18n-server-internal" + "@kbn/core-i18n-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/injected-metadata/browser-mocks/src/injected_metadata_service.mock.ts b/src/core/packages/injected-metadata/browser-mocks/src/injected_metadata_service.mock.ts index 68fa84022ce34..437bc7c15042e 100644 --- a/src/core/packages/injected-metadata/browser-mocks/src/injected_metadata_service.mock.ts +++ b/src/core/packages/injected-metadata/browser-mocks/src/injected_metadata_service.mock.ts @@ -12,68 +12,61 @@ import type { InjectedMetadataService, InternalInjectedMetadataSetup, } from '@kbn/core-injected-metadata-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createSetupContractMock = () => { - const setupContract: jest.Mocked = { - getBasePath: jest.fn(), - getServerBasePath: jest.fn(), - getAssetsHrefBase: jest.fn(), + const setupContract: jest.Mocked = lazyObject({ + getBasePath: jest.fn().mockReturnValue('/base-path'), + getServerBasePath: jest.fn().mockReturnValue('/server-base-path'), + getAssetsHrefBase: jest.fn().mockReturnValue('/assets-base-path'), getPublicBaseUrl: jest.fn(), - getKibanaVersion: jest.fn(), + getKibanaVersion: jest.fn().mockReturnValue('kibanaVersion'), getKibanaBranch: jest.fn(), getElasticsearchInfo: jest.fn(), - getCspConfig: jest.fn(), - getExternalUrlConfig: jest.fn(), - getAnonymousStatusPage: jest.fn(), - getLegacyMetadata: jest.fn(), - getTheme: jest.fn(), - getPlugins: jest.fn(), + getCspConfig: jest.fn().mockReturnValue({ warnLegacyBrowsers: true }), + getExternalUrlConfig: jest.fn().mockReturnValue({ policy: [] }), + getAnonymousStatusPage: jest.fn().mockReturnValue(false), + getLegacyMetadata: jest.fn().mockReturnValue({ + app: { + id: 'foo', + title: 'Foo App', + }, + nav: [], + uiSettings: { + defaults: { legacyInjectedUiSettingDefaults: true }, + user: { legacyInjectedUiSettingUserValues: true }, + }, + globalSettings: { + defaults: { legacyInjectedUiSettingDefaults: true }, + user: { legacyInjectedUiSettingUserValues: true }, + }, + } as any), + getTheme: jest.fn().mockReturnValue({ + darkMode: false, + name: 'amsterdam', + version: 'v8', + stylesheetPaths: { + default: ['light-1.css'], + dark: ['dark-1.css'], + }, + }), + getPlugins: jest.fn().mockReturnValue([]), getKibanaBuildNumber: jest.fn(), getCustomBranding: jest.fn(), getFeatureFlags: jest.fn(), - }; - setupContract.getBasePath.mockReturnValue('/base-path'); - setupContract.getServerBasePath.mockReturnValue('/server-base-path'); - setupContract.getAssetsHrefBase.mockReturnValue('/assets-base-path'); - setupContract.getCspConfig.mockReturnValue({ warnLegacyBrowsers: true }); - setupContract.getExternalUrlConfig.mockReturnValue({ policy: [] }); - setupContract.getKibanaVersion.mockReturnValue('kibanaVersion'); - setupContract.getAnonymousStatusPage.mockReturnValue(false); - setupContract.getLegacyMetadata.mockReturnValue({ - app: { - id: 'foo', - title: 'Foo App', - }, - nav: [], - uiSettings: { - defaults: { legacyInjectedUiSettingDefaults: true }, - user: { legacyInjectedUiSettingUserValues: true }, - }, - globalSettings: { - defaults: { legacyInjectedUiSettingDefaults: true }, - user: { legacyInjectedUiSettingUserValues: true }, - }, - } as any); - setupContract.getPlugins.mockReturnValue([]); - setupContract.getTheme.mockReturnValue({ - darkMode: false, - name: 'amsterdam', - version: 'v8', - stylesheetPaths: { - default: ['light-1.css'], - dark: ['dark-1.css'], - }, }); + return setupContract; }; const createStartContractMock = createSetupContractMock; type InjectedMetadataServiceContract = PublicMethodsOf; -const createMock = (): jest.Mocked => ({ - setup: jest.fn().mockReturnValue(createSetupContractMock()), - start: jest.fn().mockReturnValue(createStartContractMock()), -}); +const createMock = (): jest.Mocked => + lazyObject({ + setup: jest.fn().mockReturnValue(createSetupContractMock()), + start: jest.fn().mockReturnValue(createStartContractMock()), + }); export const injectedMetadataServiceMock = { create: createMock, diff --git a/src/core/packages/injected-metadata/browser-mocks/tsconfig.json b/src/core/packages/injected-metadata/browser-mocks/tsconfig.json index cc681049f5623..9583cfbdc3d17 100644 --- a/src/core/packages/injected-metadata/browser-mocks/tsconfig.json +++ b/src/core/packages/injected-metadata/browser-mocks/tsconfig.json @@ -13,7 +13,8 @@ ], "kbn_references": [ "@kbn/utility-types", - "@kbn/core-injected-metadata-browser-internal" + "@kbn/core-injected-metadata-browser-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/integrations/browser-mocks/src/integrations_service.mock.ts b/src/core/packages/integrations/browser-mocks/src/integrations_service.mock.ts index f68c6d2d6f9c6..015d6e80b3df2 100644 --- a/src/core/packages/integrations/browser-mocks/src/integrations_service.mock.ts +++ b/src/core/packages/integrations/browser-mocks/src/integrations_service.mock.ts @@ -9,15 +9,17 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import type { IntegrationsService } from '@kbn/core-integrations-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; export type IntegrationsServiceContract = PublicMethodsOf; export type IntegrationsServiceMock = jest.Mocked; -const createMock = (): IntegrationsServiceMock => ({ - setup: jest.fn(), - start: jest.fn(), - stop: jest.fn(), -}); +const createMock = (): IntegrationsServiceMock => + lazyObject({ + setup: jest.fn(), + start: jest.fn(), + stop: jest.fn(), + }); export const integrationsServiceMock = { create: createMock, diff --git a/src/core/packages/integrations/browser-mocks/tsconfig.json b/src/core/packages/integrations/browser-mocks/tsconfig.json index 6d3ab2e8e050b..06cf1ae0e4756 100644 --- a/src/core/packages/integrations/browser-mocks/tsconfig.json +++ b/src/core/packages/integrations/browser-mocks/tsconfig.json @@ -13,7 +13,8 @@ ], "kbn_references": [ "@kbn/utility-types", - "@kbn/core-integrations-browser-internal" + "@kbn/core-integrations-browser-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/lifecycle/browser-mocks/src/core_setup.mock.ts b/src/core/packages/lifecycle/browser-mocks/src/core_setup.mock.ts index 3b95cf9495b5e..2d1bf69ddb0a8 100644 --- a/src/core/packages/lifecycle/browser-mocks/src/core_setup.mock.ts +++ b/src/core/packages/lifecycle/browser-mocks/src/core_setup.mock.ts @@ -23,6 +23,7 @@ import { securityServiceMock } from '@kbn/core-security-browser-mocks'; import { userProfileServiceMock } from '@kbn/core-user-profile-browser-mocks'; import { createCoreStartMock } from './core_start.mock'; import { coreFeatureFlagsMock } from '@kbn/core-feature-flags-browser-mocks'; +import { lazyObject } from '@kbn/lazy-object'; export function createCoreSetupMock({ basePath = '', @@ -33,7 +34,7 @@ export function createCoreSetupMock({ pluginStartDeps?: object; pluginStartContract?: any; } = {}) { - const mock = { + const mock = lazyObject({ analytics: analyticsServiceMock.createAnalyticsServiceSetup(), application: applicationServiceMock.createSetupContract(), customBranding: customBrandingServiceMock.createSetupContract(), @@ -53,11 +54,11 @@ export function createCoreSetupMock({ theme: themeServiceMock.createSetupContract(), security: securityServiceMock.createSetup(), userProfile: userProfileServiceMock.createSetup(), - plugins: { + plugins: lazyObject({ onSetup: jest.fn(), onStart: jest.fn(), - }, - }; + }), + }); return mock; } diff --git a/src/core/packages/lifecycle/browser-mocks/src/core_start.mock.ts b/src/core/packages/lifecycle/browser-mocks/src/core_start.mock.ts index 7bf0d5108420e..9fc8938f61bab 100644 --- a/src/core/packages/lifecycle/browser-mocks/src/core_start.mock.ts +++ b/src/core/packages/lifecycle/browser-mocks/src/core_start.mock.ts @@ -27,9 +27,10 @@ import { userProfileServiceMock } from '@kbn/core-user-profile-browser-mocks'; import { renderingServiceMock } from '@kbn/core-rendering-browser-mocks'; import { coreFeatureFlagsMock } from '@kbn/core-feature-flags-browser-mocks'; import { pricingServiceMock } from '@kbn/core-pricing-browser-mocks'; +import { lazyObject } from '@kbn/lazy-object'; export function createCoreStartMock({ basePath = '' } = {}) { - const mock = { + const mock = lazyObject({ analytics: analyticsServiceMock.createAnalyticsServiceStart(), application: applicationServiceMock.createStartContract(), chrome: chromeServiceMock.createStartContract(), @@ -51,10 +52,10 @@ export function createCoreStartMock({ basePath = '' } = {}) { userProfile: userProfileServiceMock.createStart(), rendering: renderingServiceMock.create(), pricing: pricingServiceMock.createStartContract(), - plugins: { + plugins: lazyObject({ onStart: jest.fn(), - }, - }; + }), + }); return mock; } diff --git a/src/core/packages/lifecycle/browser-mocks/tsconfig.json b/src/core/packages/lifecycle/browser-mocks/tsconfig.json index e358dfb71f50a..4387cd372b370 100644 --- a/src/core/packages/lifecycle/browser-mocks/tsconfig.json +++ b/src/core/packages/lifecycle/browser-mocks/tsconfig.json @@ -32,6 +32,7 @@ "@kbn/core-rendering-browser-mocks", "@kbn/core-pricing-browser-mocks", "@kbn/core-di-mocks", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/core/packages/lifecycle/server-mocks/src/core_preboot.mock.ts b/src/core/packages/lifecycle/server-mocks/src/core_preboot.mock.ts index 975dfa1562fab..0f2afc63a62b5 100644 --- a/src/core/packages/lifecycle/server-mocks/src/core_preboot.mock.ts +++ b/src/core/packages/lifecycle/server-mocks/src/core_preboot.mock.ts @@ -13,18 +13,19 @@ import { httpServiceMock } from '@kbn/core-http-server-mocks'; import { prebootServiceMock } from '@kbn/core-preboot-server-mocks'; import type { MockedKeys } from '@kbn/utility-types-jest'; import type { CorePreboot } from '@kbn/core-lifecycle-server'; +import { lazyObject } from '@kbn/lazy-object'; type CorePrebootMockType = MockedKeys & { elasticsearch: ReturnType; }; export function createCorePrebootMock() { - const mock: CorePrebootMockType = { + const mock: CorePrebootMockType = lazyObject({ analytics: analyticsServiceMock.createAnalyticsServicePreboot(), elasticsearch: elasticsearchServiceMock.createPreboot(), http: httpServiceMock.createPrebootContract() as CorePrebootMockType['http'], preboot: prebootServiceMock.createPrebootContract(), - }; + }); return mock; } diff --git a/src/core/packages/lifecycle/server-mocks/src/core_setup.mock.ts b/src/core/packages/lifecycle/server-mocks/src/core_setup.mock.ts index f1dce8c5eee82..7110cdc5560cb 100644 --- a/src/core/packages/lifecycle/server-mocks/src/core_setup.mock.ts +++ b/src/core/packages/lifecycle/server-mocks/src/core_setup.mock.ts @@ -34,6 +34,7 @@ import { coreFeatureFlagsMock } from '@kbn/core-feature-flags-server-mocks'; import { pricingServiceMock } from '@kbn/core-pricing-server-mocks'; import { injectionServiceMock } from '@kbn/core-di-mocks'; import { dataStreamServiceMock } from '@kbn/core-data-streams-server-mocks'; +import { lazyObject } from '@kbn/lazy-object'; type CoreSetupMockType = MockedKeys & { elasticsearch: ReturnType; @@ -47,18 +48,18 @@ export function createCoreSetupMock({ pluginStartDeps?: object; pluginStartContract?: any; } = {}) { - const httpMock: jest.Mocked = { + const httpMock: jest.Mocked = lazyObject({ ...httpServiceMock.createSetupContract(), resources: httpResourcesMock.createRegistrar(), - }; + }); - const uiSettingsMock = { + const uiSettingsMock = lazyObject({ register: uiSettingsServiceMock.createSetupContract().register, registerGlobal: uiSettingsServiceMock.createSetupContract().registerGlobal, setAllowlist: uiSettingsServiceMock.createSetupContract().setAllowlist, - }; + }); - const mock: CoreSetupMockType = { + const mock: CoreSetupMockType = lazyObject({ analytics: analyticsServiceMock.createAnalyticsServiceSetup(), capabilities: capabilitiesServiceMock.createSetupContract(), customBranding: customBrandingServiceMock.createSetupContract(), @@ -77,22 +78,22 @@ export function createCoreSetupMock({ executionContext: executionContextServiceMock.createInternalSetupContract(), security: securityServiceMock.createSetup(), userProfile: userProfileServiceMock.createSetup(), - coreUsageData: { + coreUsageData: lazyObject({ registerUsageCounter: coreUsageDataServiceMock.createSetupContract().registerUsageCounter, registerDeprecatedUsageFetch: coreUsageDataServiceMock.createSetupContract().registerDeprecatedUsageFetch, - }, - plugins: { + }), + plugins: lazyObject({ onSetup: jest.fn(), onStart: jest.fn(), - }, + }), pricing: pricingServiceMock.createSetupContract(), injection: injectionServiceMock.createSetupContract(), dataStreams: dataStreamServiceMock.createSetupContract(), getStartServices: jest .fn, object, any]>, []>() .mockResolvedValue([createCoreStartMock(), pluginStartDeps, pluginStartContract]), - }; + }); return mock; } diff --git a/src/core/packages/lifecycle/server-mocks/src/core_start.mock.ts b/src/core/packages/lifecycle/server-mocks/src/core_start.mock.ts index 1cb9d9c79937d..fc893fc36a7ca 100644 --- a/src/core/packages/lifecycle/server-mocks/src/core_start.mock.ts +++ b/src/core/packages/lifecycle/server-mocks/src/core_start.mock.ts @@ -26,9 +26,10 @@ import { coreFeatureFlagsMock } from '@kbn/core-feature-flags-server-mocks'; import { pricingServiceMock } from '@kbn/core-pricing-server-mocks'; import { injectionServiceMock } from '@kbn/core-di-mocks'; import { dataStreamServiceMock } from '@kbn/core-data-streams-server-mocks'; +import { lazyObject } from '@kbn/lazy-object'; export function createCoreStartMock() { - const mock: MockedKeys = { + const mock: MockedKeys = lazyObject({ analytics: analyticsServiceMock.createAnalyticsServiceStart(), capabilities: capabilitiesServiceMock.createStartContract(), docLinks: docLinksServiceMock.createStartContract(), @@ -44,12 +45,12 @@ export function createCoreStartMock() { security: securityServiceMock.createStart(), userProfile: userProfileServiceMock.createStart(), injection: injectionServiceMock.createStartContract(), - plugins: { + plugins: lazyObject({ onStart: jest.fn(), - }, + }), pricing: pricingServiceMock.createStartContract(), dataStreams: dataStreamServiceMock.createStartContract(), - }; + }); return mock; } diff --git a/src/core/packages/lifecycle/server-mocks/src/internal_core_preboot.mock.ts b/src/core/packages/lifecycle/server-mocks/src/internal_core_preboot.mock.ts index 3d9fe60b92a67..6e5aa8e065b66 100644 --- a/src/core/packages/lifecycle/server-mocks/src/internal_core_preboot.mock.ts +++ b/src/core/packages/lifecycle/server-mocks/src/internal_core_preboot.mock.ts @@ -15,9 +15,10 @@ import { httpServiceMock } from '@kbn/core-http-server-mocks'; import { loggingServiceMock } from '@kbn/core-logging-server-mocks'; import { prebootServiceMock } from '@kbn/core-preboot-server-mocks'; import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; +import { lazyObject } from '@kbn/lazy-object'; export function createInternalCorePrebootMock() { - const prebootDeps = { + const prebootDeps = lazyObject({ analytics: analyticsServiceMock.createAnalyticsServicePreboot(), context: contextServiceMock.createPrebootContract(), elasticsearch: elasticsearchServiceMock.createInternalPreboot(), @@ -26,6 +27,6 @@ export function createInternalCorePrebootMock() { uiSettings: uiSettingsServiceMock.createPrebootContract(), logging: loggingServiceMock.createInternalPrebootContract(), preboot: prebootServiceMock.createInternalPrebootContract(), - }; + }); return prebootDeps; } diff --git a/src/core/packages/lifecycle/server-mocks/src/internal_core_setup.mock.ts b/src/core/packages/lifecycle/server-mocks/src/internal_core_setup.mock.ts index fc77f900c3b97..8271ea7cafad0 100644 --- a/src/core/packages/lifecycle/server-mocks/src/internal_core_setup.mock.ts +++ b/src/core/packages/lifecycle/server-mocks/src/internal_core_setup.mock.ts @@ -33,9 +33,10 @@ import { coreFeatureFlagsMock } from '@kbn/core-feature-flags-server-mocks'; import { pricingServiceMock } from '@kbn/core-pricing-server-mocks'; import { injectionServiceMock } from '@kbn/core-di-mocks'; import { dataStreamServiceMock } from '@kbn/core-data-streams-server-mocks'; +import { lazyObject } from '@kbn/lazy-object'; export function createInternalCoreSetupMock() { - const setupDeps = { + const setupDeps = lazyObject({ analytics: analyticsServiceMock.createAnalyticsServiceSetup(), capabilities: capabilitiesServiceMock.createSetupContract(), context: contextServiceMock.createSetupContract(), @@ -62,6 +63,6 @@ export function createInternalCoreSetupMock() { pricing: pricingServiceMock.createSetupContract(), injection: injectionServiceMock.createInternalSetupContract(), dataStreams: dataStreamServiceMock.createSetupContract(), - }; + }); return setupDeps; } diff --git a/src/core/packages/lifecycle/server-mocks/src/internal_core_start.mock.ts b/src/core/packages/lifecycle/server-mocks/src/internal_core_start.mock.ts index 2aa6ddd0942a2..0664a351bc43c 100644 --- a/src/core/packages/lifecycle/server-mocks/src/internal_core_start.mock.ts +++ b/src/core/packages/lifecycle/server-mocks/src/internal_core_start.mock.ts @@ -25,9 +25,10 @@ import { coreFeatureFlagsMock } from '@kbn/core-feature-flags-server-mocks'; import { pricingServiceMock } from '@kbn/core-pricing-server-mocks'; import { injectionServiceMock } from '@kbn/core-di-mocks'; import { dataStreamServiceMock } from '@kbn/core-data-streams-server-mocks'; +import { lazyObject } from '@kbn/lazy-object'; export function createInternalCoreStartMock() { - const startDeps = { + const startDeps = lazyObject({ analytics: analyticsServiceMock.createAnalyticsServiceStart(), capabilities: capabilitiesServiceMock.createStartContract(), docLinks: docLinksServiceMock.createStartContract(), @@ -46,6 +47,6 @@ export function createInternalCoreStartMock() { pricing: pricingServiceMock.createStartContract(), injection: injectionServiceMock.createInternalStartContract(), dataStreams: dataStreamServiceMock.createStartContract(), - }; + }); return startDeps; } diff --git a/src/core/packages/lifecycle/server-mocks/tsconfig.json b/src/core/packages/lifecycle/server-mocks/tsconfig.json index cf0bbe187d247..6792e9f0cc3b4 100644 --- a/src/core/packages/lifecycle/server-mocks/tsconfig.json +++ b/src/core/packages/lifecycle/server-mocks/tsconfig.json @@ -41,6 +41,7 @@ "@kbn/core-pricing-server-mocks", "@kbn/core-di-mocks", "@kbn/core-data-streams-server-mocks", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/core/packages/logging/browser-mocks/src/logging_system.mock.ts b/src/core/packages/logging/browser-mocks/src/logging_system.mock.ts index e6112962ec876..4c7a3db2b948a 100644 --- a/src/core/packages/logging/browser-mocks/src/logging_system.mock.ts +++ b/src/core/packages/logging/browser-mocks/src/logging_system.mock.ts @@ -10,6 +10,7 @@ import type { MockedLogger } from '@kbn/logging-mocks'; import { loggerMock } from '@kbn/logging-mocks'; import type { IBrowserLoggingSystem } from '@kbn/core-logging-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createLoggingSystemMock = () => { const mockLog: MockedLogger = loggerMock.create(); @@ -19,15 +20,14 @@ const createLoggingSystemMock = () => { context, })); - const mocked: jest.Mocked = { - get: jest.fn(), + const mocked: jest.Mocked = lazyObject({ + get: jest.fn().mockImplementation((...context) => ({ + ...mockLog, + context, + })), asLoggerFactory: jest.fn(), - }; + }); - mocked.get.mockImplementation((...context) => ({ - ...mockLog, - context, - })); mocked.asLoggerFactory.mockImplementation(() => mocked); return mocked; diff --git a/src/core/packages/logging/browser-mocks/tsconfig.json b/src/core/packages/logging/browser-mocks/tsconfig.json index 333eff60cbda9..eeb6c1ddba83e 100644 --- a/src/core/packages/logging/browser-mocks/tsconfig.json +++ b/src/core/packages/logging/browser-mocks/tsconfig.json @@ -14,7 +14,8 @@ ], "kbn_references": [ "@kbn/logging-mocks", - "@kbn/core-logging-browser-internal" + "@kbn/core-logging-browser-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/logging/server-mocks/src/logging_service.mock.ts b/src/core/packages/logging/server-mocks/src/logging_service.mock.ts index af5d2eca61b81..b15239e1e93d1 100644 --- a/src/core/packages/logging/server-mocks/src/logging_service.mock.ts +++ b/src/core/packages/logging/server-mocks/src/logging_service.mock.ts @@ -14,30 +14,31 @@ import type { InternalLoggingServiceSetup, InternalLoggingServicePreboot, } from '@kbn/core-logging-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; -const createInternalPrebootMock = (): jest.Mocked => ({ - configure: jest.fn(), -}); +const createInternalPrebootMock = (): jest.Mocked => + lazyObject({ + configure: jest.fn(), + }); -const createInternalSetupMock = (): jest.Mocked => ({ - configure: jest.fn(), -}); +const createInternalSetupMock = (): jest.Mocked => + lazyObject({ + configure: jest.fn(), + }); -const createSetupMock = (): jest.Mocked => ({ - configure: jest.fn(), -}); +const createSetupMock = (): jest.Mocked => + lazyObject({ + configure: jest.fn(), + }); type LoggingServiceContract = PublicMethodsOf; const createMock = (): jest.Mocked => { - const service: jest.Mocked = { - preboot: jest.fn(), - setup: jest.fn(), + const service: jest.Mocked = lazyObject({ + preboot: jest.fn().mockReturnValue(createInternalPrebootMock()), + setup: jest.fn().mockReturnValue(createInternalSetupMock()), start: jest.fn(), stop: jest.fn(), - }; - - service.preboot.mockReturnValue(createInternalPrebootMock()); - service.setup.mockReturnValue(createInternalSetupMock()); + }); return service; }; diff --git a/src/core/packages/logging/server-mocks/src/logging_system.mock.ts b/src/core/packages/logging/server-mocks/src/logging_system.mock.ts index 85ed0100fa836..b88d1e7f41851 100644 --- a/src/core/packages/logging/server-mocks/src/logging_system.mock.ts +++ b/src/core/packages/logging/server-mocks/src/logging_system.mock.ts @@ -12,6 +12,7 @@ import type { LoggerFactory } from '@kbn/logging'; import type { MockedLogger } from '@kbn/logging-mocks'; import { loggerMock } from '@kbn/logging-mocks'; import type { ILoggingSystem } from '@kbn/core-logging-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createLoggingSystemMock = () => { const mockLog = loggerMock.create(); @@ -21,18 +22,20 @@ const createLoggingSystemMock = () => { context, })); - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ get: jest.fn(), asLoggerFactory: jest.fn(), setContextConfig: jest.fn(), setGlobalContext: jest.fn(), upgrade: jest.fn(), stop: jest.fn(), - }; + }); + mocked.get.mockImplementation((...context) => ({ ...mockLog, context, })); + mocked.asLoggerFactory.mockImplementation(() => mocked); mocked.upgrade.mockResolvedValue(undefined); mocked.stop.mockResolvedValue(); diff --git a/src/core/packages/logging/server-mocks/tsconfig.json b/src/core/packages/logging/server-mocks/tsconfig.json index 5b87d2e97768c..b3f86125d5a2f 100644 --- a/src/core/packages/logging/server-mocks/tsconfig.json +++ b/src/core/packages/logging/server-mocks/tsconfig.json @@ -15,7 +15,8 @@ "@kbn/logging", "@kbn/logging-mocks", "@kbn/core-logging-server", - "@kbn/core-logging-server-internal" + "@kbn/core-logging-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/metrics/collectors-server-mocks/src/collector.mock.ts b/src/core/packages/metrics/collectors-server-mocks/src/collector.mock.ts index d984e81dbaca9..4c14581f22403 100644 --- a/src/core/packages/metrics/collectors-server-mocks/src/collector.mock.ts +++ b/src/core/packages/metrics/collectors-server-mocks/src/collector.mock.ts @@ -8,14 +8,15 @@ */ import type { MetricsCollector } from '@kbn/core-metrics-server'; +import { lazyObject } from '@kbn/lazy-object'; const createCollector = ( collectReturnValue: any = {} ): jest.Mocked> => { - const collector: jest.Mocked> = { + const collector: jest.Mocked> = lazyObject({ collect: jest.fn().mockResolvedValue(collectReturnValue), reset: jest.fn(), - }; + }); return collector; }; diff --git a/src/core/packages/metrics/collectors-server-mocks/src/mocks.ts b/src/core/packages/metrics/collectors-server-mocks/src/mocks.ts index 5f411d64c9297..76eae2336088f 100644 --- a/src/core/packages/metrics/collectors-server-mocks/src/mocks.ts +++ b/src/core/packages/metrics/collectors-server-mocks/src/mocks.ts @@ -8,23 +8,23 @@ */ import type { MetricsCollector } from '@kbn/core-metrics-server'; +import { lazyObject } from '@kbn/lazy-object'; import { createMockOpsProcessMetrics } from './process.mocks'; const createMock = () => { - const mocked: jest.Mocked> = { - collect: jest.fn(), + const mocked: jest.Mocked> = lazyObject({ + collect: jest.fn().mockResolvedValue({}), reset: jest.fn(), - }; - - mocked.collect.mockResolvedValue({}); + }); return mocked; }; -const createMockWithRegisterMetrics = () => ({ - ...createMock(), - registerMetrics: jest.fn().mockResolvedValue({}), -}); +const createMockWithRegisterMetrics = () => + lazyObject({ + ...createMock(), + registerMetrics: jest.fn().mockResolvedValue({}), + }); export const collectorMock = { create: createMock, diff --git a/src/core/packages/metrics/collectors-server-mocks/tsconfig.json b/src/core/packages/metrics/collectors-server-mocks/tsconfig.json index 70ebd1789c44a..954c58fc65f09 100644 --- a/src/core/packages/metrics/collectors-server-mocks/tsconfig.json +++ b/src/core/packages/metrics/collectors-server-mocks/tsconfig.json @@ -12,7 +12,8 @@ ], "kbn_references": [ "@kbn/core-metrics-server", - "@kbn/core-metrics-collectors-server-internal" + "@kbn/core-metrics-collectors-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/metrics/server-mocks/src/metrics_service.mock.ts b/src/core/packages/metrics/server-mocks/src/metrics_service.mock.ts index 2097039c7847c..d0d2ae5519b3d 100644 --- a/src/core/packages/metrics/server-mocks/src/metrics_service.mock.ts +++ b/src/core/packages/metrics/server-mocks/src/metrics_service.mock.ts @@ -23,6 +23,7 @@ import type { MetricsServiceSetup, MetricsServiceStart, } from '@kbn/core-metrics-server'; +import { lazyObject } from '@kbn/lazy-object'; export const sampleEsClientMetrics: ElasticsearchClientsMetrics = { totalActiveSockets: 25, @@ -31,32 +32,31 @@ export const sampleEsClientMetrics: ElasticsearchClientsMetrics = { }; const createInternalSetupContractMock = () => { - const setupContract: jest.Mocked = { + const processMock = collectorMock.createOpsProcessMetrics(); + + const setupContract: jest.Mocked = lazyObject({ collectionInterval: 30000, getEluMetrics$: jest.fn(), - getOpsMetrics$: jest.fn(), - }; - - const processMock = collectorMock.createOpsProcessMetrics(); + getOpsMetrics$: jest.fn().mockReturnValue( + new BehaviorSubject({ + collected_at: new Date('2020-01-01 01:00:00'), + process: processMock, + processes: [processMock], + os: { + platform: 'darwin' as const, + platformRelease: 'test', + load: { '1m': 1, '5m': 1, '15m': 1 }, + memory: { total_in_bytes: 1, free_in_bytes: 1, used_in_bytes: 1 }, + uptime_in_millis: 1, + }, + elasticsearch_client: sampleEsClientMetrics, + response_times: { avg_in_millis: 1, max_in_millis: 1 }, + requests: { disconnects: 1, total: 1, statusCodes: { '200': 1 } }, + concurrent_connections: 1, + }) + ), + }); - setupContract.getOpsMetrics$.mockReturnValue( - new BehaviorSubject({ - collected_at: new Date('2020-01-01 01:00:00'), - process: processMock, - processes: [processMock], - os: { - platform: 'darwin' as const, - platformRelease: 'test', - load: { '1m': 1, '5m': 1, '15m': 1 }, - memory: { total_in_bytes: 1, free_in_bytes: 1, used_in_bytes: 1 }, - uptime_in_millis: 1, - }, - elasticsearch_client: sampleEsClientMetrics, - response_times: { avg_in_millis: 1, max_in_millis: 1 }, - requests: { disconnects: 1, total: 1, statusCodes: { '200': 1 } }, - concurrent_connections: 1, - }) - ); return setupContract; }; @@ -78,11 +78,11 @@ const createStartContractMock = () => { type MetricsServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ setup: jest.fn().mockReturnValue(createSetupContractMock()), start: jest.fn().mockReturnValue(createStartContractMock()), stop: jest.fn(), - }; + }); return mocked; }; diff --git a/src/core/packages/metrics/server-mocks/tsconfig.json b/src/core/packages/metrics/server-mocks/tsconfig.json index d4df6909964c7..49f108284a5d8 100644 --- a/src/core/packages/metrics/server-mocks/tsconfig.json +++ b/src/core/packages/metrics/server-mocks/tsconfig.json @@ -14,7 +14,8 @@ "@kbn/utility-types", "@kbn/core-metrics-server", "@kbn/core-metrics-server-internal", - "@kbn/core-metrics-collectors-server-mocks" + "@kbn/core-metrics-collectors-server-mocks", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/node/server-mocks/src/node_service.mock.ts b/src/core/packages/node/server-mocks/src/node_service.mock.ts index 42a608972b2a2..c61362b5714a0 100644 --- a/src/core/packages/node/server-mocks/src/node_service.mock.ts +++ b/src/core/packages/node/server-mocks/src/node_service.mock.ts @@ -13,15 +13,16 @@ import type { InternalNodeServicePreboot, InternalNodeServiceStart, } from '@kbn/core-node-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createInternalPrebootContractMock = () => { - const prebootContract: jest.Mocked = { + const prebootContract: jest.Mocked = lazyObject({ roles: { backgroundTasks: true, ui: true, migrator: false, }, - }; + }); return prebootContract; }; @@ -36,25 +37,24 @@ const createInternalStartContractMock = ( migrator: boolean; } = { ui: true, backgroundTasks: true, migrator: false } ) => { - const startContract: jest.Mocked = { + const startContract: jest.Mocked = lazyObject({ roles: { backgroundTasks, ui, migrator, }, - }; + }); return startContract; }; type NodeServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { - preboot: jest.fn(), - start: jest.fn(), + const mocked: jest.Mocked = lazyObject({ + preboot: jest.fn().mockResolvedValue(createInternalPrebootContractMock()), + start: jest.fn().mockReturnValue(createInternalStartContractMock()), stop: jest.fn(), - }; - mocked.preboot.mockResolvedValue(createInternalPrebootContractMock()); - mocked.start.mockReturnValue(createInternalStartContractMock()); + }); + return mocked; }; diff --git a/src/core/packages/node/server-mocks/tsconfig.json b/src/core/packages/node/server-mocks/tsconfig.json index ccbc792d1c452..5de437e33afe0 100644 --- a/src/core/packages/node/server-mocks/tsconfig.json +++ b/src/core/packages/node/server-mocks/tsconfig.json @@ -13,6 +13,7 @@ "kbn_references": [ "@kbn/core-node-server-internal", "@kbn/utility-types", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/core/packages/notifications/browser-mocks/src/notifications_service.mock.ts b/src/core/packages/notifications/browser-mocks/src/notifications_service.mock.ts index dced3f237a3f6..438401cead69b 100644 --- a/src/core/packages/notifications/browser-mocks/src/notifications_service.mock.ts +++ b/src/core/packages/notifications/browser-mocks/src/notifications_service.mock.ts @@ -12,21 +12,23 @@ import type { NotificationsSetup, NotificationsStart } from '@kbn/core-notificat import { toastsServiceMock } from './toasts_service.mock'; import { createNotificationCoordinatorMock } from './notification_coordinator.mock'; +import { lazyObject } from '@kbn/lazy-object'; + const createSetupContractMock = () => { - const setupContract: DeeplyMockedKeys = { + const setupContract: DeeplyMockedKeys = lazyObject({ // we have to suppress type errors until decide how to mock es6 class toasts: toastsServiceMock.createSetupContract(), coordinator: createNotificationCoordinatorMock(), - }; + }); return setupContract; }; const createStartContractMock = () => { - const startContract: DeeplyMockedKeys = { + const startContract: DeeplyMockedKeys = lazyObject({ // we have to suppress type errors until decide how to mock es6 class toasts: toastsServiceMock.createStartContract(), showErrorDialog: jest.fn(), - }; + }); return startContract; }; @@ -40,12 +42,12 @@ export interface NotificationsServiceContract { } const createMock = () => { - const mocked: jest.Mocked = { - setup: jest.fn(), + const mocked: jest.Mocked = lazyObject({ + setup: jest.fn().mockReturnValue(createSetupContractMock()), start: jest.fn(), stop: jest.fn(), - }; - mocked.setup.mockReturnValue(createSetupContractMock()); + }); + return mocked; }; diff --git a/src/core/packages/notifications/browser-mocks/tsconfig.json b/src/core/packages/notifications/browser-mocks/tsconfig.json index b6da785c500d6..fc41109eb85d1 100644 --- a/src/core/packages/notifications/browser-mocks/tsconfig.json +++ b/src/core/packages/notifications/browser-mocks/tsconfig.json @@ -12,7 +12,8 @@ ], "kbn_references": [ "@kbn/utility-types-jest", - "@kbn/core-notifications-browser" + "@kbn/core-notifications-browser", + "@kbn/lazy-object" ], "exclude": [ "target/**/*" diff --git a/src/core/packages/overlays/browser-mocks/src/banners_service.mock.ts b/src/core/packages/overlays/browser-mocks/src/banners_service.mock.ts index 73707d1626367..3501ebe9fd839 100644 --- a/src/core/packages/overlays/browser-mocks/src/banners_service.mock.ts +++ b/src/core/packages/overlays/browser-mocks/src/banners_service.mock.ts @@ -12,24 +12,26 @@ import { type InternalOverlayBannersStart, type OverlayBannersService, } from '@kbn/core-overlays-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createStartContractMock = () => { - const startContract: jest.Mocked = { + const startContract: jest.Mocked = lazyObject({ add: jest.fn(), remove: jest.fn(), replace: jest.fn(), get$: jest.fn(), getComponent: jest.fn(), - }; + }); + return startContract; }; const createMock = () => { - const mocked: jest.Mocked> = { - start: jest.fn(), + const mocked: jest.Mocked> = lazyObject({ + start: jest.fn().mockReturnValue(createStartContractMock()), stop: jest.fn(), - }; - mocked.start.mockReturnValue(createStartContractMock()); + }); + return mocked; }; diff --git a/src/core/packages/overlays/browser-mocks/src/flyout_service.mock.ts b/src/core/packages/overlays/browser-mocks/src/flyout_service.mock.ts index 44b0cc71b3922..40f7cb87e7203 100644 --- a/src/core/packages/overlays/browser-mocks/src/flyout_service.mock.ts +++ b/src/core/packages/overlays/browser-mocks/src/flyout_service.mock.ts @@ -10,22 +10,22 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import type { OverlayFlyoutStart } from '@kbn/core-overlays-browser'; import type { FlyoutService } from '@kbn/core-overlays-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createStartContractMock = () => { - const startContract: jest.Mocked = { + const startContract: jest.Mocked = lazyObject({ open: jest.fn().mockReturnValue({ close: jest.fn(), onClose: Promise.resolve(), }), - }; + }); return startContract; }; const createMock = () => { - const mocked: jest.Mocked> = { - start: jest.fn(), - }; - mocked.start.mockReturnValue(createStartContractMock()); + const mocked: jest.Mocked> = lazyObject({ + start: jest.fn().mockReturnValue(createStartContractMock()), + }); return mocked; }; diff --git a/src/core/packages/overlays/browser-mocks/src/modal_service.mock.ts b/src/core/packages/overlays/browser-mocks/src/modal_service.mock.ts index 1830a4977c8ce..60818a7bbe355 100644 --- a/src/core/packages/overlays/browser-mocks/src/modal_service.mock.ts +++ b/src/core/packages/overlays/browser-mocks/src/modal_service.mock.ts @@ -10,23 +10,23 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import type { OverlayModalStart } from '@kbn/core-overlays-browser'; import type { ModalService } from '@kbn/core-overlays-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createStartContractMock = () => { - const startContract: jest.Mocked = { + const startContract: jest.Mocked = lazyObject({ open: jest.fn().mockReturnValue({ close: jest.fn(), onClose: Promise.resolve(), }), openConfirm: jest.fn().mockResolvedValue(true), - }; + }); return startContract; }; const createMock = () => { - const mocked: jest.Mocked> = { - start: jest.fn(), - }; - mocked.start.mockReturnValue(createStartContractMock()); + const mocked: jest.Mocked> = lazyObject({ + start: jest.fn().mockReturnValue(createStartContractMock()), + }); return mocked; }; diff --git a/src/core/packages/overlays/browser-mocks/src/overlay_service.mock.ts b/src/core/packages/overlays/browser-mocks/src/overlay_service.mock.ts index 791b0fa16f6d4..ed3bc8d4b6d26 100644 --- a/src/core/packages/overlays/browser-mocks/src/overlay_service.mock.ts +++ b/src/core/packages/overlays/browser-mocks/src/overlay_service.mock.ts @@ -14,23 +14,23 @@ import type { OverlayStart } from '@kbn/core-overlays-browser'; import { overlayBannersServiceMock } from './banners_service.mock'; import { overlayFlyoutServiceMock } from './flyout_service.mock'; import { overlayModalServiceMock } from './modal_service.mock'; +import { lazyObject } from '@kbn/lazy-object'; const createStartContractMock = () => { const overlayStart = overlayModalServiceMock.createStartContract(); - const startContract: DeeplyMockedKeys = { + const startContract: DeeplyMockedKeys = lazyObject({ openFlyout: overlayFlyoutServiceMock.createStartContract().open, openModal: overlayStart.open, openConfirm: overlayStart.openConfirm, banners: overlayBannersServiceMock.createStartContract(), - }; + }); return startContract; }; const createMock = () => { - const mocked: jest.Mocked> = { - start: jest.fn(), - }; - mocked.start.mockReturnValue(createStartContractMock()); + const mocked: jest.Mocked> = lazyObject({ + start: jest.fn().mockReturnValue(createStartContractMock()), + }); return mocked; }; diff --git a/src/core/packages/overlays/browser-mocks/tsconfig.json b/src/core/packages/overlays/browser-mocks/tsconfig.json index b25759f180279..90e1fcc4e593e 100644 --- a/src/core/packages/overlays/browser-mocks/tsconfig.json +++ b/src/core/packages/overlays/browser-mocks/tsconfig.json @@ -14,7 +14,8 @@ "@kbn/utility-types", "@kbn/utility-types-jest", "@kbn/core-overlays-browser", - "@kbn/core-overlays-browser-internal" + "@kbn/core-overlays-browser-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/plugins/browser-mocks/src/plugins_service.mock.ts b/src/core/packages/plugins/browser-mocks/src/plugins_service.mock.ts index 8f9e0164ba287..786d8e2eae639 100644 --- a/src/core/packages/plugins/browser-mocks/src/plugins_service.mock.ts +++ b/src/core/packages/plugins/browser-mocks/src/plugins_service.mock.ts @@ -16,19 +16,20 @@ import type { InternalPluginsServiceStart, } from '@kbn/core-plugins-browser-internal'; import type { BuildFlavor } from '@kbn/config/src/types'; +import { lazyObject } from '@kbn/lazy-object'; const createInternalSetupContractMock = () => { - const setupContract: jest.Mocked = { + const setupContract: jest.Mocked = lazyObject({ contracts: new Map(), - }; + }); // we have to suppress type errors until decide how to mock es6 class return setupContract as InternalPluginsServiceSetup; }; const createInternalStartContractMock = () => { - const startContract: jest.Mocked = { + const startContract: jest.Mocked = lazyObject({ contracts: new Map(), - }; + }); // we have to suppress type errors until decide how to mock es6 class return startContract as InternalPluginsServiceSetup; }; @@ -37,7 +38,7 @@ const createPluginInitializerContextMock = ( config: unknown = {}, { buildFlavor = 'serverless' }: { buildFlavor?: BuildFlavor } = {} ) => { - const mock: PluginInitializerContext = { + const mock: PluginInitializerContext = lazyObject({ opaqueId: Symbol(), env: { mode: { @@ -60,22 +61,20 @@ const createPluginInitializerContextMock = ( config: { get: () => config as T, }, - }; + }); return mock; }; type PluginsServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ getOpaqueIds: jest.fn(), - setup: jest.fn(), - start: jest.fn(), + setup: jest.fn().mockResolvedValue(createInternalSetupContractMock()), + start: jest.fn().mockResolvedValue(createInternalStartContractMock()), stop: jest.fn(), - }; + }); - mocked.setup.mockResolvedValue(createInternalSetupContractMock()); - mocked.start.mockResolvedValue(createInternalStartContractMock()); return mocked; }; diff --git a/src/core/packages/plugins/browser-mocks/tsconfig.json b/src/core/packages/plugins/browser-mocks/tsconfig.json index aae47d99db8ec..666189a821e0a 100644 --- a/src/core/packages/plugins/browser-mocks/tsconfig.json +++ b/src/core/packages/plugins/browser-mocks/tsconfig.json @@ -17,6 +17,7 @@ "@kbn/core-plugins-browser-internal", "@kbn/core-plugins-browser", "@kbn/config", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/core/packages/plugins/server-mocks/src/plugins_service.mock.ts b/src/core/packages/plugins/server-mocks/src/plugins_service.mock.ts index 4813d6c44f7c9..1c7c4f7c8be17 100644 --- a/src/core/packages/plugins/server-mocks/src/plugins_service.mock.ts +++ b/src/core/packages/plugins/server-mocks/src/plugins_service.mock.ts @@ -14,48 +14,52 @@ import { type InternalPluginsServiceSetup, type InternalPluginsServiceStart, } from '@kbn/core-plugins-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; type PluginsServiceMock = jest.Mocked>; -const createInternalSetupContractMock = (): InternalPluginsServiceSetup => ({ - contracts: new Map(), - initialized: true, -}); -const createInternalStartContractMock = (): InternalPluginsServiceStart => ({ - contracts: new Map(), -}); +const createInternalSetupContractMock = (): InternalPluginsServiceSetup => + lazyObject({ + contracts: new Map(), + initialized: true, + }); +const createInternalStartContractMock = (): InternalPluginsServiceStart => + lazyObject({ + contracts: new Map(), + }); -const createServiceMock = (): PluginsServiceMock => ({ - discover: jest.fn(), - getExposedPluginConfigsToUsage: jest.fn(), - preboot: jest.fn(), - setup: jest.fn().mockResolvedValue(createInternalSetupContractMock()), - start: jest.fn().mockResolvedValue(createInternalStartContractMock()), - stop: jest.fn(), -}); +const createServiceMock = (): PluginsServiceMock => + lazyObject({ + discover: jest.fn(), + getExposedPluginConfigsToUsage: jest.fn(), + preboot: jest.fn(), + setup: jest.fn().mockResolvedValue(createInternalSetupContractMock()), + start: jest.fn().mockResolvedValue(createInternalStartContractMock()), + stop: jest.fn(), + }); const createSetupContractMock = () => { - const contract: jest.Mocked = { + const contract: jest.Mocked = lazyObject({ onSetup: jest.fn(), onStart: jest.fn(), - }; + }); return contract; }; const createStartContractMock = () => { - const contract: jest.Mocked = { + const contract: jest.Mocked = lazyObject({ onStart: jest.fn(), - }; + }); return contract; }; function createUiPlugins() { - return { + return lazyObject({ browserConfigs: new Map(), internal: new Map(), public: new Map(), - }; + }); } export const pluginServiceMock = { diff --git a/src/core/packages/plugins/server-mocks/tsconfig.json b/src/core/packages/plugins/server-mocks/tsconfig.json index b9092121bae0c..bd81eff133d9e 100644 --- a/src/core/packages/plugins/server-mocks/tsconfig.json +++ b/src/core/packages/plugins/server-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-plugins-server-internal", - "@kbn/core-plugins-contracts-server" + "@kbn/core-plugins-contracts-server", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/preboot/server-mocks/src/preboot_service.mock.ts b/src/core/packages/preboot/server-mocks/src/preboot_service.mock.ts index bb7e15cd977d9..c9187c5e682e5 100644 --- a/src/core/packages/preboot/server-mocks/src/preboot_service.mock.ts +++ b/src/core/packages/preboot/server-mocks/src/preboot_service.mock.ts @@ -13,24 +13,25 @@ import type { PrebootService, } from '@kbn/core-preboot-server-internal'; import type { PrebootServicePreboot } from '@kbn/core-preboot-server'; +import { lazyObject } from '@kbn/lazy-object'; export type InternalPrebootServicePrebootMock = jest.Mocked; export type PrebootServicePrebootMock = jest.Mocked; const createInternalPrebootContractMock = () => { - const mock: InternalPrebootServicePrebootMock = { + const mock: InternalPrebootServicePrebootMock = lazyObject({ isSetupOnHold: jest.fn(), holdSetupUntilResolved: jest.fn(), waitUntilCanSetup: jest.fn(), - }; + }); return mock; }; const createPrebootContractMock = () => { - const mock: PrebootServicePrebootMock = { + const mock: PrebootServicePrebootMock = lazyObject({ isSetupOnHold: jest.fn(), holdSetupUntilResolved: jest.fn(), - }; + }); return mock; }; @@ -38,11 +39,11 @@ const createPrebootContractMock = () => { type PrebootServiceContract = PublicMethodsOf; const createPrebootServiceMock = () => { - const mocked: jest.Mocked = { - preboot: jest.fn(), + const mocked: jest.Mocked = lazyObject({ + preboot: jest.fn().mockReturnValue(createInternalPrebootContractMock()), stop: jest.fn(), - }; - mocked.preboot.mockReturnValue(createInternalPrebootContractMock()); + }); + return mocked; }; diff --git a/src/core/packages/preboot/server-mocks/tsconfig.json b/src/core/packages/preboot/server-mocks/tsconfig.json index fca8114447395..b049ad1cf9b18 100644 --- a/src/core/packages/preboot/server-mocks/tsconfig.json +++ b/src/core/packages/preboot/server-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-preboot-server-internal", - "@kbn/core-preboot-server" + "@kbn/core-preboot-server", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/pricing/browser-mocks/src/pricing_service.mock.ts b/src/core/packages/pricing/browser-mocks/src/pricing_service.mock.ts index a48ffda11f2ea..1c5a55278d9c7 100644 --- a/src/core/packages/pricing/browser-mocks/src/pricing_service.mock.ts +++ b/src/core/packages/pricing/browser-mocks/src/pricing_service.mock.ts @@ -10,17 +10,20 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import type { PricingServiceStart } from '@kbn/core-pricing-browser'; import type { PricingService } from '@kbn/core-pricing-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; -const createStartContractMock = (): jest.Mocked => ({ - isFeatureAvailable: jest.fn(), - getActiveProduct: jest.fn(), -}); +const createStartContractMock = (): jest.Mocked => + lazyObject({ + isFeatureAvailable: jest.fn(), + getActiveProduct: jest.fn(), + }); -const createMock = (): jest.Mocked> => ({ - setup: jest.fn(), - start: jest.fn().mockImplementation(createStartContractMock), - stop: jest.fn(), -}); +const createMock = (): jest.Mocked> => + lazyObject({ + setup: jest.fn(), + start: jest.fn().mockImplementation(createStartContractMock), + stop: jest.fn(), + }); export const pricingServiceMock = { create: createMock, diff --git a/src/core/packages/pricing/browser-mocks/tsconfig.json b/src/core/packages/pricing/browser-mocks/tsconfig.json index 8ab77f1a41f40..d89c11ca71a57 100644 --- a/src/core/packages/pricing/browser-mocks/tsconfig.json +++ b/src/core/packages/pricing/browser-mocks/tsconfig.json @@ -18,5 +18,6 @@ "@kbn/utility-types", "@kbn/core-pricing-browser", "@kbn/core-pricing-browser-internal", + "@kbn/lazy-object", ] } diff --git a/src/core/packages/pricing/server-mocks/src/pricing_service.mock.ts b/src/core/packages/pricing/server-mocks/src/pricing_service.mock.ts index 388209dc29f36..b8d508fbd7369 100644 --- a/src/core/packages/pricing/server-mocks/src/pricing_service.mock.ts +++ b/src/core/packages/pricing/server-mocks/src/pricing_service.mock.ts @@ -10,32 +10,33 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import type { PricingServiceSetup, PricingServiceStart } from '@kbn/core-pricing-server'; import type { PricingService } from '@kbn/core-pricing-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createSetupContractMock = () => { - const setupContract: jest.Mocked = { + const setupContract: jest.Mocked = lazyObject({ isFeatureAvailable: jest.fn(), registerProductFeatures: jest.fn(), - }; + }); return setupContract; }; const createStartContractMock = () => { - const startContract: jest.Mocked = { + const startContract: jest.Mocked = lazyObject({ isFeatureAvailable: jest.fn(), getActiveProduct: jest.fn(), - }; + }); return startContract; }; export type PricingServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ preboot: jest.fn(), setup: jest.fn().mockReturnValue(createSetupContractMock()), start: jest.fn().mockReturnValue(createStartContractMock()), stop: jest.fn(), - }; + }); return mocked; }; diff --git a/src/core/packages/pricing/server-mocks/tsconfig.json b/src/core/packages/pricing/server-mocks/tsconfig.json index 2863bbb451210..c6c1b1a5e1145 100644 --- a/src/core/packages/pricing/server-mocks/tsconfig.json +++ b/src/core/packages/pricing/server-mocks/tsconfig.json @@ -17,5 +17,6 @@ "@kbn/utility-types", "@kbn/core-pricing-server", "@kbn/core-pricing-server-internal", + "@kbn/lazy-object", ] } diff --git a/src/core/packages/rendering/browser-mocks/src/rendering_service.mock.tsx b/src/core/packages/rendering/browser-mocks/src/rendering_service.mock.tsx index 5613632766216..16a06c25b7c6b 100644 --- a/src/core/packages/rendering/browser-mocks/src/rendering_service.mock.tsx +++ b/src/core/packages/rendering/browser-mocks/src/rendering_service.mock.tsx @@ -11,6 +11,7 @@ import React from 'react'; import type { RenderingService } from '@kbn/core-rendering-browser'; import { EuiProvider } from '@elastic/eui'; import { I18nProvider } from '@kbn/i18n-react'; +import { lazyObject } from '@kbn/lazy-object'; /** * This is declared internally to avoid a circular dependency issue @@ -21,21 +22,21 @@ export interface RenderingServiceInternal { } const createMockInternal = () => { - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ start: jest.fn().mockImplementation(createMock), renderCore: jest.fn(), - }; + }); return mocked; }; const createMock = () => { - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ addContext: jest.fn().mockImplementation((element) => ( {element} )), - }; + }); return mocked; }; diff --git a/src/core/packages/rendering/browser-mocks/tsconfig.json b/src/core/packages/rendering/browser-mocks/tsconfig.json index 9473334a2e789..918c361175ab9 100644 --- a/src/core/packages/rendering/browser-mocks/tsconfig.json +++ b/src/core/packages/rendering/browser-mocks/tsconfig.json @@ -13,7 +13,8 @@ ], "kbn_references": [ "@kbn/core-rendering-browser", - "@kbn/i18n-react" + "@kbn/i18n-react", + "@kbn/lazy-object" ], "exclude": [ "target/**/*" diff --git a/src/core/packages/saved-objects/api-server-mocks/src/repository.mock.ts b/src/core/packages/saved-objects/api-server-mocks/src/repository.mock.ts index c9b9ab4fba2a3..8f67e53516616 100644 --- a/src/core/packages/saved-objects/api-server-mocks/src/repository.mock.ts +++ b/src/core/packages/saved-objects/api-server-mocks/src/repository.mock.ts @@ -9,9 +9,10 @@ import { savedObjectsPointInTimeFinderMock } from './point_in_time_finder.mock'; import type { ISavedObjectsRepository } from '@kbn/core-saved-objects-api-server'; +import { lazyObject } from '@kbn/lazy-object'; const create = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ checkConflicts: jest.fn(), create: jest.fn(), bulkCreate: jest.fn(), @@ -34,7 +35,7 @@ const create = () => { updateObjectsSpaces: jest.fn(), getCurrentNamespace: jest.fn(), asScopedToNamespace: jest.fn().mockImplementation(create), - }; + }); mock.createPointInTimeFinder = savedObjectsPointInTimeFinderMock.create({ savedObjectsMock: mock, diff --git a/src/core/packages/saved-objects/api-server-mocks/src/saved_objects_client.mock.ts b/src/core/packages/saved-objects/api-server-mocks/src/saved_objects_client.mock.ts index aebeeb43059f4..16a7131f317b2 100644 --- a/src/core/packages/saved-objects/api-server-mocks/src/saved_objects_client.mock.ts +++ b/src/core/packages/saved-objects/api-server-mocks/src/saved_objects_client.mock.ts @@ -9,9 +9,10 @@ import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { savedObjectsPointInTimeFinderMock } from './point_in_time_finder.mock'; +import { lazyObject } from '@kbn/lazy-object'; const create = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ create: jest.fn(), bulkCreate: jest.fn(), checkConflicts: jest.fn(), @@ -32,7 +33,7 @@ const create = () => { updateObjectsSpaces: jest.fn(), getCurrentNamespace: jest.fn(), asScopedToNamespace: jest.fn().mockImplementation(create), - }; + }); mock.createPointInTimeFinder = savedObjectsPointInTimeFinderMock.create({ savedObjectsMock: mock, diff --git a/src/core/packages/saved-objects/api-server-mocks/src/saved_objects_extensions.mock.ts b/src/core/packages/saved-objects/api-server-mocks/src/saved_objects_extensions.mock.ts index 5506c7281d78b..ca6ab9696c331 100644 --- a/src/core/packages/saved-objects/api-server-mocks/src/saved_objects_extensions.mock.ts +++ b/src/core/packages/saved-objects/api-server-mocks/src/saved_objects_extensions.mock.ts @@ -13,50 +13,55 @@ import type { ISavedObjectsSpacesExtension, SavedObjectsExtensions, } from '@kbn/core-saved-objects-server'; +import { lazyObject } from '@kbn/lazy-object'; -const createEncryptionExtension = (): jest.Mocked => ({ - isEncryptableType: jest.fn(), - decryptOrStripResponseAttributes: jest.fn(), - encryptAttributes: jest.fn(), - shouldEnforceRandomId: jest.fn(), -}); +const createEncryptionExtension = (): jest.Mocked => + lazyObject({ + isEncryptableType: jest.fn(), + decryptOrStripResponseAttributes: jest.fn(), + encryptAttributes: jest.fn(), + shouldEnforceRandomId: jest.fn(), + }); -const createSecurityExtension = (): jest.Mocked => ({ - authorizeCreate: jest.fn(), - authorizeBulkCreate: jest.fn(), - authorizeUpdate: jest.fn(), - authorizeBulkUpdate: jest.fn(), - authorizeDelete: jest.fn(), - authorizeBulkDelete: jest.fn(), - authorizeGet: jest.fn(), - authorizeBulkGet: jest.fn(), - authorizeCheckConflicts: jest.fn(), - authorizeRemoveReferences: jest.fn(), - authorizeOpenPointInTime: jest.fn(), - auditClosePointInTime: jest.fn(), - authorizeFind: jest.fn(), - getFindRedactTypeMap: jest.fn(), - authorizeAndRedactMultiNamespaceReferences: jest.fn(), - authorizeAndRedactInternalBulkResolve: jest.fn(), - redactNamespaces: jest.fn(), - authorizeUpdateSpaces: jest.fn(), - authorizeDisableLegacyUrlAliases: jest.fn(), - auditObjectsForSpaceDeletion: jest.fn(), - getCurrentUser: jest.fn(), - includeSavedObjectNames: jest.fn(), -}); +const createSecurityExtension = (): jest.Mocked => + lazyObject({ + authorizeCreate: jest.fn(), + authorizeBulkCreate: jest.fn(), + authorizeUpdate: jest.fn(), + authorizeBulkUpdate: jest.fn(), + authorizeDelete: jest.fn(), + authorizeBulkDelete: jest.fn(), + authorizeGet: jest.fn(), + authorizeBulkGet: jest.fn(), + authorizeCheckConflicts: jest.fn(), + authorizeRemoveReferences: jest.fn(), + authorizeOpenPointInTime: jest.fn(), + auditClosePointInTime: jest.fn(), + authorizeFind: jest.fn(), + getFindRedactTypeMap: jest.fn(), + authorizeAndRedactMultiNamespaceReferences: jest.fn(), + authorizeAndRedactInternalBulkResolve: jest.fn(), + redactNamespaces: jest.fn(), + authorizeUpdateSpaces: jest.fn(), + authorizeDisableLegacyUrlAliases: jest.fn(), + auditObjectsForSpaceDeletion: jest.fn(), + getCurrentUser: jest.fn(), + includeSavedObjectNames: jest.fn(), + }); -const createSpacesExtension = (): jest.Mocked => ({ - getCurrentNamespace: jest.fn(), - getSearchableNamespaces: jest.fn(), - asScopedToNamespace: jest.fn().mockImplementation(createSpacesExtension), -}); +const createSpacesExtension = (): jest.Mocked => + lazyObject({ + getCurrentNamespace: jest.fn(), + getSearchableNamespaces: jest.fn(), + asScopedToNamespace: jest.fn().mockImplementation(createSpacesExtension), + }); -const create = (): jest.Mocked => ({ - encryptionExtension: createEncryptionExtension(), - securityExtension: createSecurityExtension(), - spacesExtension: createSpacesExtension(), -}); +const create = (): jest.Mocked => + lazyObject({ + encryptionExtension: createEncryptionExtension(), + securityExtension: createSecurityExtension(), + spacesExtension: createSpacesExtension(), + }); export const savedObjectsExtensionsMock = { create, diff --git a/src/core/packages/saved-objects/api-server-mocks/src/scoped_client_provider.mock.ts b/src/core/packages/saved-objects/api-server-mocks/src/scoped_client_provider.mock.ts index cc25a38241d44..7f71f72f8f9e5 100644 --- a/src/core/packages/saved-objects/api-server-mocks/src/scoped_client_provider.mock.ts +++ b/src/core/packages/saved-objects/api-server-mocks/src/scoped_client_provider.mock.ts @@ -8,12 +8,14 @@ */ import type { ISavedObjectsClientProvider } from '@kbn/core-saved-objects-api-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; -const create = (): jest.Mocked => ({ - getClient: jest.fn(), - setClientFactory: jest.fn(), - getExtensions: jest.fn(), -}); +const create = (): jest.Mocked => + lazyObject({ + getClient: jest.fn(), + setClientFactory: jest.fn(), + getExtensions: jest.fn(), + }); export const savedObjectsClientProviderMock = { create, diff --git a/src/core/packages/saved-objects/api-server-mocks/tsconfig.json b/src/core/packages/saved-objects/api-server-mocks/tsconfig.json index 00802e30291fb..bb76e98ea553c 100644 --- a/src/core/packages/saved-objects/api-server-mocks/tsconfig.json +++ b/src/core/packages/saved-objects/api-server-mocks/tsconfig.json @@ -15,6 +15,7 @@ "@kbn/core-saved-objects-api-server-internal", "@kbn/logging-mocks", "@kbn/core-saved-objects-server", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/core/packages/saved-objects/base-server-mocks/src/document_migrator.mock.ts b/src/core/packages/saved-objects/base-server-mocks/src/document_migrator.mock.ts index 3bf517a5405c9..364f34ca62dc1 100644 --- a/src/core/packages/saved-objects/base-server-mocks/src/document_migrator.mock.ts +++ b/src/core/packages/saved-objects/base-server-mocks/src/document_migrator.mock.ts @@ -8,11 +8,12 @@ */ import type { IDocumentMigrator } from '@kbn/core-saved-objects-base-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; export const createDocumentMigratorMock = (): jest.Mocked => { - return { + return lazyObject({ migrate: jest.fn().mockImplementation((doc: unknown) => doc), migrateAndConvert: jest.fn().mockImplementation((doc: unknown) => doc), isDowngradeRequired: jest.fn().mockReturnValue(false), - }; + }); }; diff --git a/src/core/packages/saved-objects/base-server-mocks/src/saved_objects_type_registry.mock.ts b/src/core/packages/saved-objects/base-server-mocks/src/saved_objects_type_registry.mock.ts index 34c4fa0d472a2..6c7df1b763cf6 100644 --- a/src/core/packages/saved-objects/base-server-mocks/src/saved_objects_type_registry.mock.ts +++ b/src/core/packages/saved-objects/base-server-mocks/src/saved_objects_type_registry.mock.ts @@ -9,46 +9,31 @@ import type { ISavedObjectTypeRegistry } from '@kbn/core-saved-objects-server'; import { type SavedObjectTypeRegistry } from '@kbn/core-saved-objects-base-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createRegistryMock = (): jest.Mocked< ISavedObjectTypeRegistry & Pick > => { - const mock = { + const mock = lazyObject({ registerType: jest.fn(), - getLegacyTypes: jest.fn(), + getLegacyTypes: jest.fn().mockReturnValue([]), getType: jest.fn(), - getVisibleTypes: jest.fn(), - getVisibleToHttpApisTypes: jest.fn(), - getAllTypes: jest.fn(), - getImportableAndExportableTypes: jest.fn(), - isNamespaceAgnostic: jest.fn(), - isSingleNamespace: jest.fn(), - isMultiNamespace: jest.fn(), - isShareable: jest.fn(), - isHidden: jest.fn(), + getVisibleTypes: jest.fn().mockReturnValue([]), + getVisibleToHttpApisTypes: jest.fn().mockReturnValue(false), + getAllTypes: jest.fn().mockReturnValue([]), + getImportableAndExportableTypes: jest.fn().mockReturnValue([]), + isNamespaceAgnostic: jest.fn().mockImplementation((type: string) => type === 'global'), + isSingleNamespace: jest + .fn() + .mockImplementation((type: string) => type !== 'global' && type !== 'shared'), + isMultiNamespace: jest.fn().mockImplementation((type: string) => type === 'shared'), + isShareable: jest.fn().mockImplementation((type: string) => type === 'shared'), + isHidden: jest.fn().mockReturnValue(false), isHiddenFromHttpApis: jest.fn(), - getIndex: jest.fn(), - isImportableAndExportable: jest.fn(), - getNameAttribute: jest.fn(), - }; - - mock.getVisibleTypes.mockReturnValue([]); - mock.getAllTypes.mockReturnValue([]); - mock.getLegacyTypes.mockReturnValue([]); - mock.getImportableAndExportableTypes.mockReturnValue([]); - mock.getIndex.mockReturnValue('.kibana-test'); - mock.getIndex.mockReturnValue('.kibana-test'); - mock.isHidden.mockReturnValue(false); - mock.isHiddenFromHttpApis.mockReturnValue(false); - mock.isNamespaceAgnostic.mockImplementation((type: string) => type === 'global'); - mock.isSingleNamespace.mockImplementation( - (type: string) => type !== 'global' && type !== 'shared' - ); - mock.isMultiNamespace.mockImplementation((type: string) => type === 'shared'); - mock.isShareable.mockImplementation((type: string) => type === 'shared'); - mock.isImportableAndExportable.mockReturnValue(true); - mock.getVisibleToHttpApisTypes.mockReturnValue(false); - mock.getNameAttribute.mockReturnValue(undefined); + getIndex: jest.fn().mockReturnValue('.kibana-test'), + isImportableAndExportable: jest.fn().mockReturnValue(true), + getNameAttribute: jest.fn().mockReturnValue(undefined), + }); return mock; }; diff --git a/src/core/packages/saved-objects/base-server-mocks/src/serializer.mock.ts b/src/core/packages/saved-objects/base-server-mocks/src/serializer.mock.ts index b2baaae58dab9..fee79acbd082f 100644 --- a/src/core/packages/saved-objects/base-server-mocks/src/serializer.mock.ts +++ b/src/core/packages/saved-objects/base-server-mocks/src/serializer.mock.ts @@ -8,15 +8,16 @@ */ import type { ISavedObjectsSerializer } from '@kbn/core-saved-objects-server'; +import { lazyObject } from '@kbn/lazy-object'; const createSerializerMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ isRawSavedObject: jest.fn(), rawToSavedObject: jest.fn(), savedObjectToRaw: jest.fn(), generateRawId: jest.fn(), generateRawLegacyUrlAliasId: jest.fn(), - }; + }); return mock; }; diff --git a/src/core/packages/saved-objects/base-server-mocks/tsconfig.json b/src/core/packages/saved-objects/base-server-mocks/tsconfig.json index f3f4fcb8df326..40e80154f3729 100644 --- a/src/core/packages/saved-objects/base-server-mocks/tsconfig.json +++ b/src/core/packages/saved-objects/base-server-mocks/tsconfig.json @@ -12,7 +12,8 @@ ], "kbn_references": [ "@kbn/core-saved-objects-server", - "@kbn/core-saved-objects-base-server-internal" + "@kbn/core-saved-objects-base-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/saved-objects/import-export-server-mocks/src/saved_objects_exporter.mock.ts b/src/core/packages/saved-objects/import-export-server-mocks/src/saved_objects_exporter.mock.ts index 5412910d024b7..7d69dcd66bff0 100644 --- a/src/core/packages/saved-objects/import-export-server-mocks/src/saved_objects_exporter.mock.ts +++ b/src/core/packages/saved-objects/import-export-server-mocks/src/saved_objects_exporter.mock.ts @@ -8,12 +8,13 @@ */ import type { ISavedObjectsExporter } from '@kbn/core-saved-objects-server'; +import { lazyObject } from '@kbn/lazy-object'; const createExporterMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ exportByObjects: jest.fn(), exportByTypes: jest.fn(), - }; + }); return mock; }; diff --git a/src/core/packages/saved-objects/import-export-server-mocks/src/saved_objects_importer.mock.ts b/src/core/packages/saved-objects/import-export-server-mocks/src/saved_objects_importer.mock.ts index 6b0deb84d4fa0..0ef372dbdc2b0 100644 --- a/src/core/packages/saved-objects/import-export-server-mocks/src/saved_objects_importer.mock.ts +++ b/src/core/packages/saved-objects/import-export-server-mocks/src/saved_objects_importer.mock.ts @@ -8,12 +8,13 @@ */ import type { ISavedObjectsImporter } from '@kbn/core-saved-objects-server'; +import { lazyObject } from '@kbn/lazy-object'; const createImporterMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ import: jest.fn(), resolveImportErrors: jest.fn(), - }; + }); return mock; }; diff --git a/src/core/packages/saved-objects/import-export-server-mocks/tsconfig.json b/src/core/packages/saved-objects/import-export-server-mocks/tsconfig.json index 0417a7516da47..8f64507c502c8 100644 --- a/src/core/packages/saved-objects/import-export-server-mocks/tsconfig.json +++ b/src/core/packages/saved-objects/import-export-server-mocks/tsconfig.json @@ -11,7 +11,8 @@ "**/*.ts", ], "kbn_references": [ - "@kbn/core-saved-objects-server" + "@kbn/core-saved-objects-server", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/saved-objects/migration-server-mocks/src/kibana_migrator.mock.ts b/src/core/packages/saved-objects/migration-server-mocks/src/kibana_migrator.mock.ts index 1ea2980cc6c30..d281e45148241 100644 --- a/src/core/packages/saved-objects/migration-server-mocks/src/kibana_migrator.mock.ts +++ b/src/core/packages/saved-objects/migration-server-mocks/src/kibana_migrator.mock.ts @@ -18,6 +18,7 @@ import { buildTypesMappings, } from '@kbn/core-saved-objects-migration-server-internal'; import { createDocumentMigratorMock } from '@kbn/core-saved-objects-base-server-mocks'; +import { lazyObject } from '@kbn/lazy-object'; const defaultSavedObjectTypes: SavedObjectsType[] = [ { @@ -40,11 +41,11 @@ const createMigrator = ( types: SavedObjectsType[]; } = { types: defaultSavedObjectTypes } ) => { - const mockMigrator: jest.Mocked = { + const mockMigrator: jest.Mocked = lazyObject({ kibanaVersion: '8.0.0-testing', runMigrations: jest.fn(), - getActiveMappings: jest.fn(), - migrateDocument: jest.fn(), + getActiveMappings: jest.fn().mockReturnValue(buildActiveMappings(buildTypesMappings(types))), + migrateDocument: jest.fn().mockImplementation((doc) => doc), prepareMigrations: jest.fn(), getStatus$: jest.fn( () => @@ -60,13 +61,8 @@ const createMigrator = ( ], }) ), - getDocumentMigrator: jest.fn(), - }; - - mockMigrator.getActiveMappings.mockReturnValue(buildActiveMappings(buildTypesMappings(types))); - mockMigrator.migrateDocument.mockImplementation((doc) => doc); - mockMigrator.getDocumentMigrator.mockReturnValue(createDocumentMigratorMock()); - + getDocumentMigrator: jest.fn().mockReturnValue(createDocumentMigratorMock()), + }); return mockMigrator; }; diff --git a/src/core/packages/saved-objects/migration-server-mocks/src/migration.mocks.ts b/src/core/packages/saved-objects/migration-server-mocks/src/migration.mocks.ts index 48da25c6ed5e5..c8d2e33272721 100644 --- a/src/core/packages/saved-objects/migration-server-mocks/src/migration.mocks.ts +++ b/src/core/packages/saved-objects/migration-server-mocks/src/migration.mocks.ts @@ -11,15 +11,16 @@ import type { SavedObjectMigrationContext, SavedObjectsMigrationLogger, } from '@kbn/core-saved-objects-server'; +import { lazyObject } from '@kbn/lazy-object'; export const createSavedObjectsMigrationLoggerMock = (): jest.Mocked => { - const mock = { + const mock = lazyObject({ debug: jest.fn(), info: jest.fn(), warn: jest.fn(), error: jest.fn(), - }; + }); return mock; }; @@ -33,12 +34,12 @@ const createContextMock = ({ convertToMultiNamespaceTypeVersion?: string; isSingleNamespaceType?: boolean; } = {}): jest.Mocked => { - const mock = { + const mock = lazyObject({ log: createSavedObjectsMigrationLoggerMock(), migrationVersion, convertToMultiNamespaceTypeVersion, isSingleNamespaceType, - }; + }); return mock; }; diff --git a/src/core/packages/saved-objects/migration-server-mocks/tsconfig.json b/src/core/packages/saved-objects/migration-server-mocks/tsconfig.json index df754c5d879d6..8a1ab3b26af25 100644 --- a/src/core/packages/saved-objects/migration-server-mocks/tsconfig.json +++ b/src/core/packages/saved-objects/migration-server-mocks/tsconfig.json @@ -14,7 +14,8 @@ "@kbn/core-saved-objects-server", "@kbn/core-saved-objects-base-server-internal", "@kbn/core-saved-objects-migration-server-internal", - "@kbn/core-saved-objects-base-server-mocks" + "@kbn/core-saved-objects-base-server-mocks", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/saved-objects/server-mocks/src/saved_objects_service.mock.ts b/src/core/packages/saved-objects/server-mocks/src/saved_objects_service.mock.ts index 458c7081eb730..2f11edefa566c 100644 --- a/src/core/packages/saved-objects/server-mocks/src/saved_objects_service.mock.ts +++ b/src/core/packages/saved-objects/server-mocks/src/saved_objects_service.mock.ts @@ -31,88 +31,72 @@ import { } from '@kbn/core-saved-objects-import-export-server-mocks'; import { migrationMocks } from '@kbn/core-saved-objects-migration-server-mocks'; import { MAIN_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; +import { lazyObject } from '@kbn/lazy-object'; type SavedObjectsServiceContract = PublicMethodsOf; const createStartContractMock = (typeRegistry?: jest.Mocked) => { - const startContrat: jest.Mocked = { - getScopedClient: jest.fn(), - getUnsafeInternalClient: jest.fn(), - createInternalRepository: jest.fn(), - createScopedRepository: jest.fn(), + const startContrat: jest.Mocked = lazyObject({ + getScopedClient: jest.fn().mockReturnValue(savedObjectsClientMock.create()), + getUnsafeInternalClient: jest.fn().mockReturnValue(savedObjectsClientMock.create()), + createInternalRepository: jest.fn().mockReturnValue(savedObjectsRepositoryMock.create()), + createScopedRepository: jest.fn().mockReturnValue(savedObjectsRepositoryMock.create()), createSerializer: jest.fn(), - createExporter: jest.fn(), - createImporter: jest.fn(), - getTypeRegistry: jest.fn(), - getDefaultIndex: jest.fn(), - getIndexForType: jest.fn(), - getIndicesForTypes: jest.fn(), - getAllIndices: jest.fn(), - }; - - startContrat.getScopedClient.mockReturnValue(savedObjectsClientMock.create()); - startContrat.getUnsafeInternalClient.mockReturnValue(savedObjectsClientMock.create()); - startContrat.createInternalRepository.mockReturnValue(savedObjectsRepositoryMock.create()); - startContrat.createScopedRepository.mockReturnValue(savedObjectsRepositoryMock.create()); - startContrat.getTypeRegistry.mockReturnValue(typeRegistry ?? typeRegistryMock.create()); - startContrat.createExporter.mockReturnValue(savedObjectsExporterMock.create()); - startContrat.createImporter.mockReturnValue(savedObjectsImporterMock.create()); - startContrat.getDefaultIndex.mockReturnValue(MAIN_SAVED_OBJECT_INDEX); - startContrat.getIndexForType.mockReturnValue(MAIN_SAVED_OBJECT_INDEX); - startContrat.getIndicesForTypes.mockReturnValue([MAIN_SAVED_OBJECT_INDEX]); - startContrat.getAllIndices.mockReturnValue([MAIN_SAVED_OBJECT_INDEX]); + createExporter: jest.fn().mockReturnValue(savedObjectsExporterMock.create()), + createImporter: jest.fn().mockReturnValue(savedObjectsExporterMock.create()), + getTypeRegistry: jest.fn().mockReturnValue(typeRegistry ?? typeRegistryMock.create()), + getDefaultIndex: jest.fn().mockReturnValue(MAIN_SAVED_OBJECT_INDEX), + getIndexForType: jest.fn().mockReturnValue(MAIN_SAVED_OBJECT_INDEX), + getIndicesForTypes: jest.fn().mockReturnValue([MAIN_SAVED_OBJECT_INDEX]), + getAllIndices: jest.fn().mockReturnValue([MAIN_SAVED_OBJECT_INDEX]), + }); return startContrat; }; const createInternalStartContractMock = (typeRegistry?: jest.Mocked) => { - const internalStartContract: jest.Mocked = { + const internalStartContract: jest.Mocked = lazyObject({ ...createStartContractMock(typeRegistry), metrics: { migrationDuration: 0, }, - }; + }); return internalStartContract; }; const createSetupContractMock = () => { - const setupContract: jest.Mocked = { + const setupContract: jest.Mocked = lazyObject({ setClientFactoryProvider: jest.fn(), setEncryptionExtension: jest.fn(), setSecurityExtension: jest.fn(), setSpacesExtension: jest.fn(), registerType: jest.fn(), - getDefaultIndex: jest.fn(), - }; - - setupContract.getDefaultIndex.mockReturnValue(MAIN_SAVED_OBJECT_INDEX); + getDefaultIndex: jest.fn().mockReturnValue(MAIN_SAVED_OBJECT_INDEX), + }); return setupContract; }; const createInternalSetupContractMock = () => { - const internalSetupContract: jest.Mocked = { + const internalSetupContract: jest.Mocked = lazyObject({ ...createSetupContractMock(), status$: new BehaviorSubject({ level: ServiceStatusLevels.available, summary: `SavedObjects is available`, }), getTypeRegistry: jest.fn(), - }; + }); return internalSetupContract; }; const createSavedObjectsServiceMock = () => { - const mocked: jest.Mocked = { - setup: jest.fn(), - start: jest.fn(), - stop: jest.fn(), - }; + const mocked: jest.Mocked = lazyObject({ + setup: jest.fn().mockResolvedValue(createInternalSetupContractMock()), + start: jest.fn().mockResolvedValue(createInternalStartContractMock()), + stop: jest.fn().mockResolvedValue(void 0), + }); - mocked.setup.mockResolvedValue(createInternalSetupContractMock()); - mocked.start.mockResolvedValue(createInternalStartContractMock()); - mocked.stop.mockResolvedValue(); return mocked; }; diff --git a/src/core/packages/saved-objects/server-mocks/tsconfig.json b/src/core/packages/saved-objects/server-mocks/tsconfig.json index b4a8b1b3b60cc..d17a612f3d99e 100644 --- a/src/core/packages/saved-objects/server-mocks/tsconfig.json +++ b/src/core/packages/saved-objects/server-mocks/tsconfig.json @@ -18,7 +18,8 @@ "@kbn/core-saved-objects-api-server-mocks", "@kbn/core-saved-objects-base-server-mocks", "@kbn/core-saved-objects-import-export-server-mocks", - "@kbn/core-saved-objects-migration-server-mocks" + "@kbn/core-saved-objects-migration-server-mocks", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/security/browser-mocks/src/security_service.mock.ts b/src/core/packages/security/browser-mocks/src/security_service.mock.ts index ec7e6eb1ab68d..19a009f6128aa 100644 --- a/src/core/packages/security/browser-mocks/src/security_service.mock.ts +++ b/src/core/packages/security/browser-mocks/src/security_service.mock.ts @@ -14,49 +14,50 @@ import type { } from '@kbn/core-security-browser-internal'; import type { MockAuthenticatedUserProps } from '@kbn/core-security-common/mocks'; import { mockAuthenticatedUser } from '@kbn/core-security-common/mocks'; +import { lazyObject } from '@kbn/lazy-object'; const createSetupMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ registerSecurityDelegate: jest.fn(), - }; + }); return mock; }; const createStartMock = () => { - const mock: jest.MockedObjectDeep = { - authc: { + const mock: jest.MockedObjectDeep = lazyObject({ + authc: lazyObject({ getCurrentUser: jest.fn(), - }, - }; + }), + }); return mock; }; const createInternalSetupMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ registerSecurityDelegate: jest.fn(), - }; + }); return mock; }; const createInternalStartMock = () => { - const mock: jest.MockedObjectDeep = { - authc: { + const mock: jest.MockedObjectDeep = lazyObject({ + authc: lazyObject({ getCurrentUser: jest.fn(), - }, - }; + }), + }); return mock; }; const createServiceMock = () => { - const mock = { + const mock = lazyObject({ setup: jest.fn().mockReturnValue(createSetupMock()), start: jest.fn().mockReturnValue(createStartMock()), stop: jest.fn(), - }; + }); return mock; }; diff --git a/src/core/packages/security/browser-mocks/tsconfig.json b/src/core/packages/security/browser-mocks/tsconfig.json index c2a72b1c34971..acb00760d7ded 100644 --- a/src/core/packages/security/browser-mocks/tsconfig.json +++ b/src/core/packages/security/browser-mocks/tsconfig.json @@ -19,5 +19,6 @@ "@kbn/core-security-browser", "@kbn/core-security-browser-internal", "@kbn/core-security-common", + "@kbn/lazy-object", ] } diff --git a/src/core/packages/security/server-mocks/src/api_keys.mock.ts b/src/core/packages/security/server-mocks/src/api_keys.mock.ts index 0d9691cb412e8..0416e40196989 100644 --- a/src/core/packages/security/server-mocks/src/api_keys.mock.ts +++ b/src/core/packages/security/server-mocks/src/api_keys.mock.ts @@ -8,16 +8,18 @@ */ import type { APIKeysService } from '@kbn/core-security-server'; +import { lazyObject } from '@kbn/lazy-object'; export const apiKeysMock = { - create: (): jest.MockedObjectDeep => ({ - areAPIKeysEnabled: jest.fn(), - areCrossClusterAPIKeysEnabled: jest.fn(), - create: jest.fn(), - update: jest.fn(), - grantAsInternalUser: jest.fn(), - validate: jest.fn(), - invalidate: jest.fn(), - invalidateAsInternalUser: jest.fn(), - }), + create: (): jest.MockedObjectDeep => + lazyObject({ + areAPIKeysEnabled: jest.fn(), + areCrossClusterAPIKeysEnabled: jest.fn(), + create: jest.fn(), + update: jest.fn(), + grantAsInternalUser: jest.fn(), + validate: jest.fn(), + invalidate: jest.fn(), + invalidateAsInternalUser: jest.fn(), + }), }; diff --git a/src/core/packages/security/server-mocks/src/audit.mock.ts b/src/core/packages/security/server-mocks/src/audit.mock.ts index 6dccfcddd83fd..35becc8c43441 100644 --- a/src/core/packages/security/server-mocks/src/audit.mock.ts +++ b/src/core/packages/security/server-mocks/src/audit.mock.ts @@ -9,16 +9,17 @@ import type { KibanaRequest } from '@kbn/core-http-server'; import type { AuditLogger } from '@kbn/core-security-server'; +import { lazyObject } from '@kbn/lazy-object'; export type MockedAuditLogger = jest.Mocked; export const auditLoggerMock = { create(): MockedAuditLogger { - return { + return lazyObject({ log: jest.fn(), enabled: true, includeSavedObjectNames: false, - }; + }); }, }; @@ -29,9 +30,9 @@ export interface MockedAuditService { export const auditServiceMock = { create(): MockedAuditService { - return { + return lazyObject({ asScoped: jest.fn().mockReturnValue(auditLoggerMock.create()), withoutRequest: auditLoggerMock.create(), - }; + }); }, }; diff --git a/src/core/packages/security/server-mocks/src/security_service.mock.ts b/src/core/packages/security/server-mocks/src/security_service.mock.ts index a0dfeb1a19379..ac8c1f0fda20f 100644 --- a/src/core/packages/security/server-mocks/src/security_service.mock.ts +++ b/src/core/packages/security/server-mocks/src/security_service.mock.ts @@ -20,12 +20,13 @@ import { apiKeysMock } from './api_keys.mock'; import { auditServiceMock, type MockedAuditService } from './audit.mock'; import type { MockAuthenticatedUserProps } from '@kbn/core-security-common/mocks'; import { mockAuthenticatedUser } from '@kbn/core-security-common/mocks'; +import { lazyObject } from '@kbn/lazy-object'; const createSetupMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ registerSecurityDelegate: jest.fn(), fips: { isEnabled: jest.fn() }, - }; + }); return mock; }; @@ -35,22 +36,22 @@ export type SecurityStartMock = jest.MockedObjectDeep { - const mock = { - authc: { + const mock = lazyObject({ + authc: lazyObject({ getCurrentUser: jest.fn(), apiKeys: apiKeysMock.create(), - }, + }), audit: auditServiceMock.create(), - }; + }); return mock; }; const createInternalSetupMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ registerSecurityDelegate: jest.fn(), fips: { isEnabled: jest.fn() }, - }; + }); return mock; }; @@ -62,47 +63,47 @@ export type InternalSecurityStartMock = jest.MockedObjectDeep< }; const createInternalStartMock = (): InternalSecurityStartMock => { - const mock = { - authc: { + const mock = lazyObject({ + authc: lazyObject({ getCurrentUser: jest.fn(), apiKeys: apiKeysMock.create(), - }, + }), audit: auditServiceMock.create(), - }; + }); return mock; }; const createServiceMock = () => { - const mock = { + const mock = lazyObject({ setup: jest.fn().mockReturnValue(createSetupMock()), start: jest.fn().mockReturnValue(createStartMock()), stop: jest.fn(), - }; + }); return mock; }; const createRequestHandlerContextMock = () => { - const mock: jest.MockedObjectDeep = { - authc: { + const mock: jest.MockedObjectDeep = lazyObject({ + authc: lazyObject({ getCurrentUser: jest.fn(), - apiKeys: { + apiKeys: lazyObject({ areAPIKeysEnabled: jest.fn(), create: jest.fn(), update: jest.fn(), validate: jest.fn(), invalidate: jest.fn(), - }, - }, - audit: { - logger: { + }), + }), + audit: lazyObject({ + logger: lazyObject({ log: jest.fn(), enabled: true, includeSavedObjectNames: false, - }, - }, - }; + }), + }), + }); return mock; }; diff --git a/src/core/packages/security/server-mocks/tsconfig.json b/src/core/packages/security/server-mocks/tsconfig.json index 3635bcf047674..8289c0ee9a75f 100644 --- a/src/core/packages/security/server-mocks/tsconfig.json +++ b/src/core/packages/security/server-mocks/tsconfig.json @@ -18,5 +18,6 @@ "@kbn/core-security-server-internal", "@kbn/core-http-server", "@kbn/core-security-common", + "@kbn/lazy-object", ] } diff --git a/src/core/packages/status/server-mocks/src/status_service.mock.ts b/src/core/packages/status/server-mocks/src/status_service.mock.ts index 3ddffd513cff2..96cc31c1bad84 100644 --- a/src/core/packages/status/server-mocks/src/status_service.mock.ts +++ b/src/core/packages/status/server-mocks/src/status_service.mock.ts @@ -13,6 +13,7 @@ import type { ServiceStatus } from '@kbn/core-status-common'; import { ServiceStatusLevels } from '@kbn/core-status-common'; import type { StatusService, InternalStatusServiceSetup } from '@kbn/core-status-server-internal'; import type { StatusServiceSetup, CoreStatus } from '@kbn/core-status-server'; +import { lazyObject } from '@kbn/lazy-object'; const available: ServiceStatus = { level: ServiceStatusLevels.available, @@ -24,30 +25,30 @@ const availableCoreStatus: CoreStatus = { }; const createSetupContractMock = () => { - const setupContract: jest.Mocked = { + const setupContract: jest.Mocked = lazyObject({ core$: new BehaviorSubject(availableCoreStatus), overall$: new BehaviorSubject(available), set: jest.fn(), dependencies$: new BehaviorSubject({}), derivedStatus$: new BehaviorSubject(available), isStatusPageAnonymous: jest.fn().mockReturnValue(false), - }; + }); return setupContract; }; const createInternalSetupContractMock = () => { - const setupContract: jest.Mocked = { + const setupContract: jest.Mocked = lazyObject({ core$: new BehaviorSubject(availableCoreStatus), coreOverall$: new BehaviorSubject(available), overall$: new BehaviorSubject(available), isStatusPageAnonymous: jest.fn().mockReturnValue(false), - plugins: { + plugins: lazyObject({ set: jest.fn(), getDependenciesStatus$: jest.fn(), getDerivedStatus$: jest.fn(), - }, - }; + }), + }); return setupContract; }; @@ -55,12 +56,12 @@ const createInternalSetupContractMock = () => { type StatusServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ preboot: jest.fn(), setup: jest.fn().mockReturnValue(createInternalSetupContractMock()), start: jest.fn(), stop: jest.fn(), - }; + }); return mocked; }; diff --git a/src/core/packages/status/server-mocks/tsconfig.json b/src/core/packages/status/server-mocks/tsconfig.json index 95d9c863c9ec7..72b8fac99ee75 100644 --- a/src/core/packages/status/server-mocks/tsconfig.json +++ b/src/core/packages/status/server-mocks/tsconfig.json @@ -15,6 +15,7 @@ "@kbn/core-status-server", "@kbn/core-status-server-internal", "@kbn/core-status-common", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/core/packages/theme/browser-mocks/src/theme_service.mock.ts b/src/core/packages/theme/browser-mocks/src/theme_service.mock.ts index 8c27cc8561cf7..a402ac083a8ce 100644 --- a/src/core/packages/theme/browser-mocks/src/theme_service.mock.ts +++ b/src/core/packages/theme/browser-mocks/src/theme_service.mock.ts @@ -11,6 +11,7 @@ import { of } from 'rxjs'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { ThemeServiceSetup, CoreTheme } from '@kbn/core-theme-browser'; import type { ThemeService } from '@kbn/core-theme-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; const mockTheme: CoreTheme = { darkMode: false, @@ -26,24 +27,21 @@ const createTheme$Mock = (theme: CoreTheme = createThemeMock()) => { }; const createThemeContractMock = (theme: CoreTheme = createThemeMock()) => { - const themeMock: jest.Mocked = { + const themeMock: jest.Mocked = lazyObject({ theme$: createTheme$Mock(theme), getTheme: jest.fn().mockReturnValue(theme), - }; + }); return themeMock; }; type ThemeServiceContract = PublicMethodsOf; const createServiceMock = () => { - const mocked: jest.Mocked = { - setup: jest.fn(), - start: jest.fn(), + const mocked: jest.Mocked = lazyObject({ + setup: jest.fn().mockReturnValue(createThemeContractMock()), + start: jest.fn().mockReturnValue(createThemeContractMock()), stop: jest.fn(), - }; - - mocked.setup.mockReturnValue(createThemeContractMock()); - mocked.start.mockReturnValue(createThemeContractMock()); + }); return mocked; }; diff --git a/src/core/packages/theme/browser-mocks/tsconfig.json b/src/core/packages/theme/browser-mocks/tsconfig.json index 47e31c4df5dce..b04068f399b74 100644 --- a/src/core/packages/theme/browser-mocks/tsconfig.json +++ b/src/core/packages/theme/browser-mocks/tsconfig.json @@ -14,7 +14,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-theme-browser", - "@kbn/core-theme-browser-internal" + "@kbn/core-theme-browser-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/ui-settings/browser-mocks/src/client.mock.ts b/src/core/packages/ui-settings/browser-mocks/src/client.mock.ts index a1e5a77f7fb58..891ed43688283 100644 --- a/src/core/packages/ui-settings/browser-mocks/src/client.mock.ts +++ b/src/core/packages/ui-settings/browser-mocks/src/client.mock.ts @@ -9,25 +9,23 @@ import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import { Subject } from 'rxjs'; +import { lazyObject } from '@kbn/lazy-object'; export const clientMock = () => { - const mock: jest.Mocked = { - getAll: jest.fn(), + const mock: jest.Mocked = lazyObject({ + getAll: jest.fn().mockReturnValue({}), get: jest.fn(), - get$: jest.fn(), + get$: jest.fn().mockReturnValue(new Subject()), set: jest.fn(), remove: jest.fn(), isDeclared: jest.fn(), isDefault: jest.fn(), isCustom: jest.fn(), isOverridden: jest.fn(), - getUpdate$: jest.fn(), - getUpdateErrors$: jest.fn(), + getUpdate$: jest.fn().mockReturnValue(new Subject()), + getUpdateErrors$: jest.fn().mockReturnValue(new Subject()), validateValue: jest.fn(), - }; - mock.get$.mockReturnValue(new Subject()); - mock.getUpdate$.mockReturnValue(new Subject()); - mock.getUpdateErrors$.mockReturnValue(new Subject()); - mock.getAll.mockReturnValue({}); + }); + return mock; }; diff --git a/src/core/packages/ui-settings/browser-mocks/src/service_contract.mock.ts b/src/core/packages/ui-settings/browser-mocks/src/service_contract.mock.ts index 5d638a3fc8eb0..a76eb695204a5 100644 --- a/src/core/packages/ui-settings/browser-mocks/src/service_contract.mock.ts +++ b/src/core/packages/ui-settings/browser-mocks/src/service_contract.mock.ts @@ -7,10 +7,12 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { lazyObject } from '@kbn/lazy-object'; + export const serviceContractMock = (): jest.Mocked => { - return { + return lazyObject({ setup: jest.fn(), start: jest.fn(), stop: jest.fn(), - }; + }); }; diff --git a/src/core/packages/ui-settings/browser-mocks/src/settings_service.mock.ts b/src/core/packages/ui-settings/browser-mocks/src/settings_service.mock.ts index e4b70efbd0e14..1bfa4ca416a6c 100644 --- a/src/core/packages/ui-settings/browser-mocks/src/settings_service.mock.ts +++ b/src/core/packages/ui-settings/browser-mocks/src/settings_service.mock.ts @@ -9,15 +9,13 @@ import { clientMock } from './client.mock'; import { serviceContractMock } from './service_contract.mock'; +import { lazyObject } from '@kbn/lazy-object'; const createSetupContractMock = () => { - const client = clientMock(); - const globalClient = clientMock(); - - return { - client, - globalClient, - }; + return lazyObject({ + client: clientMock(), + globalClient: clientMock(), + }); }; const createMock = () => { diff --git a/src/core/packages/ui-settings/browser-mocks/tsconfig.json b/src/core/packages/ui-settings/browser-mocks/tsconfig.json index 3b46cc24412f8..849d798ae2979 100644 --- a/src/core/packages/ui-settings/browser-mocks/tsconfig.json +++ b/src/core/packages/ui-settings/browser-mocks/tsconfig.json @@ -11,7 +11,8 @@ "**/*.ts" ], "kbn_references": [ - "@kbn/core-ui-settings-browser" + "@kbn/core-ui-settings-browser", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/ui-settings/server-mocks/src/ui_settings_service.mock.ts b/src/core/packages/ui-settings/server-mocks/src/ui_settings_service.mock.ts index abb275f917113..f8f99b3d9e068 100644 --- a/src/core/packages/ui-settings/server-mocks/src/ui_settings_service.mock.ts +++ b/src/core/packages/ui-settings/server-mocks/src/ui_settings_service.mock.ts @@ -15,13 +15,14 @@ import type { InternalUiSettingsServicePreboot, UiSettingsService, } from '@kbn/core-ui-settings-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createClientMock = () => { - const mocked: jest.Mocked = { - getRegistered: jest.fn(), - get: jest.fn(), - getAll: jest.fn(), - getUserProvided: jest.fn(), + const mocked: jest.Mocked = lazyObject({ + getRegistered: jest.fn().mockReturnValue({}), + get: jest.fn().mockResolvedValue(false), + getAll: jest.fn().mockResolvedValue({}), + getUserProvided: jest.fn().mockResolvedValue({}), setMany: jest.fn(), set: jest.fn(), remove: jest.fn(), @@ -29,30 +30,25 @@ const createClientMock = () => { isOverridden: jest.fn(), isSensitive: jest.fn(), validate: jest.fn(), - }; - mocked.get.mockResolvedValue(false); - mocked.getAll.mockResolvedValue({}); - mocked.getRegistered.mockReturnValue({}); - mocked.getUserProvided.mockResolvedValue({}); + }); + return mocked; }; const createPrebootMock = () => { - const mocked: jest.Mocked = { - createDefaultsClient: jest.fn(), - }; - - mocked.createDefaultsClient.mockReturnValue(createClientMock()); + const mocked: jest.Mocked = lazyObject({ + createDefaultsClient: jest.fn().mockReturnValue(createClientMock()), + }); return mocked; }; const createSetupMock = () => { - const mocked: jest.Mocked = { + const mocked: jest.Mocked = lazyObject({ register: jest.fn(), registerGlobal: jest.fn(), setAllowlist: jest.fn(), - }; + }); return mocked; }; @@ -70,15 +66,13 @@ const createStartMock = () => { type UiSettingsServiceContract = PublicMethodsOf; const createMock = () => { - const mocked: jest.Mocked = { - preboot: jest.fn(), - setup: jest.fn(), - start: jest.fn(), + const mocked: jest.Mocked = lazyObject({ + preboot: jest.fn().mockResolvedValue(createPrebootMock()), + setup: jest.fn().mockResolvedValue(createSetupMock()), + start: jest.fn().mockResolvedValue(createStartMock()), stop: jest.fn(), - }; - mocked.preboot.mockResolvedValue(createPrebootMock()); - mocked.setup.mockResolvedValue(createSetupMock()); - mocked.start.mockResolvedValue(createStartMock()); + }); + return mocked; }; diff --git a/src/core/packages/ui-settings/server-mocks/tsconfig.json b/src/core/packages/ui-settings/server-mocks/tsconfig.json index 2dad65ec83a13..e1d39f5c7f029 100644 --- a/src/core/packages/ui-settings/server-mocks/tsconfig.json +++ b/src/core/packages/ui-settings/server-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/core-ui-settings-server", - "@kbn/core-ui-settings-server-internal" + "@kbn/core-ui-settings-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/usage-data/server-mocks/src/core_usage_data_service.mock.ts b/src/core/packages/usage-data/server-mocks/src/core_usage_data_service.mock.ts index bc14931fd31e9..82524fcff5627 100644 --- a/src/core/packages/usage-data/server-mocks/src/core_usage_data_service.mock.ts +++ b/src/core/packages/usage-data/server-mocks/src/core_usage_data_service.mock.ts @@ -13,20 +13,21 @@ import type { CoreUsageData, CoreUsageDataStart } from '@kbn/core-usage-data-ser import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { CoreUsageDataService } from '@kbn/core-usage-data-server-internal'; import { coreUsageStatsClientMock } from './core_usage_stats_client.mock'; +import { lazyObject } from '@kbn/lazy-object'; const createSetupContractMock = (usageStatsClient = coreUsageStatsClientMock.create()) => { - const setupContract: jest.Mocked = { + const setupContract: jest.Mocked = lazyObject({ registerType: jest.fn(), registerDeprecatedUsageFetch: jest.fn(), getClient: jest.fn().mockReturnValue(usageStatsClient), registerUsageCounter: jest.fn(), incrementUsageCounter: jest.fn(), - }; + }); return setupContract; }; const createStartContractMock = () => { - const startContract: jest.Mocked = { + const startContract: jest.Mocked = lazyObject({ getCoreUsageData: jest.fn().mockResolvedValue( new BehaviorSubject({ config: { @@ -162,17 +163,17 @@ const createStartContractMock = () => { }) ), getConfigsUsageData: jest.fn(), - }; + }); return startContract; }; const createMock = () => { - const mocked: jest.Mocked> = { + const mocked: jest.Mocked> = lazyObject({ setup: jest.fn().mockReturnValue(createSetupContractMock()), start: jest.fn().mockReturnValue(createStartContractMock()), stop: jest.fn(), - }; + }); return mocked; }; diff --git a/src/core/packages/usage-data/server-mocks/src/core_usage_stats_client.mock.ts b/src/core/packages/usage-data/server-mocks/src/core_usage_stats_client.mock.ts index 8896e9066ef78..e0b1f9dc99cf9 100644 --- a/src/core/packages/usage-data/server-mocks/src/core_usage_stats_client.mock.ts +++ b/src/core/packages/usage-data/server-mocks/src/core_usage_stats_client.mock.ts @@ -8,9 +8,10 @@ */ import type { ICoreUsageStatsClient } from '@kbn/core-usage-data-base-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createUsageStatsClientMock = () => - ({ + lazyObject({ getUsageStats: jest.fn().mockResolvedValue({}), getDeprecatedApiUsageStats: jest.fn().mockResolvedValue([]), incrementSavedObjectsBulkCreate: jest.fn().mockResolvedValue(null), diff --git a/src/core/packages/usage-data/server-mocks/tsconfig.json b/src/core/packages/usage-data/server-mocks/tsconfig.json index 3583f7390a92d..01fe46651cdb1 100644 --- a/src/core/packages/usage-data/server-mocks/tsconfig.json +++ b/src/core/packages/usage-data/server-mocks/tsconfig.json @@ -14,7 +14,8 @@ "@kbn/utility-types", "@kbn/core-usage-data-server", "@kbn/core-usage-data-base-server-internal", - "@kbn/core-usage-data-server-internal" + "@kbn/core-usage-data-server-internal", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/core/packages/user-profile/browser-mocks/src/user_profile_service.mock.ts b/src/core/packages/user-profile/browser-mocks/src/user_profile_service.mock.ts index ba9842d55b765..8c7a16c1ad3d6 100644 --- a/src/core/packages/user-profile/browser-mocks/src/user_profile_service.mock.ts +++ b/src/core/packages/user-profile/browser-mocks/src/user_profile_service.mock.ts @@ -16,17 +16,18 @@ import type { InternalUserProfileServiceSetup, InternalUserProfileServiceStart, } from '@kbn/core-user-profile-browser-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createSetupMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ registerUserProfileDelegate: jest.fn(), - }; + }); return mock; }; const createStartMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ getUserProfile$: jest.fn().mockReturnValue(of(null)), getEnabled$: jest.fn().mockReturnValue(of(false)), getCurrent: jest.fn(), @@ -34,21 +35,21 @@ const createStartMock = () => { suggest: jest.fn(), update: jest.fn(), partialUpdate: jest.fn(), - }; + }); return mock; }; const createInternalSetupMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ registerUserProfileDelegate: jest.fn(), - }; + }); return mock; }; const createInternalStartMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ getUserProfile$: jest.fn().mockReturnValue(of(null)), getEnabled$: jest.fn().mockReturnValue(of(false)), getCurrent: jest.fn(), @@ -56,17 +57,17 @@ const createInternalStartMock = () => { suggest: jest.fn(), update: jest.fn(), partialUpdate: jest.fn(), - }; + }); return mock; }; const createServiceMock = () => { - const mock = { + const mock = lazyObject({ setup: jest.fn().mockReturnValue(createSetupMock()), start: jest.fn().mockReturnValue(createStartMock()), stop: jest.fn(), - }; + }); return mock; }; diff --git a/src/core/packages/user-profile/browser-mocks/tsconfig.json b/src/core/packages/user-profile/browser-mocks/tsconfig.json index bbe270286c22f..d89127fe6ac4d 100644 --- a/src/core/packages/user-profile/browser-mocks/tsconfig.json +++ b/src/core/packages/user-profile/browser-mocks/tsconfig.json @@ -18,5 +18,6 @@ "kbn_references": [ "@kbn/core-user-profile-browser", "@kbn/core-user-profile-browser-internal", + "@kbn/lazy-object", ] } diff --git a/src/core/packages/user-settings/server-mocks/src/user_settings_service.mock.ts b/src/core/packages/user-settings/server-mocks/src/user_settings_service.mock.ts index 7afff83438623..58fbf560c9cb3 100644 --- a/src/core/packages/user-settings/server-mocks/src/user_settings_service.mock.ts +++ b/src/core/packages/user-settings/server-mocks/src/user_settings_service.mock.ts @@ -12,6 +12,7 @@ import type { UserSettingsService, InternalUserSettingsServiceSetup, } from '@kbn/core-user-settings-server-internal'; +import { lazyObject } from '@kbn/lazy-object'; const createSetupContractMock = (): jest.Mocked => { return { @@ -20,11 +21,10 @@ const createSetupContractMock = (): jest.Mocked> => { - const mock = { - setup: jest.fn(), + const mock = lazyObject({ + setup: jest.fn().mockReturnValue(createSetupContractMock()), start: jest.fn(), - }; - mock.setup.mockReturnValue(createSetupContractMock()); + }); return mock; }; diff --git a/src/core/packages/user-settings/server-mocks/tsconfig.json b/src/core/packages/user-settings/server-mocks/tsconfig.json index cc6f694079c34..bde3ac5e6010e 100644 --- a/src/core/packages/user-settings/server-mocks/tsconfig.json +++ b/src/core/packages/user-settings/server-mocks/tsconfig.json @@ -10,6 +10,7 @@ "kbn_references": [ "@kbn/core-user-settings-server-internal", "@kbn/utility-types", + "@kbn/lazy-object", ], "include": [ "**/*.ts", diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts index 66be5a6bac730..688c290978bec 100644 --- a/src/core/public/mocks.ts +++ b/src/core/public/mocks.ts @@ -32,16 +32,17 @@ export { applicationServiceMock, scopedHistoryMock } from '@kbn/core-application export { deprecationsServiceMock } from '@kbn/core-deprecations-browser-mocks'; export { loggingSystemMock } from '@kbn/core-logging-browser-mocks'; export { securityServiceMock } from '@kbn/core-security-browser-mocks'; +import { lazyObject } from '@kbn/lazy-object'; function createStorageMock() { - const storageMock: jest.Mocked = { + const storageMock: jest.Mocked = lazyObject({ getItem: jest.fn(), setItem: jest.fn(), removeItem: jest.fn(), clear: jest.fn(), key: jest.fn(), length: 10, - }; + }); return storageMock; } @@ -51,14 +52,14 @@ function createAppMountParametersMock(appBasePath = '') { rawHistory.push(appBasePath); const history = new CoreScopedHistory(rawHistory, appBasePath); - const params: jest.Mocked = { + const params: jest.Mocked = lazyObject({ appBasePath, element: document.createElement('div'), history, theme$: themeServiceMock.createTheme$(), onAppLeave: jest.fn(), setHeaderActionMenu: jest.fn(), - }; + }); return params; } diff --git a/src/core/tsconfig.json b/src/core/tsconfig.json index bb0f49811cbec..b08b65e0c7d39 100644 --- a/src/core/tsconfig.json +++ b/src/core/tsconfig.json @@ -173,6 +173,7 @@ "@kbn/core-pricing-browser", "@kbn/core-pricing-server-internal", "@kbn/core-pricing-common", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/platform/packages/private/kbn-config-mocks/src/config.mock.ts b/src/platform/packages/private/kbn-config-mocks/src/config.mock.ts index 9dc35d8a721b8..1d5719a1e5d18 100644 --- a/src/platform/packages/private/kbn-config-mocks/src/config.mock.ts +++ b/src/platform/packages/private/kbn-config-mocks/src/config.mock.ts @@ -8,16 +8,18 @@ */ import type { Config } from '@kbn/config'; +import { lazyObject } from '@kbn/lazy-object'; export type ConfigMock = jest.Mocked; -const createConfigMock = (): ConfigMock => ({ - has: jest.fn(), - get: jest.fn(), - set: jest.fn(), - getFlattenedPaths: jest.fn(), - toRaw: jest.fn(), -}); +const createConfigMock = (): ConfigMock => + lazyObject({ + has: jest.fn(), + get: jest.fn(), + set: jest.fn(), + getFlattenedPaths: jest.fn(), + toRaw: jest.fn(), + }); export const configMock = { create: createConfigMock, diff --git a/src/platform/packages/private/kbn-config-mocks/src/config_service.mock.ts b/src/platform/packages/private/kbn-config-mocks/src/config_service.mock.ts index 1e4a4bca6156e..1e231e7828bda 100644 --- a/src/platform/packages/private/kbn-config-mocks/src/config_service.mock.ts +++ b/src/platform/packages/private/kbn-config-mocks/src/config_service.mock.ts @@ -10,6 +10,7 @@ import { BehaviorSubject } from 'rxjs'; import type { IConfigService } from '@kbn/config'; import { ObjectToConfigAdapter } from '@kbn/config'; +import { lazyObject } from '@kbn/lazy-object'; export type IConfigServiceMock = jest.Mocked; @@ -17,31 +18,26 @@ const createConfigServiceMock = ({ atPath = {}, getConfig$ = {}, }: { atPath?: Record; getConfig$?: Record } = {}) => { - const mocked: IConfigServiceMock = { - atPath: jest.fn(), - atPathSync: jest.fn(), - getConfig$: jest.fn(), - getUsedPaths: jest.fn(), - getUnusedPaths: jest.fn(), - isEnabledAtPath: jest.fn(), + const mocked: IConfigServiceMock = lazyObject({ + atPath: jest.fn().mockReturnValue(new BehaviorSubject(atPath)), + atPathSync: jest.fn().mockReturnValue(atPath), + getConfig$: jest + .fn() + .mockReturnValue(new BehaviorSubject(new ObjectToConfigAdapter(getConfig$))), + getUsedPaths: jest.fn().mockResolvedValue([]), + getUnusedPaths: jest.fn().mockResolvedValue([]), + isEnabledAtPath: jest.fn().mockResolvedValue(true), setSchema: jest.fn(), addDeprecationProvider: jest.fn(), validate: jest.fn(), - getHandledDeprecatedConfigs: jest.fn(), - getDeprecatedConfigPath$: jest.fn(), + getHandledDeprecatedConfigs: jest.fn().mockReturnValue([]), + getDeprecatedConfigPath$: jest + .fn() + .mockReturnValue(new BehaviorSubject({ set: [], unset: [] })), addDynamicConfigPaths: jest.fn(), setDynamicConfigOverrides: jest.fn(), setGlobalStripUnknownKeys: jest.fn(), - }; - - mocked.atPath.mockReturnValue(new BehaviorSubject(atPath)); - mocked.atPathSync.mockReturnValue(atPath); - mocked.getConfig$.mockReturnValue(new BehaviorSubject(new ObjectToConfigAdapter(getConfig$))); - mocked.getDeprecatedConfigPath$.mockReturnValue(new BehaviorSubject({ set: [], unset: [] })); - mocked.getUsedPaths.mockResolvedValue([]); - mocked.getUnusedPaths.mockResolvedValue([]); - mocked.isEnabledAtPath.mockResolvedValue(true); - mocked.getHandledDeprecatedConfigs.mockReturnValue([]); + }); return mocked; }; diff --git a/src/platform/packages/private/kbn-config-mocks/src/env.mock.ts b/src/platform/packages/private/kbn-config-mocks/src/env.mock.ts index 3cbb57c705fc9..57a19141e99b1 100644 --- a/src/platform/packages/private/kbn-config-mocks/src/env.mock.ts +++ b/src/platform/packages/private/kbn-config-mocks/src/env.mock.ts @@ -10,6 +10,7 @@ import { REPO_ROOT } from '@kbn/repo-info'; import { getPackages } from '@kbn/repo-packages'; import { Env, type RawPackageInfo, type EnvOptions } from '@kbn/config'; +import { lazyObject } from '@kbn/lazy-object'; type DeepPartial = { [P in keyof T]?: P extends 'repoPackages' @@ -20,7 +21,7 @@ type DeepPartial = { }; export function getEnvOptions(options: DeepPartial = {}): EnvOptions { - return { + return lazyObject({ configs: options.configs || [], cliArgs: { dev: true, @@ -35,7 +36,7 @@ export function getEnvOptions(options: DeepPartial = {}): EnvOptions ...(options.cliArgs || {}), }, repoPackages: options.repoPackages ?? getPackages(REPO_ROOT), - }; + }); } export const createTestPackageInfo = ({ dist = true }: { dist?: boolean } = {}): RawPackageInfo => { diff --git a/src/platform/packages/private/kbn-config-mocks/src/raw_config_service.mock.ts b/src/platform/packages/private/kbn-config-mocks/src/raw_config_service.mock.ts index c252c6c26882f..aa163c529730e 100644 --- a/src/platform/packages/private/kbn-config-mocks/src/raw_config_service.mock.ts +++ b/src/platform/packages/private/kbn-config-mocks/src/raw_config_service.mock.ts @@ -11,6 +11,7 @@ import type { Observable } from 'rxjs'; import { of } from 'rxjs'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { RawConfigService } from '@kbn/config'; +import { lazyObject } from '@kbn/lazy-object'; export type RawConfigServiceMock = jest.Mocked>; @@ -18,12 +19,12 @@ const createRawConfigServiceMock = ({ rawConfig = {}, rawConfig$ = undefined, }: { rawConfig?: Record; rawConfig$?: Observable> } = {}) => { - const mocked: RawConfigServiceMock = { + const mocked: RawConfigServiceMock = lazyObject({ loadConfig: jest.fn(), stop: jest.fn(), reloadConfig: jest.fn(), getConfig$: jest.fn().mockReturnValue(rawConfig$ || of(rawConfig)), - }; + }); return mocked; }; diff --git a/src/platform/packages/private/kbn-config-mocks/tsconfig.json b/src/platform/packages/private/kbn-config-mocks/tsconfig.json index bad5aa51f85c6..745d1e8d0154a 100644 --- a/src/platform/packages/private/kbn-config-mocks/tsconfig.json +++ b/src/platform/packages/private/kbn-config-mocks/tsconfig.json @@ -16,6 +16,7 @@ "@kbn/doc-links", "@kbn/repo-info", "@kbn/repo-packages", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/platform/packages/shared/kbn-babel-register/index.js b/src/platform/packages/shared/kbn-babel-register/index.js index daed25c51219c..70b5779265cf7 100644 --- a/src/platform/packages/shared/kbn-babel-register/index.js +++ b/src/platform/packages/shared/kbn-babel-register/index.js @@ -61,6 +61,8 @@ const IGNORE_PATTERNS = [ // ignore packages with "babel" in their names /[\/\\]packages[\/\\]([^\/\\]+-)?babel(-[^\/\\]+)?[\/\\]/, + // ignore babel plugins + /lazy_babel_plugin\.js$/, // ignore paths matching `/canvas/canvas_plugin/` /[\/\\]canvas[\/\\]canvas_plugin[\/\\]/, diff --git a/src/platform/packages/shared/kbn-lazy-object/README.md b/src/platform/packages/shared/kbn-lazy-object/README.md new file mode 100644 index 0000000000000..740db0853224e --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/README.md @@ -0,0 +1,3 @@ +# @kbn/lazy-object + +Empty package generated by @kbn/generate diff --git a/src/platform/packages/shared/kbn-lazy-object/index.ts b/src/platform/packages/shared/kbn-lazy-object/index.ts new file mode 100644 index 0000000000000..160fd801aaafc --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/index.ts @@ -0,0 +1,16 @@ +/* + * 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 { createLazyObjectFromFactories } from './src/create_lazy_object_from_factories'; +export { getLazyObjectMetrics } from './src/metrics'; +export { lazyObject } from './src/lazy_object'; +export { + createLazyObjectFromAnnotations, + annotateLazy, +} from './src/create_lazy_object_from_annotations'; diff --git a/src/platform/packages/shared/kbn-lazy-object/jest.config.js b/src/platform/packages/shared/kbn-lazy-object/jest.config.js new file mode 100644 index 0000000000000..e9372a772b428 --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/jest.config.js @@ -0,0 +1,14 @@ +/* + * 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". + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../../..', + roots: ['/src/platform/packages/shared/kbn-lazy-object'], +}; diff --git a/src/platform/packages/shared/kbn-lazy-object/kibana.jsonc b/src/platform/packages/shared/kbn-lazy-object/kibana.jsonc new file mode 100644 index 0000000000000..f91a11c095000 --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/kibana.jsonc @@ -0,0 +1,8 @@ +{ + "type": "shared-common", + "id": "@kbn/lazy-object", + "owner": "@elastic/kibana-operations", + "group": "platform", + "visibility": "shared", + "devOnly": true +} diff --git a/src/platform/packages/shared/kbn-lazy-object/package.json b/src/platform/packages/shared/kbn-lazy-object/package.json new file mode 100644 index 0000000000000..88b208ac9feb9 --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/lazy-object", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0" +} \ No newline at end of file diff --git a/src/platform/packages/shared/kbn-lazy-object/src/create_lazy_object_from_annotations.ts b/src/platform/packages/shared/kbn-lazy-object/src/create_lazy_object_from_annotations.ts new file mode 100644 index 0000000000000..ea85a6c404386 --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/src/create_lazy_object_from_annotations.ts @@ -0,0 +1,85 @@ +/* + * 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 { isLazyObjectDisabled } from './is_disabled'; +import { LAZY_OBJECT_KEY_CALLED, LAZY_OBJECT_KEY_COUNT } from './metrics'; + +const LAZY_ANNOTATION_KEY = '@kbn/lazy-object/lazy-annotation' as const; + +const DISABLED = isLazyObjectDisabled(); + +/** + * Annotate a factory function to indicate the value should be lazily computed. + * Without this, we can't differentiate between a plain function, and a lazified + * getter. + */ +export function annotateLazy(factory: () => T): () => T { + // fallback string key, to not depend on + if (!(LAZY_ANNOTATION_KEY in factory)) { + Object.defineProperty(factory, LAZY_ANNOTATION_KEY, { + value: 1, + enumerable: false, + configurable: false, + writable: false, + }); + } + return factory; +} + +/** + * Create an object where only annotated properties are lazily evaluated. + * Non-annotated properties are defined eagerly as writable value properties. + */ +export function createLazyObjectFromAnnotations>(obj: T): T { + const target: Record = {}; + + for (const key of Object.keys(obj)) { + const value = obj[key]; + const isAnnotated = typeof value === 'function' && value[LAZY_ANNOTATION_KEY] === 1; + + if (isAnnotated && !DISABLED) { + globalThis[LAZY_OBJECT_KEY_COUNT]++; + Object.defineProperty(target, key, { + enumerable: true, + configurable: true, + get() { + globalThis[LAZY_OBJECT_KEY_CALLED]++; + const computed = value(); + Object.defineProperty(target, key, { + value: computed, + enumerable: true, + configurable: true, + writable: true, + }); + return computed; + }, + set(v) { + // when set, simply override the lazy getter + Object.defineProperty(target, key, { + value: v, + enumerable: true, + configurable: true, + writable: true, + }); + }, + }); + + continue; + } + // Either not annotated, or laziness disabled: define eagerly as a writable value + Object.defineProperty(target, key, { + value: isAnnotated ? value() : value, + enumerable: true, + configurable: true, + writable: true, + }); + } + + return target as T; +} diff --git a/src/platform/packages/shared/kbn-lazy-object/src/create_lazy_object_from_factories.ts b/src/platform/packages/shared/kbn-lazy-object/src/create_lazy_object_from_factories.ts new file mode 100644 index 0000000000000..cc91119b5fdad --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/src/create_lazy_object_from_factories.ts @@ -0,0 +1,40 @@ +/* + * 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 { + annotateLazy, + createLazyObjectFromAnnotations, +} from './create_lazy_object_from_annotations'; +import { isLazyObjectDisabled } from './is_disabled'; + +const DISABLED = isLazyObjectDisabled(); + +export function createLazyObjectFromFactories any>>( + factories: TFactories +): { [K in keyof TFactories]: ReturnType } { + if (DISABLED) { + // Evaluate all factories eagerly + const eager: Record = {}; + for (const key of Object.keys(factories)) { + eager[key] = factories[key](); + } + return eager as { [K in keyof TFactories]: ReturnType }; + } + + // Build an annotated object where each property value is the factory annotated as lazy + const annotated: Record = {}; + for (const key of Object.keys(factories)) { + annotated[key] = annotateLazy(factories[key]); + } + // Delegate to the annotations-based runtime so behavior stays in one place + // and metrics increment occurs there on access. + return createLazyObjectFromAnnotations( + annotated as unknown as { [K in keyof TFactories]: ReturnType } + ); +} diff --git a/src/platform/packages/shared/kbn-lazy-object/src/is_disabled.ts b/src/platform/packages/shared/kbn-lazy-object/src/is_disabled.ts new file mode 100644 index 0000000000000..0290c87394370 --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/src/is_disabled.ts @@ -0,0 +1,12 @@ +/* + * 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 const isLazyObjectDisabled = () => { + return !!process.env.KBN_DISABLE_LAZY_OBJECT; +}; diff --git a/src/platform/packages/shared/kbn-lazy-object/src/lazy_object.ts b/src/platform/packages/shared/kbn-lazy-object/src/lazy_object.ts new file mode 100644 index 0000000000000..b9035c23e8d15 --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/src/lazy_object.ts @@ -0,0 +1,15 @@ +/* + * 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 function lazyObject>(obj: T): T { + // At runtime (without Babel), this is a no-op identity. + // The Babel plugin will rewrite calls to lazyObject({ ... }) into + // createLazyObjectFromFactories({ key: () => expr, ... }). + return obj; +} diff --git a/src/platform/packages/shared/kbn-lazy-object/src/metrics.ts b/src/platform/packages/shared/kbn-lazy-object/src/metrics.ts new file mode 100644 index 0000000000000..bec00a5bb09b7 --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/src/metrics.ts @@ -0,0 +1,29 @@ +/* + * 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 const LAZY_OBJECT_KEY_COUNT = '__LAZY_OBJECT_KEY_COUNT__'; +export const LAZY_OBJECT_KEY_CALLED = '__LAZY_OBJECT_KEY_CALLED__'; + +// Extend the global 'var' declarations for NodeJS +declare global { + // eslint-disable-next-line no-var + var __LAZY_OBJECT_KEY_COUNT__: number; + // eslint-disable-next-line no-var + var __LAZY_OBJECT_KEY_CALLED__: number; +} + +globalThis[LAZY_OBJECT_KEY_CALLED] = globalThis[LAZY_OBJECT_KEY_CALLED] || 0; +globalThis[LAZY_OBJECT_KEY_COUNT] = globalThis[LAZY_OBJECT_KEY_COUNT] || 0; + +export function getLazyObjectMetrics(): { count: number; called: number } { + return { + count: globalThis[LAZY_OBJECT_KEY_COUNT], + called: globalThis[LAZY_OBJECT_KEY_CALLED], + }; +} diff --git a/src/platform/packages/shared/kbn-lazy-object/src/plugin/lazy_babel_plugin.js b/src/platform/packages/shared/kbn-lazy-object/src/plugin/lazy_babel_plugin.js new file mode 100644 index 0000000000000..0d19a689a75cd --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/src/plugin/lazy_babel_plugin.js @@ -0,0 +1,176 @@ +/* + * 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". + */ + +/** + * @typedef {import('@babel/core').types} t + * @typedef {import('@babel/core').PluginObj} PluginObj + */ + +/** + * Transforms calls to `lazyObject({...})` into a lazily-evaluated object. + * Each property is rewritten to a memoized getter that evaluates the original + * expression on first access, then replaces itself with a writable data + * property holding the computed value. A setter is also defined to allow + * overriding the memoized value. + */ +/** + * @param {{ types: t }} babel + * @returns {PluginObj} + */ +function lazyBabelPlugin({ types: bt }) { + /** + * @param {any} node + * @returns {boolean} + */ + const isLazyObjectCallee = (node) => + !!node && bt.isIdentifier(node) && node.name === 'lazyObject'; + + return { + name: 'kbn-lazy-object-transform', + visitor: { + CallExpression(path) { + const { node } = path; + if (!isLazyObjectCallee(node.callee)) return; + if (node.arguments.length !== 1) return; + const arg = node.arguments[0]; + if (!bt.isObjectExpression(arg)) return; + + // Build the argument object, annotating laziness on statically-known simple properties + const newProps = []; + + for (const prop of arg.properties) { + // Handle spreads by merging into target to preserve semantics + if (bt.isSpreadElement(prop)) { + newProps.push(prop); + continue; + } + + // Object methods: define eagerly as function values + if (bt.isObjectMethod(prop)) { + const key = prop.key; + let propNameLiteral = null; + if (bt.isIdentifier(key)) { + propNameLiteral = bt.stringLiteral(key.name); + } else if (bt.isStringLiteral(key)) { + propNameLiteral = key; + } + if (!propNameLiteral) continue; + const fnExpr = bt.functionExpression( + null, + prop.params, + prop.body, + prop.generator || false, + prop.async || false + ); + newProps.push(bt.objectProperty(propNameLiteral, fnExpr)); + continue; + } + + if (!bt.isObjectProperty(prop)) continue; + + // Compute key name for simple keys; computed keys are defined eagerly + let keyName = null; + if (bt.isIdentifier(prop.key)) keyName = prop.key.name; + else if (bt.isStringLiteral(prop.key)) keyName = prop.key.value; + + const valueExpr = prop.value; + + // If we can't lazify (computed key or unknown key), define eagerly and continue + if (!keyName || prop.computed) { + let nameNode; + if (bt.isIdentifier(prop.key)) { + nameNode = bt.identifier(prop.key.name); + } else if (bt.isStringLiteral(prop.key)) { + nameNode = bt.stringLiteral(prop.key.value); + } else { + nameNode = prop.key; + } + newProps.push(bt.objectProperty(nameNode, valueExpr, Boolean(prop.computed), false)); + continue; + } + + // Lazify normal properties with simple keys by wrapping value in annotateLazy(() => value) + const keyNode = bt.stringLiteral(keyName); + const factory = bt.arrowFunctionExpression([], valueExpr); + const annotated = bt.callExpression(bt.identifier('annotateLazy'), [factory]); + newProps.push(bt.objectProperty(keyNode, annotated)); + } + + // Replace with createLazyObjectFromAnnotations({...annotated...}) call + const replacement = bt.callExpression(bt.identifier('createLazyObjectFromAnnotations'), [ + bt.objectExpression(newProps), + ]); + + // Insert import if not present: import { createLazyObjectFromAnnotations, annotateLazy } from '@kbn/lazy-object' + const program = path.findParent((p) => p.isProgram()); + if (program) { + const hasCreateImport = program.node.body.some( + (n) => + bt.isImportDeclaration(n) && + n.source.value === '@kbn/lazy-object' && + n.specifiers.some( + (s) => + bt.isImportSpecifier(s) && s.imported.name === 'createLazyObjectFromAnnotations' + ) + ); + const hasAnnotateImport = program.node.body.some( + (n) => + bt.isImportDeclaration(n) && + n.source.value === '@kbn/lazy-object' && + n.specifiers.some( + (s) => bt.isImportSpecifier(s) && s.imported.name === 'annotateLazy' + ) + ); + if (!hasCreateImport || !hasAnnotateImport) { + // If there's already an import from @kbn/lazy-object, extend it; otherwise add a new one + const existing = program.node.body.find( + (n) => bt.isImportDeclaration(n) && n.source.value === '@kbn/lazy-object' + ); + if (existing && bt.isImportDeclaration(existing)) { + const existingNames = new Set( + existing.specifiers + .filter((s) => bt.isImportSpecifier(s)) + .map((s) => s.imported.name) + ); + if (!existingNames.has('createLazyObjectFromAnnotations')) { + existing.specifiers.push( + bt.importSpecifier( + bt.identifier('createLazyObjectFromAnnotations'), + bt.identifier('createLazyObjectFromAnnotations') + ) + ); + } + if (!existingNames.has('annotateLazy')) { + existing.specifiers.push( + bt.importSpecifier(bt.identifier('annotateLazy'), bt.identifier('annotateLazy')) + ); + } + } else { + const importDecl = bt.importDeclaration( + [ + bt.importSpecifier( + bt.identifier('createLazyObjectFromAnnotations'), + bt.identifier('createLazyObjectFromAnnotations') + ), + bt.importSpecifier(bt.identifier('annotateLazy'), bt.identifier('annotateLazy')), + ], + bt.stringLiteral('@kbn/lazy-object') + ); + program.node.body.unshift(importDecl); + } + } + } + + path.replaceWith(replacement); + }, + }, + }; +} + +module.exports = lazyBabelPlugin; diff --git a/src/platform/packages/shared/kbn-lazy-object/src/plugin/lazy_babel_plugin.test.ts b/src/platform/packages/shared/kbn-lazy-object/src/plugin/lazy_babel_plugin.test.ts new file mode 100644 index 0000000000000..98c3d0934d3d3 --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/src/plugin/lazy_babel_plugin.test.ts @@ -0,0 +1,188 @@ +/* + * 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 Babel from '@babel/core'; +import { runInNewContext } from 'vm'; +import { + createLazyObjectFromAnnotations, + annotateLazy, +} from '../create_lazy_object_from_annotations'; + +function transform(code: string) { + // Use Kibana's node preset which includes the lazy plugin and converts ESM to CJS + const result = Babel.transformSync(code, { + presets: ['@kbn/babel-preset/node_preset'], + filename: 'test.js', + }); + if (!result || !result.code) throw new Error('Transform failed'); + return result.code; +} + +// Minimal runtime shim for the "macro" marker +function lazyObject(obj: T): T { + return obj; +} + +describe('lazyBabelPlugin', () => { + it('wraps properties in lazy getters and memoizes on first access', () => { + const code = transform(` + const o = lazyObject({ + a: (() => { globalThis.__hits = (globalThis.__hits||0)+1; return 1; })(), + }); + o; + `); + + // Execute transformed code in isolated context + const ctx: any = { __hits: 0, module: { exports: {} }, exports: {} }; + ctx.globalThis = ctx; + ctx.lazyObject = lazyObject; + // Provide a CJS require stub for the injected import from '@kbn/lazy-object' + ctx.require = (id: string) => { + if (id === '@kbn/lazy-object') { + return { + createLazyObjectFromAnnotations, + annotateLazy, + lazyObject: (x: any) => x, + }; + } + throw new Error(`Unknown module: ${id}`); + }; + runInNewContext(code + '\nmodule.exports = o;', ctx); + const o: any = ctx.module.exports; + + expect(ctx.__hits).toBe(0); // not executed yet + expect(o.a).toBe(1); // first access executes + expect(ctx.__hits).toBe(1); + expect(o.a).toBe(1); // second access memoized + expect(ctx.__hits).toBe(1); + }); + + it('allows setting property to override memoized value', () => { + const code = transform(` + const o = lazyObject({ + x: (() => { globalThis.__hits = (globalThis.__hits||0)+1; return 5; })(), + }); + o; + `); + + const ctx: any = { __hits: 0, module: { exports: {} }, exports: {} }; + ctx.globalThis = ctx; + ctx.lazyObject = lazyObject; + ctx.require = (id: string) => { + if (id === '@kbn/lazy-object') { + return { + createLazyObjectFromAnnotations, + annotateLazy, + lazyObject: (x: any) => x, + }; + } + throw new Error(`Unknown module: ${id}`); + }; + runInNewContext(code + '\nmodule.exports = o;', ctx); + const o: any = ctx.module.exports; + + o.x = 9; + expect(o.x).toBe(9); + expect(ctx.__hits).toBe(0); // setter should not trigger original evaluation + }); + + it('keeps properties enumerable', () => { + const code = transform(` + const o = lazyObject({ a: 1, b: 2 }); + o; + `); + const ctx: any = { module: { exports: {} }, exports: {} }; + ctx.globalThis = ctx; + ctx.lazyObject = lazyObject; + ctx.require = (id: string) => { + if (id === '@kbn/lazy-object') { + return { + createLazyObjectFromAnnotations, + annotateLazy, + lazyObject: (x: any) => x, + }; + } + throw new Error(`Unknown module: ${id}`); + }; + runInNewContext(code + '\nmodule.exports = o;', ctx); + const o: any = ctx.module.exports; + expect(Object.keys(o)).toEqual(['a', 'b']); + }); + + it('handles spread properties without crashing', () => { + const code = transform(` + const base = { a: 1 }; + const o = lazyObject({ ...base, b: (() => { globalThis.__hits = (globalThis.__hits||0)+1; return 2; })() }); + o; + `); + + const ctx: any = { __hits: 0, module: { exports: {} }, exports: {} }; + ctx.globalThis = ctx; + ctx.lazyObject = lazyObject; + ctx.require = (id: string) => { + if (id === '@kbn/lazy-object') { + return { + createLazyObjectFromAnnotations, + annotateLazy, + lazyObject: (x: any) => x, + }; + } + throw new Error(`Unknown module: ${id}`); + }; + runInNewContext(code + '\nmodule.exports = o;', ctx); + const o: any = ctx.module.exports; + + expect(o.a).toBe(1); + + // Should not have executed b yet + expect(ctx.__hits).toBe(0); + // Accessing b should evaluate once + expect(o.b).toBe(2); + expect(ctx.__hits).toBe(1); + }); + + it('handles spread of call expressions without crashing', () => { + const code = transform(` + function createCoreMock() { + globalThis.__spreadHits = (globalThis.__spreadHits||0)+1; + return { a: 1 }; + } + const o = lazyObject({ + ...createCoreMock(), + b: (() => { globalThis.__lazyHits = (globalThis.__lazyHits||0)+1; return 2; })(), + }); + o; + `); + + const ctx: any = { __spreadHits: 0, __lazyHits: 0, module: { exports: {} }, exports: {} }; + ctx.globalThis = ctx; + ctx.lazyObject = lazyObject; + ctx.require = (id: string) => { + if (id === '@kbn/lazy-object') { + return { + createLazyObjectFromAnnotations, + annotateLazy, + lazyObject: (x: any) => x, + }; + } + throw new Error(`Unknown module: ${id}`); + }; + runInNewContext(code + '\nmodule.exports = o;', ctx); + const o: any = ctx.module.exports; + + // Spread of call expression is applied eagerly during construction + expect(ctx.__spreadHits).toBe(1); + expect(o.a).toBe(1); + + // Non-spread property remains lazy + expect(ctx.__lazyHits).toBe(0); + expect(o.b).toBe(2); + expect(ctx.__lazyHits).toBe(1); + }); +}); diff --git a/src/platform/packages/shared/kbn-lazy-object/tsconfig.json b/src/platform/packages/shared/kbn-lazy-object/tsconfig.json new file mode 100644 index 0000000000000..7aba1b1a9378a --- /dev/null +++ b/src/platform/packages/shared/kbn-lazy-object/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [] +} diff --git a/src/platform/packages/shared/kbn-logging-mocks/src/logger.mock.ts b/src/platform/packages/shared/kbn-logging-mocks/src/logger.mock.ts index 29b096c43f4f0..e0c0a1a76c32f 100644 --- a/src/platform/packages/shared/kbn-logging-mocks/src/logger.mock.ts +++ b/src/platform/packages/shared/kbn-logging-mocks/src/logger.mock.ts @@ -8,11 +8,12 @@ */ import type { Logger, LogMeta, LogMessageSource } from '@kbn/logging'; +import { lazyObject } from '@kbn/lazy-object'; export type MockedLogger = jest.Mocked & { context: string[] }; const createLoggerMock = (context: string[] = []) => { - const mockLog: MockedLogger = { + const mockLog: MockedLogger = lazyObject({ context, debug: jest.fn(), error: jest.fn(), @@ -22,15 +23,14 @@ const createLoggerMock = (context: string[] = []) => { trace: jest.fn(), warn: jest.fn(), get: jest.fn(), - isLevelEnabled: jest.fn(), - }; + isLevelEnabled: jest.fn().mockReturnValue(true), + }); + mockLog.get.mockImplementation((...ctx) => ({ ...mockLog, context: Array.isArray(context) ? context.concat(ctx) : [context, ...ctx].filter(Boolean), })); - mockLog.isLevelEnabled.mockReturnValue(true); - return mockLog; }; @@ -69,7 +69,7 @@ const convertMessageSourceOrError = ( }; const collectLoggerMock = (logger: MockedLogger) => { - return { + return lazyObject({ debug: logger.debug.mock.calls.map(convertMessageSource), error: logger.error.mock.calls.map(convertMessageSourceOrError), fatal: logger.fatal.mock.calls.map(convertMessageSourceOrError), @@ -77,7 +77,7 @@ const collectLoggerMock = (logger: MockedLogger) => { log: logger.log.mock.calls, trace: logger.trace.mock.calls.map(convertMessageSource), warn: logger.warn.mock.calls.map(convertMessageSourceOrError), - }; + }); }; export const loggerMock = { diff --git a/src/platform/packages/shared/kbn-logging-mocks/tsconfig.json b/src/platform/packages/shared/kbn-logging-mocks/tsconfig.json index c101096106966..fb349c29e7d45 100644 --- a/src/platform/packages/shared/kbn-logging-mocks/tsconfig.json +++ b/src/platform/packages/shared/kbn-logging-mocks/tsconfig.json @@ -11,7 +11,8 @@ "**/*.ts" ], "kbn_references": [ - "@kbn/logging" + "@kbn/logging", + "@kbn/lazy-object" ], "exclude": [ "target/**/*", diff --git a/src/platform/packages/shared/kbn-test/jest-preset.js b/src/platform/packages/shared/kbn-test/jest-preset.js index e836dc2336cd7..32c33415ed475 100644 --- a/src/platform/packages/shared/kbn-test/jest-preset.js +++ b/src/platform/packages/shared/kbn-test/jest-preset.js @@ -10,6 +10,18 @@ // For a detailed explanation regarding each configuration property, visit: // https://jestjs.io/docs/en/configuration.html +const ciStatsJestReporter = [ + '/src/platform/packages/shared/kbn-test/src/jest/ci_stats_jest_reporter.ts', + { + testGroupType: process.env.TEST_GROUP_TYPE_UNIT, + }, +]; + +const scoutReporter = [ + '/src/platform/packages/private/kbn-scout-reporting/src/reporting/jest', + { name: 'Jest tests (unit)', configCategory: 'unit-test' }, +]; + /** @type {import("@jest/types").Config.InitialOptions} */ module.exports = { // The directory where Jest should output its coverage files @@ -42,24 +54,8 @@ module.exports = { rootDirectory: '.', }, ], - ...(process.env.TEST_GROUP_TYPE_UNIT - ? [ - [ - '/src/platform/packages/shared/kbn-test/src/jest/ci_stats_jest_reporter.ts', - { - testGroupType: process.env.TEST_GROUP_TYPE_UNIT, - }, - ], - ] - : []), - ...(['1', 'yes', 'true'].includes(process.env.SCOUT_REPORTER_ENABLED) - ? [ - [ - '/src/platform/packages/private/kbn-scout-reporting/src/reporting/jest', - { name: 'Jest tests (unit)', configCategory: 'unit-test' }, - ], - ] - : []), + ...(process.env.TEST_GROUP_TYPE_UNIT ? [ciStatsJestReporter] : []), + ...(['1', 'yes', 'true'].includes(process.env.SCOUT_REPORTER_ENABLED) ? [scoutReporter] : []), ], // The paths to modules that run some code to configure or set up the testing environment before each test diff --git a/src/platform/plugins/shared/files/server/mocks.ts b/src/platform/plugins/shared/files/server/mocks.ts index d50e4c36d6eb4..200585f3a7909 100644 --- a/src/platform/plugins/shared/files/server/mocks.ts +++ b/src/platform/plugins/shared/files/server/mocks.ts @@ -11,34 +11,37 @@ import type { KibanaRequest } from '@kbn/core/server'; import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; import * as stream from 'stream'; import { clone } from 'lodash'; +import { lazyObject } from '@kbn/lazy-object'; import type { File, FileJSON } from '../common'; import type { FileClient, FileServiceFactory, FileServiceStart, FilesSetup } from '.'; -export const createFileServiceMock = (): DeeplyMockedKeys => ({ - create: jest.fn(), - delete: jest.fn(), - bulkDelete: jest.fn(), - deleteShareObject: jest.fn(), - find: jest.fn(), - getById: jest.fn(), - bulkGetById: jest.fn(), - getByToken: jest.fn(), - getShareObject: jest.fn(), - getUsageMetrics: jest.fn(), - listShareObjects: jest.fn(), - update: jest.fn(), - updateShareObject: jest.fn(), -}); +export const createFileServiceMock = (): DeeplyMockedKeys => + lazyObject({ + create: jest.fn(), + delete: jest.fn(), + bulkDelete: jest.fn(), + deleteShareObject: jest.fn(), + find: jest.fn(), + getById: jest.fn(), + bulkGetById: jest.fn(), + getByToken: jest.fn(), + getShareObject: jest.fn(), + getUsageMetrics: jest.fn(), + listShareObjects: jest.fn(), + update: jest.fn(), + updateShareObject: jest.fn(), + }); -export const createFileServiceFactoryMock = (): DeeplyMockedKeys => ({ - asInternal: jest.fn(createFileServiceMock), - asScoped: jest.fn((_: KibanaRequest) => createFileServiceMock()), -}); +export const createFileServiceFactoryMock = (): DeeplyMockedKeys => + lazyObject({ + asInternal: jest.fn(createFileServiceMock), + asScoped: jest.fn((_: KibanaRequest) => createFileServiceMock()), + }); export const createFileMock = ( fileDataOverride: Partial> = {} ): DeeplyMockedKeys => { - const fileMock: DeeplyMockedKeys = { + const fileMock: DeeplyMockedKeys = lazyObject({ id: '123', data: { id: '123', @@ -65,7 +68,7 @@ export const createFileMock = ( toJSON: jest.fn(() => { return clone(fileMock.data); }), - }; + }); fileMock.update.mockResolvedValue(fileMock); fileMock.uploadContent.mockResolvedValue(fileMock); @@ -78,7 +81,7 @@ export const createFileClientMock = ( ): DeeplyMockedKeys => { const fileMock = createFileMock(fileDataOverride); - return { + return lazyObject({ fileKind: 'none', create: jest.fn().mockResolvedValue(fileMock), get: jest.fn().mockResolvedValue(fileMock), @@ -88,11 +91,11 @@ export const createFileClientMock = ( share: jest.fn(), unshare: jest.fn(), listShares: jest.fn().mockResolvedValue({ shares: [] }), - }; + }); }; export const createFilesSetupMock = (): DeeplyMockedKeys => { - return { + return lazyObject({ registerFileKind: jest.fn(), - }; + }); }; diff --git a/src/platform/plugins/shared/files/tsconfig.json b/src/platform/plugins/shared/files/tsconfig.json index a5297703e7958..4bda1ca567abe 100644 --- a/src/platform/plugins/shared/files/tsconfig.json +++ b/src/platform/plugins/shared/files/tsconfig.json @@ -34,6 +34,7 @@ "@kbn/core-http-common", "@kbn/core-lifecycle-server-internal", "@kbn/cbor", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/src/platform/plugins/shared/usage_collection/server/mocks.ts b/src/platform/plugins/shared/usage_collection/server/mocks.ts index f2a016eed455f..65ba0f8e35718 100644 --- a/src/platform/plugins/shared/usage_collection/server/mocks.ts +++ b/src/platform/plugins/shared/usage_collection/server/mocks.ts @@ -14,10 +14,12 @@ import { savedObjectsClientMock, } from '@kbn/core/server/mocks'; +import { lazyObject } from '@kbn/lazy-object'; import { type CollectorOptions, CollectorSet } from './collector'; import { Collector } from './collector/collector'; import type { UsageCollectionSetup, CollectorFetchContext } from '.'; import { usageCountersServiceMock } from './usage_counters/usage_counters_service.mock'; + export type { CollectorOptions }; export { Collector }; @@ -30,7 +32,7 @@ export const createUsageCollectionSetupMock = () => { const { createUsageCounter, getUsageCounterByDomainId } = usageCountersServiceMock.createSetupContract(); - const usageCollectionSetupMock: jest.Mocked = { + const usageCollectionSetupMock: jest.Mocked = lazyObject({ createUsageCounter, getUsageCounterByDomainId, bulkFetch: jest.fn().mockImplementation(collectorSet.bulkFetch), @@ -40,16 +42,16 @@ export const createUsageCollectionSetupMock = () => { makeStatsCollector: jest.fn().mockImplementation(collectorSet.makeStatsCollector), makeUsageCollector: jest.fn().mockImplementation(collectorSet.makeUsageCollector), registerCollector: jest.fn().mockImplementation(collectorSet.registerCollector), - }; + }); return usageCollectionSetupMock; }; export function createCollectorFetchContextMock(): jest.Mocked { - const collectorFetchClientsMock: jest.Mocked = { + const collectorFetchClientsMock: jest.Mocked = lazyObject({ esClient: elasticsearchServiceMock.createClusterClient().asInternalUser, soClient: savedObjectsClientMock.create(), - }; + }); return collectorFetchClientsMock; } diff --git a/src/platform/plugins/shared/usage_collection/tsconfig.json b/src/platform/plugins/shared/usage_collection/tsconfig.json index b1f637e38a166..4b8be1ebe2d57 100644 --- a/src/platform/plugins/shared/usage_collection/tsconfig.json +++ b/src/platform/plugins/shared/usage_collection/tsconfig.json @@ -27,6 +27,7 @@ "@kbn/es-query", "@kbn/core-saved-objects-utils-server", "@kbn/core-saved-objects-api-server", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/tsconfig.base.json b/tsconfig.base.json index b1d20843b2786..44e22afc327a3 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1268,6 +1268,8 @@ "@kbn/langgraph-checkpoint-saver/*": ["x-pack/platform/packages/shared/kbn-langgraph-checkpoint-saver/*"], "@kbn/language-documentation": ["src/platform/packages/private/kbn-language-documentation"], "@kbn/language-documentation/*": ["src/platform/packages/private/kbn-language-documentation/*"], + "@kbn/lazy-object": ["src/platform/packages/shared/kbn-lazy-object"], + "@kbn/lazy-object/*": ["src/platform/packages/shared/kbn-lazy-object/*"], "@kbn/lens-config-builder-example-plugin": ["x-pack/examples/lens_config_builder_example"], "@kbn/lens-config-builder-example-plugin/*": ["x-pack/examples/lens_config_builder_example/*"], "@kbn/lens-embeddable-utils": ["src/platform/packages/shared/kbn-lens-embeddable-utils"], diff --git a/x-pack/platform/plugins/shared/actions/server/mocks.ts b/x-pack/platform/plugins/shared/actions/server/mocks.ts index f2434049f886c..e068db4f12601 100644 --- a/x-pack/platform/plugins/shared/actions/server/mocks.ts +++ b/x-pack/platform/plugins/shared/actions/server/mocks.ts @@ -13,6 +13,7 @@ import { } from '@kbn/core/server/mocks'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import type { Logger } from '@kbn/core/server'; +import { lazyObject } from '@kbn/lazy-object'; import type { ActionsClientMock } from './actions_client/actions_client.mock'; import { actionsClientMock } from './actions_client/actions_client.mock'; import type { PluginSetupContract, PluginStartContract } from './plugin'; @@ -28,7 +29,7 @@ export type { ActionsClientMock }; const logger = loggingSystemMock.create().get() as jest.Mocked; const createSetupMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ registerType: jest.fn(), registerSubActionConnectorType: jest.fn(), isPreconfiguredConnector: jest.fn(), @@ -40,12 +41,12 @@ const createSetupMock = () => { }), setEnabledConnectorTypes: jest.fn(), isActionTypeEnabled: jest.fn(), - }; + }); return mock; }; const createStartMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ isActionTypeEnabled: jest.fn(), isActionExecutable: jest.fn(), getAllTypes: jest.fn(), @@ -57,7 +58,8 @@ const createStartMock = () => { inMemoryConnectors: [], renderActionParameterTemplates: jest.fn(), isSystemActionConnector: jest.fn(), - }; + }); + return mock; }; @@ -83,7 +85,7 @@ const createServicesMock = () => { Services & { savedObjectsClient: ReturnType; } - > = { + > = lazyObject({ savedObjectsClient: savedObjectsClientMock.create(), scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient().asCurrentUser, connectorTokenClient: new ConnectorTokenClient({ @@ -91,7 +93,7 @@ const createServicesMock = () => { encryptedSavedObjectsClient: encryptedSavedObjectsMock.createClient(), logger, }), - }; + }); return mock; }; @@ -100,7 +102,7 @@ const createUnsecuredServicesMock = () => { UnsecuredServices & { savedObjectsClient: ReturnType; } - > = { + > = lazyObject({ savedObjectsClient: savedObjectsRepositoryMock.create(), scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient().asCurrentUser, connectorTokenClient: new ConnectorTokenClient({ @@ -108,7 +110,7 @@ const createUnsecuredServicesMock = () => { encryptedSavedObjectsClient: encryptedSavedObjectsMock.createClient(), logger, }), - }; + }); return mock; }; diff --git a/x-pack/platform/plugins/shared/actions/tsconfig.json b/x-pack/platform/plugins/shared/actions/tsconfig.json index 1a3f5157f3ff9..b000ca27061cf 100644 --- a/x-pack/platform/plugins/shared/actions/tsconfig.json +++ b/x-pack/platform/plugins/shared/actions/tsconfig.json @@ -52,6 +52,7 @@ "@kbn/es-errors", "@kbn/kibana-utils-plugin", "@kbn/licensing-types", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/x-pack/platform/plugins/shared/alerting/server/mocks.ts b/x-pack/platform/plugins/shared/alerting/server/mocks.ts index b0922ff2215d0..dbaa54986ec33 100644 --- a/x-pack/platform/plugins/shared/alerting/server/mocks.ts +++ b/x-pack/platform/plugins/shared/alerting/server/mocks.ts @@ -13,6 +13,7 @@ import { import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { searchSourceCommonMock } from '@kbn/data-plugin/common/search/search_source/mocks'; import type { SharePluginStart } from '@kbn/share-plugin/server'; +import { lazyObject } from '@kbn/lazy-object'; import { rulesClientMock } from './rules_client.mock'; import type { AlertingServerSetup, AlertingServerStart } from './plugin'; import type { Alert, AlertFactoryDoneUtils } from './alert'; @@ -27,17 +28,18 @@ import { publicAlertsClientMock } from './alerts_client/alerts_client.mock'; export { rulesClientMock }; const createSetupMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ registerType: jest.fn(), getSecurityHealth: jest.fn(), getConfig: jest.fn(), - frameworkAlerts: { + frameworkAlerts: lazyObject({ enabled: jest.fn(), getContextInitializationPromise: jest.fn(), - }, + }), getDataStreamAdapter: jest.fn(), registerConnectorAdapter: jest.fn(), - }; + }); + return mock; }; @@ -57,7 +59,7 @@ const createShareStartMock = () => { }; const createStartMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ listTypes: jest.fn(), getType: jest.fn(), getAllTypes: jest.fn(), @@ -65,7 +67,7 @@ const createStartMock = () => { getAlertingAuthorizationWithRequest: jest.fn(), getRulesClientWithRequest: jest.fn().mockResolvedValue(rulesClientMock.create()), getFrameworkHealth: jest.fn(), - }; + }); return mock; }; @@ -79,7 +81,7 @@ export const createAlertFactoryMock = { InstanceState extends AlertInstanceState = AlertInstanceState, InstanceContext extends AlertInstanceContext = AlertInstanceContext >() => { - const mock = { + const mock = lazyObject({ hasScheduledActions: jest.fn(), isThrottled: jest.fn(), getScheduledActionOptions: jest.fn(), @@ -91,7 +93,7 @@ export const createAlertFactoryMock = { updateLastScheduledActions: jest.fn(), toJSON: jest.fn(), toRaw: jest.fn(), - }; + }); // support chaining mock.replaceState.mockReturnValue(mock); @@ -106,48 +108,48 @@ export const createAlertFactoryMock = { ActionGroupIds extends string = string >() => { const mock: jest.Mocked> = - { + lazyObject({ getRecoveredAlerts: jest.fn().mockReturnValue([]), - }; + }); return mock; }, }; const createAbortableSearchClientMock = () => { - const mock = { + const mock = lazyObject({ search: jest.fn(), - }; + }); return mock; }; const createAbortableSearchServiceMock = () => { - return { + return lazyObject({ asInternalUser: createAbortableSearchClientMock(), asCurrentUser: createAbortableSearchClientMock(), - }; + }); }; const createRuleMonitoringServiceMock = () => { - const mock = { + const mock = lazyObject({ setLastRunMetricsTotalSearchDurationMs: jest.fn(), setLastRunMetricsTotalIndexingDurationMs: jest.fn(), setLastRunMetricsTotalAlertsDetected: jest.fn(), setLastRunMetricsTotalAlertsCreated: jest.fn(), setLastRunMetricsGapDurationS: jest.fn(), - } as unknown as jest.Mocked; + }) as unknown as jest.Mocked; return mock; }; const createRuleLastRunServiceMock = () => { - const mock = { + const mock = lazyObject({ getLastRunErrors: jest.fn(), getLastRunWarnings: jest.fn(), getLastRunOutcomeMessages: jest.fn(), getLastRunResults: jest.fn(), getLastRunSetters: jest.fn(), - } as unknown as jest.Mocked; + }) as unknown as jest.Mocked; return mock; }; @@ -158,15 +160,15 @@ const createRuleExecutorServicesMock = < >() => { const alertFactoryMockCreate = createAlertFactoryMock.create(); const alertFactoryMockDone = createAlertFactoryMock.done(); - return { - alertFactory: { + return lazyObject({ + alertFactory: lazyObject({ create: jest.fn().mockReturnValue(alertFactoryMockCreate), - alertLimit: { + alertLimit: lazyObject({ getValue: jest.fn().mockReturnValue(1000), setLimitReached: jest.fn(), - }, + }), done: jest.fn().mockReturnValue(alertFactoryMockDone), - }, + }), alertsClient: publicAlertsClientMock.create(), getDataViews: jest.fn().mockResolvedValue(dataViewPluginMocks.createStartContract()), getMaintenanceWindowIds: jest.fn().mockResolvedValue([]), @@ -176,11 +178,11 @@ const createRuleExecutorServicesMock = < scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), search: createAbortableSearchServiceMock(), share: createShareStartMock(), - shouldStopExecution: () => true, - shouldWriteAlerts: () => true, + shouldStopExecution: () => true as boolean, + shouldWriteAlerts: () => true as boolean, uiSettingsClient: uiSettingsServiceMock.createClient(), getAsyncSearchClient: jest.fn().mockReturnValue(createAbortableSearchClientMock()), - }; + }); }; export type RuleExecutorServicesMock = ReturnType; diff --git a/x-pack/platform/plugins/shared/alerting/server/rules_client_factory.test.ts b/x-pack/platform/plugins/shared/alerting/server/rules_client_factory.test.ts index cefcf507898ae..7df560e8b1f9a 100644 --- a/x-pack/platform/plugins/shared/alerting/server/rules_client_factory.test.ts +++ b/x-pack/platform/plugins/shared/alerting/server/rules_client_factory.test.ts @@ -37,49 +37,74 @@ import { } from './saved_objects'; import { backfillClientMock } from './backfill_client/backfill_client.mock'; import { ConnectorAdapterRegistry } from './connector_adapters/connector_adapter_registry'; +import type { SavedObjectsClientContract } from '@kbn/core/server'; + +import type { SecurityStartMock } from '@kbn/core-security-server-mocks'; +import type { ActionsAuthorizationMock } from '@kbn/actions-plugin/server/authorization/actions_authorization.mock'; +import type { BackfillClient } from './backfill_client/backfill_client'; + +let savedObjectsClient: jest.Mocked; +let savedObjectsService: ReturnType; +let securityPluginSetup: ReturnType; +let securityPluginStart: ReturnType; +let securityService: SecurityStartMock; +let alertingAuthorization: ReturnType; + +let rulesClientFactoryParams: jest.Mocked; +let alertingAuthorizationClientFactory: ReturnType< + typeof alertingAuthorizationClientFactoryMock.createFactory +>; + +let actionsAuthorization: ActionsAuthorizationMock; +let backfillClient: jest.Mocked; jest.mock('./rules_client'); jest.mock('./authorization/alerting_authorization'); -const savedObjectsClient = savedObjectsClientMock.create(); -const savedObjectsService = savedObjectsServiceMock.createInternalStartContract(); - -const securityPluginSetup = securityMock.createSetup(); -const securityPluginStart = securityMock.createStart(); -const securityService = securityServiceMock.createStart(); - -const alertingAuthorization = alertingAuthorizationMock.create(); -const alertingAuthorizationClientFactory = alertingAuthorizationClientFactoryMock.createFactory(); -const internalSavedObjectsRepository = savedObjectsRepositoryMock.create(); -const backfillClient = backfillClientMock.create(); - -const rulesClientFactoryParams: jest.Mocked = { - logger: loggingSystemMock.create().get(), - taskManager: taskManagerMock.createStart(), - ruleTypeRegistry: ruleTypeRegistryMock.create(), - getSpaceId: jest.fn(), - spaceIdToNamespace: jest.fn(), - maxScheduledPerMinute: 10000, - minimumScheduleInterval: { value: '1m', enforce: false }, - internalSavedObjectsRepository, - encryptedSavedObjectsClient: encryptedSavedObjectsMock.createClient(), - actions: actionsMock.createStart(), - eventLog: eventLogMock.createStart(), - kibanaVersion: '7.10.0', - authorization: - alertingAuthorizationClientFactory as unknown as AlertingAuthorizationClientFactory, - backfillClient, - connectorAdapterRegistry: new ConnectorAdapterRegistry(), - uiSettings: uiSettingsServiceMock.createStartContract(), - securityService: securityServiceMock.createStart(), - getAlertIndicesAlias: jest.fn(), - alertsService: null, -}; - -const actionsAuthorization = actionsAuthorizationMock.create(); - beforeEach(() => { - jest.resetAllMocks(); + jest.clearAllMocks(); + + savedObjectsClient = savedObjectsClientMock.create(); + savedObjectsService = savedObjectsServiceMock.createInternalStartContract(); + + securityPluginSetup = securityMock.createSetup(); + + securityPluginStart = securityMock.createStart(); + + securityService = securityServiceMock.createStart(); + + alertingAuthorization = alertingAuthorizationMock.create(); + + alertingAuthorizationClientFactory = alertingAuthorizationClientFactoryMock.createFactory(); + + actionsAuthorization = actionsAuthorizationMock.create(); + + const internalSavedObjectsRepository = savedObjectsRepositoryMock.create(); + backfillClient = backfillClientMock.create(); + + rulesClientFactoryParams = { + logger: loggingSystemMock.create().get(), + taskManager: taskManagerMock.createStart(), + ruleTypeRegistry: ruleTypeRegistryMock.create(), + getSpaceId: jest.fn(), + spaceIdToNamespace: jest.fn(), + maxScheduledPerMinute: 10000, + minimumScheduleInterval: { value: '1m', enforce: false }, + internalSavedObjectsRepository, + encryptedSavedObjectsClient: encryptedSavedObjectsMock.createClient(), + actions: actionsMock.createStart(), + eventLog: eventLogMock.createStart(), + kibanaVersion: '7.10.0', + authorization: + alertingAuthorizationClientFactory as unknown as AlertingAuthorizationClientFactory, + backfillClient, + connectorAdapterRegistry: new ConnectorAdapterRegistry(), + uiSettings: uiSettingsServiceMock.createStartContract(), + securityService: securityServiceMock.createStart(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, + }; + rulesClientFactoryParams.actions = actionsMock.createStart(); ( rulesClientFactoryParams.actions as jest.Mocked @@ -123,6 +148,11 @@ test('creates a rules client with proper constructor arguments when security is ); expect(jest.requireMock('./rules_client').RulesClient).toHaveBeenCalledWith({ + auditLogger: { + enabled: true, + includeSavedObjectNames: false, + log: expect.any(Function), + }, unsecuredSavedObjectsClient: savedObjectsClient, authorization: alertingAuthorization, actionsAuthorization, diff --git a/x-pack/platform/plugins/shared/alerting/tsconfig.json b/x-pack/platform/plugins/shared/alerting/tsconfig.json index 8221beafc980f..08010bc1ae93e 100644 --- a/x-pack/platform/plugins/shared/alerting/tsconfig.json +++ b/x-pack/platform/plugins/shared/alerting/tsconfig.json @@ -78,7 +78,8 @@ "@kbn/elastic-assistant-common", "@kbn/response-ops-recurring-schedule-form", "@kbn/licensing-types", - "@kbn/es-types" + "@kbn/es-types", + "@kbn/lazy-object" ], "exclude": [ "target/**/*" diff --git a/x-pack/platform/plugins/shared/cases/public/common/lib/kibana/kibana_react.mock.tsx b/x-pack/platform/plugins/shared/cases/public/common/lib/kibana/kibana_react.mock.tsx index 0f45c0ceeac01..a449b7e3a3269 100644 --- a/x-pack/platform/plugins/shared/cases/public/common/lib/kibana/kibana_react.mock.tsx +++ b/x-pack/platform/plugins/shared/cases/public/common/lib/kibana/kibana_react.mock.tsx @@ -22,6 +22,7 @@ import { triggersActionsUiMock } from '@kbn/triggers-actions-ui-plugin/public/mo import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; import { registerConnectorsToMockActionRegistry } from '../../mock/register_connectors'; import { connectorsMock } from '../../mock/connectors'; +import { lazyObject } from '@kbn/lazy-object'; interface StartServiceArgs { license?: ILicense | null; @@ -31,24 +32,31 @@ export const createStartServicesMock = ({ license }: StartServiceArgs = {}): Sta const licensingPluginMock = licensingMock.createStart(); const triggersActionsUi = triggersActionsUiMock.createStart(); - const services = { - ...coreMock.createStart(), - storage: { ...coreMock.createStorage(), get: jest.fn(), set: jest.fn(), remove: jest.fn() }, - lens: { + const core = coreMock.createStart(); + + const services = lazyObject({ + ...core, + storage: lazyObject({ + ...coreMock.createStorage(), + get: jest.fn(), + set: jest.fn(), + remove: jest.fn(), + }), + lens: lazyObject({ canUseEditor: jest.fn(), navigateToPrefilledEditor: jest.fn(), - }, + }), security: securityMock.createStart(), - triggersActionsUi: { + triggersActionsUi: lazyObject({ actionTypeRegistry: triggersActionsUi.actionTypeRegistry, getAlertsStateTable: jest.fn(() =>
), - }, + }), spaces: spacesPluginMock.createStartContract(), licensing: license != null ? { ...licensingPluginMock, license$: new BehaviorSubject(license) } : licensingPluginMock, - } as unknown as StartServices; + }) as unknown as StartServices; services.application.currentAppId$ = new BehaviorSubject('testAppId'); services.application.applications$ = new BehaviorSubject>( diff --git a/x-pack/platform/plugins/shared/cases/public/common/mock/test_providers.tsx b/x-pack/platform/plugins/shared/cases/public/common/mock/test_providers.tsx index 751a5d9b43fac..6819ee4f96647 100644 --- a/x-pack/platform/plugins/shared/cases/public/common/mock/test_providers.tsx +++ b/x-pack/platform/plugins/shared/cases/public/common/mock/test_providers.tsx @@ -49,7 +49,7 @@ interface TestProviderProps { filesClient?: BaseFilesClient; } -window.scrollTo = jest.fn(); +jest.spyOn(window, 'scrollTo').mockImplementation(() => {}); const getMockedFilesClient = (): BaseFilesClient => { const mockedFilesClient = createMockFilesClient(); @@ -93,11 +93,12 @@ const TestProvidersComponent: React.FC = ({ queryClient, filesClient, }) => { - const finalCoreStart = useMemo(() => coreStart ?? coreMock.createStart(), [coreStart]); - const finalServices = useMemo( - () => ({ ...createStartServicesMock({ license }), ...coreStart, ...services }), - [coreStart, license, services] - ); + const finalCoreStart = useMemo(() => { + return coreStart ?? coreMock.createStart(); + }, [coreStart]); + const finalServices = useMemo(() => { + return { ...createStartServicesMock({ license }), ...coreStart, ...services }; + }, [coreStart, license, services]); const defaultQueryClient = useMemo(() => createTestQueryClient(), []); @@ -168,7 +169,7 @@ const TestProvidersComponent: React.FC = ({ TestProvidersComponent.displayName = 'TestProviders'; -export const TestProviders = React.memo(TestProvidersComponent); +export const TestProviders = TestProvidersComponent; type CustomRenderOptions = Omit & { wrapperProps?: Omit; diff --git a/x-pack/platform/plugins/shared/cases/server/client/mocks.ts b/x-pack/platform/plugins/shared/cases/server/client/mocks.ts index f305fbec6d536..6d55effe02574 100644 --- a/x-pack/platform/plugins/shared/cases/server/client/mocks.ts +++ b/x-pack/platform/plugins/shared/cases/server/client/mocks.ts @@ -27,6 +27,7 @@ import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { notificationsMock } from '@kbn/notifications-plugin/server/mocks'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { lazyObject } from '@kbn/lazy-object'; import type { CasesSearchRequest } from '../../common/types/api'; import type { CasesClient, CasesClientInternal } from '.'; import type { AttachmentsSubClient } from './attachments/client'; @@ -57,7 +58,7 @@ import { type CasesSubClientMock = jest.Mocked; const createCasesSubClientMock = (): CasesSubClientMock => { - return { + return lazyObject({ create: jest.fn(), bulkCreate: jest.fn(), search: jest.fn(), @@ -76,23 +77,23 @@ const createCasesSubClientMock = (): CasesSubClientMock => { addObservable: jest.fn(), updateObservable: jest.fn(), deleteObservable: jest.fn(), - }; + }); }; type MetricsSubClientMock = jest.Mocked; const createMetricsSubClientMock = (): MetricsSubClientMock => { - return { + return lazyObject({ getCaseMetrics: jest.fn(), getCasesMetrics: jest.fn(), getStatusTotalsByType: jest.fn(), - }; + }); }; type AttachmentsSubClientMock = jest.Mocked; const createAttachmentsSubClientMock = (): AttachmentsSubClientMock => { - return { + return lazyObject({ bulkGet: jest.fn(), add: jest.fn(), addFile: jest.fn(), @@ -105,40 +106,40 @@ const createAttachmentsSubClientMock = (): AttachmentsSubClientMock => { get: jest.fn(), update: jest.fn(), getAllAlertsAttachToCase: jest.fn(), - }; + }); }; type UserActionsSubClientMock = jest.Mocked; const createUserActionsSubClientMock = (): UserActionsSubClientMock => { - return { + return lazyObject({ find: jest.fn(), getAll: jest.fn(), getConnectors: jest.fn(), stats: jest.fn(), getUsers: jest.fn(), - }; + }); }; type ConfigureSubClientMock = jest.Mocked; const createConfigureSubClientMock = (): ConfigureSubClientMock => { - return { + return lazyObject({ get: jest.fn(), getConnectors: jest.fn(), update: jest.fn(), create: jest.fn(), - }; + }); }; type InternalConfigureSubClientMock = jest.Mocked; const createInternalConfigureSubClientMock = (): InternalConfigureSubClientMock => { - return { + return lazyObject({ getMappings: jest.fn(), createMappings: jest.fn(), updateMappings: jest.fn(), - }; + }); }; export interface CasesClientMock extends CasesClient { @@ -148,22 +149,22 @@ export interface CasesClientMock extends CasesClient { } export const createCasesClientMock = (): CasesClientMock => { - const client: PublicContract = { + const client: PublicContract = lazyObject({ cases: createCasesSubClientMock(), attachments: createAttachmentsSubClientMock(), userActions: createUserActionsSubClientMock(), configure: createConfigureSubClientMock(), metrics: createMetricsSubClientMock(), - }; + }); return client as unknown as CasesClientMock; }; type CasesClientInternalMock = jest.Mocked; export const createCasesClientInternalMock = (): CasesClientInternalMock => { - const client: PublicContract = { + const client: PublicContract = lazyObject({ configuration: createInternalConfigureSubClientMock(), - }; + }); return client as unknown as CasesClientInternalMock; }; diff --git a/x-pack/platform/plugins/shared/cases/server/services/mocks.ts b/x-pack/platform/plugins/shared/cases/server/services/mocks.ts index 4612671b891b1..be39fb4230a72 100644 --- a/x-pack/platform/plugins/shared/cases/server/services/mocks.ts +++ b/x-pack/platform/plugins/shared/cases/server/services/mocks.ts @@ -6,6 +6,7 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; +import { lazyObject } from '@kbn/lazy-object'; import type { AlertService, CaseConfigureService, @@ -45,7 +46,7 @@ export type LicensingServiceMock = jest.Mocked; export type NotificationServiceMock = jest.Mocked; export const createCaseServiceMock = (): CaseServiceMock => { - const service: PublicMethodsOf = { + const service: PublicMethodsOf = lazyObject({ deleteCase: jest.fn(), findCases: jest.fn(), getAllCaseComments: jest.fn(), @@ -64,38 +65,38 @@ export const createCaseServiceMock = (): CaseServiceMock => { executeAggregations: jest.fn(), bulkDeleteCaseEntities: jest.fn(), getCategories: jest.fn(), - }; + }); // the cast here is required because jest.Mocked tries to include private members and would throw an error return service as unknown as CaseServiceMock; }; export const createConfigureServiceMock = (): CaseConfigureServiceMock => { - const service: PublicMethodsOf = { + const service: PublicMethodsOf = lazyObject({ delete: jest.fn(), get: jest.fn(), find: jest.fn(), patch: jest.fn(), post: jest.fn(), - }; + }); // the cast here is required because jest.Mocked tries to include private members and would throw an error return service as unknown as CaseConfigureServiceMock; }; export const connectorMappingsServiceMock = (): ConnectorMappingsServiceMock => { - const service: PublicMethodsOf = { + const service: PublicMethodsOf = lazyObject({ find: jest.fn(), post: jest.fn(), update: jest.fn(), - }; + }); // the cast here is required because jest.Mocked tries to include private members and would throw an error return service as unknown as ConnectorMappingsServiceMock; }; const createUserActionPersisterServiceMock = (): CaseUserActionPersisterServiceMock => { - const service: PublicMethodsOf = { + const service: PublicMethodsOf = lazyObject({ bulkAuditLogCaseDeletion: jest.fn(), bulkCreateUpdateCase: jest.fn(), buildUserActions: jest.fn(), @@ -103,7 +104,7 @@ const createUserActionPersisterServiceMock = (): CaseUserActionPersisterServiceM bulkCreateAttachmentCreation: jest.fn(), createUserAction: jest.fn(), bulkCreateUserAction: jest.fn(), - }; + }); return service as unknown as CaseUserActionPersisterServiceMock; }; @@ -120,7 +121,7 @@ const createUserActionFinderServiceMock = (): CaseUserActionFinderServiceMock => type FakeUserActionService = PublicMethodsOf & UserActionServiceOperations; export const createUserActionServiceMock = (): CaseUserActionServiceMock => { - const service: FakeUserActionService = { + const service: FakeUserActionService = lazyObject({ creator: createUserActionPersisterServiceMock(), finder: createUserActionFinderServiceMock(), getConnectorFieldsBeforeLatestPush: jest.fn(), @@ -132,14 +133,14 @@ export const createUserActionServiceMock = (): CaseUserActionServiceMock => { getMultipleCasesUserActionsTotal: jest.fn(), getCaseUserActionStats: jest.fn(), getUsers: jest.fn(), - }; + }); // the cast here is required because jest.Mocked tries to include private members and would throw an error return service as unknown as CaseUserActionServiceMock; }; export const createAlertServiceMock = (): AlertServiceMock => { - const service: PublicMethodsOf = { + const service: PublicMethodsOf = lazyObject({ updateAlertsStatus: jest.fn(), getAlerts: jest.fn(), executeAggregations: jest.fn(), @@ -147,14 +148,14 @@ export const createAlertServiceMock = (): AlertServiceMock => { ensureAlertsAuthorized: jest.fn(), removeCaseIdFromAlerts: jest.fn(), removeCaseIdsFromAllAlerts: jest.fn(), - }; + }); // the cast here is required because jest.Mocked tries to include private members and would throw an error return service as unknown as AlertServiceMock; }; const createAttachmentGetterServiceMock = (): AttachmentGetterServiceMock => { - const service: PublicMethodsOf = { + const service: PublicMethodsOf = lazyObject({ get: jest.fn(), bulkGet: jest.fn(), getAllAlertsAttachToCase: jest.fn(), @@ -162,7 +163,7 @@ const createAttachmentGetterServiceMock = (): AttachmentGetterServiceMock => { getAttachmentIdsForCases: jest.fn(), getFileAttachments: jest.fn(), getAllAlertIds: jest.fn(), - }; + }); return service as unknown as AttachmentGetterServiceMock; }; @@ -170,7 +171,7 @@ const createAttachmentGetterServiceMock = (): AttachmentGetterServiceMock => { type FakeAttachmentService = PublicMethodsOf & AttachmentServiceOperations; export const createAttachmentServiceMock = (): AttachmentServiceMock => { - const service: FakeAttachmentService = { + const service: FakeAttachmentService = lazyObject({ getter: createAttachmentGetterServiceMock(), bulkDelete: jest.fn(), create: jest.fn(), @@ -182,31 +183,31 @@ export const createAttachmentServiceMock = (): AttachmentServiceMock => { executeCaseActionsAggregations: jest.fn(), executeCaseAggregations: jest.fn(), countPersistableStateAndExternalReferenceAttachments: jest.fn(), - }; + }); // the cast here is required because jest.Mocked tries to include private members and would throw an error return service as unknown as AttachmentServiceMock; }; export const createLicensingServiceMock = (): LicensingServiceMock => { - const service: PublicMethodsOf = { + const service: PublicMethodsOf = lazyObject({ notifyUsage: jest.fn(), getLicenseInformation: jest.fn(), isAtLeast: jest.fn(), isAtLeastPlatinum: jest.fn().mockReturnValue(true), isAtLeastGold: jest.fn(), isAtLeastEnterprise: jest.fn(), - }; + }); // the cast here is required because jest.Mocked tries to include private members and would throw an error return service as unknown as LicensingServiceMock; }; export const createNotificationServiceMock = (): NotificationServiceMock => { - const service: PublicMethodsOf = { + const service: PublicMethodsOf = lazyObject({ notifyAssignees: jest.fn(), bulkNotifyAssignees: jest.fn(), - }; + }); // the cast here is required because jest.Mocked tries to include private members and would throw an error return service as unknown as NotificationServiceMock; diff --git a/x-pack/platform/plugins/shared/cases/tsconfig.json b/x-pack/platform/plugins/shared/cases/tsconfig.json index 69fc00d3c048d..7f8835bfa17d5 100644 --- a/x-pack/platform/plugins/shared/cases/tsconfig.json +++ b/x-pack/platform/plugins/shared/cases/tsconfig.json @@ -98,7 +98,8 @@ "@kbn/inference-common", "@kbn/inference-plugin", "@kbn/licensing-types", - "@kbn/cases-ai" + "@kbn/cases-ai", + "@kbn/lazy-object" ], "exclude": ["target/**/*"] } diff --git a/x-pack/platform/plugins/shared/features/server/mocks.ts b/x-pack/platform/plugins/shared/features/server/mocks.ts index 2ed232085a615..65ea793bf6e77 100644 --- a/x-pack/platform/plugins/shared/features/server/mocks.ts +++ b/x-pack/platform/plugins/shared/features/server/mocks.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { lazyObject } from '@kbn/lazy-object'; import type { FeaturesPluginSetup, FeaturesPluginStart } from './plugin'; import { featurePrivilegeIterator, @@ -12,7 +13,7 @@ import { } from './feature_privilege_iterator'; const createSetup = (): jest.Mocked => { - return { + return lazyObject({ getKibanaFeatures: jest.fn(), getElasticsearchFeatures: jest.fn(), registerKibanaFeature: jest.fn(), @@ -20,14 +21,14 @@ const createSetup = (): jest.Mocked => { enableReportingUiCapabilities: jest.fn(), featurePrivilegeIterator: jest.fn().mockImplementation(featurePrivilegeIterator), subFeaturePrivilegeIterator: jest.fn().mockImplementation(subFeaturePrivilegeIterator), - }; + }); }; const createStart = (): jest.Mocked => { - return { + return lazyObject({ getKibanaFeatures: jest.fn().mockReturnValue([]), getElasticsearchFeatures: jest.fn().mockReturnValue([]), - }; + }); }; export const featuresPluginMock = { diff --git a/x-pack/platform/plugins/shared/features/tsconfig.json b/x-pack/platform/plugins/shared/features/tsconfig.json index def816908deb0..bd26d56f97c93 100644 --- a/x-pack/platform/plugins/shared/features/tsconfig.json +++ b/x-pack/platform/plugins/shared/features/tsconfig.json @@ -16,6 +16,7 @@ "@kbn/config-schema", "@kbn/i18n", "@kbn/licensing-types", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/x-pack/platform/plugins/shared/licensing/public/mocks.ts b/x-pack/platform/plugins/shared/licensing/public/mocks.ts index 119c4d0f7a59a..85b852e71f7f0 100644 --- a/x-pack/platform/plugins/shared/licensing/public/mocks.ts +++ b/x-pack/platform/plugins/shared/licensing/public/mocks.ts @@ -6,31 +6,30 @@ */ import { BehaviorSubject } from 'rxjs'; +import { lazyObject } from '@kbn/lazy-object'; import type { LicensingPluginSetup, LicensingPluginStart } from './types'; import { licenseMock } from '../common/licensing.mock'; import { featureUsageMock } from './services/feature_usage_service.mock'; const createSetupMock = () => { const license = licenseMock.createLicense(); - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ license$: new BehaviorSubject(license), - refresh: jest.fn(), + refresh: jest.fn().mockResolvedValue(license), featureUsage: featureUsageMock.createSetup(), - }; - mock.refresh.mockResolvedValue(license); + }); return mock; }; const createStartMock = () => { const license = licenseMock.createLicense(); - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ license$: new BehaviorSubject(license), getLicense: jest.fn(), - refresh: jest.fn(), + refresh: jest.fn().mockResolvedValue(license), featureUsage: featureUsageMock.createStart(), - }; - mock.refresh.mockResolvedValue(license); + }); return mock; }; diff --git a/x-pack/platform/plugins/shared/licensing/server/mocks.ts b/x-pack/platform/plugins/shared/licensing/server/mocks.ts index 6a51eb7077f7e..ce77c1bb037bc 100644 --- a/x-pack/platform/plugins/shared/licensing/server/mocks.ts +++ b/x-pack/platform/plugins/shared/licensing/server/mocks.ts @@ -6,6 +6,7 @@ */ import { BehaviorSubject } from 'rxjs'; +import { lazyObject } from '@kbn/lazy-object'; import type { LicensingPluginSetup, LicensingPluginStart, @@ -16,30 +17,31 @@ import { featureUsageMock } from './services/feature_usage_service.mock'; const createSetupMock = (): jest.Mocked => { const license = licenseMock.createLicense(); - const mock = { + const mock = lazyObject({ license$: new BehaviorSubject(license), - refresh: jest.fn(), + refresh: jest.fn().mockResolvedValue(license), featureUsage: featureUsageMock.createSetup(), - }; - mock.refresh.mockResolvedValue(license); + }); return mock; }; const createStartMock = (): jest.Mocked => { const license = licenseMock.createLicense(); - const mock = { - license$: new BehaviorSubject(license), + + const license$ = new BehaviorSubject(license); + + const refresh = jest.fn().mockResolvedValue(license); + + const mock = lazyObject({ + license$, getLicense: jest.fn(), - refresh: jest.fn(), - createLicensePoller: jest.fn(), + refresh, + createLicensePoller: jest.fn().mockReturnValue({ + license$, + refresh, + }), featureUsage: featureUsageMock.createStart(), - }; - - mock.refresh.mockResolvedValue(license); - mock.createLicensePoller.mockReturnValue({ - license$: mock.license$, - refresh: mock.refresh, }); return mock; @@ -48,10 +50,10 @@ const createStartMock = (): jest.Mocked => { const createRequestHandlerContextMock = ( ...options: Parameters ): jest.Mocked => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ license: licenseMock.createLicense(...options), featureUsage: featureUsageMock.createStart(), - }; + }); return mock; }; diff --git a/x-pack/platform/plugins/shared/licensing/tsconfig.json b/x-pack/platform/plugins/shared/licensing/tsconfig.json index bc682e6a6b249..392c08b1ca4c7 100644 --- a/x-pack/platform/plugins/shared/licensing/tsconfig.json +++ b/x-pack/platform/plugins/shared/licensing/tsconfig.json @@ -15,6 +15,7 @@ "@kbn/logging-mocks", "@kbn/react-kibana-mount", "@kbn/licensing-types", + "@kbn/lazy-object", ], "exclude": ["target/**/*"] } diff --git a/x-pack/platform/plugins/shared/notifications/server/mocks.ts b/x-pack/platform/plugins/shared/notifications/server/mocks.ts index 037a3f2d9baf5..9d18d1c8045ba 100644 --- a/x-pack/platform/plugins/shared/notifications/server/mocks.ts +++ b/x-pack/platform/plugins/shared/notifications/server/mocks.ts @@ -6,34 +6,35 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; +import { lazyObject } from '@kbn/lazy-object'; import type { EmailService } from './services'; import type { NotificationsServerStart } from './types'; import type { NotificationsPlugin } from './plugin'; -const emailServiceMock: jest.Mocked = { +const emailServiceMock: jest.Mocked = lazyObject({ sendPlainTextEmail: jest.fn(), sendHTMLEmail: jest.fn(), sendAttachmentEmail: jest.fn(), -}; +}); const createEmailServiceMock = () => { return emailServiceMock; }; -const startMock: jest.Mocked = { +const startMock: jest.Mocked = lazyObject({ isEmailServiceAvailable: jest.fn(), getEmailService: jest.fn(createEmailServiceMock), -}; +}); const createStartMock = () => { return startMock; }; -const notificationsPluginMock: jest.Mocked> = { +const notificationsPluginMock: jest.Mocked> = lazyObject({ setup: jest.fn(), start: jest.fn(createStartMock) as jest.Mock, stop: jest.fn(), -}; +}); const createNotificationsPluginMock = () => { return notificationsPluginMock; diff --git a/x-pack/platform/plugins/shared/notifications/tsconfig.json b/x-pack/platform/plugins/shared/notifications/tsconfig.json index 85acbd68abadc..05c7fb1cc6e86 100644 --- a/x-pack/platform/plugins/shared/notifications/tsconfig.json +++ b/x-pack/platform/plugins/shared/notifications/tsconfig.json @@ -19,6 +19,7 @@ "@kbn/logging", "@kbn/logging-mocks", "@kbn/licensing-types", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/x-pack/platform/plugins/shared/security/public/authentication/index.mock.ts b/x-pack/platform/plugins/shared/security/public/authentication/index.mock.ts index f30d47af3f701..75af4e3f1b52c 100644 --- a/x-pack/platform/plugins/shared/security/public/authentication/index.mock.ts +++ b/x-pack/platform/plugins/shared/security/public/authentication/index.mock.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { lazyObject } from '@kbn/lazy-object'; import type { AuthenticationServiceSetup, AuthenticationServiceStart, @@ -13,41 +14,45 @@ import type { } from '@kbn/security-plugin-types-public'; export const authenticationMock = { - createSetup: (): jest.Mocked => ({ - getCurrentUser: jest.fn(), - areAPIKeysEnabled: jest.fn(), - }), - createStart: (): jest.Mocked => ({ - getCurrentUser: jest.fn(), - areAPIKeysEnabled: jest.fn(), - }), + createSetup: (): jest.Mocked => + lazyObject({ + getCurrentUser: jest.fn(), + areAPIKeysEnabled: jest.fn(), + }), + createStart: (): jest.Mocked => + lazyObject({ + getCurrentUser: jest.fn(), + areAPIKeysEnabled: jest.fn(), + }), }; export const authorizationMock = { - createSetup: (): jest.Mocked => ({ - isRoleManagementEnabled: jest.fn(), - roles: { - getRoles: jest.fn(), - getRole: jest.fn(), - deleteRole: jest.fn(), - saveRole: jest.fn(), - bulkUpdateRoles: jest.fn(), - }, - privileges: { - getAll: jest.fn(), - }, - }), - createStart: (): jest.Mocked => ({ - isRoleManagementEnabled: jest.fn(), - roles: { - getRoles: jest.fn(), - getRole: jest.fn(), - deleteRole: jest.fn(), - saveRole: jest.fn(), - bulkUpdateRoles: jest.fn(), - }, - privileges: { - getAll: jest.fn(), - }, - }), + createSetup: (): jest.Mocked => + lazyObject({ + isRoleManagementEnabled: jest.fn(), + roles: lazyObject({ + getRoles: jest.fn(), + getRole: jest.fn(), + deleteRole: jest.fn(), + saveRole: jest.fn(), + bulkUpdateRoles: jest.fn(), + }), + privileges: lazyObject({ + getAll: jest.fn(), + }), + }), + createStart: (): jest.Mocked => + lazyObject({ + isRoleManagementEnabled: jest.fn(), + roles: lazyObject({ + getRoles: jest.fn(), + getRole: jest.fn(), + deleteRole: jest.fn(), + saveRole: jest.fn(), + bulkUpdateRoles: jest.fn(), + }), + privileges: lazyObject({ + getAll: jest.fn(), + }), + }), }; diff --git a/x-pack/platform/plugins/shared/security/public/mocks.ts b/x-pack/platform/plugins/shared/security/public/mocks.ts index d2700afc1c12d..c67f02cb5ecdd 100644 --- a/x-pack/platform/plugins/shared/security/public/mocks.ts +++ b/x-pack/platform/plugins/shared/security/public/mocks.ts @@ -8,6 +8,7 @@ import { of } from 'rxjs'; import { securityServiceMock } from '@kbn/core-security-server-mocks'; +import { lazyObject } from '@kbn/lazy-object'; import { authenticationMock, authorizationMock } from './authentication/index.mock'; import { navControlServiceMock } from './nav_control/index.mock'; @@ -15,18 +16,18 @@ import { getUiApiMock } from './ui_api/index.mock'; import { licenseMock } from '../common/licensing/index.mock'; function createSetupMock() { - return { + return lazyObject({ authc: authenticationMock.createSetup(), authz: authorizationMock.createStart(), license: licenseMock.create(), - }; + }); } function createStartMock() { - return { + return lazyObject({ authc: authenticationMock.createStart(), authz: authorizationMock.createStart(), navControlService: navControlServiceMock.createStart(), - userProfiles: { + userProfiles: lazyObject({ getCurrent: jest.fn(), bulkGet: jest.fn(), suggest: jest.fn(), @@ -35,9 +36,9 @@ function createStartMock() { userProfile$: of({}), userProfileLoaded$: of(true), enabled$: of(true), - }, + }), uiApi: getUiApiMock.createStart(), - }; + }); } export const securityMock = { diff --git a/x-pack/platform/plugins/shared/security/server/audit/mocks.ts b/x-pack/platform/plugins/shared/security/server/audit/mocks.ts index c0c2d539bc797..b3cbe2c02d0cc 100644 --- a/x-pack/platform/plugins/shared/security/server/audit/mocks.ts +++ b/x-pack/platform/plugins/shared/security/server/audit/mocks.ts @@ -5,26 +5,26 @@ * 2.0. */ +import { lazyObject } from '@kbn/lazy-object'; import type { AuditLogger } from '@kbn/security-plugin-types-server'; import type { AuditService } from './audit_service'; export const auditLoggerMock = { create() { - return { + return lazyObject({ log: jest.fn(), enabled: true, includeSavedObjectNames: false, - } as jest.Mocked; + }) as jest.Mocked; }, }; export const auditServiceMock = { create() { - return { - getLogger: jest.fn(), + return lazyObject({ asScoped: jest.fn().mockReturnValue(auditLoggerMock.create()), withoutRequest: auditLoggerMock.create(), - } as jest.Mocked>; + }) as jest.Mocked>; }, }; diff --git a/x-pack/platform/plugins/shared/security/server/mocks.ts b/x-pack/platform/plugins/shared/security/server/mocks.ts index e47faeba525a0..6316bf071ea9e 100644 --- a/x-pack/platform/plugins/shared/security/server/mocks.ts +++ b/x-pack/platform/plugins/shared/security/server/mocks.ts @@ -7,11 +7,13 @@ import type { TransportResult } from '@elastic/elasticsearch'; -import { apiKeysMock, securityServiceMock } from '@kbn/core-security-server-mocks'; +import { securityServiceMock } from '@kbn/core-security-server-mocks'; +import { lazyObject } from '@kbn/lazy-object'; import { auditServiceMock } from './audit/mocks'; import { authenticationServiceMock } from './authentication/authentication_service.mock'; import { authorizationMock } from './authorization/index.mock'; +import type { SecurityPluginSetup } from './plugin'; import { userProfileServiceMock } from './user_profile/user_profile_service.mock'; import { licenseMock } from '../common/licensing/index.mock'; @@ -19,48 +21,45 @@ function createSetupMock() { const mockAuthz = authorizationMock.create(); return { audit: auditServiceMock.create(), - authc: { + authc: lazyObject({ getCurrentUser: jest.fn(), - apiKeys: apiKeysMock.create(), - }, - authz: { + }), + authz: lazyObject({ actions: mockAuthz.actions, checkPrivilegesWithRequest: mockAuthz.checkPrivilegesWithRequest, checkPrivilegesDynamicallyWithRequest: mockAuthz.checkPrivilegesDynamicallyWithRequest, checkSavedObjectsPrivilegesWithRequest: mockAuthz.checkSavedObjectsPrivilegesWithRequest, mode: mockAuthz.mode, - }, - registerSpacesService: jest.fn(), + }), license: licenseMock.create(), - privilegeDeprecationsService: { + privilegeDeprecationsService: lazyObject({ getKibanaRolesByFeatureId: jest.fn(), - }, - setIsElasticCloudDeployment: jest.fn(), - }; + }), + } satisfies jest.Mocked; } function createStartMock() { const mockAuthz = authorizationMock.create(); const mockAuthc = authenticationServiceMock.createStart(); const mockUserProfiles = userProfileServiceMock.createStart(); - return { - authc: { + return lazyObject({ + authc: lazyObject({ apiKeys: mockAuthc.apiKeys, getCurrentUser: mockAuthc.getCurrentUser, - }, - authz: { + }), + authz: lazyObject({ actions: mockAuthz.actions, checkPrivilegesWithRequest: mockAuthz.checkPrivilegesWithRequest, checkPrivilegesDynamicallyWithRequest: mockAuthz.checkPrivilegesDynamicallyWithRequest, checkSavedObjectsPrivilegesWithRequest: mockAuthz.checkSavedObjectsPrivilegesWithRequest, mode: mockAuthz.mode, - }, - userProfiles: { + }), + userProfiles: lazyObject({ getCurrent: mockUserProfiles.getCurrent, suggest: mockUserProfiles.suggest, bulkGet: mockUserProfiles.bulkGet, - }, - }; + }), + }); } function createApiResponseMock( diff --git a/x-pack/platform/plugins/shared/security/tsconfig.json b/x-pack/platform/plugins/shared/security/tsconfig.json index 712dccf6781e0..70785de4f4f00 100644 --- a/x-pack/platform/plugins/shared/security/tsconfig.json +++ b/x-pack/platform/plugins/shared/security/tsconfig.json @@ -95,6 +95,7 @@ "@kbn/react-kibana-context-theme", "@kbn/css-utils", "@kbn/licensing-types", + "@kbn/lazy-object", ], "exclude": [ "target/**/*", diff --git a/x-pack/platform/plugins/shared/task_manager/server/mocks.ts b/x-pack/platform/plugins/shared/task_manager/server/mocks.ts index 4ae21f255d07d..e25873ab04ad7 100644 --- a/x-pack/platform/plugins/shared/task_manager/server/mocks.ts +++ b/x-pack/platform/plugins/shared/task_manager/server/mocks.ts @@ -6,22 +6,24 @@ */ import { v4 as uuidv4 } from 'uuid'; +import { lazyObject } from '@kbn/lazy-object'; import type { TaskManagerSetupContract, TaskManagerStartContract } from './plugin'; import type { ConcreteTaskInstance } from './task'; import { TaskStatus } from './task'; const createSetupMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ index: '.kibana_task_manager', addMiddleware: jest.fn(), registerTaskDefinitions: jest.fn(), registerCanEncryptedSavedObjects: jest.fn(), - }; + }); + return mock; }; const createStartMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = lazyObject({ fetch: jest.fn(), get: jest.fn(), bulkGet: jest.fn(), @@ -39,7 +41,8 @@ const createStartMock = () => { getRegisteredTypes: jest.fn(), bulkUpdateState: jest.fn(), registerEncryptedSavedObjectsClient: jest.fn(), - }; + }); + return mock; }; diff --git a/x-pack/platform/plugins/shared/task_manager/tsconfig.json b/x-pack/platform/plugins/shared/task_manager/tsconfig.json index ee12bcf4001f2..9280646028ef7 100644 --- a/x-pack/platform/plugins/shared/task_manager/tsconfig.json +++ b/x-pack/platform/plugins/shared/task_manager/tsconfig.json @@ -39,6 +39,7 @@ "@kbn/logging-mocks", "@kbn/spaces-utils", "@kbn/licensing-types", + "@kbn/lazy-object", ], "exclude": ["target/**/*"] } diff --git a/x-pack/solutions/observability/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/solutions/observability/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index dcb7fc2c8fd21..8c8b004882ab4 100644 --- a/x-pack/solutions/observability/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/solutions/observability/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -116,7 +116,7 @@ describe('The metric threshold rule type', () => { jest.setSystemTime(); }); beforeEach(() => { - jest.resetAllMocks(); + jest.clearAllMocks(); mockAssetDetailsLocator.getRedirectUrl.mockImplementation( ({ entityId, entityType, assetDetails }: AssetDetailsLocatorParams) => diff --git a/yarn.lock b/yarn.lock index ab9a1daa94991..a0e603eb0f076 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6504,6 +6504,10 @@ version "0.0.0" uid "" +"@kbn/lazy-object@link:src/platform/packages/shared/kbn-lazy-object": + version "0.0.0" + uid "" + "@kbn/lens-config-builder-example-plugin@link:x-pack/examples/lens_config_builder_example": version "0.0.0" uid "" From 8b74b3d183b77c773e57218c04cd675f95697f88 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Sat, 13 Sep 2025 09:13:49 +0200 Subject: [PATCH 2/2] [Jest] Lazy ES mock --- .../client-server-mocks/src/mocks.ts | 208 +++++++++++++----- 1 file changed, 158 insertions(+), 50 deletions(-) diff --git a/src/core/packages/elasticsearch/client-server-mocks/src/mocks.ts b/src/core/packages/elasticsearch/client-server-mocks/src/mocks.ts index 587c93396c09b..2197e129ae427 100644 --- a/src/core/packages/elasticsearch/client-server-mocks/src/mocks.ts +++ b/src/core/packages/elasticsearch/client-server-mocks/src/mocks.ts @@ -14,12 +14,10 @@ import { PRODUCT_RESPONSE_HEADER } from '@kbn/core-elasticsearch-client-server-i import { lazyObject } from '@kbn/lazy-object'; const omittedProps = [ - 'diagnostic', 'name', 'connectionPool', 'transport', 'serializer', - 'helpers', 'acceptedParams', ] as Array>; @@ -57,6 +55,7 @@ export interface ClientApiMockInstance extends jest.MockInst ): this; } +// Helper to create a jest mock function with response helpers const createMockedApi = < T = unknown, Y extends [any, TransportRequestOptions] = [any, TransportRequestOptions] @@ -122,67 +121,176 @@ const createMockedApi = < return mock; }; +// Build a shape of the Elasticsearch client once, using a hoisted real client instance // use jest.requireActual() to prevent weird errors when people mock @elastic/elasticsearch const { Client: UnmockedClient } = jest.requireActual('@elastic/elasticsearch'); -const createInternalClientMock = (res?: Promise): DeeplyMockedApi => { - // we mimic 'reflection' on a concrete instance of the client to generate the mocked functions. - const client = new UnmockedClient({ - node: 'http://127.0.0.1', - }); - const getAllPropertyDescriptors = (obj: Record) => { - const descriptors = Object.entries(Object.getOwnPropertyDescriptors(obj)); - let prototype = Object.getPrototypeOf(obj); - while (prototype != null && prototype !== Object.prototype) { - descriptors.push(...Object.entries(Object.getOwnPropertyDescriptors(prototype))); - prototype = Object.getPrototypeOf(prototype); +type ShapeNode = { type: 'method' } | { type: 'object'; props: Record }; + +let cachedShape: ShapeNode | null = null; + +function getAllPropertyDescriptors(obj: Record) { + const map: Record = {}; + let cur: any = obj; + while (cur && cur !== Object.prototype) { + const descs = Object.getOwnPropertyDescriptors(cur); + for (const [k, d] of Object.entries(descs)) { + if (!(k in map)) map[k] = d; } - return descriptors; - }; + cur = Object.getPrototypeOf(cur); + } + return map; +} - const mockify = (obj: Record, omitted: string[] = []) => { - // the @elastic/elasticsearch::Client uses prototypical inheritance - // so we have to crawl up the prototype chain and get all descriptors - // to find everything that we should be mocking - const descriptors = getAllPropertyDescriptors(obj); - descriptors - .filter(([key]) => !omitted.includes(key)) - .forEach(([key, descriptor]) => { - if (typeof descriptor.value === 'function') { - const mock = createMockedApi(); - mock.mockImplementation(() => res ?? createSuccessTransportRequestPromise({})); - obj[key] = mock; - } else if (typeof obj[key] === 'object' && obj[key] != null) { - mockify(obj[key], omitted); - } - }); - }; +function buildShapeRecursive(obj: any, isTopLevel: boolean, seen: WeakSet): ShapeNode { + const props: Record = {}; + const descriptors = getAllPropertyDescriptors(obj); + for (const [key, desc] of Object.entries(descriptors)) { + if (key === 'constructor') continue; + if (isTopLevel && (omittedProps as string[]).includes(key)) continue; + + let value: any; + if ('value' in desc) value = (desc as any).value; + else if (typeof desc.get === 'function') { + try { + value = desc.get.call(obj); + } catch { + value = undefined; + } + } - mockify(client, omittedProps as string[]); + if (typeof value === 'function') { + props[key] = { type: 'method' }; + } else if (value && typeof value === 'object') { + if (seen.has(value)) continue; + seen.add(value); + props[key] = buildShapeRecursive(value, false, seen); + } + } + return { type: 'object', props }; +} + +function getClientShape(): ShapeNode { + if (cachedShape) return cachedShape; + const client = new UnmockedClient({ node: 'http://127.0.0.1' }); + try { + const shape = buildShapeRecursive(client, true, new WeakSet()); + cachedShape = shape; + return shape; + } finally { + try { + // ensure we close the actual client instance (ignore errors) + void client.close(); + } catch { + // ignore + } + } +} - client.close = jest.fn().mockReturnValue(Promise.resolve()); - client.child = jest.fn().mockImplementation(() => createInternalClientMock()); +function buildLazyMockFromShape(shape: ShapeNode, res?: Promise): any { + if (shape.type !== 'object') return {}; + const target: Record = {}; - const mockGetter = (obj: Record, propertyName: string) => { - Object.defineProperty(obj, propertyName, { + const defineLazyMethod = (obj: Record, key: string) => { + Object.defineProperty(obj, key, { configurable: true, - enumerable: false, - get: () => jest.fn(), - set: undefined, + enumerable: true, + get() { + const fn = createMockedApi(); + fn.mockImplementation(() => res ?? createSuccessTransportRequestPromise({})); + Object.defineProperty(obj, key, { + value: fn, + configurable: true, + enumerable: true, + writable: true, + }); + return fn; + }, + set(value) { + Object.defineProperty(obj, key, { + value, + configurable: true, + enumerable: true, + writable: true, + }); + }, }); }; - // `on`, `off`, and `once` are properties without a setter. - // We can't `client.diagnostic.on = jest.fn()` because the following error will be thrown: - // TypeError: Cannot set property on of # which has only a getter - mockGetter(client.diagnostic, 'on'); - mockGetter(client.diagnostic, 'off'); - mockGetter(client.diagnostic, 'once'); - client.transport = { - request: jest.fn(), + const defineLazyObject = (obj: Record, key: string, childShape: ShapeNode) => { + Object.defineProperty(obj, key, { + configurable: true, + enumerable: true, + get() { + const child = buildLazyMockFromShape(childShape, res); + Object.defineProperty(obj, key, { + value: child, + configurable: true, + enumerable: true, + writable: true, + }); + return child; + }, + }); }; - return client as DeeplyMockedApi; + for (const [key, node] of Object.entries(shape.props)) { + if (node.type === 'method') { + defineLazyMethod(target, key); + } else if (node.type === 'object') { + defineLazyObject(target, key, node); + } + } + + // Special cases based on prior behavior + Object.defineProperty(target, 'diagnostic', { + configurable: true, + enumerable: false, + get() { + const d: any = {}; + for (const k of ['on', 'off', 'once']) { + Object.defineProperty(d, k, { + configurable: true, + enumerable: false, + get: () => jest.fn(), + }); + } + Object.defineProperty(target, 'diagnostic', { + value: d, + configurable: true, + enumerable: false, + writable: true, + }); + return d; + }, + }); + + Object.defineProperty(target, 'transport', { + configurable: true, + enumerable: true, + get() { + const t = { request: jest.fn() } as any; + Object.defineProperty(target, 'transport', { + value: t, + configurable: true, + enumerable: true, + writable: true, + }); + return t; + }, + }); + + return target; +} + +const createInternalClientMock = (res?: Promise): DeeplyMockedApi => { + const shape = getClientShape(); + const mockClient: any = buildLazyMockFromShape(shape, res); + + mockClient.close = jest.fn().mockReturnValue(Promise.resolve()); + mockClient.child = jest.fn().mockImplementation(() => createInternalClientMock()); + + return mockClient as DeeplyMockedApi; }; export type ElasticsearchClientMock = DeeplyMockedApi; @@ -226,7 +334,7 @@ const createCustomClusterClientMock = () => { const mock: CustomClusterClientMock = lazyObject({ asInternalUser: createClientMock(), asScoped: jest.fn().mockReturnValue(createScopedClusterClientMock()), - close: jest.fn().mockResolvedValue(Promise.resolve()), + close: jest.fn().mockReturnValue(Promise.resolve()), }); return mock;