@backstage/test-utils 0.2.5 → 1.0.0

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 CHANGED
@@ -1,5 +1,47 @@
1
1
  # @backstage/test-utils
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - b58c70c223: This package has been promoted to v1.0! To understand how this change affects the package, please check out our [versioning policy](https://backstage.io/docs/overview/versioning-policy).
8
+
9
+ ### Patch Changes
10
+
11
+ - a422d7ce5e: chore(deps): bump `@testing-library/react` from 11.2.6 to 12.1.3
12
+ - f24ef7864e: Minor typo fixes
13
+ - Updated dependencies
14
+ - @backstage/core-app-api@1.0.0
15
+ - @backstage/core-plugin-api@1.0.0
16
+ - @backstage/plugin-permission-react@0.3.4
17
+ - @backstage/config@1.0.0
18
+ - @backstage/types@1.0.0
19
+ - @backstage/plugin-permission-common@0.5.3
20
+
21
+ ## 0.3.0
22
+
23
+ ### Minor Changes
24
+
25
+ - bb2bb36651: **BREAKING**: Removed the deprecated `get` method from `StorageAPI` and its implementations, this method has been replaced by the `snapshot` method. The return value from snapshot no longer includes `newValue` which has been replaced by `value`. For getting notified when a value changes, use `observe# @backstage/test-utils.
26
+ - af5eaa87f4: **BREAKING**: Removed deprecated `auth0AuthApiRef`, `oauth2ApiRef`, `samlAuthApiRef` and `oidcAuthApiRef` as these APIs are too generic to be useful. Instructions for how to migrate can be found at [https://backstage.io/docs/api/deprecations#generic-auth-api-refs](https://backstage.io/docs/api/deprecations#generic-auth-api-refs).
27
+
28
+ ### Patch Changes
29
+
30
+ - Updated dependencies
31
+ - @backstage/core-app-api@0.6.0
32
+ - @backstage/core-plugin-api@0.8.0
33
+ - @backstage/plugin-permission-common@0.5.2
34
+ - @backstage/plugin-permission-react@0.3.3
35
+
36
+ ## 0.2.6
37
+
38
+ ### Patch Changes
39
+
40
+ - Updated dependencies
41
+ - @backstage/core-plugin-api@0.7.0
42
+ - @backstage/core-app-api@0.5.4
43
+ - @backstage/plugin-permission-react@0.3.2
44
+
3
45
  ## 0.2.5
4
46
 
5
47
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -91,7 +91,7 @@ declare type ErrorWithContext = {
91
91
  };
92
92
  /**
93
93
  * Mock implementation of the {@link core-plugin-api#ErrorApi} to be used in tests.
94
- * Incudes withForError and getErrors methods for error testing.
94
+ * Includes withForError and getErrors methods for error testing.
95
95
  * @public
96
96
  */
97
97
  declare class MockErrorApi implements ErrorApi {
@@ -213,7 +213,6 @@ declare class MockStorageApi implements StorageApi {
213
213
  private constructor();
214
214
  static create(data?: MockStorageBucket): MockStorageApi;
215
215
  forBucket(name: string): StorageApi;
216
- get<T>(key: string): T | undefined;
217
216
  snapshot<T extends JsonValue>(key: string): StorageValueSnapshot<T>;
218
217
  set<T>(key: string, data: T): Promise<void>;
219
218
  remove(key: string): Promise<void>;
@@ -302,33 +301,40 @@ declare function setupRequestMockHandlers(worker: {
302
301
 
303
302
  /**
304
303
  * Severity levels of {@link CollectedLogs}
305
- * @public */
304
+ * @public
305
+ */
306
306
  declare type LogFuncs = 'log' | 'warn' | 'error';
307
307
  /**
308
308
  * AsyncLogCollector type used in {@link (withLogCollector:1)} callback function.
309
- * @public */
309
+ * @public
310
+ */
310
311
  declare type AsyncLogCollector = () => Promise<void>;
311
312
  /**
312
313
  * SyncLogCollector type used in {@link (withLogCollector:2)} callback function.
313
- * @public */
314
+ * @public
315
+ */
314
316
  declare type SyncLogCollector = () => void;
315
317
  /**
316
318
  * Union type used in {@link (withLogCollector:3)} callback function.
317
- * @public */
319
+ * @public
320
+ */
318
321
  declare type LogCollector = AsyncLogCollector | SyncLogCollector;
319
322
  /**
320
323
  * Map of severity level and corresponding log lines.
321
- * @public */
324
+ * @public
325
+ */
322
326
  declare type CollectedLogs<T extends LogFuncs> = {
323
327
  [key in T]: string[];
324
328
  };
325
329
  /**
326
330
  * Asynchronous log collector with that collects all categories
327
- * @public */
331
+ * @public
332
+ */
328
333
  declare function withLogCollector(callback: AsyncLogCollector): Promise<CollectedLogs<LogFuncs>>;
329
334
  /**
330
335
  * Synchronous log collector with that collects all categories
331
- * @public */
336
+ * @public
337
+ */
332
338
  declare function withLogCollector(callback: SyncLogCollector): CollectedLogs<LogFuncs>;
333
339
  /**
334
340
  * Asynchronous log collector with that only collects selected categories
@@ -337,7 +343,8 @@ declare function withLogCollector(callback: SyncLogCollector): CollectedLogs<Log
337
343
  declare function withLogCollector<T extends LogFuncs>(logsToCollect: T[], callback: AsyncLogCollector): Promise<CollectedLogs<T>>;
338
344
  /**
339
345
  * Synchronous log collector with that only collects selected categories
340
- * @public */
346
+ * @public
347
+ */
341
348
  declare function withLogCollector<T extends LogFuncs>(logsToCollect: T[], callback: SyncLogCollector): CollectedLogs<T>;
342
349
 
343
350
  /**
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ConfigReader } from '@backstage/config';
2
- import { createFetchApi, FetchMiddlewares, UrlPatternDiscovery, AlertApiForwarder, NoOpAnalyticsApi, ErrorAlerter, ErrorApiForwarder, UnhandledErrorForwarder, WebStorage, OAuthRequestManager, GoogleAuth, MicrosoftAuth, GithubAuth, OktaAuth, GitlabAuth, Auth0Auth, OAuth2, SamlAuth, OneLoginAuth, BitbucketAuth, AtlassianAuth, createSpecializedApp, ApiProvider } from '@backstage/core-app-api';
2
+ import { createFetchApi, FetchMiddlewares, UrlPatternDiscovery, AlertApiForwarder, NoOpAnalyticsApi, ErrorAlerter, ErrorApiForwarder, UnhandledErrorForwarder, WebStorage, OAuthRequestManager, GoogleAuth, MicrosoftAuth, GithubAuth, OktaAuth, GitlabAuth, OneLoginAuth, BitbucketAuth, AtlassianAuth, createSpecializedApp, ApiProvider } from '@backstage/core-app-api';
3
3
  import crossFetch, { Response } from 'cross-fetch';
4
4
  import { AuthorizeResult } from '@backstage/plugin-permission-common';
5
5
  import ObservableImpl from 'zen-observable';
@@ -10,7 +10,7 @@ import { lightTheme } from '@backstage/theme';
10
10
  import { ThemeProvider } from '@material-ui/core/styles';
11
11
  import { CssBaseline } from '@material-ui/core';
12
12
  import MockIcon from '@material-ui/icons/AcUnit';
13
- import { createApiFactory, discoveryApiRef, configApiRef, alertApiRef, analyticsApiRef, errorApiRef, storageApiRef, oauthRequestApiRef, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, oktaAuthApiRef, gitlabAuthApiRef, auth0AuthApiRef, oauth2ApiRef, samlAuthApiRef, oneloginAuthApiRef, oidcAuthApiRef, bitbucketAuthApiRef, atlassianAuthApiRef, createRouteRef, attachComponentData } from '@backstage/core-plugin-api';
13
+ import { createApiFactory, discoveryApiRef, configApiRef, alertApiRef, analyticsApiRef, errorApiRef, storageApiRef, oauthRequestApiRef, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, oktaAuthApiRef, gitlabAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, atlassianAuthApiRef, createRouteRef, attachComponentData } from '@backstage/core-plugin-api';
14
14
  import { act, render } from '@testing-library/react';
15
15
 
16
16
  class MockAnalyticsApi {
@@ -206,24 +206,19 @@ class MockStorageApi {
206
206
  }
207
207
  return this.bucketStorageApis.get(name);
208
208
  }
209
- get(key) {
210
- return this.snapshot(key).value;
211
- }
212
209
  snapshot(key) {
213
210
  if (this.data.hasOwnProperty(this.getKeyName(key))) {
214
211
  const data = this.data[this.getKeyName(key)];
215
212
  return {
216
213
  key,
217
214
  presence: "present",
218
- value: data,
219
- newValue: data
215
+ value: data
220
216
  };
221
217
  }
222
218
  return {
223
219
  key,
224
220
  presence: "absent",
225
- value: void 0,
226
- newValue: void 0
221
+ value: void 0
227
222
  };
228
223
  }
229
224
  async set(key, data) {
@@ -237,8 +232,7 @@ class MockStorageApi {
237
232
  this.notifyChanges({
238
233
  key,
239
234
  presence: "present",
240
- value: serialized,
241
- newValue: serialized
235
+ value: serialized
242
236
  });
243
237
  }
244
238
  async remove(key) {
@@ -246,8 +240,7 @@ class MockStorageApi {
246
240
  this.notifyChanges({
247
241
  key,
248
242
  presence: "absent",
249
- value: void 0,
250
- newValue: void 0
243
+ value: void 0
251
244
  });
252
245
  }
253
246
  observe$(key) {
@@ -379,43 +372,6 @@ const defaultApis = [
379
372
  environment: configApi.getOptionalString("auth.environment")
380
373
  })
381
374
  }),
382
- createApiFactory({
383
- api: auth0AuthApiRef,
384
- deps: {
385
- discoveryApi: discoveryApiRef,
386
- oauthRequestApi: oauthRequestApiRef,
387
- configApi: configApiRef
388
- },
389
- factory: ({ discoveryApi, oauthRequestApi, configApi }) => Auth0Auth.create({
390
- discoveryApi,
391
- oauthRequestApi,
392
- environment: configApi.getOptionalString("auth.environment")
393
- })
394
- }),
395
- createApiFactory({
396
- api: oauth2ApiRef,
397
- deps: {
398
- discoveryApi: discoveryApiRef,
399
- oauthRequestApi: oauthRequestApiRef,
400
- configApi: configApiRef
401
- },
402
- factory: ({ discoveryApi, oauthRequestApi, configApi }) => OAuth2.create({
403
- discoveryApi,
404
- oauthRequestApi,
405
- environment: configApi.getOptionalString("auth.environment")
406
- })
407
- }),
408
- createApiFactory({
409
- api: samlAuthApiRef,
410
- deps: {
411
- discoveryApi: discoveryApiRef,
412
- configApi: configApiRef
413
- },
414
- factory: ({ discoveryApi, configApi }) => SamlAuth.create({
415
- discoveryApi,
416
- environment: configApi.getOptionalString("auth.environment")
417
- })
418
- }),
419
375
  createApiFactory({
420
376
  api: oneloginAuthApiRef,
421
377
  deps: {
@@ -429,24 +385,6 @@ const defaultApis = [
429
385
  environment: configApi.getOptionalString("auth.environment")
430
386
  })
431
387
  }),
432
- createApiFactory({
433
- api: oidcAuthApiRef,
434
- deps: {
435
- discoveryApi: discoveryApiRef,
436
- oauthRequestApi: oauthRequestApiRef,
437
- configApi: configApiRef
438
- },
439
- factory: ({ discoveryApi, oauthRequestApi, configApi }) => OAuth2.create({
440
- discoveryApi,
441
- oauthRequestApi,
442
- provider: {
443
- id: "oidc",
444
- title: "Your Identity Provider",
445
- icon: () => null
446
- },
447
- environment: configApi.getOptionalString("auth.environment")
448
- })
449
- }),
450
388
  createApiFactory({
451
389
  api: bitbucketAuthApiRef,
452
390
  deps: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/testUtils/apis/AnalyticsApi/MockAnalyticsApi.ts","../src/testUtils/apis/ConfigApi/MockConfigApi.ts","../src/testUtils/apis/ErrorApi/MockErrorApi.ts","../src/testUtils/apis/FetchApi/MockFetchApi.ts","../src/testUtils/apis/PermissionApi/MockPermissionApi.ts","../src/testUtils/apis/StorageApi/MockStorageApi.ts","../src/testUtils/mockBreakpoint.ts","../src/testUtils/testingLibrary.ts","../src/testUtils/defaultApis.ts","../src/testUtils/mockApis.ts","../src/testUtils/appWrappers.tsx","../src/testUtils/msw/setupRequestMockHandlers.ts","../src/testUtils/logCollector.ts","../src/testUtils/TestApiProvider.tsx"],"sourcesContent":["/*\n * Copyright 2021 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/core-plugin-api';\n\n/**\n * Mock implementation of {@link core-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","/*\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 = new MockConfigApi({\n * 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: 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","/*\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 // Need to be true if getErrors is used in testing.\n collect?: boolean;\n};\n\n/**\n * ErrorWithContext contains error and ErrorApiErrorContext\n * @public\n */\nexport type ErrorWithContext = {\n error: ErrorApiError;\n context?: ErrorApiErrorContext;\n};\n\ntype Waiter = {\n pattern: RegExp;\n resolve: (err: ErrorWithContext) => 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 * Incudes withForError and getErrors methods for error testing.\n * @public\n */\nexport class MockErrorApi implements ErrorApi {\n private readonly errors = new Array<ErrorWithContext>();\n private readonly waiters = new Set<Waiter>();\n\n constructor(private readonly options: MockErrorApiOptions = {}) {}\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(): ErrorWithContext[] {\n return this.errors;\n }\n\n waitForError(\n pattern: RegExp,\n timeoutMs: number = 2000,\n ): Promise<ErrorWithContext> {\n return new Promise<ErrorWithContext>((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","/*\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';\nimport crossFetch, { Response } from 'cross-fetch';\n\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 crossFetch;\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 crossFetch {\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 crossFetch {\n const implementation = options?.baseImplementation;\n if (!implementation) {\n return crossFetch;\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","/*\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 AuthorizeDecision,\n AuthorizeQuery,\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 * @public\n */\nexport class MockPermissionApi implements PermissionApi {\n constructor(\n private readonly requestHandler: (\n request: AuthorizeQuery,\n ) => AuthorizeResult.ALLOW | AuthorizeResult.DENY = () =>\n AuthorizeResult.ALLOW,\n ) {}\n\n async authorize(request: AuthorizeQuery): Promise<AuthorizeDecision> {\n return { result: this.requestHandler(request) };\n }\n}\n","/*\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 { JsonValue, Observable } from '@backstage/types';\nimport ObservableImpl from 'zen-observable';\n\n/**\n * Type for map holding data in {@link MockStorageApi}\n * @public\n */\nexport type MockStorageBucket = { [key: string]: any };\n\n/**\n * Mock implementation of the {@link core-plugin-api#StorageApi} to be used in tests\n * @public\n */\nexport class MockStorageApi implements StorageApi {\n private readonly namespace: string;\n private readonly data: MockStorageBucket;\n private readonly bucketStorageApis: Map<string, MockStorageApi>;\n\n private constructor(\n namespace: string,\n bucketStorageApis: Map<string, MockStorageApi>,\n data?: MockStorageBucket,\n ) {\n this.namespace = namespace;\n this.bucketStorageApis = bucketStorageApis;\n this.data = { ...data };\n }\n\n static create(data?: MockStorageBucket) {\n return new MockStorageApi('', new Map(), data);\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 get<T>(key: string): T | undefined {\n return this.snapshot(key).value as T | undefined;\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,\n newValue: data,\n };\n }\n return {\n key,\n presence: 'absent',\n value: undefined,\n newValue: 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 newValue: 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 newValue: undefined,\n });\n }\n\n observe$<T>(key: string): 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>(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","/*\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\n/**\n * This is a mocking method suggested in the Jest docs, as it is not implemented in JSDOM yet.\n * It can be used to mock values for the MUI `useMediaQuery` hook if it is used in a tested component.\n *\n * For issues checkout the documentation:\n * https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom\n *\n * If there are any updates from MUI React on testing `useMediaQuery` this mock should be replaced\n * https://material-ui.com/components/use-media-query/#testing\n *\n * @public\n */\nexport default function mockBreakpoint(options: { matches: boolean }) {\n Object.defineProperty(window, 'matchMedia', {\n writable: true,\n value: jest.fn().mockImplementation(query => ({\n matches: options.matches ?? false,\n media: query,\n onchange: null,\n addListener: jest.fn(), // deprecated\n removeListener: jest.fn(), // deprecated\n addEventListener: jest.fn(),\n removeEventListener: jest.fn(),\n dispatchEvent: jest.fn(),\n })),\n });\n}\n","/*\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 { ReactElement } from 'react';\nimport { act, render, RenderResult } from '@testing-library/react';\n\n/**\n * @public\n * Simplifies rendering of async components in by taking care of the wrapping inside act\n *\n * @remarks\n *\n * Components using useEffect to perform an asynchronous action (such as fetch) must be rendered within an async\n * act call to properly get the final state, even with mocked responses. This utility method makes the signature a bit\n * cleaner, since act doesn't return the result of the evaluated function.\n * https://github.com/testing-library/react-testing-library/issues/281\n * https://github.com/facebook/react/pull/14853\n */\nexport async function renderWithEffects(\n nodes: ReactElement,\n): Promise<RenderResult> {\n let value: RenderResult;\n await act(async () => {\n value = render(nodes);\n });\n return value!;\n}\n","/*\n * Copyright 2021 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 AlertApiForwarder,\n NoOpAnalyticsApi,\n ErrorApiForwarder,\n ErrorAlerter,\n GoogleAuth,\n GithubAuth,\n OAuth2,\n OktaAuth,\n GitlabAuth,\n Auth0Auth,\n MicrosoftAuth,\n BitbucketAuth,\n OAuthRequestManager,\n WebStorage,\n UrlPatternDiscovery,\n SamlAuth,\n OneLoginAuth,\n UnhandledErrorForwarder,\n AtlassianAuth,\n} from '@backstage/core-app-api';\n\nimport {\n createApiFactory,\n alertApiRef,\n analyticsApiRef,\n errorApiRef,\n discoveryApiRef,\n oauthRequestApiRef,\n googleAuthApiRef,\n githubAuthApiRef,\n oauth2ApiRef,\n oktaAuthApiRef,\n gitlabAuthApiRef,\n auth0AuthApiRef,\n microsoftAuthApiRef,\n storageApiRef,\n configApiRef,\n samlAuthApiRef,\n oneloginAuthApiRef,\n oidcAuthApiRef,\n bitbucketAuthApiRef,\n atlassianAuthApiRef,\n} from '@backstage/core-plugin-api';\n\n// TODO(Rugvip): This is just a copy of the createApp default APIs for now, but\n// we should clean up this list a bit move more things over to mocks.\nexport const defaultApis = [\n createApiFactory({\n api: discoveryApiRef,\n deps: { configApi: configApiRef },\n factory: ({ configApi }) =>\n UrlPatternDiscovery.compile(\n `${configApi.getString('backend.baseUrl')}/api/{{ pluginId }}`,\n ),\n }),\n createApiFactory(alertApiRef, new AlertApiForwarder()),\n createApiFactory(analyticsApiRef, new NoOpAnalyticsApi()),\n createApiFactory({\n api: errorApiRef,\n deps: { alertApi: alertApiRef },\n factory: ({ alertApi }) => {\n const errorApi = new ErrorAlerter(alertApi, new ErrorApiForwarder());\n UnhandledErrorForwarder.forward(errorApi, { hidden: false });\n return errorApi;\n },\n }),\n createApiFactory({\n api: storageApiRef,\n deps: { errorApi: errorApiRef },\n factory: ({ errorApi }) => WebStorage.create({ errorApi }),\n }),\n createApiFactory(oauthRequestApiRef, new OAuthRequestManager()),\n createApiFactory({\n api: googleAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n GoogleAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: microsoftAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n MicrosoftAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: githubAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n GithubAuth.create({\n discoveryApi,\n oauthRequestApi,\n defaultScopes: ['read:user'],\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: oktaAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n OktaAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: gitlabAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n GitlabAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: auth0AuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n Auth0Auth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: oauth2ApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: samlAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, configApi }) =>\n SamlAuth.create({\n discoveryApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: oneloginAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n OneLoginAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: oidcAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n provider: {\n id: 'oidc',\n title: 'Your Identity Provider',\n icon: () => null,\n },\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: bitbucketAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n BitbucketAuth.create({\n discoveryApi,\n oauthRequestApi,\n defaultScopes: ['team'],\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: atlassianAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) => {\n return AtlassianAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n });\n },\n }),\n];\n","/*\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 storageApiRef,\n errorApiRef,\n createApiFactory,\n} from '@backstage/core-plugin-api';\nimport { MockErrorApi, MockStorageApi } from './apis';\n\nexport const mockApis = [\n createApiFactory(errorApiRef, new MockErrorApi()),\n createApiFactory(storageApiRef, MockStorageApi.create()),\n];\n","/*\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 React, { ComponentType, ReactNode, ReactElement } from 'react';\nimport { MemoryRouter } from 'react-router';\nimport { Route } from 'react-router-dom';\nimport { lightTheme } from '@backstage/theme';\nimport { ThemeProvider } from '@material-ui/core/styles';\nimport { CssBaseline } from '@material-ui/core';\nimport MockIcon from '@material-ui/icons/AcUnit';\nimport { createSpecializedApp } from '@backstage/core-app-api';\nimport {\n BootErrorPageProps,\n RouteRef,\n ExternalRouteRef,\n attachComponentData,\n createRouteRef,\n} from '@backstage/core-plugin-api';\nimport { RenderResult } from '@testing-library/react';\nimport { renderWithEffects } from './testingLibrary';\nimport { defaultApis } from './defaultApis';\nimport { mockApis } from './mockApis';\n\nconst mockIcons = {\n 'kind:api': MockIcon,\n 'kind:component': MockIcon,\n 'kind:domain': MockIcon,\n 'kind:group': MockIcon,\n 'kind:location': MockIcon,\n 'kind:system': MockIcon,\n 'kind:user': MockIcon,\n\n brokenImage: MockIcon,\n catalog: MockIcon,\n scaffolder: MockIcon,\n techdocs: MockIcon,\n search: MockIcon,\n chat: MockIcon,\n dashboard: MockIcon,\n docs: MockIcon,\n email: MockIcon,\n github: MockIcon,\n group: MockIcon,\n help: MockIcon,\n user: MockIcon,\n warning: MockIcon,\n};\n\nconst ErrorBoundaryFallback = ({ error }: { error: Error }) => {\n throw new Error(`Reached ErrorBoundaryFallback Page with error, ${error}`);\n};\nconst NotFoundErrorPage = () => {\n throw new Error('Reached NotFound Page');\n};\nconst BootErrorPage = ({ step, error }: BootErrorPageProps) => {\n throw new Error(`Reached BootError Page at step ${step} with error ${error}`);\n};\nconst Progress = () => <div data-testid=\"progress\" />;\n\n/**\n * Options to customize the behavior of the test app wrapper.\n * @public\n */\nexport type TestAppOptions = {\n /**\n * Initial route entries to pass along as `initialEntries` to the router.\n */\n routeEntries?: string[];\n\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 * wrapInTestApp(<MyComponent />, \\{\n * mountedRoutes: \\{\n * '/my-path': myRouteRef,\n * \\}\n * \\})\n * // ...\n * const link = useRouteRef(myRouteRef)\n */\n mountedRoutes?: { [path: string]: RouteRef | ExternalRouteRef };\n};\n\nfunction isExternalRouteRef(\n routeRef: RouteRef | ExternalRouteRef,\n): routeRef is ExternalRouteRef {\n // TODO(Rugvip): Least ugly workaround for now, but replace :D\n return String(routeRef).includes('{type=external,');\n}\n\n/**\n * Wraps a component inside a Backstage test app, providing a mocked theme\n * and app context, along with mocked APIs.\n *\n * @param Component - A component or react node to render inside the test app.\n * @param options - Additional options for the rendering.\n * @public\n */\nexport function wrapInTestApp(\n Component: ComponentType | ReactNode,\n options: TestAppOptions = {},\n): ReactElement {\n const { routeEntries = ['/'] } = options;\n const boundRoutes = new Map<ExternalRouteRef, RouteRef>();\n\n const app = createSpecializedApp({\n apis: mockApis,\n defaultApis,\n // Bit of a hack to make sure that the default config loader isn't used\n // as that would force every single test to wait for config loading.\n configLoader: false as unknown as undefined,\n components: {\n Progress,\n BootErrorPage,\n NotFoundErrorPage,\n ErrorBoundaryFallback,\n Router: ({ children }) => (\n <MemoryRouter initialEntries={routeEntries} children={children} />\n ),\n },\n icons: mockIcons,\n plugins: [],\n themes: [\n {\n id: 'light',\n title: 'Test App Theme',\n variant: 'light',\n Provider: ({ children }) => (\n <ThemeProvider theme={lightTheme}>\n <CssBaseline>{children}</CssBaseline>\n </ThemeProvider>\n ),\n },\n ],\n bindRoutes: ({ bind }) => {\n for (const [externalRef, absoluteRef] of boundRoutes) {\n bind(\n { ref: externalRef },\n {\n ref: absoluteRef,\n },\n );\n }\n },\n });\n\n let wrappedElement: React.ReactElement;\n if (Component instanceof Function) {\n wrappedElement = <Component />;\n } else {\n wrappedElement = Component as React.ReactElement;\n }\n\n const routeElements = Object.entries(options.mountedRoutes ?? {}).map(\n ([path, routeRef]) => {\n const Page = () => <div>Mounted at {path}</div>;\n\n // Allow external route refs to be bound to paths as well, for convenience.\n // We work around it by creating and binding an absolute ref to the external one.\n if (isExternalRouteRef(routeRef)) {\n const absoluteRef = createRouteRef({ id: 'id' });\n boundRoutes.set(routeRef, absoluteRef);\n attachComponentData(Page, 'core.mountPoint', absoluteRef);\n } else {\n attachComponentData(Page, 'core.mountPoint', routeRef);\n }\n return <Route key={path} path={path} element={<Page />} />;\n },\n );\n\n const AppProvider = app.getProvider();\n const AppRouter = app.getRouter();\n\n return (\n <AppProvider>\n <AppRouter>\n {routeElements}\n {/* The path of * here is needed to be set as a catch all, so it will render the wrapper element\n * and work with nested routes if they exist too */}\n <Route path=\"*\" element={wrappedElement} />\n </AppRouter>\n </AppProvider>\n );\n}\n\n/**\n * Renders a component inside a Backstage test app, providing a mocked theme\n * and app context, along with mocked APIs.\n *\n * The render executes async effects similar to `renderWithEffects`. To avoid this\n * behavior, use a regular `render()` + `wrapInTestApp()` instead.\n *\n * @param Component - A component or react node to render inside the test app.\n * @param options - Additional options for the rendering.\n * @public\n */\nexport async function renderInTestApp(\n Component: ComponentType | ReactNode,\n options: TestAppOptions = {},\n): Promise<RenderResult> {\n return renderWithEffects(wrapInTestApp(Component, options));\n}\n","/*\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\n/**\n * Sets up handlers for request mocking\n * @public\n * @param worker - service worker\n */\nexport function setupRequestMockHandlers(worker: {\n listen: (t: any) => void;\n close: () => void;\n resetHandlers: () => void;\n}) {\n beforeAll(() => worker.listen({ onUnhandledRequest: 'error' }));\n afterAll(() => worker.close());\n afterEach(() => worker.resetHandlers());\n}\n","/*\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\n/* eslint-disable no-console */\n\n/**\n * Severity levels of {@link CollectedLogs}\n * @public */\nexport type LogFuncs = 'log' | 'warn' | 'error';\n/**\n * AsyncLogCollector type used in {@link (withLogCollector:1)} callback function.\n * @public */\nexport type AsyncLogCollector = () => Promise<void>;\n/**\n * SyncLogCollector type used in {@link (withLogCollector:2)} callback function.\n * @public */\nexport type SyncLogCollector = () => void;\n/**\n * Union type used in {@link (withLogCollector:3)} callback function.\n * @public */\nexport type LogCollector = AsyncLogCollector | SyncLogCollector;\n/**\n * Map of severity level and corresponding log lines.\n * @public */\nexport type CollectedLogs<T extends LogFuncs> = { [key in T]: string[] };\n\nconst allCategories = ['log', 'warn', 'error'];\n\n/**\n * Asynchronous log collector with that collects all categories\n * @public */\nexport function withLogCollector(\n callback: AsyncLogCollector,\n): Promise<CollectedLogs<LogFuncs>>;\n\n/**\n * Synchronous log collector with that collects all categories\n * @public */\nexport function withLogCollector(\n callback: SyncLogCollector,\n): CollectedLogs<LogFuncs>;\n\n/**\n * Asynchronous log collector with that only collects selected categories\n * @public\n */\nexport function withLogCollector<T extends LogFuncs>(\n logsToCollect: T[],\n callback: AsyncLogCollector,\n): Promise<CollectedLogs<T>>;\n\n/**\n * Synchronous log collector with that only collects selected categories\n * @public */\nexport function withLogCollector<T extends LogFuncs>(\n logsToCollect: T[],\n callback: SyncLogCollector,\n): CollectedLogs<T>;\n\n/**\n * Log collector that collect logs either from a sync or async collector.\n * @public\n * */\nexport function withLogCollector(\n logsToCollect: LogFuncs[] | LogCollector,\n callback?: LogCollector,\n): CollectedLogs<LogFuncs> | Promise<CollectedLogs<LogFuncs>> {\n const oneArg = !callback;\n const actualCallback = (oneArg ? logsToCollect : callback) as LogCollector;\n const categories = (oneArg ? allCategories : logsToCollect) as LogFuncs[];\n\n const logs = {\n log: new Array<string>(),\n warn: new Array<string>(),\n error: new Array<string>(),\n };\n\n const origLog = console.log;\n const origWarn = console.warn;\n const origError = console.error;\n\n if (categories.includes('log')) {\n console.log = (message: string) => {\n logs.log.push(message);\n };\n }\n if (categories.includes('warn')) {\n console.warn = (message: string) => {\n logs.warn.push(message);\n };\n }\n if (categories.includes('error')) {\n console.error = (message: string) => {\n logs.error.push(message);\n };\n }\n\n const restore = () => {\n console.log = origLog;\n console.warn = origWarn;\n console.error = origError;\n };\n\n try {\n const ret = actualCallback();\n\n if (!ret || !ret.then) {\n restore();\n return logs;\n }\n\n return ret.then(\n () => {\n restore();\n return logs;\n },\n error => {\n restore();\n throw error;\n },\n );\n } catch (error) {\n restore();\n throw error;\n }\n}\n","/*\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 React, { ReactNode } from 'react';\nimport { ApiProvider } from '@backstage/core-app-api';\nimport { ApiRef, ApiHolder } from '@backstage/core-plugin-api';\n\n/** @ignore */\ntype TestApiProviderPropsApiPair<TApi> = TApi extends infer TImpl\n ? readonly [ApiRef<TApi>, Partial<TImpl>]\n : never;\n\n/** @ignore */\ntype TestApiProviderPropsApiPairs<TApiPairs> = {\n [TIndex in keyof TApiPairs]: TestApiProviderPropsApiPair<TApiPairs[TIndex]>;\n};\n\n/**\n * Properties for the {@link TestApiProvider} component.\n *\n * @public\n */\nexport type TestApiProviderProps<TApiPairs extends any[]> = {\n apis: readonly [...TestApiProviderPropsApiPairs<TApiPairs>];\n children: ReactNode;\n};\n\n/**\n * The `TestApiRegistry` is an {@link @backstage/core-plugin-api#ApiHolder} implementation\n * that is particularly well suited for development and test environments such as\n * unit tests, storybooks, and isolated plugin development setups.\n *\n * @public\n */\nexport class TestApiRegistry implements ApiHolder {\n /**\n * Creates a new {@link TestApiRegistry} with a list of API implementation pairs.\n *\n * Similar to the {@link TestApiProvider}, there is no need to provide a full\n * implementation of each API, it's enough to implement the methods that are tested.\n *\n * @example\n * ```ts\n * const apis = TestApiRegistry.from(\n * [configApiRef, new ConfigReader({})],\n * [identityApiRef, { getUserId: () => 'tester' }],\n * );\n * ```\n *\n * @public\n * @param apis - A list of pairs mapping an ApiRef to its respective implementation.\n */\n static from<TApiPairs extends any[]>(\n ...apis: readonly [...TestApiProviderPropsApiPairs<TApiPairs>]\n ) {\n return new TestApiRegistry(\n new Map(apis.map(([api, impl]) => [api.id, impl])),\n );\n }\n\n private constructor(private readonly apis: Map<string, unknown>) {}\n\n /**\n * Returns an implementation of the API.\n *\n * @public\n */\n get<T>(api: ApiRef<T>): T | undefined {\n return this.apis.get(api.id) as T | undefined;\n }\n}\n\n/**\n * The `TestApiProvider` is a Utility API context provider that is particularly\n * well suited for development and test environments such as unit tests, storybooks,\n * and isolated plugin development setups.\n *\n * It lets you provide any number of API implementations, without necessarily\n * having to fully implement each of the APIs.\n *\n * A migration from `ApiRegistry` and `ApiProvider` might look like this, from:\n *\n * ```tsx\n * renderInTestApp(\n * <ApiProvider\n * apis={ApiRegistry.from([\n * [identityApiRef, mockIdentityApi as unknown as IdentityApi]\n * ])}\n * >\n * {...}\n * </ApiProvider>\n * )\n * ```\n *\n * To the following:\n *\n * ```tsx\n * renderInTestApp(\n * <TestApiProvider apis={[[identityApiRef, mockIdentityApi]]}>\n * {...}\n * </TestApiProvider>\n * )\n * ```\n *\n * Note that the cast to `IdentityApi` is no longer needed as long as the mock API\n * implements a subset of the `IdentityApi`.\n *\n * @public\n **/\nexport const TestApiProvider = <T extends any[]>(\n props: TestApiProviderProps<T>,\n) => {\n return (\n <ApiProvider\n apis={TestApiRegistry.from(...props.apis)}\n children={props.children}\n />\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/testUtils/apis/AnalyticsApi/MockAnalyticsApi.ts","../src/testUtils/apis/ConfigApi/MockConfigApi.ts","../src/testUtils/apis/ErrorApi/MockErrorApi.ts","../src/testUtils/apis/FetchApi/MockFetchApi.ts","../src/testUtils/apis/PermissionApi/MockPermissionApi.ts","../src/testUtils/apis/StorageApi/MockStorageApi.ts","../src/testUtils/mockBreakpoint.ts","../src/testUtils/testingLibrary.ts","../src/testUtils/defaultApis.ts","../src/testUtils/mockApis.ts","../src/testUtils/appWrappers.tsx","../src/testUtils/msw/setupRequestMockHandlers.ts","../src/testUtils/logCollector.ts","../src/testUtils/TestApiProvider.tsx"],"sourcesContent":["/*\n * Copyright 2021 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/core-plugin-api';\n\n/**\n * Mock implementation of {@link core-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","/*\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 = new MockConfigApi({\n * 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: 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","/*\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 // Need to be true if getErrors is used in testing.\n collect?: boolean;\n};\n\n/**\n * ErrorWithContext contains error and ErrorApiErrorContext\n * @public\n */\nexport type ErrorWithContext = {\n error: ErrorApiError;\n context?: ErrorApiErrorContext;\n};\n\ntype Waiter = {\n pattern: RegExp;\n resolve: (err: ErrorWithContext) => 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 */\nexport class MockErrorApi implements ErrorApi {\n private readonly errors = new Array<ErrorWithContext>();\n private readonly waiters = new Set<Waiter>();\n\n constructor(private readonly options: MockErrorApiOptions = {}) {}\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(): ErrorWithContext[] {\n return this.errors;\n }\n\n waitForError(\n pattern: RegExp,\n timeoutMs: number = 2000,\n ): Promise<ErrorWithContext> {\n return new Promise<ErrorWithContext>((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","/*\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';\nimport crossFetch, { Response } from 'cross-fetch';\n\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 crossFetch;\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 crossFetch {\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 crossFetch {\n const implementation = options?.baseImplementation;\n if (!implementation) {\n return crossFetch;\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","/*\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 AuthorizeDecision,\n AuthorizeQuery,\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 * @public\n */\nexport class MockPermissionApi implements PermissionApi {\n constructor(\n private readonly requestHandler: (\n request: AuthorizeQuery,\n ) => AuthorizeResult.ALLOW | AuthorizeResult.DENY = () =>\n AuthorizeResult.ALLOW,\n ) {}\n\n async authorize(request: AuthorizeQuery): Promise<AuthorizeDecision> {\n return { result: this.requestHandler(request) };\n }\n}\n","/*\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 { JsonValue, Observable } from '@backstage/types';\nimport ObservableImpl from 'zen-observable';\n\n/**\n * Type for map holding data in {@link MockStorageApi}\n * @public\n */\nexport type MockStorageBucket = { [key: string]: any };\n\n/**\n * Mock implementation of the {@link core-plugin-api#StorageApi} to be used in tests\n * @public\n */\nexport class MockStorageApi implements StorageApi {\n private readonly namespace: string;\n private readonly data: MockStorageBucket;\n private readonly bucketStorageApis: Map<string, MockStorageApi>;\n\n private constructor(\n namespace: string,\n bucketStorageApis: Map<string, MockStorageApi>,\n data?: MockStorageBucket,\n ) {\n this.namespace = namespace;\n this.bucketStorageApis = bucketStorageApis;\n this.data = { ...data };\n }\n\n static create(data?: MockStorageBucket) {\n return new MockStorageApi('', new Map(), data);\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,\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>(key: string): 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>(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","/*\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\n/**\n * This is a mocking method suggested in the Jest docs, as it is not implemented in JSDOM yet.\n * It can be used to mock values for the MUI `useMediaQuery` hook if it is used in a tested component.\n *\n * For issues checkout the documentation:\n * https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom\n *\n * If there are any updates from MUI React on testing `useMediaQuery` this mock should be replaced\n * https://material-ui.com/components/use-media-query/#testing\n *\n * @public\n */\nexport default function mockBreakpoint(options: { matches: boolean }) {\n Object.defineProperty(window, 'matchMedia', {\n writable: true,\n value: jest.fn().mockImplementation(query => ({\n matches: options.matches ?? false,\n media: query,\n onchange: null,\n addListener: jest.fn(), // deprecated\n removeListener: jest.fn(), // deprecated\n addEventListener: jest.fn(),\n removeEventListener: jest.fn(),\n dispatchEvent: jest.fn(),\n })),\n });\n}\n","/*\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 { ReactElement } from 'react';\nimport { act, render, RenderResult } from '@testing-library/react';\n\n/**\n * @public\n * Simplifies rendering of async components in by taking care of the wrapping inside act\n *\n * @remarks\n *\n * Components using useEffect to perform an asynchronous action (such as fetch) must be rendered within an async\n * act call to properly get the final state, even with mocked responses. This utility method makes the signature a bit\n * cleaner, since act doesn't return the result of the evaluated function.\n * https://github.com/testing-library/react-testing-library/issues/281\n * https://github.com/facebook/react/pull/14853\n */\nexport async function renderWithEffects(\n nodes: ReactElement,\n): Promise<RenderResult> {\n let value: RenderResult;\n await act(async () => {\n value = render(nodes);\n });\n return value!;\n}\n","/*\n * Copyright 2021 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 AlertApiForwarder,\n NoOpAnalyticsApi,\n ErrorApiForwarder,\n ErrorAlerter,\n GoogleAuth,\n GithubAuth,\n OktaAuth,\n GitlabAuth,\n MicrosoftAuth,\n BitbucketAuth,\n OAuthRequestManager,\n WebStorage,\n UrlPatternDiscovery,\n OneLoginAuth,\n UnhandledErrorForwarder,\n AtlassianAuth,\n} from '@backstage/core-app-api';\n\nimport {\n createApiFactory,\n alertApiRef,\n analyticsApiRef,\n errorApiRef,\n discoveryApiRef,\n oauthRequestApiRef,\n googleAuthApiRef,\n githubAuthApiRef,\n oktaAuthApiRef,\n gitlabAuthApiRef,\n microsoftAuthApiRef,\n storageApiRef,\n configApiRef,\n oneloginAuthApiRef,\n bitbucketAuthApiRef,\n atlassianAuthApiRef,\n} from '@backstage/core-plugin-api';\n\n// TODO(Rugvip): This is just a copy of the createApp default APIs for now, but\n// we should clean up this list a bit move more things over to mocks.\nexport const defaultApis = [\n createApiFactory({\n api: discoveryApiRef,\n deps: { configApi: configApiRef },\n factory: ({ configApi }) =>\n UrlPatternDiscovery.compile(\n `${configApi.getString('backend.baseUrl')}/api/{{ pluginId }}`,\n ),\n }),\n createApiFactory(alertApiRef, new AlertApiForwarder()),\n createApiFactory(analyticsApiRef, new NoOpAnalyticsApi()),\n createApiFactory({\n api: errorApiRef,\n deps: { alertApi: alertApiRef },\n factory: ({ alertApi }) => {\n const errorApi = new ErrorAlerter(alertApi, new ErrorApiForwarder());\n UnhandledErrorForwarder.forward(errorApi, { hidden: false });\n return errorApi;\n },\n }),\n createApiFactory({\n api: storageApiRef,\n deps: { errorApi: errorApiRef },\n factory: ({ errorApi }) => WebStorage.create({ errorApi }),\n }),\n createApiFactory(oauthRequestApiRef, new OAuthRequestManager()),\n createApiFactory({\n api: googleAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n GoogleAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: microsoftAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n MicrosoftAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: githubAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n GithubAuth.create({\n discoveryApi,\n oauthRequestApi,\n defaultScopes: ['read:user'],\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: oktaAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n OktaAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: gitlabAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n GitlabAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: oneloginAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n OneLoginAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: bitbucketAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n BitbucketAuth.create({\n discoveryApi,\n oauthRequestApi,\n defaultScopes: ['team'],\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: atlassianAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) => {\n return AtlassianAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n });\n },\n }),\n];\n","/*\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 storageApiRef,\n errorApiRef,\n createApiFactory,\n} from '@backstage/core-plugin-api';\nimport { MockErrorApi, MockStorageApi } from './apis';\n\nexport const mockApis = [\n createApiFactory(errorApiRef, new MockErrorApi()),\n createApiFactory(storageApiRef, MockStorageApi.create()),\n];\n","/*\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 React, { ComponentType, ReactNode, ReactElement } from 'react';\nimport { MemoryRouter } from 'react-router';\nimport { Route } from 'react-router-dom';\nimport { lightTheme } from '@backstage/theme';\nimport { ThemeProvider } from '@material-ui/core/styles';\nimport { CssBaseline } from '@material-ui/core';\nimport MockIcon from '@material-ui/icons/AcUnit';\nimport { createSpecializedApp } from '@backstage/core-app-api';\nimport {\n BootErrorPageProps,\n RouteRef,\n ExternalRouteRef,\n attachComponentData,\n createRouteRef,\n} from '@backstage/core-plugin-api';\nimport { RenderResult } from '@testing-library/react';\nimport { renderWithEffects } from './testingLibrary';\nimport { defaultApis } from './defaultApis';\nimport { mockApis } from './mockApis';\n\nconst mockIcons = {\n 'kind:api': MockIcon,\n 'kind:component': MockIcon,\n 'kind:domain': MockIcon,\n 'kind:group': MockIcon,\n 'kind:location': MockIcon,\n 'kind:system': MockIcon,\n 'kind:user': MockIcon,\n\n brokenImage: MockIcon,\n catalog: MockIcon,\n scaffolder: MockIcon,\n techdocs: MockIcon,\n search: MockIcon,\n chat: MockIcon,\n dashboard: MockIcon,\n docs: MockIcon,\n email: MockIcon,\n github: MockIcon,\n group: MockIcon,\n help: MockIcon,\n user: MockIcon,\n warning: MockIcon,\n};\n\nconst ErrorBoundaryFallback = ({ error }: { error: Error }) => {\n throw new Error(`Reached ErrorBoundaryFallback Page with error, ${error}`);\n};\nconst NotFoundErrorPage = () => {\n throw new Error('Reached NotFound Page');\n};\nconst BootErrorPage = ({ step, error }: BootErrorPageProps) => {\n throw new Error(`Reached BootError Page at step ${step} with error ${error}`);\n};\nconst Progress = () => <div data-testid=\"progress\" />;\n\n/**\n * Options to customize the behavior of the test app wrapper.\n * @public\n */\nexport type TestAppOptions = {\n /**\n * Initial route entries to pass along as `initialEntries` to the router.\n */\n routeEntries?: string[];\n\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 * wrapInTestApp(<MyComponent />, \\{\n * mountedRoutes: \\{\n * '/my-path': myRouteRef,\n * \\}\n * \\})\n * // ...\n * const link = useRouteRef(myRouteRef)\n */\n mountedRoutes?: { [path: string]: RouteRef | ExternalRouteRef };\n};\n\nfunction isExternalRouteRef(\n routeRef: RouteRef | ExternalRouteRef,\n): routeRef is ExternalRouteRef {\n // TODO(Rugvip): Least ugly workaround for now, but replace :D\n return String(routeRef).includes('{type=external,');\n}\n\n/**\n * Wraps a component inside a Backstage test app, providing a mocked theme\n * and app context, along with mocked APIs.\n *\n * @param Component - A component or react node to render inside the test app.\n * @param options - Additional options for the rendering.\n * @public\n */\nexport function wrapInTestApp(\n Component: ComponentType | ReactNode,\n options: TestAppOptions = {},\n): ReactElement {\n const { routeEntries = ['/'] } = options;\n const boundRoutes = new Map<ExternalRouteRef, RouteRef>();\n\n const app = createSpecializedApp({\n apis: mockApis,\n defaultApis,\n // Bit of a hack to make sure that the default config loader isn't used\n // as that would force every single test to wait for config loading.\n configLoader: false as unknown as undefined,\n components: {\n Progress,\n BootErrorPage,\n NotFoundErrorPage,\n ErrorBoundaryFallback,\n Router: ({ children }) => (\n <MemoryRouter initialEntries={routeEntries} children={children} />\n ),\n },\n icons: mockIcons,\n plugins: [],\n themes: [\n {\n id: 'light',\n title: 'Test App Theme',\n variant: 'light',\n Provider: ({ children }) => (\n <ThemeProvider theme={lightTheme}>\n <CssBaseline>{children}</CssBaseline>\n </ThemeProvider>\n ),\n },\n ],\n bindRoutes: ({ bind }) => {\n for (const [externalRef, absoluteRef] of boundRoutes) {\n bind(\n { ref: externalRef },\n {\n ref: absoluteRef,\n },\n );\n }\n },\n });\n\n let wrappedElement: React.ReactElement;\n if (Component instanceof Function) {\n wrappedElement = <Component />;\n } else {\n wrappedElement = Component as React.ReactElement;\n }\n\n const routeElements = Object.entries(options.mountedRoutes ?? {}).map(\n ([path, routeRef]) => {\n const Page = () => <div>Mounted at {path}</div>;\n\n // Allow external route refs to be bound to paths as well, for convenience.\n // We work around it by creating and binding an absolute ref to the external one.\n if (isExternalRouteRef(routeRef)) {\n const absoluteRef = createRouteRef({ id: 'id' });\n boundRoutes.set(routeRef, absoluteRef);\n attachComponentData(Page, 'core.mountPoint', absoluteRef);\n } else {\n attachComponentData(Page, 'core.mountPoint', routeRef);\n }\n return <Route key={path} path={path} element={<Page />} />;\n },\n );\n\n const AppProvider = app.getProvider();\n const AppRouter = app.getRouter();\n\n return (\n <AppProvider>\n <AppRouter>\n {routeElements}\n {/* The path of * here is needed to be set as a catch all, so it will render the wrapper element\n * and work with nested routes if they exist too */}\n <Route path=\"*\" element={wrappedElement} />\n </AppRouter>\n </AppProvider>\n );\n}\n\n/**\n * Renders a component inside a Backstage test app, providing a mocked theme\n * and app context, along with mocked APIs.\n *\n * The render executes async effects similar to `renderWithEffects`. To avoid this\n * behavior, use a regular `render()` + `wrapInTestApp()` instead.\n *\n * @param Component - A component or react node to render inside the test app.\n * @param options - Additional options for the rendering.\n * @public\n */\nexport async function renderInTestApp(\n Component: ComponentType | ReactNode,\n options: TestAppOptions = {},\n): Promise<RenderResult> {\n return renderWithEffects(wrapInTestApp(Component, options));\n}\n","/*\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\n/**\n * Sets up handlers for request mocking\n * @public\n * @param worker - service worker\n */\nexport function setupRequestMockHandlers(worker: {\n listen: (t: any) => void;\n close: () => void;\n resetHandlers: () => void;\n}) {\n beforeAll(() => worker.listen({ onUnhandledRequest: 'error' }));\n afterAll(() => worker.close());\n afterEach(() => worker.resetHandlers());\n}\n","/*\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\n/* eslint-disable no-console */\n\n/**\n * Severity levels of {@link CollectedLogs}\n * @public\n */\nexport type LogFuncs = 'log' | 'warn' | 'error';\n/**\n * AsyncLogCollector type used in {@link (withLogCollector:1)} callback function.\n * @public\n */\nexport type AsyncLogCollector = () => Promise<void>;\n/**\n * SyncLogCollector type used in {@link (withLogCollector:2)} callback function.\n * @public\n */\nexport type SyncLogCollector = () => void;\n/**\n * Union type used in {@link (withLogCollector:3)} callback function.\n * @public\n */\nexport type LogCollector = AsyncLogCollector | SyncLogCollector;\n/**\n * Map of severity level and corresponding log lines.\n * @public\n */\nexport type CollectedLogs<T extends LogFuncs> = { [key in T]: string[] };\n\nconst allCategories = ['log', 'warn', 'error'];\n\n/**\n * Asynchronous log collector with that collects all categories\n * @public\n */\nexport function withLogCollector(\n callback: AsyncLogCollector,\n): Promise<CollectedLogs<LogFuncs>>;\n\n/**\n * Synchronous log collector with that collects all categories\n * @public\n */\nexport function withLogCollector(\n callback: SyncLogCollector,\n): CollectedLogs<LogFuncs>;\n\n/**\n * Asynchronous log collector with that only collects selected categories\n * @public\n */\nexport function withLogCollector<T extends LogFuncs>(\n logsToCollect: T[],\n callback: AsyncLogCollector,\n): Promise<CollectedLogs<T>>;\n\n/**\n * Synchronous log collector with that only collects selected categories\n * @public\n */\nexport function withLogCollector<T extends LogFuncs>(\n logsToCollect: T[],\n callback: SyncLogCollector,\n): CollectedLogs<T>;\n\n/**\n * Log collector that collect logs either from a sync or async collector.\n * @public\n */\nexport function withLogCollector(\n logsToCollect: LogFuncs[] | LogCollector,\n callback?: LogCollector,\n): CollectedLogs<LogFuncs> | Promise<CollectedLogs<LogFuncs>> {\n const oneArg = !callback;\n const actualCallback = (oneArg ? logsToCollect : callback) as LogCollector;\n const categories = (oneArg ? allCategories : logsToCollect) as LogFuncs[];\n\n const logs = {\n log: new Array<string>(),\n warn: new Array<string>(),\n error: new Array<string>(),\n };\n\n const origLog = console.log;\n const origWarn = console.warn;\n const origError = console.error;\n\n if (categories.includes('log')) {\n console.log = (message: string) => {\n logs.log.push(message);\n };\n }\n if (categories.includes('warn')) {\n console.warn = (message: string) => {\n logs.warn.push(message);\n };\n }\n if (categories.includes('error')) {\n console.error = (message: string) => {\n logs.error.push(message);\n };\n }\n\n const restore = () => {\n console.log = origLog;\n console.warn = origWarn;\n console.error = origError;\n };\n\n try {\n const ret = actualCallback();\n\n if (!ret || !ret.then) {\n restore();\n return logs;\n }\n\n return ret.then(\n () => {\n restore();\n return logs;\n },\n error => {\n restore();\n throw error;\n },\n );\n } catch (error) {\n restore();\n throw error;\n }\n}\n","/*\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 React, { ReactNode } from 'react';\nimport { ApiProvider } from '@backstage/core-app-api';\nimport { ApiRef, ApiHolder } from '@backstage/core-plugin-api';\n\n/** @ignore */\ntype TestApiProviderPropsApiPair<TApi> = TApi extends infer TImpl\n ? readonly [ApiRef<TApi>, Partial<TImpl>]\n : never;\n\n/** @ignore */\ntype TestApiProviderPropsApiPairs<TApiPairs> = {\n [TIndex in keyof TApiPairs]: TestApiProviderPropsApiPair<TApiPairs[TIndex]>;\n};\n\n/**\n * Properties for the {@link TestApiProvider} component.\n *\n * @public\n */\nexport type TestApiProviderProps<TApiPairs extends any[]> = {\n apis: readonly [...TestApiProviderPropsApiPairs<TApiPairs>];\n children: ReactNode;\n};\n\n/**\n * The `TestApiRegistry` is an {@link @backstage/core-plugin-api#ApiHolder} implementation\n * that is particularly well suited for development and test environments such as\n * unit tests, storybooks, and isolated plugin development setups.\n *\n * @public\n */\nexport class TestApiRegistry implements ApiHolder {\n /**\n * Creates a new {@link TestApiRegistry} with a list of API implementation pairs.\n *\n * Similar to the {@link TestApiProvider}, there is no need to provide a full\n * implementation of each API, it's enough to implement the methods that are tested.\n *\n * @example\n * ```ts\n * const apis = TestApiRegistry.from(\n * [configApiRef, new ConfigReader({})],\n * [identityApiRef, { getUserId: () => 'tester' }],\n * );\n * ```\n *\n * @public\n * @param apis - A list of pairs mapping an ApiRef to its respective implementation.\n */\n static from<TApiPairs extends any[]>(\n ...apis: readonly [...TestApiProviderPropsApiPairs<TApiPairs>]\n ) {\n return new TestApiRegistry(\n new Map(apis.map(([api, impl]) => [api.id, impl])),\n );\n }\n\n private constructor(private readonly apis: Map<string, unknown>) {}\n\n /**\n * Returns an implementation of the API.\n *\n * @public\n */\n get<T>(api: ApiRef<T>): T | undefined {\n return this.apis.get(api.id) as T | undefined;\n }\n}\n\n/**\n * The `TestApiProvider` is a Utility API context provider that is particularly\n * well suited for development and test environments such as unit tests, storybooks,\n * and isolated plugin development setups.\n *\n * It lets you provide any number of API implementations, without necessarily\n * having to fully implement each of the APIs.\n *\n * A migration from `ApiRegistry` and `ApiProvider` might look like this, from:\n *\n * ```tsx\n * renderInTestApp(\n * <ApiProvider\n * apis={ApiRegistry.from([\n * [identityApiRef, mockIdentityApi as unknown as IdentityApi]\n * ])}\n * >\n * {...}\n * </ApiProvider>\n * )\n * ```\n *\n * To the following:\n *\n * ```tsx\n * renderInTestApp(\n * <TestApiProvider apis={[[identityApiRef, mockIdentityApi]]}>\n * {...}\n * </TestApiProvider>\n * )\n * ```\n *\n * Note that the cast to `IdentityApi` is no longer needed as long as the mock API\n * implements a subset of the `IdentityApi`.\n *\n * @public\n **/\nexport const TestApiProvider = <T extends any[]>(\n props: TestApiProviderProps<T>,\n) => {\n return (\n <ApiProvider\n apis={TestApiRegistry.from(...props.apis)}\n children={props.children}\n />\n );\n};\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@backstage/test-utils",
3
3
  "description": "Utilities to test Backstage plugins and apps.",
4
- "version": "0.2.5",
4
+ "version": "1.0.0",
5
5
  "private": false,
6
6
  "publishConfig": {
7
7
  "access": "public",
@@ -33,17 +33,17 @@
33
33
  "start": "backstage-cli package start"
34
34
  },
35
35
  "dependencies": {
36
- "@backstage/config": "^0.1.14",
37
- "@backstage/core-app-api": "^0.5.3",
38
- "@backstage/core-plugin-api": "^0.6.1",
39
- "@backstage/plugin-permission-common": "^0.5.0",
40
- "@backstage/plugin-permission-react": "^0.3.1",
36
+ "@backstage/config": "^1.0.0",
37
+ "@backstage/core-app-api": "^1.0.0",
38
+ "@backstage/core-plugin-api": "^1.0.0",
39
+ "@backstage/plugin-permission-common": "^0.5.3",
40
+ "@backstage/plugin-permission-react": "^0.3.4",
41
41
  "@backstage/theme": "^0.2.15",
42
- "@backstage/types": "^0.1.2",
42
+ "@backstage/types": "^1.0.0",
43
43
  "@material-ui/core": "^4.12.2",
44
44
  "@material-ui/icons": "^4.11.2",
45
45
  "@testing-library/jest-dom": "^5.10.1",
46
- "@testing-library/react": "^11.2.5",
46
+ "@testing-library/react": "^12.1.3",
47
47
  "@testing-library/user-event": "^13.1.8",
48
48
  "cross-fetch": "^3.1.5",
49
49
  "react-router": "6.0.0-beta.0",
@@ -55,7 +55,7 @@
55
55
  "react": "^16.13.1 || ^17.0.0"
56
56
  },
57
57
  "devDependencies": {
58
- "@backstage/cli": "^0.14.0",
58
+ "@backstage/cli": "^0.16.0",
59
59
  "@types/jest": "^26.0.7",
60
60
  "@types/node": "^14.14.32",
61
61
  "msw": "^0.35.0"
@@ -63,5 +63,5 @@
63
63
  "files": [
64
64
  "dist"
65
65
  ],
66
- "gitHead": "4805c3d13ce9bfc369e53c271b1b95e722b3b4dc"
66
+ "gitHead": "e9496f746b31600dbfac7fa76987479e66426257"
67
67
  }