@backstage/frontend-test-utils 0.5.1-next.1 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/dist/apis/AlertApi/MockAlertApi.esm.js.map +1 -1
- package/dist/apis/AnalyticsApi/MockAnalyticsApi.esm.js.map +1 -1
- package/dist/apis/ConfigApi/MockConfigApi.esm.js.map +1 -1
- package/dist/apis/ErrorApi/MockErrorApi.esm.js.map +1 -1
- package/dist/apis/FeatureFlagsApi/MockFeatureFlagsApi.esm.js.map +1 -1
- package/dist/apis/FetchApi/MockFetchApi.esm.js.map +1 -1
- package/dist/apis/PermissionApi/MockPermissionApi.esm.js.map +1 -1
- package/dist/apis/StorageApi/MockStorageApi.esm.js.map +1 -1
- package/dist/apis/TranslationApi/MockTranslationApi.esm.js.map +1 -1
- package/dist/apis/mockApis.esm.js.map +1 -1
- package/dist/app/renderInTestApp.esm.js +3 -3
- package/dist/app/renderInTestApp.esm.js.map +1 -1
- package/dist/app/renderTestApp.esm.js +3 -3
- package/dist/app/renderTestApp.esm.js.map +1 -1
- package/dist/frontend-app-api/src/tree/instantiateAppNodeTree.esm.js +72 -15
- package/dist/frontend-app-api/src/tree/instantiateAppNodeTree.esm.js.map +1 -1
- package/dist/frontend-app-api/src/tree/resolveAppNodeSpecs.esm.js +50 -9
- package/dist/frontend-app-api/src/tree/resolveAppNodeSpecs.esm.js.map +1 -1
- package/dist/frontend-app-api/src/wiring/createErrorCollector.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/InternalExtensionDefinition.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/InternalFrontendPlugin.esm.js.map +1 -1
- package/dist/frontend-plugin-api/src/wiring/createFrontendModule.esm.js.map +1 -1
- package/dist/frontend-plugin-api/src/wiring/resolveExtensionDefinition.esm.js.map +1 -1
- package/dist/index.d.ts +35 -14
- package/package.json +16 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @backstage/frontend-test-utils
|
|
2
2
|
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b56f573: Deprecated standalone mock API exports in favor of the `mockApis` namespace. This includes the mock classes (`MockAlertApi`, `MockAnalyticsApi`, `MockConfigApi`, `MockErrorApi`, `MockFetchApi`, `MockFeatureFlagsApi`, `MockPermissionApi`, `MockStorageApi`, `MockTranslationApi`), their option types (`MockErrorApiOptions`, `MockFeatureFlagsApiOptions`), and the `ErrorWithContext` type. `MockFetchApiOptions` is kept as a non-deprecated export. Use the `mockApis` namespace instead, for example `mockApis.alert()` or `mockApis.alert.mock()`.
|
|
8
|
+
- 479282f: Fixed type inference of `TestApiPair` when using tuple syntax by wrapping `MockWithApiFactory` in `NoInfer`.
|
|
9
|
+
- 8e09233: Added a missing dependency on `@backstage/filter-predicates` to `@backstage/frontend-test-utils`. This fixes package metadata for consumers using the frontend test app helpers with predicate-based behavior.
|
|
10
|
+
- a49a40d: Updated dependency `zod` to `^3.25.76 || ^4.0.0` & migrated to `/v3` or `/v4` imports.
|
|
11
|
+
- 909c742: Switched `MockTranslationApi` and related test utility imports from `@backstage/core-plugin-api/alpha` to the stable `@backstage/frontend-plugin-api` export. The `TranslationApi` type in the API report is now sourced from a single package. This has no effect on runtime behavior.
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
- @backstage/frontend-app-api@0.16.0
|
|
14
|
+
- @backstage/core-plugin-api@1.12.4
|
|
15
|
+
- @backstage/frontend-plugin-api@0.15.0
|
|
16
|
+
- @backstage/core-app-api@1.19.6
|
|
17
|
+
- @backstage/plugin-app@0.4.1
|
|
18
|
+
- @backstage/plugin-app-react@0.2.1
|
|
19
|
+
- @backstage/plugin-permission-react@0.4.41
|
|
20
|
+
- @backstage/filter-predicates@0.1.1
|
|
21
|
+
- @backstage/plugin-permission-common@0.9.7
|
|
22
|
+
- @backstage/test-utils@1.7.16
|
|
23
|
+
|
|
24
|
+
## 0.5.1-next.2
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- b56f573: Deprecated standalone mock API exports in favor of the `mockApis` namespace. This includes the mock classes (`MockAlertApi`, `MockAnalyticsApi`, `MockConfigApi`, `MockErrorApi`, `MockFetchApi`, `MockFeatureFlagsApi`, `MockPermissionApi`, `MockStorageApi`, `MockTranslationApi`), their option types (`MockErrorApiOptions`, `MockFeatureFlagsApiOptions`), and the `ErrorWithContext` type. `MockFetchApiOptions` is kept as a non-deprecated export. Use the `mockApis` namespace instead, for example `mockApis.alert()` or `mockApis.alert.mock()`.
|
|
29
|
+
- Updated dependencies
|
|
30
|
+
- @backstage/core-app-api@1.19.6-next.1
|
|
31
|
+
- @backstage/frontend-plugin-api@0.15.0-next.1
|
|
32
|
+
- @backstage/core-plugin-api@1.12.4-next.1
|
|
33
|
+
- @backstage/frontend-app-api@0.16.0-next.1
|
|
34
|
+
- @backstage/plugin-app-react@0.2.1-next.1
|
|
35
|
+
- @backstage/plugin-app@0.4.1-next.2
|
|
36
|
+
|
|
3
37
|
## 0.5.1-next.1
|
|
4
38
|
|
|
5
39
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MockAlertApi.esm.js","sources":["../../../src/apis/AlertApi/MockAlertApi.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AlertMessage } from '@backstage/frontend-plugin-api';\nimport { AlertApi } from '@backstage/frontend-plugin-api';\nimport { Observable } from '@backstage/types';\nimport ObservableImpl from 'zen-observable';\n\n/**\n * Mock implementation of {@link @backstage/frontend-plugin-api#AlertApi} for testing alert behavior.\n *\n * @public\n * @example\n * ```ts\n * const alertApi =
|
|
1
|
+
{"version":3,"file":"MockAlertApi.esm.js","sources":["../../../src/apis/AlertApi/MockAlertApi.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AlertMessage } from '@backstage/frontend-plugin-api';\nimport { AlertApi } from '@backstage/frontend-plugin-api';\nimport { Observable } from '@backstage/types';\nimport ObservableImpl from 'zen-observable';\n\n/**\n * Mock implementation of {@link @backstage/frontend-plugin-api#AlertApi} for testing alert behavior.\n *\n * @public\n * @deprecated Use `mockApis.alert()` instead.\n * @example\n * ```ts\n * const alertApi = mockApis.alert();\n * alertApi.post({ message: 'Test alert' });\n * expect(alertApi.getAlerts()).toHaveLength(1);\n * ```\n */\nexport class MockAlertApi implements AlertApi {\n private readonly alerts: AlertMessage[] = [];\n private readonly observers = new Set<(alert: AlertMessage) => void>();\n\n post(alert: AlertMessage) {\n this.alerts.push(alert);\n this.observers.forEach(observer => observer(alert));\n }\n\n alert$(): Observable<AlertMessage> {\n return new ObservableImpl(subscriber => {\n const observer = (alert: AlertMessage) => {\n subscriber.next(alert);\n };\n this.observers.add(observer);\n return () => {\n this.observers.delete(observer);\n };\n });\n }\n\n /**\n * Get all alerts that have been posted.\n */\n getAlerts(): AlertMessage[] {\n return this.alerts;\n }\n\n /**\n * Clear all collected alerts.\n */\n clearAlerts(): void {\n this.alerts.length = 0;\n }\n\n /**\n * Wait for an alert matching the given predicate.\n *\n * @param predicate - Function to test each alert\n * @param timeoutMs - Maximum time to wait in milliseconds\n * @returns Promise that resolves with the matching alert\n */\n async waitForAlert(\n predicate: (alert: AlertMessage) => boolean,\n timeoutMs: number = 2000,\n ): Promise<AlertMessage> {\n const existing = this.alerts.find(predicate);\n if (existing) {\n return existing;\n }\n const observers = this.observers;\n\n return new Promise<AlertMessage>((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n observers.delete(observer);\n reject(new Error('Timed out waiting for alert'));\n }, timeoutMs);\n\n function observer(alert: AlertMessage) {\n if (predicate(alert)) {\n clearTimeout(timeoutId);\n observers.delete(observer);\n resolve(alert);\n }\n }\n\n observers.add(observer);\n });\n }\n}\n"],"names":[],"mappings":";;AAiCO,MAAM,YAAA,CAAiC;AAAA,EAC3B,SAAyB,EAAC;AAAA,EAC1B,SAAA,uBAAgB,GAAA,EAAmC;AAAA,EAEpE,KAAK,KAAA,EAAqB;AACxB,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,KAAK,CAAA;AACtB,IAAA,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,CAAA,QAAA,KAAY,QAAA,CAAS,KAAK,CAAC,CAAA;AAAA,EACpD;AAAA,EAEA,MAAA,GAAmC;AACjC,IAAA,OAAO,IAAI,eAAe,CAAA,UAAA,KAAc;AACtC,MAAA,MAAM,QAAA,GAAW,CAAC,KAAA,KAAwB;AACxC,QAAA,UAAA,CAAW,KAAK,KAAK,CAAA;AAAA,MACvB,CAAA;AACA,MAAA,IAAA,CAAK,SAAA,CAAU,IAAI,QAAQ,CAAA;AAC3B,MAAA,OAAO,MAAM;AACX,QAAA,IAAA,CAAK,SAAA,CAAU,OAAO,QAAQ,CAAA;AAAA,MAChC,CAAA;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,SAAA,GAA4B;AAC1B,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,WAAA,GAAoB;AAClB,IAAA,IAAA,CAAK,OAAO,MAAA,GAAS,CAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,YAAA,CACJ,SAAA,EACA,SAAA,GAAoB,GAAA,EACG;AACvB,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA;AAC3C,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,OAAO,QAAA;AAAA,IACT;AACA,IAAA,MAAM,YAAY,IAAA,CAAK,SAAA;AAEvB,IAAA,OAAO,IAAI,OAAA,CAAsB,CAAC,OAAA,EAAS,MAAA,KAAW;AACpD,MAAA,MAAM,SAAA,GAAY,WAAW,MAAM;AACjC,QAAA,SAAA,CAAU,OAAO,QAAQ,CAAA;AACzB,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,6BAA6B,CAAC,CAAA;AAAA,MACjD,GAAG,SAAS,CAAA;AAEZ,MAAA,SAAS,SAAS,KAAA,EAAqB;AACrC,QAAA,IAAI,SAAA,CAAU,KAAK,CAAA,EAAG;AACpB,UAAA,YAAA,CAAa,SAAS,CAAA;AACtB,UAAA,SAAA,CAAU,OAAO,QAAQ,CAAA;AACzB,UAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,QACf;AAAA,MACF;AAEA,MAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AAAA,IACxB,CAAC,CAAA;AAAA,EACH;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MockAnalyticsApi.esm.js","sources":["../../../src/apis/AnalyticsApi/MockAnalyticsApi.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AnalyticsApi, AnalyticsEvent } from '@backstage/frontend-plugin-api';\n\n/**\n * Mock implementation of {@link frontend-plugin-api#AnalyticsApi} with helpers to ensure that events are sent correctly.\n * Use getEvents in tests to verify captured events.\n *\n * @public\n */\nexport class MockAnalyticsApi implements AnalyticsApi {\n private events: AnalyticsEvent[] = [];\n\n captureEvent(event: AnalyticsEvent) {\n const { action, subject, value, attributes, context } = event;\n\n this.events.push({\n action,\n subject,\n context,\n ...(value !== undefined ? { value } : {}),\n ...(attributes !== undefined ? { attributes } : {}),\n });\n }\n\n getEvents(): AnalyticsEvent[] {\n return this.events;\n }\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MockAnalyticsApi.esm.js","sources":["../../../src/apis/AnalyticsApi/MockAnalyticsApi.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AnalyticsApi, AnalyticsEvent } from '@backstage/frontend-plugin-api';\n\n/**\n * Mock implementation of {@link frontend-plugin-api#AnalyticsApi} with helpers to ensure that events are sent correctly.\n * Use getEvents in tests to verify captured events.\n *\n * @public\n * @deprecated Use `mockApis.analytics()` instead.\n */\nexport class MockAnalyticsApi implements AnalyticsApi {\n private events: AnalyticsEvent[] = [];\n\n captureEvent(event: AnalyticsEvent) {\n const { action, subject, value, attributes, context } = event;\n\n this.events.push({\n action,\n subject,\n context,\n ...(value !== undefined ? { value } : {}),\n ...(attributes !== undefined ? { attributes } : {}),\n });\n }\n\n getEvents(): AnalyticsEvent[] {\n return this.events;\n }\n}\n"],"names":[],"mappings":"AAyBO,MAAM,gBAAA,CAAyC;AAAA,EAC5C,SAA2B,EAAC;AAAA,EAEpC,aAAa,KAAA,EAAuB;AAClC,IAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,EAAS,KAAA,EAAO,UAAA,EAAY,SAAQ,GAAI,KAAA;AAExD,IAAA,IAAA,CAAK,OAAO,IAAA,CAAK;AAAA,MACf,MAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,GAAI,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,KAAU,EAAC;AAAA,MACvC,GAAI,UAAA,KAAe,MAAA,GAAY,EAAE,UAAA,KAAe;AAAC,KAClD,CAAA;AAAA,EACH;AAAA,EAEA,SAAA,GAA8B;AAC5B,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MockConfigApi.esm.js","sources":["../../../src/apis/ConfigApi/MockConfigApi.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config, ConfigReader } from '@backstage/config';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport { ConfigApi } from '@backstage/core-plugin-api';\n\n/**\n * MockConfigApi is a thin wrapper around {@link @backstage/config#ConfigReader}\n * that can be used to mock configuration using a plain object.\n *\n * @public\n * @example\n * ```tsx\n * const mockConfig =
|
|
1
|
+
{"version":3,"file":"MockConfigApi.esm.js","sources":["../../../src/apis/ConfigApi/MockConfigApi.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config, ConfigReader } from '@backstage/config';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport { ConfigApi } from '@backstage/core-plugin-api';\n\n/**\n * MockConfigApi is a thin wrapper around {@link @backstage/config#ConfigReader}\n * that can be used to mock configuration using a plain object.\n *\n * @public\n * @deprecated Use `mockApis.config()` instead.\n * @example\n * ```tsx\n * const mockConfig = mockApis.config({\n * data: { app: { baseUrl: 'https://example.com' } },\n * });\n *\n * const rendered = await renderInTestApp(\n * <TestApiProvider apis={[[configApiRef, mockConfig]]}>\n * <MyTestedComponent />\n * </TestApiProvider>,\n * );\n * ```\n */\nexport class MockConfigApi implements ConfigApi {\n private readonly config: ConfigReader;\n\n // NOTE: not extending in order to avoid inheriting the static `.fromConfigs`\n constructor({ data }: { data: JsonObject }) {\n this.config = new ConfigReader(data);\n }\n\n /** {@inheritdoc @backstage/config#Config.has} */\n has(key: string): boolean {\n return this.config.has(key);\n }\n /** {@inheritdoc @backstage/config#Config.keys} */\n keys(): string[] {\n return this.config.keys();\n }\n /** {@inheritdoc @backstage/config#Config.get} */\n get<T = JsonValue>(key?: string): T {\n return this.config.get(key);\n }\n /** {@inheritdoc @backstage/config#Config.getOptional} */\n getOptional<T = JsonValue>(key?: string): T | undefined {\n return this.config.getOptional(key);\n }\n /** {@inheritdoc @backstage/config#Config.getConfig} */\n getConfig(key: string): Config {\n return this.config.getConfig(key);\n }\n /** {@inheritdoc @backstage/config#Config.getOptionalConfig} */\n getOptionalConfig(key: string): Config | undefined {\n return this.config.getOptionalConfig(key);\n }\n /** {@inheritdoc @backstage/config#Config.getConfigArray} */\n getConfigArray(key: string): Config[] {\n return this.config.getConfigArray(key);\n }\n /** {@inheritdoc @backstage/config#Config.getOptionalConfigArray} */\n getOptionalConfigArray(key: string): Config[] | undefined {\n return this.config.getOptionalConfigArray(key);\n }\n /** {@inheritdoc @backstage/config#Config.getNumber} */\n getNumber(key: string): number {\n return this.config.getNumber(key);\n }\n /** {@inheritdoc @backstage/config#Config.getOptionalNumber} */\n getOptionalNumber(key: string): number | undefined {\n return this.config.getOptionalNumber(key);\n }\n /** {@inheritdoc @backstage/config#Config.getBoolean} */\n getBoolean(key: string): boolean {\n return this.config.getBoolean(key);\n }\n /** {@inheritdoc @backstage/config#Config.getOptionalBoolean} */\n getOptionalBoolean(key: string): boolean | undefined {\n return this.config.getOptionalBoolean(key);\n }\n /** {@inheritdoc @backstage/config#Config.getString} */\n getString(key: string): string {\n return this.config.getString(key);\n }\n /** {@inheritdoc @backstage/config#Config.getOptionalString} */\n getOptionalString(key: string): string | undefined {\n return this.config.getOptionalString(key);\n }\n /** {@inheritdoc @backstage/config#Config.getStringArray} */\n getStringArray(key: string): string[] {\n return this.config.getStringArray(key);\n }\n /** {@inheritdoc @backstage/config#Config.getOptionalStringArray} */\n getOptionalStringArray(key: string): string[] | undefined {\n return this.config.getOptionalStringArray(key);\n }\n}\n"],"names":[],"mappings":";;AAuCO,MAAM,aAAA,CAAmC;AAAA,EAC7B,MAAA;AAAA;AAAA,EAGjB,WAAA,CAAY,EAAE,IAAA,EAAK,EAAyB;AAC1C,IAAA,IAAA,CAAK,MAAA,GAAS,IAAI,YAAA,CAAa,IAAI,CAAA;AAAA,EACrC;AAAA;AAAA,EAGA,IAAI,GAAA,EAAsB;AACxB,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAAA,EAC5B;AAAA;AAAA,EAEA,IAAA,GAAiB;AACf,IAAA,OAAO,IAAA,CAAK,OAAO,IAAA,EAAK;AAAA,EAC1B;AAAA;AAAA,EAEA,IAAmB,GAAA,EAAiB;AAClC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAAA,EAC5B;AAAA;AAAA,EAEA,YAA2B,GAAA,EAA6B;AACtD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,WAAA,CAAY,GAAG,CAAA;AAAA,EACpC;AAAA;AAAA,EAEA,UAAU,GAAA,EAAqB;AAC7B,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA;AAAA,EAClC;AAAA;AAAA,EAEA,kBAAkB,GAAA,EAAiC;AACjD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,iBAAA,CAAkB,GAAG,CAAA;AAAA,EAC1C;AAAA;AAAA,EAEA,eAAe,GAAA,EAAuB;AACpC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,cAAA,CAAe,GAAG,CAAA;AAAA,EACvC;AAAA;AAAA,EAEA,uBAAuB,GAAA,EAAmC;AACxD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,sBAAA,CAAuB,GAAG,CAAA;AAAA,EAC/C;AAAA;AAAA,EAEA,UAAU,GAAA,EAAqB;AAC7B,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA;AAAA,EAClC;AAAA;AAAA,EAEA,kBAAkB,GAAA,EAAiC;AACjD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,iBAAA,CAAkB,GAAG,CAAA;AAAA,EAC1C;AAAA;AAAA,EAEA,WAAW,GAAA,EAAsB;AAC/B,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,UAAA,CAAW,GAAG,CAAA;AAAA,EACnC;AAAA;AAAA,EAEA,mBAAmB,GAAA,EAAkC;AACnD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,kBAAA,CAAmB,GAAG,CAAA;AAAA,EAC3C;AAAA;AAAA,EAEA,UAAU,GAAA,EAAqB;AAC7B,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA;AAAA,EAClC;AAAA;AAAA,EAEA,kBAAkB,GAAA,EAAiC;AACjD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,iBAAA,CAAkB,GAAG,CAAA;AAAA,EAC1C;AAAA;AAAA,EAEA,eAAe,GAAA,EAAuB;AACpC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,cAAA,CAAe,GAAG,CAAA;AAAA,EACvC;AAAA;AAAA,EAEA,uBAAuB,GAAA,EAAmC;AACxD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,sBAAA,CAAuB,GAAG,CAAA;AAAA,EAC/C;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MockErrorApi.esm.js","sources":["../../../src/apis/ErrorApi/MockErrorApi.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ErrorApi,\n ErrorApiError,\n ErrorApiErrorContext,\n} from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\n\n/**\n * Constructor arguments for {@link MockErrorApi}\n * @public\n */\nexport type MockErrorApiOptions = {\n
|
|
1
|
+
{"version":3,"file":"MockErrorApi.esm.js","sources":["../../../src/apis/ErrorApi/MockErrorApi.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ErrorApi,\n ErrorApiError,\n ErrorApiErrorContext,\n} from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\n\n/**\n * Constructor arguments for {@link MockErrorApi}\n * @public\n * @deprecated Use `mockApis.error()` instead.\n */\nexport type MockErrorApiOptions = {\n collect?: boolean;\n};\n\n/**\n * ErrorWithContext contains error and ErrorApiErrorContext\n * @public\n * @deprecated Use the return type of `MockErrorApi.getErrors` instead.\n */\nexport type ErrorWithContext = {\n error: ErrorApiError;\n context?: ErrorApiErrorContext;\n};\n\ntype Waiter = {\n pattern: RegExp;\n resolve: (err: {\n error: ErrorApiError;\n context?: ErrorApiErrorContext;\n }) => void;\n};\n\nconst nullObservable = {\n subscribe: () => ({ unsubscribe: () => {}, closed: true }),\n\n [Symbol.observable]() {\n return this;\n },\n};\n\n/**\n * Mock implementation of the {@link core-plugin-api#ErrorApi} to be used in tests.\n * Includes withForError and getErrors methods for error testing.\n * @public\n * @deprecated Use `mockApis.error()` instead.\n */\nexport class MockErrorApi implements ErrorApi {\n private readonly errors = new Array<{\n error: ErrorApiError;\n context?: ErrorApiErrorContext;\n }>();\n private readonly waiters = new Set<Waiter>();\n\n constructor(private readonly options: { collect?: boolean } = {}) {}\n\n post(error: ErrorApiError, context?: ErrorApiErrorContext) {\n if (this.options.collect) {\n this.errors.push({ error, context });\n\n for (const waiter of this.waiters) {\n if (waiter.pattern.test(error.message)) {\n this.waiters.delete(waiter);\n waiter.resolve({ error, context });\n }\n }\n\n return;\n }\n\n throw new Error(`MockErrorApi received unexpected error, ${error}`);\n }\n\n error$(): Observable<{\n error: ErrorApiError;\n context?: ErrorApiErrorContext;\n }> {\n return nullObservable;\n }\n\n getErrors(): { error: ErrorApiError; context?: ErrorApiErrorContext }[] {\n return this.errors;\n }\n\n waitForError(\n pattern: RegExp,\n timeoutMs: number = 2000,\n ): Promise<{ error: ErrorApiError; context?: ErrorApiErrorContext }> {\n return new Promise<{\n error: ErrorApiError;\n context?: ErrorApiErrorContext;\n }>((resolve, reject) => {\n setTimeout(() => {\n reject(new Error('Timed out waiting for error'));\n }, timeoutMs);\n\n this.waiters.add({ resolve, pattern });\n });\n }\n}\n"],"names":[],"mappings":"AAkDA,MAAM,cAAA,GAAiB;AAAA,EACrB,SAAA,EAAW,OAAO,EAAE,WAAA,EAAa,MAAM;AAAA,EAAC,CAAA,EAAG,QAAQ,IAAA,EAAK,CAAA;AAAA,EAExD,CAAC,MAAA,CAAO,UAAU,CAAA,GAAI;AACpB,IAAA,OAAO,IAAA;AAAA,EACT;AACF,CAAA;AAQO,MAAM,YAAA,CAAiC;AAAA,EAO5C,WAAA,CAA6B,OAAA,GAAiC,EAAC,EAAG;AAArC,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAAsC;AAAA,EANlD,MAAA,GAAS,IAAI,KAAA,EAG3B;AAAA,EACc,OAAA,uBAAc,GAAA,EAAY;AAAA,EAI3C,IAAA,CAAK,OAAsB,OAAA,EAAgC;AACzD,IAAA,IAAI,IAAA,CAAK,QAAQ,OAAA,EAAS;AACxB,MAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,EAAE,KAAA,EAAO,SAAS,CAAA;AAEnC,MAAA,KAAA,MAAW,MAAA,IAAU,KAAK,OAAA,EAAS;AACjC,QAAA,IAAI,MAAA,CAAO,OAAA,CAAQ,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA,EAAG;AACtC,UAAA,IAAA,CAAK,OAAA,CAAQ,OAAO,MAAM,CAAA;AAC1B,UAAA,MAAA,CAAO,OAAA,CAAQ,EAAE,KAAA,EAAO,OAAA,EAAS,CAAA;AAAA,QACnC;AAAA,MACF;AAEA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wCAAA,EAA2C,KAAK,CAAA,CAAE,CAAA;AAAA,EACpE;AAAA,EAEA,MAAA,GAGG;AACD,IAAA,OAAO,cAAA;AAAA,EACT;AAAA,EAEA,SAAA,GAAwE;AACtE,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA,EAEA,YAAA,CACE,OAAA,EACA,SAAA,GAAoB,GAAA,EAC+C;AACnE,IAAA,OAAO,IAAI,OAAA,CAGR,CAAC,OAAA,EAAS,MAAA,KAAW;AACtB,MAAA,UAAA,CAAW,MAAM;AACf,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,6BAA6B,CAAC,CAAA;AAAA,MACjD,GAAG,SAAS,CAAA;AAEZ,MAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,EAAE,OAAA,EAAS,SAAS,CAAA;AAAA,IACvC,CAAC,CAAA;AAAA,EACH;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MockFeatureFlagsApi.esm.js","sources":["../../../src/apis/FeatureFlagsApi/MockFeatureFlagsApi.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FeatureFlag,\n FeatureFlagsApi,\n FeatureFlagsSaveOptions,\n FeatureFlagState,\n} from '@backstage/frontend-plugin-api';\n\n/**\n * Options for configuring {@link MockFeatureFlagsApi}.\n *\n * @public\n */\nexport interface MockFeatureFlagsApiOptions {\n /**\n * Initial feature flag states.\n */\n initialStates?: Record<string, FeatureFlagState>;\n}\n\n/**\n * Mock implementation of {@link @backstage/frontend-plugin-api#FeatureFlagsApi} for testing feature flag behavior.\n *\n * @public\n * @example\n * ```ts\n * const api =
|
|
1
|
+
{"version":3,"file":"MockFeatureFlagsApi.esm.js","sources":["../../../src/apis/FeatureFlagsApi/MockFeatureFlagsApi.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FeatureFlag,\n FeatureFlagsApi,\n FeatureFlagsSaveOptions,\n FeatureFlagState,\n} from '@backstage/frontend-plugin-api';\n\n/**\n * Options for configuring {@link MockFeatureFlagsApi}.\n *\n * @public\n * @deprecated Use `mockApis.featureFlags()` instead.\n */\nexport interface MockFeatureFlagsApiOptions {\n /**\n * Initial feature flag states.\n */\n initialStates?: Record<string, FeatureFlagState>;\n}\n\n/**\n * Mock implementation of {@link @backstage/frontend-plugin-api#FeatureFlagsApi} for testing feature flag behavior.\n *\n * @public\n * @deprecated Use `mockApis.featureFlags()` instead.\n * @example\n * ```ts\n * const api = mockApis.featureFlags({\n * initialStates: { 'my-feature': FeatureFlagState.Active },\n * });\n * expect(api.isActive('my-feature')).toBe(true);\n * ```\n */\nexport class MockFeatureFlagsApi implements FeatureFlagsApi {\n private readonly registeredFlags: FeatureFlag[] = [];\n private readonly states: Map<string, FeatureFlagState>;\n\n constructor(options?: MockFeatureFlagsApiOptions) {\n this.states = new Map(Object.entries(options?.initialStates ?? {}));\n }\n\n registerFlag(flag: FeatureFlag): void {\n if (!this.registeredFlags.some(f => f.name === flag.name)) {\n this.registeredFlags.push(flag);\n }\n }\n\n getRegisteredFlags(): FeatureFlag[] {\n return this.registeredFlags;\n }\n\n isActive(name: string): boolean {\n return this.states.get(name) === FeatureFlagState.Active;\n }\n\n save(options: FeatureFlagsSaveOptions): void {\n if (options.merge) {\n for (const [name, state] of Object.entries(options.states)) {\n this.states.set(name, state);\n }\n } else {\n this.states.clear();\n for (const [name, state] of Object.entries(options.states)) {\n this.states.set(name, state);\n }\n }\n }\n\n /**\n * Get the current state of all feature flags as a record.\n */\n getState(): Record<string, FeatureFlagState> {\n return Object.fromEntries(this.states);\n }\n\n /**\n * Set the state of multiple feature flags.\n */\n setState(states: Record<string, FeatureFlagState>): void {\n for (const [name, state] of Object.entries(states)) {\n this.states.set(name, state);\n }\n }\n\n /**\n * Clear all feature flag states.\n */\n clearState(): void {\n this.states.clear();\n }\n}\n"],"names":[],"mappings":";;AAiDO,MAAM,mBAAA,CAA+C;AAAA,EACzC,kBAAiC,EAAC;AAAA,EAClC,MAAA;AAAA,EAEjB,YAAY,OAAA,EAAsC;AAChD,IAAA,IAAA,CAAK,MAAA,GAAS,IAAI,GAAA,CAAI,MAAA,CAAO,QAAQ,OAAA,EAAS,aAAA,IAAiB,EAAE,CAAC,CAAA;AAAA,EACpE;AAAA,EAEA,aAAa,IAAA,EAAyB;AACpC,IAAA,IAAI,CAAC,KAAK,eAAA,CAAgB,IAAA,CAAK,OAAK,CAAA,CAAE,IAAA,KAAS,IAAA,CAAK,IAAI,CAAA,EAAG;AACzD,MAAA,IAAA,CAAK,eAAA,CAAgB,KAAK,IAAI,CAAA;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,kBAAA,GAAoC;AAClC,IAAA,OAAO,IAAA,CAAK,eAAA;AAAA,EACd;AAAA,EAEA,SAAS,IAAA,EAAuB;AAC9B,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,IAAI,MAAM,gBAAA,CAAiB,MAAA;AAAA,EACpD;AAAA,EAEA,KAAK,OAAA,EAAwC;AAC3C,IAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,MAAA,KAAA,MAAW,CAAC,MAAM,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC1D,QAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,IAAA,EAAM,KAAK,CAAA;AAAA,MAC7B;AAAA,IACF,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAClB,MAAA,KAAA,MAAW,CAAC,MAAM,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC1D,QAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,IAAA,EAAM,KAAK,CAAA;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAA,GAA6C;AAC3C,IAAA,OAAO,MAAA,CAAO,WAAA,CAAY,IAAA,CAAK,MAAM,CAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,MAAA,EAAgD;AACvD,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,EAAG;AAClD,MAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,IAAA,EAAM,KAAK,CAAA;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAA,GAAmB;AACjB,IAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,EACpB;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MockFetchApi.esm.js","sources":["../../../src/apis/FetchApi/MockFetchApi.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createFetchApi,\n FetchMiddleware,\n FetchMiddlewares,\n} from '@backstage/core-app-api';\nimport {\n DiscoveryApi,\n FetchApi,\n IdentityApi,\n} from '@backstage/core-plugin-api';\n/**\n * The options given when constructing a {@link MockFetchApi}.\n *\n * @public\n */\nexport interface MockFetchApiOptions {\n /**\n * Define the underlying base `fetch` implementation.\n *\n * @defaultValue undefined\n * @remarks\n *\n * Leaving out this parameter or passing `undefined`, makes the API use the\n * global `fetch` implementation to make real network requests.\n *\n * `'none'` swallows all calls and makes no requests at all.\n *\n * You can also pass in any `fetch` compatible callback, such as a\n * `jest.fn()`, if you want to use a custom implementation or to just track\n * and assert on calls.\n */\n baseImplementation?: undefined | 'none' | typeof fetch;\n\n /**\n * Add translation from `plugin://` URLs to concrete http(s) URLs, basically\n * simulating what\n * {@link @backstage/core-app-api#FetchMiddlewares.resolvePluginProtocol}\n * does.\n *\n * @defaultValue undefined\n * @remarks\n *\n * Leaving out this parameter or passing `undefined`, disables plugin protocol\n * translation.\n *\n * To enable the feature, pass in a discovery API which is then used to\n * resolve the URLs.\n */\n resolvePluginProtocol?:\n | undefined\n | { discoveryApi: Pick<DiscoveryApi, 'getBaseUrl'> };\n\n /**\n * Add token based Authorization headers to requests, basically simulating\n * what {@link @backstage/core-app-api#FetchMiddlewares.injectIdentityAuth}\n * does.\n *\n * @defaultValue undefined\n * @remarks\n *\n * Leaving out this parameter or passing `undefined`, disables auth injection.\n *\n * To enable the feature, pass in either a static token or an identity API\n * which is queried on each request for a token.\n */\n injectIdentityAuth?:\n | undefined\n | { token: string }\n | { identityApi: Pick<IdentityApi, 'getCredentials'> };\n}\n\n/**\n * A test helper implementation of {@link @backstage/core-plugin-api#FetchApi}.\n *\n * @public\n */\nexport class MockFetchApi implements FetchApi {\n private readonly implementation: FetchApi;\n\n /**\n * Creates a mock {@link @backstage/core-plugin-api#FetchApi}.\n */\n constructor(options?: MockFetchApiOptions) {\n this.implementation = build(options);\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#FetchApi.fetch} */\n get fetch(): typeof fetch {\n return this.implementation.fetch;\n }\n}\n\n//\n// Helpers\n//\n\nfunction build(options?: MockFetchApiOptions): FetchApi {\n return createFetchApi({\n baseImplementation: baseImplementation(options),\n middleware: [\n resolvePluginProtocol(options),\n injectIdentityAuth(options),\n ].filter((x): x is FetchMiddleware => Boolean(x)),\n });\n}\n\nfunction baseImplementation(\n options: MockFetchApiOptions | undefined,\n): typeof fetch {\n const implementation = options?.baseImplementation;\n if (!implementation) {\n // Return a wrapper that evaluates global.fetch at call time, not construction time.\n // This allows MSW to patch global.fetch after MockFetchApi is constructed.\n return (input, init) => global.fetch(input, init);\n } else if (implementation === 'none') {\n return () => Promise.resolve(new Response());\n }\n return implementation;\n}\n\nfunction resolvePluginProtocol(\n allOptions: MockFetchApiOptions | undefined,\n): FetchMiddleware | undefined {\n const options = allOptions?.resolvePluginProtocol;\n if (!options) {\n return undefined;\n }\n\n return FetchMiddlewares.resolvePluginProtocol({\n discoveryApi: options.discoveryApi,\n });\n}\n\nfunction injectIdentityAuth(\n allOptions: MockFetchApiOptions | undefined,\n): FetchMiddleware | undefined {\n const options = allOptions?.injectIdentityAuth;\n if (!options) {\n return undefined;\n }\n\n const identityApi: Pick<IdentityApi, 'getCredentials'> =\n 'token' in options\n ? { getCredentials: async () => ({ token: options.token }) }\n : options.identityApi;\n\n return FetchMiddlewares.injectIdentityAuth({\n identityApi: identityApi as IdentityApi,\n allowUrl: () => true,\n });\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"MockFetchApi.esm.js","sources":["../../../src/apis/FetchApi/MockFetchApi.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createFetchApi,\n FetchMiddleware,\n FetchMiddlewares,\n} from '@backstage/core-app-api';\nimport {\n DiscoveryApi,\n FetchApi,\n IdentityApi,\n} from '@backstage/core-plugin-api';\n/**\n * The options given when constructing a {@link MockFetchApi}.\n *\n * @public\n */\nexport interface MockFetchApiOptions {\n /**\n * Define the underlying base `fetch` implementation.\n *\n * @defaultValue undefined\n * @remarks\n *\n * Leaving out this parameter or passing `undefined`, makes the API use the\n * global `fetch` implementation to make real network requests.\n *\n * `'none'` swallows all calls and makes no requests at all.\n *\n * You can also pass in any `fetch` compatible callback, such as a\n * `jest.fn()`, if you want to use a custom implementation or to just track\n * and assert on calls.\n */\n baseImplementation?: undefined | 'none' | typeof fetch;\n\n /**\n * Add translation from `plugin://` URLs to concrete http(s) URLs, basically\n * simulating what\n * {@link @backstage/core-app-api#FetchMiddlewares.resolvePluginProtocol}\n * does.\n *\n * @defaultValue undefined\n * @remarks\n *\n * Leaving out this parameter or passing `undefined`, disables plugin protocol\n * translation.\n *\n * To enable the feature, pass in a discovery API which is then used to\n * resolve the URLs.\n */\n resolvePluginProtocol?:\n | undefined\n | { discoveryApi: Pick<DiscoveryApi, 'getBaseUrl'> };\n\n /**\n * Add token based Authorization headers to requests, basically simulating\n * what {@link @backstage/core-app-api#FetchMiddlewares.injectIdentityAuth}\n * does.\n *\n * @defaultValue undefined\n * @remarks\n *\n * Leaving out this parameter or passing `undefined`, disables auth injection.\n *\n * To enable the feature, pass in either a static token or an identity API\n * which is queried on each request for a token.\n */\n injectIdentityAuth?:\n | undefined\n | { token: string }\n | { identityApi: Pick<IdentityApi, 'getCredentials'> };\n}\n\n/**\n * A test helper implementation of {@link @backstage/core-plugin-api#FetchApi}.\n *\n * @public\n * @deprecated Use `mockApis.fetch()` instead.\n */\nexport class MockFetchApi implements FetchApi {\n private readonly implementation: FetchApi;\n\n /**\n * Creates a mock {@link @backstage/core-plugin-api#FetchApi}.\n */\n constructor(options?: MockFetchApiOptions) {\n this.implementation = build(options);\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#FetchApi.fetch} */\n get fetch(): typeof fetch {\n return this.implementation.fetch;\n }\n}\n\n//\n// Helpers\n//\n\nfunction build(options?: MockFetchApiOptions): FetchApi {\n return createFetchApi({\n baseImplementation: baseImplementation(options),\n middleware: [\n resolvePluginProtocol(options),\n injectIdentityAuth(options),\n ].filter((x): x is FetchMiddleware => Boolean(x)),\n });\n}\n\nfunction baseImplementation(\n options: MockFetchApiOptions | undefined,\n): typeof fetch {\n const implementation = options?.baseImplementation;\n if (!implementation) {\n // Return a wrapper that evaluates global.fetch at call time, not construction time.\n // This allows MSW to patch global.fetch after MockFetchApi is constructed.\n return (input, init) => global.fetch(input, init);\n } else if (implementation === 'none') {\n return () => Promise.resolve(new Response());\n }\n return implementation;\n}\n\nfunction resolvePluginProtocol(\n allOptions: MockFetchApiOptions | undefined,\n): FetchMiddleware | undefined {\n const options = allOptions?.resolvePluginProtocol;\n if (!options) {\n return undefined;\n }\n\n return FetchMiddlewares.resolvePluginProtocol({\n discoveryApi: options.discoveryApi,\n });\n}\n\nfunction injectIdentityAuth(\n allOptions: MockFetchApiOptions | undefined,\n): FetchMiddleware | undefined {\n const options = allOptions?.injectIdentityAuth;\n if (!options) {\n return undefined;\n }\n\n const identityApi: Pick<IdentityApi, 'getCredentials'> =\n 'token' in options\n ? { getCredentials: async () => ({ token: options.token }) }\n : options.identityApi;\n\n return FetchMiddlewares.injectIdentityAuth({\n identityApi: identityApi as IdentityApi,\n allowUrl: () => true,\n });\n}\n"],"names":[],"mappings":";;AA6FO,MAAM,YAAA,CAAiC;AAAA,EAC3B,cAAA;AAAA;AAAA;AAAA;AAAA,EAKjB,YAAY,OAAA,EAA+B;AACzC,IAAA,IAAA,CAAK,cAAA,GAAiB,MAAM,OAAO,CAAA;AAAA,EACrC;AAAA;AAAA,EAGA,IAAI,KAAA,GAAsB;AACxB,IAAA,OAAO,KAAK,cAAA,CAAe,KAAA;AAAA,EAC7B;AACF;AAMA,SAAS,MAAM,OAAA,EAAyC;AACtD,EAAA,OAAO,cAAA,CAAe;AAAA,IACpB,kBAAA,EAAoB,mBAAmB,OAAO,CAAA;AAAA,IAC9C,UAAA,EAAY;AAAA,MACV,sBAAsB,OAAO,CAAA;AAAA,MAC7B,mBAAmB,OAAO;AAAA,MAC1B,MAAA,CAAO,CAAC,CAAA,KAA4B,OAAA,CAAQ,CAAC,CAAC;AAAA,GACjD,CAAA;AACH;AAEA,SAAS,mBACP,OAAA,EACc;AACd,EAAA,MAAM,iBAAiB,OAAA,EAAS,kBAAA;AAChC,EAAA,IAAI,CAAC,cAAA,EAAgB;AAGnB,IAAA,OAAO,CAAC,KAAA,EAAO,IAAA,KAAS,MAAA,CAAO,KAAA,CAAM,OAAO,IAAI,CAAA;AAAA,EAClD,CAAA,MAAA,IAAW,mBAAmB,MAAA,EAAQ;AACpC,IAAA,OAAO,MAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,UAAU,CAAA;AAAA,EAC7C;AACA,EAAA,OAAO,cAAA;AACT;AAEA,SAAS,sBACP,UAAA,EAC6B;AAC7B,EAAA,MAAM,UAAU,UAAA,EAAY,qBAAA;AAC5B,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,iBAAiB,qBAAA,CAAsB;AAAA,IAC5C,cAAc,OAAA,CAAQ;AAAA,GACvB,CAAA;AACH;AAEA,SAAS,mBACP,UAAA,EAC6B;AAC7B,EAAA,MAAM,UAAU,UAAA,EAAY,kBAAA;AAC5B,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAA,GACJ,OAAA,IAAW,OAAA,GACP,EAAE,cAAA,EAAgB,aAAa,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAM,CAAA,EAAG,GACzD,OAAA,CAAQ,WAAA;AAEd,EAAA,OAAO,iBAAiB,kBAAA,CAAmB;AAAA,IACzC,WAAA;AAAA,IACA,UAAU,MAAM;AAAA,GACjB,CAAA;AACH;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MockPermissionApi.esm.js","sources":["../../../src/apis/PermissionApi/MockPermissionApi.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PermissionApi } from '@backstage/plugin-permission-react';\nimport {\n EvaluatePermissionResponse,\n EvaluatePermissionRequest,\n AuthorizeResult,\n} from '@backstage/plugin-permission-common';\n\n/**\n * Mock implementation of\n * {@link @backstage/plugin-permission-react#PermissionApi}. Supply a\n * requestHandler function to override the mock result returned for a given\n * request.\n *\n * @public\n */\nexport class MockPermissionApi implements PermissionApi {\n constructor(\n private readonly requestHandler: (\n request: EvaluatePermissionRequest,\n ) => AuthorizeResult.ALLOW | AuthorizeResult.DENY = () =>\n AuthorizeResult.ALLOW,\n ) {}\n\n async authorize(\n request: EvaluatePermissionRequest,\n ): Promise<EvaluatePermissionResponse> {\n return { result: this.requestHandler(request) };\n }\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"MockPermissionApi.esm.js","sources":["../../../src/apis/PermissionApi/MockPermissionApi.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PermissionApi } from '@backstage/plugin-permission-react';\nimport {\n EvaluatePermissionResponse,\n EvaluatePermissionRequest,\n AuthorizeResult,\n} from '@backstage/plugin-permission-common';\n\n/**\n * Mock implementation of\n * {@link @backstage/plugin-permission-react#PermissionApi}. Supply a\n * requestHandler function to override the mock result returned for a given\n * request.\n *\n * @public\n * @deprecated Use `mockApis.permission()` instead.\n */\nexport class MockPermissionApi implements PermissionApi {\n constructor(\n private readonly requestHandler: (\n request: EvaluatePermissionRequest,\n ) => AuthorizeResult.ALLOW | AuthorizeResult.DENY = () =>\n AuthorizeResult.ALLOW,\n ) {}\n\n async authorize(\n request: EvaluatePermissionRequest,\n ): Promise<EvaluatePermissionResponse> {\n return { result: this.requestHandler(request) };\n }\n}\n"],"names":[],"mappings":";;AAgCO,MAAM,iBAAA,CAA2C;AAAA,EACtD,WAAA,CACmB,cAAA,GAEmC,MAClD,eAAA,CAAgB,KAAA,EAClB;AAJiB,IAAA,IAAA,CAAA,cAAA,GAAA,cAAA;AAAA,EAIhB;AAAA,EAEH,MAAM,UACJ,OAAA,EACqC;AACrC,IAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,CAAK,cAAA,CAAe,OAAO,CAAA,EAAE;AAAA,EAChD;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MockStorageApi.esm.js","sources":["../../../src/apis/StorageApi/MockStorageApi.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { StorageApi, StorageValueSnapshot } from '@backstage/core-plugin-api';\nimport { JsonObject, JsonValue, Observable } from '@backstage/types';\nimport ObservableImpl from 'zen-observable';\n\n/**\n * Mock implementation of the {@link core-plugin-api#StorageApi} to be used in tests
|
|
1
|
+
{"version":3,"file":"MockStorageApi.esm.js","sources":["../../../src/apis/StorageApi/MockStorageApi.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { StorageApi, StorageValueSnapshot } from '@backstage/core-plugin-api';\nimport { JsonObject, JsonValue, Observable } from '@backstage/types';\nimport ObservableImpl from 'zen-observable';\n\n/**\n * Mock implementation of the {@link core-plugin-api#StorageApi} to be used in tests.\n *\n * @public\n * @deprecated Use `mockApis.storage()` instead.\n */\nexport class MockStorageApi implements StorageApi {\n private readonly namespace: string;\n private readonly data: JsonObject;\n private readonly bucketStorageApis: Map<string, MockStorageApi>;\n\n private constructor(\n namespace: string,\n bucketStorageApis: Map<string, MockStorageApi>,\n data?: JsonObject,\n ) {\n this.namespace = namespace;\n this.bucketStorageApis = bucketStorageApis;\n this.data = { ...data };\n }\n\n static create(data?: JsonObject) {\n // Translate a nested data object structure into a flat object with keys\n // like `/a/b` with their corresponding leaf values\n const keyValues: { [key: string]: any } = {};\n function put(value: { [key: string]: any }, namespace: string) {\n for (const [key, val] of Object.entries(value)) {\n if (typeof val === 'object' && val !== null) {\n put(val, `${namespace}/${key}`);\n } else {\n const namespacedKey = `${namespace}/${key.replace(/^\\//, '')}`;\n keyValues[namespacedKey] = val;\n }\n }\n }\n put(data ?? {}, '');\n return new MockStorageApi('', new Map(), keyValues);\n }\n\n forBucket(name: string): StorageApi {\n if (!this.bucketStorageApis.has(name)) {\n this.bucketStorageApis.set(\n name,\n new MockStorageApi(\n `${this.namespace}/${name}`,\n this.bucketStorageApis,\n this.data,\n ),\n );\n }\n return this.bucketStorageApis.get(name)!;\n }\n\n snapshot<T extends JsonValue>(key: string): StorageValueSnapshot<T> {\n if (this.data.hasOwnProperty(this.getKeyName(key))) {\n const data = this.data[this.getKeyName(key)];\n return {\n key,\n presence: 'present',\n value: data as T,\n };\n }\n return {\n key,\n presence: 'absent',\n value: undefined,\n };\n }\n\n async set<T>(key: string, data: T): Promise<void> {\n const serialized = JSON.parse(JSON.stringify(data), (_key, value) => {\n if (typeof value === 'object' && value !== null) {\n Object.freeze(value);\n }\n return value;\n });\n this.data[this.getKeyName(key)] = serialized;\n this.notifyChanges({\n key,\n presence: 'present',\n value: serialized,\n });\n }\n\n async remove(key: string): Promise<void> {\n delete this.data[this.getKeyName(key)];\n this.notifyChanges({\n key,\n presence: 'absent',\n value: undefined,\n });\n }\n\n observe$<T extends JsonValue>(\n key: string,\n ): Observable<StorageValueSnapshot<T>> {\n return this.observable.filter(({ key: messageKey }) => messageKey === key);\n }\n\n private getKeyName(key: string) {\n return `${this.namespace}/${encodeURIComponent(key)}`;\n }\n\n private notifyChanges<T extends JsonValue>(message: StorageValueSnapshot<T>) {\n for (const subscription of this.subscribers) {\n subscription.next(message);\n }\n }\n\n private subscribers = new Set<\n ZenObservable.SubscriptionObserver<StorageValueSnapshot<JsonValue>>\n >();\n\n private readonly observable = new ObservableImpl<\n StorageValueSnapshot<JsonValue>\n >(subscriber => {\n this.subscribers.add(subscriber);\n return () => {\n this.subscribers.delete(subscriber);\n };\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MockTranslationApi.esm.js","sources":["../../../src/apis/TranslationApi/MockTranslationApi.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n TranslationApi,\n TranslationRef,\n TranslationSnapshot,\n} from '@backstage/frontend-plugin-api';\nimport { createInstance as createI18n, type i18n as I18n } from 'i18next';\nimport ObservableImpl from 'zen-observable';\n\nimport { Observable } from '@backstage/types';\n// Internal import to avoid code duplication, this will lead to duplication in build output\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalTranslationRef } from '../../../../frontend-plugin-api/src/translation/TranslationRef';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { JsxInterpolator } from '../../../../core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi';\n\nconst DEFAULT_LANGUAGE = 'en';\n\n/**\n * Mock implementation of {@link @backstage/frontend-plugin-api#TranslationApi}.\n *\n * @public\n */\nexport class MockTranslationApi implements TranslationApi {\n static create() {\n const i18n = createI18n({\n fallbackLng: DEFAULT_LANGUAGE,\n supportedLngs: [DEFAULT_LANGUAGE],\n interpolation: {\n escapeValue: false,\n // Used for the JsxInterpolator format hook\n alwaysFormat: true,\n },\n ns: [],\n defaultNS: false,\n fallbackNS: false,\n\n // Disable resource loading on init, meaning i18n will be ready to use immediately\n initImmediate: false,\n });\n\n i18n.init();\n if (!i18n.isInitialized) {\n throw new Error('i18next was unexpectedly not initialized');\n }\n\n const interpolator = JsxInterpolator.fromI18n(i18n);\n\n return new MockTranslationApi(i18n, interpolator);\n }\n\n readonly #i18n: I18n;\n readonly #interpolator: JsxInterpolator;\n readonly #registeredRefs = new Set<string>();\n\n private constructor(i18n: I18n, interpolator: JsxInterpolator) {\n this.#i18n = i18n;\n this.#interpolator = interpolator;\n }\n\n getTranslation<TMessages extends { [key in string]: string }>(\n translationRef: TranslationRef<string, TMessages>,\n ): TranslationSnapshot<TMessages> {\n const internalRef = toInternalTranslationRef(translationRef);\n\n if (!this.#registeredRefs.has(internalRef.id)) {\n this.#registeredRefs.add(internalRef.id);\n this.#i18n.addResourceBundle(\n DEFAULT_LANGUAGE,\n internalRef.id,\n internalRef.getDefaultMessages(),\n false, // do not merge\n true, // overwrite existing\n );\n }\n\n const t = this.#interpolator.wrapT<TMessages>(\n this.#i18n.getFixedT(null, internalRef.id),\n );\n\n return {\n ready: true,\n t,\n };\n }\n\n translation$<TMessages extends { [key in string]: string }>(): Observable<\n TranslationSnapshot<TMessages>\n > {\n // No need to implement, getTranslation will always return a ready snapshot\n return new ObservableImpl<TranslationSnapshot<TMessages>>(_subscriber => {\n return () => {};\n });\n }\n}\n"],"names":["createI18n"],"mappings":";;;;;AA+BA,MAAM,gBAAA,GAAmB,IAAA;
|
|
1
|
+
{"version":3,"file":"MockTranslationApi.esm.js","sources":["../../../src/apis/TranslationApi/MockTranslationApi.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n TranslationApi,\n TranslationRef,\n TranslationSnapshot,\n} from '@backstage/frontend-plugin-api';\nimport { createInstance as createI18n, type i18n as I18n } from 'i18next';\nimport ObservableImpl from 'zen-observable';\n\nimport { Observable } from '@backstage/types';\n// Internal import to avoid code duplication, this will lead to duplication in build output\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalTranslationRef } from '../../../../frontend-plugin-api/src/translation/TranslationRef';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { JsxInterpolator } from '../../../../core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi';\n\nconst DEFAULT_LANGUAGE = 'en';\n\n/**\n * Mock implementation of {@link @backstage/frontend-plugin-api#TranslationApi}.\n *\n * @public\n * @deprecated Use `mockApis.translation()` instead.\n */\nexport class MockTranslationApi implements TranslationApi {\n static create() {\n const i18n = createI18n({\n fallbackLng: DEFAULT_LANGUAGE,\n supportedLngs: [DEFAULT_LANGUAGE],\n interpolation: {\n escapeValue: false,\n // Used for the JsxInterpolator format hook\n alwaysFormat: true,\n },\n ns: [],\n defaultNS: false,\n fallbackNS: false,\n\n // Disable resource loading on init, meaning i18n will be ready to use immediately\n initImmediate: false,\n });\n\n i18n.init();\n if (!i18n.isInitialized) {\n throw new Error('i18next was unexpectedly not initialized');\n }\n\n const interpolator = JsxInterpolator.fromI18n(i18n);\n\n return new MockTranslationApi(i18n, interpolator);\n }\n\n readonly #i18n: I18n;\n readonly #interpolator: JsxInterpolator;\n readonly #registeredRefs = new Set<string>();\n\n private constructor(i18n: I18n, interpolator: JsxInterpolator) {\n this.#i18n = i18n;\n this.#interpolator = interpolator;\n }\n\n getTranslation<TMessages extends { [key in string]: string }>(\n translationRef: TranslationRef<string, TMessages>,\n ): TranslationSnapshot<TMessages> {\n const internalRef = toInternalTranslationRef(translationRef);\n\n if (!this.#registeredRefs.has(internalRef.id)) {\n this.#registeredRefs.add(internalRef.id);\n this.#i18n.addResourceBundle(\n DEFAULT_LANGUAGE,\n internalRef.id,\n internalRef.getDefaultMessages(),\n false, // do not merge\n true, // overwrite existing\n );\n }\n\n const t = this.#interpolator.wrapT<TMessages>(\n this.#i18n.getFixedT(null, internalRef.id),\n );\n\n return {\n ready: true,\n t,\n };\n }\n\n translation$<TMessages extends { [key in string]: string }>(): Observable<\n TranslationSnapshot<TMessages>\n > {\n // No need to implement, getTranslation will always return a ready snapshot\n return new ObservableImpl<TranslationSnapshot<TMessages>>(_subscriber => {\n return () => {};\n });\n }\n}\n"],"names":["createI18n"],"mappings":";;;;;AA+BA,MAAM,gBAAA,GAAmB,IAAA;AAQlB,MAAM,kBAAA,CAA6C;AAAA,EACxD,OAAO,MAAA,GAAS;AACd,IAAA,MAAM,OAAOA,cAAA,CAAW;AAAA,MACtB,WAAA,EAAa,gBAAA;AAAA,MACb,aAAA,EAAe,CAAC,gBAAgB,CAAA;AAAA,MAChC,aAAA,EAAe;AAAA,QACb,WAAA,EAAa,KAAA;AAAA;AAAA,QAEb,YAAA,EAAc;AAAA,OAChB;AAAA,MACA,IAAI,EAAC;AAAA,MACL,SAAA,EAAW,KAAA;AAAA,MACX,UAAA,EAAY,KAAA;AAAA;AAAA,MAGZ,aAAA,EAAe;AAAA,KAChB,CAAA;AAED,IAAA,IAAA,CAAK,IAAA,EAAK;AACV,IAAA,IAAI,CAAC,KAAK,aAAA,EAAe;AACvB,MAAA,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAAA,IAC5D;AAEA,IAAA,MAAM,YAAA,GAAe,eAAA,CAAgB,QAAA,CAAS,IAAI,CAAA;AAElD,IAAA,OAAO,IAAI,kBAAA,CAAmB,IAAA,EAAM,YAAY,CAAA;AAAA,EAClD;AAAA,EAES,KAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA,uBAAsB,GAAA,EAAY;AAAA,EAEnC,WAAA,CAAY,MAAY,YAAA,EAA+B;AAC7D,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,IAAA,IAAA,CAAK,aAAA,GAAgB,YAAA;AAAA,EACvB;AAAA,EAEA,eACE,cAAA,EACgC;AAChC,IAAA,MAAM,WAAA,GAAc,yBAAyB,cAAc,CAAA;AAE3D,IAAA,IAAI,CAAC,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,WAAA,CAAY,EAAE,CAAA,EAAG;AAC7C,MAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,WAAA,CAAY,EAAE,CAAA;AACvC,MAAA,IAAA,CAAK,KAAA,CAAM,iBAAA;AAAA,QACT,gBAAA;AAAA,QACA,WAAA,CAAY,EAAA;AAAA,QACZ,YAAY,kBAAA,EAAmB;AAAA,QAC/B,KAAA;AAAA;AAAA,QACA;AAAA;AAAA,OACF;AAAA,IACF;AAEA,IAAA,MAAM,CAAA,GAAI,KAAK,aAAA,CAAc,KAAA;AAAA,MAC3B,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,IAAA,EAAM,YAAY,EAAE;AAAA,KAC3C;AAEA,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,IAAA;AAAA,MACP;AAAA,KACF;AAAA,EACF;AAAA,EAEA,YAAA,GAEE;AAEA,IAAA,OAAO,IAAI,eAA+C,CAAA,WAAA,KAAe;AACvE,MAAA,OAAO,MAAM;AAAA,MAAC,CAAA;AAAA,IAChB,CAAC,CAAA;AAAA,EACH;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockApis.esm.js","sources":["../../src/apis/mockApis.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n alertApiRef,\n analyticsApiRef,\n configApiRef,\n discoveryApiRef,\n errorApiRef,\n fetchApiRef,\n featureFlagsApiRef,\n identityApiRef,\n storageApiRef,\n translationApiRef,\n type AnalyticsApi,\n type ConfigApi,\n type DiscoveryApi,\n type ErrorApi,\n type FetchApi,\n type IdentityApi,\n type StorageApi,\n type TranslationApi,\n} from '@backstage/frontend-plugin-api';\nimport {\n permissionApiRef,\n type PermissionApi,\n} from '@backstage/plugin-permission-react';\nimport { JsonObject } from '@backstage/types';\nimport {\n AuthorizeResult,\n EvaluatePermissionRequest,\n} from '@backstage/plugin-permission-common';\nimport { MockAlertApi } from './AlertApi';\nimport {\n MockFeatureFlagsApi,\n MockFeatureFlagsApiOptions,\n} from './FeatureFlagsApi';\nimport { MockAnalyticsApi } from './AnalyticsApi';\nimport { MockConfigApi } from './ConfigApi';\nimport { MockErrorApi, MockErrorApiOptions } from './ErrorApi';\nimport { MockFetchApi, MockFetchApiOptions } from './FetchApi';\nimport { MockStorageApi } from './StorageApi';\nimport { MockPermissionApi } from './PermissionApi';\nimport { MockTranslationApi } from './TranslationApi';\nimport {\n mockWithApiFactory,\n type MockWithApiFactory,\n} from './MockWithApiFactory';\nimport { createApiMock } from './createApiMock';\n\n/**\n * Mock implementations of the core utility APIs, to be used in tests.\n *\n * @public\n * @remarks\n *\n * There are some variations among the APIs depending on what needs tests\n * might have, but overall there are two main usage patterns:\n *\n * 1: Creating an actual fake API instance, often with a simplified version\n * of functionality, by calling the mock API itself as a function.\n *\n * ```ts\n * // The function often accepts parameters that control its behavior\n * const foo = mockApis.foo();\n * ```\n *\n * 2: Creating a mock API, where all methods are replaced with jest mocks, by\n * calling the API's `mock` function.\n *\n * ```ts\n * // You can optionally supply a subset of its methods to implement\n * const foo = mockApis.foo.mock({\n * someMethod: () => 'mocked result',\n * });\n * // After exercising your test, you can make assertions on the mock:\n * expect(foo.someMethod).toHaveBeenCalledTimes(2);\n * expect(foo.otherMethod).toHaveBeenCalledWith(testData);\n * ```\n */\nexport namespace mockApis {\n /**\n * Fake implementation of {@link @backstage/frontend-plugin-api#AlertApi}.\n *\n * @public\n * @example\n *\n * ```tsx\n * const alertApi = mockApis.alert();\n * alertApi.post({ message: 'Test alert' });\n * expect(alertApi.getAlerts()).toHaveLength(1);\n * ```\n */\n export function alert(): MockWithApiFactory<MockAlertApi> {\n const instance = new MockAlertApi();\n return mockWithApiFactory(\n alertApiRef,\n instance,\n ) as MockWithApiFactory<MockAlertApi>;\n }\n /**\n * Mock helpers for {@link @backstage/frontend-plugin-api#AlertApi}.\n *\n * @see {@link @backstage/frontend-plugin-api#mockApis.alert}\n * @public\n */\n export namespace alert {\n /**\n * Creates a mock implementation of\n * {@link @backstage/frontend-plugin-api#AlertApi}. All methods are\n * replaced with jest mock functions, and you can optionally pass in a\n * subset of methods with an explicit implementation.\n *\n * @public\n */\n export const mock = createApiMock(alertApiRef, () => ({\n post: jest.fn(),\n alert$: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/frontend-plugin-api#FeatureFlagsApi}.\n *\n * @public\n * @example\n *\n * ```tsx\n * const featureFlagsApi = mockApis.featureFlags({\n * initialStates: { 'my-feature': FeatureFlagState.Active },\n * });\n * expect(featureFlagsApi.isActive('my-feature')).toBe(true);\n * ```\n */\n export function featureFlags(\n options?: MockFeatureFlagsApiOptions,\n ): MockWithApiFactory<MockFeatureFlagsApi> {\n const instance = new MockFeatureFlagsApi(options);\n return mockWithApiFactory(\n featureFlagsApiRef,\n instance,\n ) as MockWithApiFactory<MockFeatureFlagsApi>;\n }\n /**\n * Mock helpers for {@link @backstage/frontend-plugin-api#FeatureFlagsApi}.\n *\n * @see {@link @backstage/frontend-plugin-api#mockApis.featureFlags}\n * @public\n */\n export namespace featureFlags {\n /**\n * Creates a mock implementation of\n * {@link @backstage/frontend-plugin-api#FeatureFlagsApi}. All methods are\n * replaced with jest mock functions, and you can optionally pass in a\n * subset of methods with an explicit implementation.\n *\n * @public\n */\n export const mock = createApiMock(featureFlagsApiRef, () => ({\n registerFlag: jest.fn(),\n getRegisteredFlags: jest.fn(),\n isActive: jest.fn(),\n save: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#AnalyticsApi}.\n *\n * @public\n */\n export function analytics(): MockAnalyticsApi &\n MockWithApiFactory<AnalyticsApi> {\n const instance = new MockAnalyticsApi();\n return mockWithApiFactory(analyticsApiRef, instance) as MockAnalyticsApi &\n MockWithApiFactory<AnalyticsApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#AnalyticsApi}.\n *\n * @public\n */\n export namespace analytics {\n export const mock = createApiMock(analyticsApiRef, () => ({\n captureEvent: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/frontend-plugin-api#TranslationApi}.\n * By default returns the default translation.\n *\n * @public\n */\n export function translation(): MockTranslationApi &\n MockWithApiFactory<TranslationApi> {\n const instance = MockTranslationApi.create();\n return mockWithApiFactory(\n translationApiRef,\n instance,\n ) as MockTranslationApi & MockWithApiFactory<TranslationApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/frontend-plugin-api#TranslationApi}.\n *\n * @see {@link @backstage/frontend-plugin-api#mockApis.translation}\n * @public\n */\n export namespace translation {\n /**\n * Creates a mock of {@link @backstage/frontend-plugin-api#TranslationApi}.\n *\n * @public\n */\n export const mock = createApiMock(translationApiRef, () => ({\n getTranslation: jest.fn(),\n translation$: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#ConfigApi}.\n *\n * @public\n */\n export function config(options?: {\n data?: JsonObject;\n }): MockConfigApi & MockWithApiFactory<ConfigApi> {\n const instance = new MockConfigApi({ data: options?.data ?? {} });\n return mockWithApiFactory(configApiRef, instance) as MockConfigApi &\n MockWithApiFactory<ConfigApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#ConfigApi}.\n *\n * @public\n */\n export namespace config {\n export const mock = createApiMock(configApiRef, () => ({\n has: jest.fn(),\n keys: jest.fn(),\n get: jest.fn(),\n getOptional: jest.fn(),\n getConfig: jest.fn(),\n getOptionalConfig: jest.fn(),\n getConfigArray: jest.fn(),\n getOptionalConfigArray: jest.fn(),\n getNumber: jest.fn(),\n getOptionalNumber: jest.fn(),\n getBoolean: jest.fn(),\n getOptionalBoolean: jest.fn(),\n getString: jest.fn(),\n getOptionalString: jest.fn(),\n getStringArray: jest.fn(),\n getOptionalStringArray: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#DiscoveryApi}.\n *\n * @public\n */\n export function discovery(options?: {\n baseUrl?: string;\n }): DiscoveryApi & MockWithApiFactory<DiscoveryApi> {\n const baseUrl = options?.baseUrl ?? 'http://example.com';\n const instance: DiscoveryApi = {\n async getBaseUrl(pluginId: string) {\n return `${baseUrl}/api/${pluginId}`;\n },\n };\n return mockWithApiFactory(discoveryApiRef, instance) as DiscoveryApi &\n MockWithApiFactory<DiscoveryApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#DiscoveryApi}.\n *\n * @public\n */\n export namespace discovery {\n export const mock = createApiMock(discoveryApiRef, () => ({\n getBaseUrl: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#IdentityApi}.\n *\n * @public\n */\n export function identity(options?: {\n userEntityRef?: string;\n ownershipEntityRefs?: string[];\n token?: string;\n email?: string;\n displayName?: string;\n picture?: string;\n }): MockWithApiFactory<IdentityApi> {\n const {\n userEntityRef = 'user:default/test',\n ownershipEntityRefs = ['user:default/test'],\n token,\n email,\n displayName,\n picture,\n } = options ?? {};\n const instance: IdentityApi = {\n async getBackstageIdentity() {\n return { type: 'user', ownershipEntityRefs, userEntityRef };\n },\n async getCredentials() {\n return { token };\n },\n async getProfileInfo() {\n return { email, displayName, picture };\n },\n async signOut() {},\n };\n return mockWithApiFactory(identityApiRef, instance) as IdentityApi &\n MockWithApiFactory<IdentityApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#IdentityApi}.\n *\n * @public\n */\n export namespace identity {\n export const mock = createApiMock(identityApiRef, () => ({\n getBackstageIdentity: jest.fn(),\n getCredentials: jest.fn(),\n getProfileInfo: jest.fn(),\n signOut: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/plugin-permission-react#PermissionApi}.\n *\n * @public\n */\n export function permission(options?: {\n authorize?:\n | AuthorizeResult.ALLOW\n | AuthorizeResult.DENY\n | ((\n request: EvaluatePermissionRequest,\n ) => AuthorizeResult.ALLOW | AuthorizeResult.DENY);\n }): MockPermissionApi & MockWithApiFactory<PermissionApi> {\n const authorizeInput = options?.authorize;\n const handler =\n typeof authorizeInput === 'function'\n ? authorizeInput\n : () => authorizeInput ?? AuthorizeResult.ALLOW;\n const instance = new MockPermissionApi(handler);\n return mockWithApiFactory(permissionApiRef, instance) as MockPermissionApi &\n MockWithApiFactory<PermissionApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/plugin-permission-react#PermissionApi}.\n *\n * @public\n */\n export namespace permission {\n export const mock = createApiMock(permissionApiRef, () => ({\n authorize: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#StorageApi}.\n *\n * @public\n */\n export function storage(options?: {\n data?: JsonObject;\n }): MockStorageApi & MockWithApiFactory<StorageApi> {\n const instance = MockStorageApi.create(options?.data);\n return mockWithApiFactory(storageApiRef, instance) as MockStorageApi &\n MockWithApiFactory<StorageApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#StorageApi}.\n *\n * @public\n */\n export namespace storage {\n export const mock = createApiMock(storageApiRef, () => ({\n forBucket: jest.fn(),\n snapshot: jest.fn(),\n set: jest.fn(),\n remove: jest.fn(),\n observe$: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#ErrorApi}.\n *\n * @public\n */\n export function error(\n options?: MockErrorApiOptions,\n ): MockErrorApi & MockWithApiFactory<ErrorApi> {\n const instance = new MockErrorApi(options);\n return mockWithApiFactory(errorApiRef, instance) as MockErrorApi &\n MockWithApiFactory<ErrorApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#ErrorApi}.\n *\n * @public\n */\n export namespace error {\n export const mock = createApiMock(errorApiRef, () => ({\n post: jest.fn(),\n error$: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#FetchApi}.\n *\n * @public\n */\n export function fetch(\n options?: MockFetchApiOptions,\n ): MockFetchApi & MockWithApiFactory<FetchApi> {\n const instance = new MockFetchApi(options);\n return mockWithApiFactory(fetchApiRef, instance) as MockFetchApi &\n MockWithApiFactory<FetchApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#FetchApi}.\n *\n * @public\n */\n export namespace fetch {\n export const mock = createApiMock(fetchApiRef, () => ({\n fetch: jest.fn(),\n }));\n }\n}\n"],"names":["mockApis","alert","featureFlags","analytics","translation","config","discovery","identity","permission","storage","error","fetch"],"mappings":";;;;;;;;;;;;;;;AA6FO,IAAU;AAAA,CAAV,CAAUA,SAAAA,KAAV;AAaE,EAAA,SAAS,KAAA,GAA0C;AACxD,IAAA,MAAM,QAAA,GAAW,IAAI,YAAA,EAAa;AAClC,IAAA,OAAO,kBAAA;AAAA,MACL,WAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AANO,EAAAA,SAAAA,CAAS,KAAA,GAAA,KAAA;AAaT,EAAA,CAAA,CAAUC,MAAAA,KAAV;AASE,IAAMA,MAAAA,CAAA,IAAA,GAAO,aAAA,CAAc,WAAA,EAAa,OAAO;AAAA,MACpD,IAAA,EAAM,KAAK,EAAA,EAAG;AAAA,MACd,MAAA,EAAQ,KAAK,EAAA;AAAG,KAClB,CAAE,CAAA;AAAA,EAAA,CAAA,EAZa,KAAA,GAAAD,SAAAA,CAAA,KAAA,KAAAA,SAAAA,CAAA,KAAA,GAAA,EAAA,CAAA,CAAA;AA4BV,EAAA,SAAS,aACd,OAAA,EACyC;AACzC,IAAA,MAAM,QAAA,GAAW,IAAI,mBAAA,CAAoB,OAAO,CAAA;AAChD,IAAA,OAAO,kBAAA;AAAA,MACL,kBAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AARO,EAAAA,SAAAA,CAAS,YAAA,GAAA,YAAA;AAeT,EAAA,CAAA,CAAUE,aAAAA,KAAV;AASE,IAAMA,aAAAA,CAAA,IAAA,GAAO,aAAA,CAAc,kBAAA,EAAoB,OAAO;AAAA,MAC3D,YAAA,EAAc,KAAK,EAAA,EAAG;AAAA,MACtB,kBAAA,EAAoB,KAAK,EAAA,EAAG;AAAA,MAC5B,QAAA,EAAU,KAAK,EAAA,EAAG;AAAA,MAClB,IAAA,EAAM,KAAK,EAAA;AAAG,KAChB,CAAE,CAAA;AAAA,EAAA,CAAA,EAda,YAAA,GAAAF,SAAAA,CAAA,YAAA,KAAAA,SAAAA,CAAA,YAAA,GAAA,EAAA,CAAA,CAAA;AAsBV,EAAA,SAAS,SAAA,GACmB;AACjC,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,EAAiB;AACtC,IAAA,OAAO,kBAAA,CAAmB,iBAAiB,QAAQ,CAAA;AAAA,EAErD;AALO,EAAAA,SAAAA,CAAS,SAAA,GAAA,SAAA;AAYT,EAAA,CAAA,CAAUG,UAAAA,KAAV;AACE,IAAMA,UAAAA,CAAA,IAAA,GAAO,aAAA,CAAc,eAAA,EAAiB,OAAO;AAAA,MACxD,YAAA,EAAc,KAAK,EAAA;AAAG,KACxB,CAAE,CAAA;AAAA,EAAA,CAAA,EAHa,SAAA,GAAAH,SAAAA,CAAA,SAAA,KAAAA,SAAAA,CAAA,SAAA,GAAA,EAAA,CAAA,CAAA;AAYV,EAAA,SAAS,WAAA,GACqB;AACnC,IAAA,MAAM,QAAA,GAAW,mBAAmB,MAAA,EAAO;AAC3C,IAAA,OAAO,kBAAA;AAAA,MACL,iBAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAPO,EAAAA,SAAAA,CAAS,WAAA,GAAA,WAAA;AAeT,EAAA,CAAA,CAAUI,YAAAA,KAAV;AAME,IAAMA,YAAAA,CAAA,IAAA,GAAO,aAAA,CAAc,iBAAA,EAAmB,OAAO;AAAA,MAC1D,cAAA,EAAgB,KAAK,EAAA,EAAG;AAAA,MACxB,YAAA,EAAc,KAAK,EAAA;AAAG,KACxB,CAAE,CAAA;AAAA,EAAA,CAAA,EATa,WAAA,GAAAJ,SAAAA,CAAA,WAAA,KAAAA,SAAAA,CAAA,WAAA,GAAA,EAAA,CAAA,CAAA;AAiBV,EAAA,SAAS,OAAO,OAAA,EAE2B;AAChD,IAAA,MAAM,QAAA,GAAW,IAAI,aAAA,CAAc,EAAE,MAAM,OAAA,EAAS,IAAA,IAAQ,EAAC,EAAG,CAAA;AAChE,IAAA,OAAO,kBAAA,CAAmB,cAAc,QAAQ,CAAA;AAAA,EAElD;AANO,EAAAA,SAAAA,CAAS,MAAA,GAAA,MAAA;AAaT,EAAA,CAAA,CAAUK,OAAAA,KAAV;AACE,IAAMA,OAAAA,CAAA,IAAA,GAAO,aAAA,CAAc,YAAA,EAAc,OAAO;AAAA,MACrD,GAAA,EAAK,KAAK,EAAA,EAAG;AAAA,MACb,IAAA,EAAM,KAAK,EAAA,EAAG;AAAA,MACd,GAAA,EAAK,KAAK,EAAA,EAAG;AAAA,MACb,WAAA,EAAa,KAAK,EAAA,EAAG;AAAA,MACrB,SAAA,EAAW,KAAK,EAAA,EAAG;AAAA,MACnB,iBAAA,EAAmB,KAAK,EAAA,EAAG;AAAA,MAC3B,cAAA,EAAgB,KAAK,EAAA,EAAG;AAAA,MACxB,sBAAA,EAAwB,KAAK,EAAA,EAAG;AAAA,MAChC,SAAA,EAAW,KAAK,EAAA,EAAG;AAAA,MACnB,iBAAA,EAAmB,KAAK,EAAA,EAAG;AAAA,MAC3B,UAAA,EAAY,KAAK,EAAA,EAAG;AAAA,MACpB,kBAAA,EAAoB,KAAK,EAAA,EAAG;AAAA,MAC5B,SAAA,EAAW,KAAK,EAAA,EAAG;AAAA,MACnB,iBAAA,EAAmB,KAAK,EAAA,EAAG;AAAA,MAC3B,cAAA,EAAgB,KAAK,EAAA,EAAG;AAAA,MACxB,sBAAA,EAAwB,KAAK,EAAA;AAAG,KAClC,CAAE,CAAA;AAAA,EAAA,CAAA,EAlBa,MAAA,GAAAL,SAAAA,CAAA,MAAA,KAAAA,SAAAA,CAAA,MAAA,GAAA,EAAA,CAAA,CAAA;AA0BV,EAAA,SAAS,UAAU,OAAA,EAE0B;AAClD,IAAA,MAAM,OAAA,GAAU,SAAS,OAAA,IAAW,oBAAA;AACpC,IAAA,MAAM,QAAA,GAAyB;AAAA,MAC7B,MAAM,WAAW,QAAA,EAAkB;AACjC,QAAA,OAAO,CAAA,EAAG,OAAO,CAAA,KAAA,EAAQ,QAAQ,CAAA,CAAA;AAAA,MACnC;AAAA,KACF;AACA,IAAA,OAAO,kBAAA,CAAmB,iBAAiB,QAAQ,CAAA;AAAA,EAErD;AAXO,EAAAA,SAAAA,CAAS,SAAA,GAAA,SAAA;AAkBT,EAAA,CAAA,CAAUM,UAAAA,KAAV;AACE,IAAMA,UAAAA,CAAA,IAAA,GAAO,aAAA,CAAc,eAAA,EAAiB,OAAO;AAAA,MACxD,UAAA,EAAY,KAAK,EAAA;AAAG,KACtB,CAAE,CAAA;AAAA,EAAA,CAAA,EAHa,SAAA,GAAAN,SAAAA,CAAA,SAAA,KAAAA,SAAAA,CAAA,SAAA,GAAA,EAAA,CAAA,CAAA;AAWV,EAAA,SAAS,SAAS,OAAA,EAOW;AAClC,IAAA,MAAM;AAAA,MACJ,aAAA,GAAgB,mBAAA;AAAA,MAChB,mBAAA,GAAsB,CAAC,mBAAmB,CAAA;AAAA,MAC1C,KAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA,KACF,GAAI,WAAW,EAAC;AAChB,IAAA,MAAM,QAAA,GAAwB;AAAA,MAC5B,MAAM,oBAAA,GAAuB;AAC3B,QAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,mBAAA,EAAqB,aAAA,EAAc;AAAA,MAC5D,CAAA;AAAA,MACA,MAAM,cAAA,GAAiB;AACrB,QAAA,OAAO,EAAE,KAAA,EAAM;AAAA,MACjB,CAAA;AAAA,MACA,MAAM,cAAA,GAAiB;AACrB,QAAA,OAAO,EAAE,KAAA,EAAO,WAAA,EAAa,OAAA,EAAQ;AAAA,MACvC,CAAA;AAAA,MACA,MAAM,OAAA,GAAU;AAAA,MAAC;AAAA,KACnB;AACA,IAAA,OAAO,kBAAA,CAAmB,gBAAgB,QAAQ,CAAA;AAAA,EAEpD;AA9BO,EAAAA,SAAAA,CAAS,QAAA,GAAA,QAAA;AAqCT,EAAA,CAAA,CAAUO,SAAAA,KAAV;AACE,IAAMA,SAAAA,CAAA,IAAA,GAAO,aAAA,CAAc,cAAA,EAAgB,OAAO;AAAA,MACvD,oBAAA,EAAsB,KAAK,EAAA,EAAG;AAAA,MAC9B,cAAA,EAAgB,KAAK,EAAA,EAAG;AAAA,MACxB,cAAA,EAAgB,KAAK,EAAA,EAAG;AAAA,MACxB,OAAA,EAAS,KAAK,EAAA;AAAG,KACnB,CAAE,CAAA;AAAA,EAAA,CAAA,EANa,QAAA,GAAAP,SAAAA,CAAA,QAAA,KAAAA,SAAAA,CAAA,QAAA,GAAA,EAAA,CAAA,CAAA;AAcV,EAAA,SAAS,WAAW,OAAA,EAO+B;AACxD,IAAA,MAAM,iBAAiB,OAAA,EAAS,SAAA;AAChC,IAAA,MAAM,UACJ,OAAO,cAAA,KAAmB,aACtB,cAAA,GACA,MAAM,kBAAkB,eAAA,CAAgB,KAAA;AAC9C,IAAA,MAAM,QAAA,GAAW,IAAI,iBAAA,CAAkB,OAAO,CAAA;AAC9C,IAAA,OAAO,kBAAA,CAAmB,kBAAkB,QAAQ,CAAA;AAAA,EAEtD;AAhBO,EAAAA,SAAAA,CAAS,UAAA,GAAA,UAAA;AAuBT,EAAA,CAAA,CAAUQ,WAAAA,KAAV;AACE,IAAMA,WAAAA,CAAA,IAAA,GAAO,aAAA,CAAc,gBAAA,EAAkB,OAAO;AAAA,MACzD,SAAA,EAAW,KAAK,EAAA;AAAG,KACrB,CAAE,CAAA;AAAA,EAAA,CAAA,EAHa,UAAA,GAAAR,SAAAA,CAAA,UAAA,KAAAA,SAAAA,CAAA,UAAA,GAAA,EAAA,CAAA,CAAA;AAWV,EAAA,SAAS,QAAQ,OAAA,EAE4B;AAClD,IAAA,MAAM,QAAA,GAAW,cAAA,CAAe,MAAA,CAAO,OAAA,EAAS,IAAI,CAAA;AACpD,IAAA,OAAO,kBAAA,CAAmB,eAAe,QAAQ,CAAA;AAAA,EAEnD;AANO,EAAAA,SAAAA,CAAS,OAAA,GAAA,OAAA;AAaT,EAAA,CAAA,CAAUS,QAAAA,KAAV;AACE,IAAMA,QAAAA,CAAA,IAAA,GAAO,aAAA,CAAc,aAAA,EAAe,OAAO;AAAA,MACtD,SAAA,EAAW,KAAK,EAAA,EAAG;AAAA,MACnB,QAAA,EAAU,KAAK,EAAA,EAAG;AAAA,MAClB,GAAA,EAAK,KAAK,EAAA,EAAG;AAAA,MACb,MAAA,EAAQ,KAAK,EAAA,EAAG;AAAA,MAChB,QAAA,EAAU,KAAK,EAAA;AAAG,KACpB,CAAE,CAAA;AAAA,EAAA,CAAA,EAPa,OAAA,GAAAT,SAAAA,CAAA,OAAA,KAAAA,SAAAA,CAAA,OAAA,GAAA,EAAA,CAAA,CAAA;AAeV,EAAA,SAAS,MACd,OAAA,EAC6C;AAC7C,IAAA,MAAM,QAAA,GAAW,IAAI,YAAA,CAAa,OAAO,CAAA;AACzC,IAAA,OAAO,kBAAA,CAAmB,aAAa,QAAQ,CAAA;AAAA,EAEjD;AANO,EAAAA,SAAAA,CAAS,KAAA,GAAA,KAAA;AAaT,EAAA,CAAA,CAAUU,MAAAA,KAAV;AACE,IAAMA,MAAAA,CAAA,IAAA,GAAO,aAAA,CAAc,WAAA,EAAa,OAAO;AAAA,MACpD,IAAA,EAAM,KAAK,EAAA,EAAG;AAAA,MACd,MAAA,EAAQ,KAAK,EAAA;AAAG,KAClB,CAAE,CAAA;AAAA,EAAA,CAAA,EAJa,KAAA,GAAAV,SAAAA,CAAA,KAAA,KAAAA,SAAAA,CAAA,KAAA,GAAA,EAAA,CAAA,CAAA;AAYV,EAAA,SAAS,MACd,OAAA,EAC6C;AAC7C,IAAA,MAAM,QAAA,GAAW,IAAI,YAAA,CAAa,OAAO,CAAA;AACzC,IAAA,OAAO,kBAAA,CAAmB,aAAa,QAAQ,CAAA;AAAA,EAEjD;AANO,EAAAA,SAAAA,CAAS,KAAA,GAAA,KAAA;AAaT,EAAA,CAAA,CAAUW,MAAAA,KAAV;AACE,IAAMA,MAAAA,CAAA,IAAA,GAAO,aAAA,CAAc,WAAA,EAAa,OAAO;AAAA,MACpD,KAAA,EAAO,KAAK,EAAA;AAAG,KACjB,CAAE,CAAA;AAAA,EAAA,CAAA,EAHa,KAAA,GAAAX,SAAAA,CAAA,KAAA,KAAAA,SAAAA,CAAA,KAAA,GAAA,EAAA,CAAA,CAAA;AAAA,CAAA,EA9WF,QAAA,KAAA,QAAA,GAAA,EAAA,CAAA,CAAA;;;;"}
|
|
1
|
+
{"version":3,"file":"mockApis.esm.js","sources":["../../src/apis/mockApis.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n alertApiRef,\n analyticsApiRef,\n configApiRef,\n discoveryApiRef,\n errorApiRef,\n fetchApiRef,\n featureFlagsApiRef,\n identityApiRef,\n storageApiRef,\n translationApiRef,\n type AnalyticsApi,\n type ConfigApi,\n type DiscoveryApi,\n type ErrorApi,\n type FetchApi,\n type FeatureFlagState,\n type IdentityApi,\n type StorageApi,\n type TranslationApi,\n} from '@backstage/frontend-plugin-api';\nimport {\n permissionApiRef,\n type PermissionApi,\n} from '@backstage/plugin-permission-react';\nimport { JsonObject } from '@backstage/types';\nimport {\n AuthorizeResult,\n EvaluatePermissionRequest,\n} from '@backstage/plugin-permission-common';\nimport { MockAlertApi } from './AlertApi';\nimport { MockFeatureFlagsApi } from './FeatureFlagsApi';\nimport { MockAnalyticsApi } from './AnalyticsApi';\nimport { MockConfigApi } from './ConfigApi';\nimport { MockErrorApi } from './ErrorApi';\nimport { MockFetchApi, MockFetchApiOptions } from './FetchApi';\nimport { MockStorageApi } from './StorageApi';\nimport { MockPermissionApi } from './PermissionApi';\nimport { MockTranslationApi } from './TranslationApi';\nimport {\n mockWithApiFactory,\n type MockWithApiFactory,\n} from './MockWithApiFactory';\nimport { createApiMock } from './createApiMock';\n\n/**\n * Mock implementations of the core utility APIs, to be used in tests.\n *\n * @public\n * @remarks\n *\n * There are some variations among the APIs depending on what needs tests\n * might have, but overall there are two main usage patterns:\n *\n * 1: Creating an actual fake API instance, often with a simplified version\n * of functionality, by calling the mock API itself as a function.\n *\n * ```ts\n * // The function often accepts parameters that control its behavior\n * const foo = mockApis.foo();\n * ```\n *\n * 2: Creating a mock API, where all methods are replaced with jest mocks, by\n * calling the API's `mock` function.\n *\n * ```ts\n * // You can optionally supply a subset of its methods to implement\n * const foo = mockApis.foo.mock({\n * someMethod: () => 'mocked result',\n * });\n * // After exercising your test, you can make assertions on the mock:\n * expect(foo.someMethod).toHaveBeenCalledTimes(2);\n * expect(foo.otherMethod).toHaveBeenCalledWith(testData);\n * ```\n */\nexport namespace mockApis {\n /**\n * Fake implementation of {@link @backstage/frontend-plugin-api#AlertApi}.\n *\n * @public\n * @example\n *\n * ```tsx\n * const alertApi = mockApis.alert();\n * alertApi.post({ message: 'Test alert' });\n * expect(alertApi.getAlerts()).toHaveLength(1);\n * ```\n */\n export function alert(): MockWithApiFactory<MockAlertApi> {\n const instance = new MockAlertApi();\n return mockWithApiFactory(\n alertApiRef,\n instance,\n ) as MockWithApiFactory<MockAlertApi>;\n }\n /**\n * Mock helpers for {@link @backstage/frontend-plugin-api#AlertApi}.\n *\n * @public\n */\n export namespace alert {\n /**\n * Creates a mock implementation of\n * {@link @backstage/frontend-plugin-api#AlertApi}. All methods are\n * replaced with jest mock functions, and you can optionally pass in a\n * subset of methods with an explicit implementation.\n *\n * @public\n */\n export const mock = createApiMock(alertApiRef, () => ({\n post: jest.fn(),\n alert$: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/frontend-plugin-api#FeatureFlagsApi}.\n *\n * @public\n * @example\n *\n * ```tsx\n * const featureFlagsApi = mockApis.featureFlags({\n * initialStates: { 'my-feature': FeatureFlagState.Active },\n * });\n * expect(featureFlagsApi.isActive('my-feature')).toBe(true);\n * ```\n */\n export function featureFlags(options?: {\n initialStates?: Record<string, FeatureFlagState>;\n }): MockWithApiFactory<MockFeatureFlagsApi> {\n const instance = new MockFeatureFlagsApi(options);\n return mockWithApiFactory(\n featureFlagsApiRef,\n instance,\n ) as MockWithApiFactory<MockFeatureFlagsApi>;\n }\n /**\n * Mock helpers for {@link @backstage/frontend-plugin-api#FeatureFlagsApi}.\n *\n * @public\n */\n export namespace featureFlags {\n /**\n * Creates a mock implementation of\n * {@link @backstage/frontend-plugin-api#FeatureFlagsApi}. All methods are\n * replaced with jest mock functions, and you can optionally pass in a\n * subset of methods with an explicit implementation.\n *\n * @public\n */\n export const mock = createApiMock(featureFlagsApiRef, () => ({\n registerFlag: jest.fn(),\n getRegisteredFlags: jest.fn(),\n isActive: jest.fn(),\n save: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#AnalyticsApi}.\n *\n * @public\n */\n export function analytics(): MockAnalyticsApi &\n MockWithApiFactory<AnalyticsApi> {\n const instance = new MockAnalyticsApi();\n return mockWithApiFactory(analyticsApiRef, instance) as MockAnalyticsApi &\n MockWithApiFactory<AnalyticsApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#AnalyticsApi}.\n *\n * @public\n */\n export namespace analytics {\n export const mock = createApiMock(analyticsApiRef, () => ({\n captureEvent: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/frontend-plugin-api#TranslationApi}.\n * By default returns the default translation.\n *\n * @public\n */\n export function translation(): MockTranslationApi &\n MockWithApiFactory<TranslationApi> {\n const instance = MockTranslationApi.create();\n return mockWithApiFactory(\n translationApiRef,\n instance,\n ) as MockTranslationApi & MockWithApiFactory<TranslationApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/frontend-plugin-api#TranslationApi}.\n *\n * @public\n */\n export namespace translation {\n /**\n * Creates a mock of {@link @backstage/frontend-plugin-api#TranslationApi}.\n *\n * @public\n */\n export const mock = createApiMock(translationApiRef, () => ({\n getTranslation: jest.fn(),\n translation$: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#ConfigApi}.\n *\n * @public\n */\n export function config(options?: {\n data?: JsonObject;\n }): MockConfigApi & MockWithApiFactory<ConfigApi> {\n const instance = new MockConfigApi({ data: options?.data ?? {} });\n return mockWithApiFactory(configApiRef, instance) as MockConfigApi &\n MockWithApiFactory<ConfigApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#ConfigApi}.\n *\n * @public\n */\n export namespace config {\n export const mock = createApiMock(configApiRef, () => ({\n has: jest.fn(),\n keys: jest.fn(),\n get: jest.fn(),\n getOptional: jest.fn(),\n getConfig: jest.fn(),\n getOptionalConfig: jest.fn(),\n getConfigArray: jest.fn(),\n getOptionalConfigArray: jest.fn(),\n getNumber: jest.fn(),\n getOptionalNumber: jest.fn(),\n getBoolean: jest.fn(),\n getOptionalBoolean: jest.fn(),\n getString: jest.fn(),\n getOptionalString: jest.fn(),\n getStringArray: jest.fn(),\n getOptionalStringArray: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#DiscoveryApi}.\n *\n * @public\n */\n export function discovery(options?: {\n baseUrl?: string;\n }): DiscoveryApi & MockWithApiFactory<DiscoveryApi> {\n const baseUrl = options?.baseUrl ?? 'http://example.com';\n const instance: DiscoveryApi = {\n async getBaseUrl(pluginId: string) {\n return `${baseUrl}/api/${pluginId}`;\n },\n };\n return mockWithApiFactory(discoveryApiRef, instance) as DiscoveryApi &\n MockWithApiFactory<DiscoveryApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#DiscoveryApi}.\n *\n * @public\n */\n export namespace discovery {\n export const mock = createApiMock(discoveryApiRef, () => ({\n getBaseUrl: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#IdentityApi}.\n *\n * @public\n */\n export function identity(options?: {\n userEntityRef?: string;\n ownershipEntityRefs?: string[];\n token?: string;\n email?: string;\n displayName?: string;\n picture?: string;\n }): MockWithApiFactory<IdentityApi> {\n const {\n userEntityRef = 'user:default/test',\n ownershipEntityRefs = ['user:default/test'],\n token,\n email,\n displayName,\n picture,\n } = options ?? {};\n const instance: IdentityApi = {\n async getBackstageIdentity() {\n return { type: 'user', ownershipEntityRefs, userEntityRef };\n },\n async getCredentials() {\n return { token };\n },\n async getProfileInfo() {\n return { email, displayName, picture };\n },\n async signOut() {},\n };\n return mockWithApiFactory(identityApiRef, instance) as IdentityApi &\n MockWithApiFactory<IdentityApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#IdentityApi}.\n *\n * @public\n */\n export namespace identity {\n export const mock = createApiMock(identityApiRef, () => ({\n getBackstageIdentity: jest.fn(),\n getCredentials: jest.fn(),\n getProfileInfo: jest.fn(),\n signOut: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/plugin-permission-react#PermissionApi}.\n *\n * @public\n */\n export function permission(options?: {\n authorize?:\n | AuthorizeResult.ALLOW\n | AuthorizeResult.DENY\n | ((\n request: EvaluatePermissionRequest,\n ) => AuthorizeResult.ALLOW | AuthorizeResult.DENY);\n }): MockPermissionApi & MockWithApiFactory<PermissionApi> {\n const authorizeInput = options?.authorize;\n const handler =\n typeof authorizeInput === 'function'\n ? authorizeInput\n : () => authorizeInput ?? AuthorizeResult.ALLOW;\n const instance = new MockPermissionApi(handler);\n return mockWithApiFactory(permissionApiRef, instance) as MockPermissionApi &\n MockWithApiFactory<PermissionApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/plugin-permission-react#PermissionApi}.\n *\n * @public\n */\n export namespace permission {\n export const mock = createApiMock(permissionApiRef, () => ({\n authorize: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#StorageApi}.\n *\n * @public\n */\n export function storage(options?: {\n data?: JsonObject;\n }): MockStorageApi & MockWithApiFactory<StorageApi> {\n const instance = MockStorageApi.create(options?.data);\n return mockWithApiFactory(storageApiRef, instance) as MockStorageApi &\n MockWithApiFactory<StorageApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#StorageApi}.\n *\n * @public\n */\n export namespace storage {\n export const mock = createApiMock(storageApiRef, () => ({\n forBucket: jest.fn(),\n snapshot: jest.fn(),\n set: jest.fn(),\n remove: jest.fn(),\n observe$: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#ErrorApi}.\n *\n * @public\n */\n export function error(options?: {\n collect?: boolean;\n }): MockErrorApi & MockWithApiFactory<ErrorApi> {\n const instance = new MockErrorApi(options);\n return mockWithApiFactory(errorApiRef, instance) as MockErrorApi &\n MockWithApiFactory<ErrorApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#ErrorApi}.\n *\n * @public\n */\n export namespace error {\n export const mock = createApiMock(errorApiRef, () => ({\n post: jest.fn(),\n error$: jest.fn(),\n }));\n }\n\n /**\n * Fake implementation of {@link @backstage/core-plugin-api#FetchApi}.\n *\n * @public\n */\n export function fetch(\n options?: MockFetchApiOptions,\n ): MockFetchApi & MockWithApiFactory<FetchApi> {\n const instance = new MockFetchApi(options);\n return mockWithApiFactory(fetchApiRef, instance) as MockFetchApi &\n MockWithApiFactory<FetchApi>;\n }\n\n /**\n * Mock helpers for {@link @backstage/core-plugin-api#FetchApi}.\n *\n * @public\n */\n export namespace fetch {\n export const mock = createApiMock(fetchApiRef, () => ({\n fetch: jest.fn(),\n }));\n }\n}\n"],"names":["mockApis","alert","featureFlags","analytics","translation","config","discovery","identity","permission","storage","error","fetch"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { Fragment } from 'react';
|
|
3
3
|
import { Link, MemoryRouter } from 'react-router-dom';
|
|
4
|
-
import {
|
|
4
|
+
import { prepareSpecializedApp } from '@backstage/frontend-app-api';
|
|
5
5
|
import { render } from '@testing-library/react';
|
|
6
6
|
import { ConfigReader } from '@backstage/config';
|
|
7
7
|
import { coreExtensionData, NavItemBlueprint, useRouteRef, createExtension, createFrontendModule, createFrontendPlugin, createApiFactory } from '@backstage/frontend-plugin-api';
|
|
@@ -122,7 +122,7 @@ function renderInTestApp(element, options) {
|
|
|
122
122
|
if (options?.features) {
|
|
123
123
|
features.push(...options.features);
|
|
124
124
|
}
|
|
125
|
-
const app =
|
|
125
|
+
const app = prepareSpecializedApp({
|
|
126
126
|
features,
|
|
127
127
|
config: ConfigReader.fromConfigs([
|
|
128
128
|
{
|
|
@@ -140,7 +140,7 @@ function renderInTestApp(element, options) {
|
|
|
140
140
|
return createApiFactory(apiRef, implementation);
|
|
141
141
|
})
|
|
142
142
|
}
|
|
143
|
-
});
|
|
143
|
+
}).finalize();
|
|
144
144
|
return render(
|
|
145
145
|
app.tree.root.instance.getData(coreExtensionData.reactElement)
|
|
146
146
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderInTestApp.esm.js","sources":["../../src/app/renderInTestApp.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Fragment } from 'react';\nimport { Link, MemoryRouter } from 'react-router-dom';\nimport { createSpecializedApp } from '@backstage/frontend-app-api';\nimport { RenderResult, render } from '@testing-library/react';\nimport { ConfigReader } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport {\n createExtension,\n ExtensionDefinition,\n coreExtensionData,\n RouteRef,\n useRouteRef,\n IconComponent,\n NavItemBlueprint,\n createFrontendPlugin,\n FrontendFeature,\n createFrontendModule,\n createApiFactory,\n type ApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { RouterBlueprint } from '@backstage/plugin-app-react';\nimport appPlugin from '@backstage/plugin-app';\nimport { getMockApiFactory } from '../apis/MockWithApiFactory';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport type { CreateSpecializedAppInternalOptions } from '../../../frontend-app-api/src/wiring/createSpecializedApp';\nimport { TestApiPairs } from '../apis/TestApiProvider';\n\nconst DEFAULT_MOCK_CONFIG = {\n app: { baseUrl: 'http://localhost:3000' },\n backend: { baseUrl: 'http://localhost:7007' },\n};\n\n/**\n * Options to customize the behavior of the test app.\n * @public\n */\nexport type TestAppOptions<TApiPairs extends any[] = any[]> = {\n /**\n * An object of paths to mount route ref on, with the key being the path and the value\n * being the RouteRef that the path will be bound to. This allows the route refs to be\n * used by `useRouteRef` in the rendered elements.\n *\n * @example\n * ```ts\n * renderInTestApp(<MyComponent />, {\n * mountedRoutes: {\n * '/my-path': myRouteRef,\n * }\n * })\n * // ...\n * const link = useRouteRef(myRouteRef)\n * ```\n */\n mountedRoutes?: { [path: string]: RouteRef };\n\n /**\n * Additional configuration passed to the app when rendering elements inside it.\n */\n config?: JsonObject;\n\n /**\n * Additional features to add to the test app.\n */\n features?: FrontendFeature[];\n\n /**\n * Initial route entries to use for the router.\n */\n initialRouteEntries?: string[];\n\n /**\n * API overrides to provide to the test app. Use `mockApis` helpers\n * from `@backstage/frontend-test-utils` to create mock implementations.\n *\n * @example\n * ```ts\n * import { mockApis } from '@backstage/frontend-test-utils';\n *\n * renderInTestApp(<MyComponent />, {\n * apis: [mockApis.identity({ userEntityRef: 'user:default/guest' })],\n * })\n * ```\n */\n apis?: readonly [...TestApiPairs<TApiPairs>];\n};\n\nconst NavItem = (props: {\n routeRef: RouteRef<undefined>;\n title: string;\n icon: IconComponent;\n}) => {\n const { routeRef, title, icon: Icon } = props;\n const link = useRouteRef(routeRef);\n if (!link) {\n return null;\n }\n return (\n <li>\n <Link to={link()}>\n <Icon /> {title}\n </Link>\n </li>\n );\n};\n\nconst appPluginOverride = appPlugin.withOverrides({\n extensions: [\n appPlugin.getExtension('sign-in-page:app').override({\n disabled: true,\n }),\n appPlugin.getExtension('app/layout').override({\n disabled: true,\n }),\n appPlugin.getExtension('app/routes').override({\n disabled: true,\n }),\n appPlugin.getExtension('app/nav').override({\n output: [coreExtensionData.reactElement],\n factory(_originalFactory, { inputs }) {\n return [\n coreExtensionData.reactElement(\n <nav>\n <ul>\n {inputs.items.map((item, index) => {\n const { icon, title, routeRef } = item.get(\n NavItemBlueprint.dataRefs.target,\n );\n\n return (\n <NavItem\n key={index}\n icon={icon}\n title={title}\n routeRef={routeRef}\n />\n );\n })}\n </ul>\n </nav>,\n ),\n ];\n },\n }),\n ],\n});\n\n/**\n * @public\n * Renders the given element in a test app, for use in unit tests.\n */\nexport function renderInTestApp<const TApiPairs extends any[] = any[]>(\n element: JSX.Element,\n options?: TestAppOptions<TApiPairs>,\n): RenderResult {\n const extensions: Array<ExtensionDefinition> = [\n createExtension({\n attachTo: { id: 'app/root', input: 'children' },\n output: [coreExtensionData.reactElement],\n factory: () => {\n return [coreExtensionData.reactElement(element)];\n },\n }),\n ];\n\n if (options?.mountedRoutes) {\n for (const [path, routeRef] of Object.entries(options.mountedRoutes)) {\n // TODO(Rugvip): add support for external route refs\n extensions.push(\n createExtension({\n kind: 'test-route',\n name: path,\n attachTo: { id: 'app/root', input: 'elements' },\n output: [\n coreExtensionData.reactElement,\n coreExtensionData.routePath,\n coreExtensionData.routeRef,\n ],\n factory: () => [\n coreExtensionData.reactElement(<Fragment />),\n coreExtensionData.routePath(path),\n coreExtensionData.routeRef(routeRef),\n ],\n }),\n );\n }\n }\n\n const features: FrontendFeature[] = [\n createFrontendModule({\n pluginId: 'app',\n extensions: [\n RouterBlueprint.make({\n params: {\n component: ({ children }) => (\n <MemoryRouter\n initialEntries={options?.initialRouteEntries}\n future={{\n v7_relativeSplatPath: false,\n v7_startTransition: false,\n }}\n >\n {children}\n </MemoryRouter>\n ),\n },\n }),\n ],\n }),\n createFrontendPlugin({\n pluginId: 'test',\n extensions,\n }),\n appPluginOverride,\n ];\n\n if (options?.features) {\n features.push(...options.features);\n }\n\n const app = createSpecializedApp({\n features,\n config: ConfigReader.fromConfigs([\n {\n context: 'render-config',\n data: options?.config ?? DEFAULT_MOCK_CONFIG,\n },\n ]),\n __internal: options?.apis && {\n apiFactoryOverrides: options.apis.map(entry => {\n const mockFactory = getMockApiFactory(entry);\n if (mockFactory) {\n return mockFactory;\n }\n const [apiRef, implementation] = entry as readonly [ApiRef<any>, any];\n return createApiFactory(apiRef, implementation);\n }),\n },\n } as CreateSpecializedAppInternalOptions);\n\n return render(\n app.tree.root.instance!.getData(coreExtensionData.reactElement),\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"renderInTestApp.esm.js","sources":["../../src/app/renderInTestApp.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Fragment } from 'react';\nimport { Link, MemoryRouter } from 'react-router-dom';\nimport { prepareSpecializedApp } from '@backstage/frontend-app-api';\nimport { RenderResult, render } from '@testing-library/react';\nimport { ConfigReader } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport {\n createExtension,\n ExtensionDefinition,\n coreExtensionData,\n RouteRef,\n useRouteRef,\n IconComponent,\n NavItemBlueprint,\n createFrontendPlugin,\n FrontendFeature,\n createFrontendModule,\n createApiFactory,\n type ApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { RouterBlueprint } from '@backstage/plugin-app-react';\nimport appPlugin from '@backstage/plugin-app';\nimport { getMockApiFactory } from '../apis/MockWithApiFactory';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport type { CreateSpecializedAppInternalOptions } from '../../../frontend-app-api/src/wiring/createSpecializedApp';\nimport { TestApiPairs } from '../apis/TestApiProvider';\n\nconst DEFAULT_MOCK_CONFIG = {\n app: { baseUrl: 'http://localhost:3000' },\n backend: { baseUrl: 'http://localhost:7007' },\n};\n\n/**\n * Options to customize the behavior of the test app.\n * @public\n */\nexport type TestAppOptions<TApiPairs extends any[] = any[]> = {\n /**\n * An object of paths to mount route ref on, with the key being the path and the value\n * being the RouteRef that the path will be bound to. This allows the route refs to be\n * used by `useRouteRef` in the rendered elements.\n *\n * @example\n * ```ts\n * renderInTestApp(<MyComponent />, {\n * mountedRoutes: {\n * '/my-path': myRouteRef,\n * }\n * })\n * // ...\n * const link = useRouteRef(myRouteRef)\n * ```\n */\n mountedRoutes?: { [path: string]: RouteRef };\n\n /**\n * Additional configuration passed to the app when rendering elements inside it.\n */\n config?: JsonObject;\n\n /**\n * Additional features to add to the test app.\n */\n features?: FrontendFeature[];\n\n /**\n * Initial route entries to use for the router.\n */\n initialRouteEntries?: string[];\n\n /**\n * API overrides to provide to the test app. Use `mockApis` helpers\n * from `@backstage/frontend-test-utils` to create mock implementations.\n *\n * @example\n * ```ts\n * import { mockApis } from '@backstage/frontend-test-utils';\n *\n * renderInTestApp(<MyComponent />, {\n * apis: [mockApis.identity({ userEntityRef: 'user:default/guest' })],\n * })\n * ```\n */\n apis?: readonly [...TestApiPairs<TApiPairs>];\n};\n\nconst NavItem = (props: {\n routeRef: RouteRef<undefined>;\n title: string;\n icon: IconComponent;\n}) => {\n const { routeRef, title, icon: Icon } = props;\n const link = useRouteRef(routeRef);\n if (!link) {\n return null;\n }\n return (\n <li>\n <Link to={link()}>\n <Icon /> {title}\n </Link>\n </li>\n );\n};\n\nconst appPluginOverride = appPlugin.withOverrides({\n extensions: [\n appPlugin.getExtension('sign-in-page:app').override({\n disabled: true,\n }),\n appPlugin.getExtension('app/layout').override({\n disabled: true,\n }),\n appPlugin.getExtension('app/routes').override({\n disabled: true,\n }),\n appPlugin.getExtension('app/nav').override({\n output: [coreExtensionData.reactElement],\n factory(_originalFactory, { inputs }) {\n return [\n coreExtensionData.reactElement(\n <nav>\n <ul>\n {inputs.items.map((item, index) => {\n const { icon, title, routeRef } = item.get(\n NavItemBlueprint.dataRefs.target,\n );\n\n return (\n <NavItem\n key={index}\n icon={icon}\n title={title}\n routeRef={routeRef}\n />\n );\n })}\n </ul>\n </nav>,\n ),\n ];\n },\n }),\n ],\n});\n\n/**\n * @public\n * Renders the given element in a test app, for use in unit tests.\n */\nexport function renderInTestApp<const TApiPairs extends any[] = any[]>(\n element: JSX.Element,\n options?: TestAppOptions<TApiPairs>,\n): RenderResult {\n const extensions: Array<ExtensionDefinition> = [\n createExtension({\n attachTo: { id: 'app/root', input: 'children' },\n output: [coreExtensionData.reactElement],\n factory: () => {\n return [coreExtensionData.reactElement(element)];\n },\n }),\n ];\n\n if (options?.mountedRoutes) {\n for (const [path, routeRef] of Object.entries(options.mountedRoutes)) {\n // TODO(Rugvip): add support for external route refs\n extensions.push(\n createExtension({\n kind: 'test-route',\n name: path,\n attachTo: { id: 'app/root', input: 'elements' },\n output: [\n coreExtensionData.reactElement,\n coreExtensionData.routePath,\n coreExtensionData.routeRef,\n ],\n factory: () => [\n coreExtensionData.reactElement(<Fragment />),\n coreExtensionData.routePath(path),\n coreExtensionData.routeRef(routeRef),\n ],\n }),\n );\n }\n }\n\n const features: FrontendFeature[] = [\n createFrontendModule({\n pluginId: 'app',\n extensions: [\n RouterBlueprint.make({\n params: {\n component: ({ children }) => (\n <MemoryRouter\n initialEntries={options?.initialRouteEntries}\n future={{\n v7_relativeSplatPath: false,\n v7_startTransition: false,\n }}\n >\n {children}\n </MemoryRouter>\n ),\n },\n }),\n ],\n }),\n createFrontendPlugin({\n pluginId: 'test',\n extensions,\n }),\n appPluginOverride,\n ];\n\n if (options?.features) {\n features.push(...options.features);\n }\n\n const app = prepareSpecializedApp({\n features,\n config: ConfigReader.fromConfigs([\n {\n context: 'render-config',\n data: options?.config ?? DEFAULT_MOCK_CONFIG,\n },\n ]),\n __internal: options?.apis && {\n apiFactoryOverrides: options.apis.map(entry => {\n const mockFactory = getMockApiFactory(entry);\n if (mockFactory) {\n return mockFactory;\n }\n const [apiRef, implementation] = entry as readonly [ApiRef<any>, any];\n return createApiFactory(apiRef, implementation);\n }),\n },\n } as CreateSpecializedAppInternalOptions).finalize();\n\n return render(\n app.tree.root.instance!.getData(coreExtensionData.reactElement),\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { Fragment } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { prepareSpecializedApp } from '@backstage/frontend-app-api';
|
|
4
4
|
import { createExtension, coreExtensionData, createFrontendModule, createFrontendPlugin, createApiFactory } from '@backstage/frontend-plugin-api';
|
|
5
5
|
import { render } from '@testing-library/react';
|
|
6
6
|
import appPlugin from '@backstage/plugin-app';
|
|
@@ -73,7 +73,7 @@ function renderTestApp(options) {
|
|
|
73
73
|
if (options?.features) {
|
|
74
74
|
features.push(...options.features);
|
|
75
75
|
}
|
|
76
|
-
const app =
|
|
76
|
+
const app = prepareSpecializedApp({
|
|
77
77
|
features,
|
|
78
78
|
config: ConfigReader.fromConfigs([
|
|
79
79
|
{
|
|
@@ -91,7 +91,7 @@ function renderTestApp(options) {
|
|
|
91
91
|
return createApiFactory(apiRef, implementation);
|
|
92
92
|
})
|
|
93
93
|
}
|
|
94
|
-
});
|
|
94
|
+
}).finalize();
|
|
95
95
|
return render(
|
|
96
96
|
app.tree.root.instance.getData(coreExtensionData.reactElement)
|
|
97
97
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderTestApp.esm.js","sources":["../../src/app/renderTestApp.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Fragment } from 'react';\nimport {
|
|
1
|
+
{"version":3,"file":"renderTestApp.esm.js","sources":["../../src/app/renderTestApp.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Fragment } from 'react';\nimport { prepareSpecializedApp } from '@backstage/frontend-app-api';\nimport {\n coreExtensionData,\n createApiFactory,\n createExtension,\n createFrontendModule,\n createFrontendPlugin,\n ExtensionDefinition,\n FrontendFeature,\n RouteRef,\n type ApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { render, type RenderResult } from '@testing-library/react';\nimport appPlugin from '@backstage/plugin-app';\nimport { JsonObject } from '@backstage/types';\nimport { ConfigReader } from '@backstage/config';\nimport { MemoryRouter } from 'react-router-dom';\nimport { RouterBlueprint } from '@backstage/plugin-app-react';\nimport { getMockApiFactory } from '../apis/MockWithApiFactory';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport type { CreateSpecializedAppInternalOptions } from '../../../frontend-app-api/src/wiring/createSpecializedApp';\nimport { TestApiPairs } from '../apis/TestApiProvider';\n\nconst DEFAULT_MOCK_CONFIG = {\n app: { baseUrl: 'http://localhost:3000' },\n backend: { baseUrl: 'http://localhost:7007' },\n};\n\n/**\n * Options for `renderTestApp`.\n *\n * @public\n */\nexport type RenderTestAppOptions<TApiPairs extends any[] = any[]> = {\n /**\n * Additional configuration passed to the app when rendering elements inside it.\n */\n config?: JsonObject;\n /**\n * Additional extensions to add to the test app.\n */\n extensions?: ExtensionDefinition<any>[];\n\n /**\n * Additional features to add to the test app.\n */\n features?: FrontendFeature[];\n\n /**\n * Initial route entries to use for the router.\n */\n initialRouteEntries?: string[];\n\n /**\n * An object of paths to mount route refs on, with the key being the path and\n * the value being the RouteRef that the path will be bound to. This allows\n * the route refs to be used by `useRouteRef` in the rendered elements.\n *\n * @example\n * ```ts\n * renderTestApp({\n * mountedRoutes: {\n * '/my-path': myRouteRef,\n * },\n * extensions: [...],\n * })\n * ```\n */\n mountedRoutes?: { [path: string]: RouteRef };\n\n /**\n * API overrides to provide to the test app. Use `mockApis` helpers\n * from `@backstage/frontend-test-utils` to create mock implementations.\n *\n * @example\n * ```ts\n * import { mockApis } from '@backstage/frontend-test-utils';\n *\n * renderTestApp({\n * apis: [mockApis.identity({ userEntityRef: 'user:default/guest' })],\n * extensions: [...],\n * })\n * ```\n */\n apis?: readonly [...TestApiPairs<TApiPairs>];\n};\n\nconst appPluginOverride = appPlugin.withOverrides({\n extensions: [\n appPlugin.getExtension('sign-in-page:app').override({\n disabled: true,\n }),\n ],\n});\n\n/**\n * Renders the provided extensions inside a Backstage app, returning the same\n * utilities as `@testing-library/react` `render` function.\n *\n * @public\n */\nexport function renderTestApp<const TApiPairs extends any[] = any[]>(\n options?: RenderTestAppOptions<TApiPairs>,\n): RenderResult {\n const extensions = [...(options?.extensions ?? [])];\n\n if (options?.mountedRoutes) {\n for (const [path, routeRef] of Object.entries(options.mountedRoutes)) {\n extensions.push(\n createExtension({\n kind: 'test-route',\n name: path,\n attachTo: { id: 'app/routes', input: 'routes' },\n output: [\n coreExtensionData.reactElement,\n coreExtensionData.routePath,\n coreExtensionData.routeRef,\n ],\n factory: () => [\n coreExtensionData.reactElement(<Fragment />),\n coreExtensionData.routePath(path),\n coreExtensionData.routeRef(routeRef),\n ],\n }),\n );\n }\n }\n\n const features: FrontendFeature[] = [\n createFrontendModule({\n pluginId: 'app',\n extensions: [\n RouterBlueprint.make({\n params: {\n component: ({ children }) => (\n <MemoryRouter\n initialEntries={options?.initialRouteEntries}\n future={{\n v7_relativeSplatPath: false,\n v7_startTransition: false,\n }}\n >\n {children}\n </MemoryRouter>\n ),\n },\n }),\n ],\n }),\n createFrontendPlugin({\n pluginId: 'test',\n extensions,\n }),\n appPluginOverride,\n ];\n\n if (options?.features) {\n features.push(...options.features);\n }\n\n const app = prepareSpecializedApp({\n features,\n config: ConfigReader.fromConfigs([\n {\n context: 'render-config',\n data: options?.config ?? DEFAULT_MOCK_CONFIG,\n },\n ]),\n __internal: options?.apis && {\n apiFactoryOverrides: options.apis.map(entry => {\n const mockFactory = getMockApiFactory(entry);\n if (mockFactory) {\n return mockFactory;\n }\n const [apiRef, implementation] = entry as readonly [ApiRef<any>, any];\n return createApiFactory(apiRef, implementation);\n }),\n },\n } as CreateSpecializedAppInternalOptions).finalize();\n\n return render(\n app.tree.root.instance!.getData(coreExtensionData.reactElement),\n );\n}\n"],"names":[],"mappings":"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"}
|