@backstage/backend-test-utils 1.6.0-next.1 → 1.6.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 +61 -0
- package/dist/alpha/services/ActionsRegistryServiceMock.cjs.js +26 -0
- package/dist/alpha/services/ActionsRegistryServiceMock.cjs.js.map +1 -0
- package/dist/alpha/services/ActionsServiceMock.cjs.js +15 -0
- package/dist/alpha/services/ActionsServiceMock.cjs.js.map +1 -0
- package/dist/alpha/services/MockActionsRegistry.cjs.js +83 -0
- package/dist/alpha/services/MockActionsRegistry.cjs.js.map +1 -0
- package/dist/alpha/services/simpleMock.cjs.js +28 -0
- package/dist/alpha/services/simpleMock.cjs.js.map +1 -0
- package/dist/alpha.cjs.js +18 -0
- package/dist/alpha.cjs.js.map +1 -0
- package/dist/alpha.d.ts +89 -0
- package/dist/backend-app-api/src/lib/DependencyGraph.cjs.js +19 -3
- package/dist/backend-app-api/src/lib/DependencyGraph.cjs.js.map +1 -1
- package/dist/index.cjs.js +6 -6
- package/dist/index.d.ts +106 -92
- package/dist/services/MockAuthService.cjs.js.map +1 -0
- package/dist/services/MockEventsService.cjs.js.map +1 -0
- package/dist/services/MockHttpAuthService.cjs.js.map +1 -0
- package/dist/services/MockPermissionsService.cjs.js +25 -0
- package/dist/services/MockPermissionsService.cjs.js.map +1 -0
- package/dist/services/MockRootLoggerService.cjs.js.map +1 -0
- package/dist/services/MockUserInfoService.cjs.js.map +1 -0
- package/dist/{next/services → services}/mockCredentials.cjs.js +16 -8
- package/dist/services/mockCredentials.cjs.js.map +1 -0
- package/dist/{next/services → services}/mockServices.cjs.js +32 -58
- package/dist/services/mockServices.cjs.js.map +1 -0
- package/dist/services/simpleMock.cjs.js +28 -0
- package/dist/services/simpleMock.cjs.js.map +1 -0
- package/dist/util/errorHandler.cjs.js +2 -5
- package/dist/util/errorHandler.cjs.js.map +1 -1
- package/dist/{next/wiring → wiring}/ServiceFactoryTester.cjs.js +1 -1
- package/dist/wiring/ServiceFactoryTester.cjs.js.map +1 -0
- package/dist/{next/wiring → wiring}/TestBackend.cjs.js +9 -1
- package/dist/wiring/TestBackend.cjs.js.map +1 -0
- package/package.json +23 -12
- package/dist/next/services/MockAuthService.cjs.js.map +0 -1
- package/dist/next/services/MockEventsService.cjs.js.map +0 -1
- package/dist/next/services/MockHttpAuthService.cjs.js.map +0 -1
- package/dist/next/services/MockRootLoggerService.cjs.js.map +0 -1
- package/dist/next/services/MockUserInfoService.cjs.js.map +0 -1
- package/dist/next/services/mockCredentials.cjs.js.map +0 -1
- package/dist/next/services/mockServices.cjs.js.map +0 -1
- package/dist/next/wiring/ServiceFactoryTester.cjs.js.map +0 -1
- package/dist/next/wiring/TestBackend.cjs.js.map +0 -1
- /package/dist/{next/services → services}/MockAuthService.cjs.js +0 -0
- /package/dist/{next/services → services}/MockEventsService.cjs.js +0 -0
- /package/dist/{next/services → services}/MockHttpAuthService.cjs.js +0 -0
- /package/dist/{next/services → services}/MockRootLoggerService.cjs.js +0 -0
- /package/dist/{next/services → services}/MockUserInfoService.cjs.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# @backstage/backend-test-utils
|
|
2
2
|
|
|
3
|
+
## 1.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 6dfb7be: Added `mockServices.permissions()` that can return actual results.
|
|
8
|
+
- c999c25: Added an `actionsRegistryServiceMock` and `actionsServiceMock` to `/alpha` export for the experimental services.
|
|
9
|
+
|
|
10
|
+
This allows you to write tests for your actions by doing something similar to the following:
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha';
|
|
14
|
+
|
|
15
|
+
const mockActionsRegistry = actionsRegistryServiceMock();
|
|
16
|
+
const mockCatalog = catalogServiceMock({
|
|
17
|
+
entities: [
|
|
18
|
+
...
|
|
19
|
+
],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
createGetCatalogEntityAction({
|
|
23
|
+
catalog: mockCatalog,
|
|
24
|
+
actionsRegistry: mockActionsRegistry,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
await expect(
|
|
28
|
+
mockActionsRegistry.invoke({
|
|
29
|
+
id: 'test:get-catalog-entity',
|
|
30
|
+
input: { name: 'test' },
|
|
31
|
+
}),
|
|
32
|
+
).resolves.toEqual(...)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- 12c1fd4: Make the `user` credentials mock behave more like production
|
|
38
|
+
- Updated dependencies
|
|
39
|
+
- @backstage/backend-defaults@0.11.0
|
|
40
|
+
- @backstage/plugin-auth-node@0.6.4
|
|
41
|
+
- @backstage/backend-app-api@1.2.4
|
|
42
|
+
- @backstage/backend-plugin-api@1.4.0
|
|
43
|
+
- @backstage/config@1.3.2
|
|
44
|
+
- @backstage/errors@1.2.7
|
|
45
|
+
- @backstage/types@1.2.1
|
|
46
|
+
- @backstage/plugin-events-node@0.4.12
|
|
47
|
+
- @backstage/plugin-permission-common@0.9.0
|
|
48
|
+
|
|
49
|
+
## 1.6.0-next.2
|
|
50
|
+
|
|
51
|
+
### Patch Changes
|
|
52
|
+
|
|
53
|
+
- 12c1fd4: Make the `user` credentials mock behave more like production
|
|
54
|
+
- Updated dependencies
|
|
55
|
+
- @backstage/backend-defaults@0.11.0-next.2
|
|
56
|
+
- @backstage/backend-app-api@1.2.4-next.2
|
|
57
|
+
- @backstage/backend-plugin-api@1.4.0-next.1
|
|
58
|
+
- @backstage/config@1.3.2
|
|
59
|
+
- @backstage/errors@1.2.7
|
|
60
|
+
- @backstage/types@1.2.1
|
|
61
|
+
- @backstage/plugin-auth-node@0.6.4-next.1
|
|
62
|
+
- @backstage/plugin-events-node@0.4.12-next.1
|
|
63
|
+
|
|
3
64
|
## 1.6.0-next.1
|
|
4
65
|
|
|
5
66
|
### Patch Changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var mockServices = require('../../services/mockServices.cjs.js');
|
|
4
|
+
require('../../services/mockCredentials.cjs.js');
|
|
5
|
+
var MockActionsRegistry = require('./MockActionsRegistry.cjs.js');
|
|
6
|
+
var simpleMock = require('./simpleMock.cjs.js');
|
|
7
|
+
var alpha$1 = require('@backstage/backend-plugin-api/alpha');
|
|
8
|
+
var alpha = require('@backstage/backend-defaults/alpha');
|
|
9
|
+
|
|
10
|
+
function actionsRegistryServiceMock(options) {
|
|
11
|
+
return MockActionsRegistry.MockActionsRegistry.create({
|
|
12
|
+
logger: options?.logger ?? mockServices.mockServices.logger.mock()
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
((actionsRegistryServiceMock2) => {
|
|
16
|
+
actionsRegistryServiceMock2.factory = () => alpha.actionsRegistryServiceFactory;
|
|
17
|
+
actionsRegistryServiceMock2.mock = simpleMock.simpleMock(
|
|
18
|
+
alpha$1.actionsRegistryServiceRef,
|
|
19
|
+
() => ({
|
|
20
|
+
register: jest.fn()
|
|
21
|
+
})
|
|
22
|
+
);
|
|
23
|
+
})(actionsRegistryServiceMock || (actionsRegistryServiceMock = {}));
|
|
24
|
+
|
|
25
|
+
exports.actionsRegistryServiceMock = actionsRegistryServiceMock;
|
|
26
|
+
//# sourceMappingURL=ActionsRegistryServiceMock.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActionsRegistryServiceMock.cjs.js","sources":["../../../src/alpha/services/ActionsRegistryServiceMock.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { mockServices } from '../../services';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { MockActionsRegistry } from './MockActionsRegistry';\nimport { simpleMock } from './simpleMock';\nimport {\n ActionsRegistryService,\n actionsRegistryServiceRef,\n} from '@backstage/backend-plugin-api/alpha';\nimport { actionsRegistryServiceFactory } from '@backstage/backend-defaults/alpha';\n\n/**\n * @alpha\n */\nexport function actionsRegistryServiceMock(options?: {\n logger: LoggerService;\n}): MockActionsRegistry {\n return MockActionsRegistry.create({\n logger: options?.logger ?? mockServices.logger.mock(),\n });\n}\n\n/**\n * @alpha\n */\nexport namespace actionsRegistryServiceMock {\n export const factory = () => actionsRegistryServiceFactory;\n\n export const mock = simpleMock<ActionsRegistryService>(\n actionsRegistryServiceRef,\n () => ({\n register: jest.fn(),\n }),\n );\n}\n"],"names":["MockActionsRegistry","mockServices","actionsRegistryServiceMock","actionsRegistryServiceFactory","simpleMock","actionsRegistryServiceRef"],"mappings":";;;;;;;;;AA4BO,SAAS,2BAA2B,OAEnB,EAAA;AACtB,EAAA,OAAOA,wCAAoB,MAAO,CAAA;AAAA,IAChC,MAAQ,EAAA,OAAA,EAAS,MAAU,IAAAC,yBAAA,CAAa,OAAO,IAAK;AAAA,GACrD,CAAA;AACH;AAAA,CAKO,CAAUC,2BAAV,KAAA;AACE,EAAMA,2BAAAA,CAAA,UAAU,MAAMC,mCAAA;AAEtB,EAAMD,4BAAA,IAAO,GAAAE,qBAAA;AAAA,IAClBC,iCAAA;AAAA,IACA,OAAO;AAAA,MACL,QAAA,EAAU,KAAK,EAAG;AAAA,KACpB;AAAA,GACF;AAAA,CARe,EAAA,0BAAA,KAAA,0BAAA,GAAA,EAAA,CAAA,CAAA;;;;"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var simpleMock = require('./simpleMock.cjs.js');
|
|
4
|
+
var alpha$1 = require('@backstage/backend-plugin-api/alpha');
|
|
5
|
+
var alpha = require('@backstage/backend-defaults/alpha');
|
|
6
|
+
|
|
7
|
+
exports.actionsServiceMock = void 0;
|
|
8
|
+
((actionsServiceMock2) => {
|
|
9
|
+
actionsServiceMock2.factory = () => alpha.actionsServiceFactory;
|
|
10
|
+
actionsServiceMock2.mock = simpleMock.simpleMock(alpha$1.actionsServiceRef, () => ({
|
|
11
|
+
invoke: jest.fn(),
|
|
12
|
+
list: jest.fn()
|
|
13
|
+
}));
|
|
14
|
+
})(exports.actionsServiceMock || (exports.actionsServiceMock = {}));
|
|
15
|
+
//# sourceMappingURL=ActionsServiceMock.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActionsServiceMock.cjs.js","sources":["../../../src/alpha/services/ActionsServiceMock.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { simpleMock } from './simpleMock';\nimport {\n ActionsService,\n actionsServiceRef,\n} from '@backstage/backend-plugin-api/alpha';\nimport { actionsServiceFactory } from '@backstage/backend-defaults/alpha';\n\n/**\n * @alpha\n */\nexport namespace actionsServiceMock {\n export const factory = () => actionsServiceFactory;\n\n export const mock = simpleMock<ActionsService>(actionsServiceRef, () => ({\n invoke: jest.fn(),\n list: jest.fn(),\n }));\n}\n"],"names":["actionsServiceMock","actionsServiceFactory","simpleMock","actionsServiceRef"],"mappings":";;;;;;AA0BiBA;AAAA,CAAV,CAAUA,mBAAV,KAAA;AACE,EAAMA,mBAAAA,CAAA,UAAU,MAAMC,2BAAA;AAEtB,EAAMD,mBAAA,CAAA,IAAA,GAAOE,qBAA2B,CAAAC,yBAAA,EAAmB,OAAO;AAAA,IACvE,MAAA,EAAQ,KAAK,EAAG,EAAA;AAAA,IAChB,IAAA,EAAM,KAAK,EAAG;AAAA,GACd,CAAA,CAAA;AAAA,CANa,EAAAH,0BAAA,KAAAA,0BAAA,GAAA,EAAA,CAAA,CAAA;;"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('@backstage/errors');
|
|
4
|
+
var zod = require('zod');
|
|
5
|
+
var zodToJsonSchema = require('zod-to-json-schema');
|
|
6
|
+
require('../../services/mockServices.cjs.js');
|
|
7
|
+
var mockCredentials = require('../../services/mockCredentials.cjs.js');
|
|
8
|
+
|
|
9
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
var zodToJsonSchema__default = /*#__PURE__*/_interopDefaultCompat(zodToJsonSchema);
|
|
12
|
+
|
|
13
|
+
class MockActionsRegistry {
|
|
14
|
+
constructor(logger) {
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
}
|
|
17
|
+
static create(opts) {
|
|
18
|
+
return new MockActionsRegistry(opts.logger);
|
|
19
|
+
}
|
|
20
|
+
actions = /* @__PURE__ */ new Map();
|
|
21
|
+
async list() {
|
|
22
|
+
return {
|
|
23
|
+
actions: Array.from(this.actions.entries()).map(([id, action]) => ({
|
|
24
|
+
id,
|
|
25
|
+
name: action.name,
|
|
26
|
+
title: action.title,
|
|
27
|
+
description: action.description,
|
|
28
|
+
attributes: {
|
|
29
|
+
destructive: action.attributes?.destructive ?? true,
|
|
30
|
+
idempotent: action.attributes?.idempotent ?? false,
|
|
31
|
+
readOnly: action.attributes?.readOnly ?? false
|
|
32
|
+
},
|
|
33
|
+
schema: {
|
|
34
|
+
input: action.schema?.input ? zodToJsonSchema__default.default(action.schema.input(zod.z)) : zodToJsonSchema__default.default(zod.z.object({})),
|
|
35
|
+
output: action.schema?.output ? zodToJsonSchema__default.default(action.schema.output(zod.z)) : zodToJsonSchema__default.default(zod.z.object({}))
|
|
36
|
+
}
|
|
37
|
+
}))
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async invoke(opts) {
|
|
41
|
+
const action = this.actions.get(opts.id);
|
|
42
|
+
if (!action) {
|
|
43
|
+
const availableActionIds = Array.from(this.actions.keys()).join(", ");
|
|
44
|
+
throw new errors.NotFoundError(
|
|
45
|
+
`Action "${opts.id}" not found, available actions: ${availableActionIds ? `"${availableActionIds}"` : "none"}`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
const input = action.schema?.input ? action.schema.input(zod.z).safeParse(opts.input) : { success: true, data: void 0 };
|
|
49
|
+
if (!input.success) {
|
|
50
|
+
throw new errors.InputError(`Invalid input to action "${opts.id}"`, input.error);
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const result = await action.action({
|
|
54
|
+
input: input.data,
|
|
55
|
+
credentials: opts.credentials ?? mockCredentials.mockCredentials.none(),
|
|
56
|
+
logger: this.logger
|
|
57
|
+
});
|
|
58
|
+
const output = action.schema?.output ? action.schema.output(zod.z).safeParse(result?.output) : { success: true, data: result?.output };
|
|
59
|
+
if (!output.success) {
|
|
60
|
+
throw new errors.InputError(
|
|
61
|
+
`Invalid output from action "${opts.id}"`,
|
|
62
|
+
output.error
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return { output: output.data };
|
|
66
|
+
} catch (error) {
|
|
67
|
+
throw new errors.ForwardedError(
|
|
68
|
+
`Failed execution of action "${opts.id}"`,
|
|
69
|
+
error
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
register(options) {
|
|
74
|
+
const id = `test:${options.name}`;
|
|
75
|
+
if (this.actions.has(id)) {
|
|
76
|
+
throw new Error(`Action with id "${id}" is already registered`);
|
|
77
|
+
}
|
|
78
|
+
this.actions.set(id, options);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
exports.MockActionsRegistry = MockActionsRegistry;
|
|
83
|
+
//# sourceMappingURL=MockActionsRegistry.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockActionsRegistry.cjs.js","sources":["../../../src/alpha/services/MockActionsRegistry.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n BackstageCredentials,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { ForwardedError, InputError, NotFoundError } from '@backstage/errors';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport { z, AnyZodObject } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { mockCredentials } from '../../services';\nimport {\n ActionsRegistryActionOptions,\n ActionsRegistryService,\n ActionsService,\n ActionsServiceAction,\n} from '@backstage/backend-plugin-api/alpha';\n\n/**\n * A mock implementation of the ActionsRegistryService and ActionsService that can be used in tests.\n *\n * This is useful for testing actions that are registered with the ActionsRegistryService and ActionsService.\n *\n * The plugin ID is hardcoded to `testing` in the mock implementation.\n *\n * @example\n * ```ts\n * const actionsRegistry = mockServices.actionsRegistry();\n *\n * actionsRegistry.register({\n * name: 'test',\n * title: 'Test',\n * description: 'Test',\n * schema: {\n * input: z.object({ name: z.string() }),\n * output: z.object({ name: z.string() }),\n * },\n * action: async ({ input }) => ({ output: { name: input.name } }),\n * });\n *\n *\n * const result = await actionsRegistry.invoke({\n * id: 'testing:test',\n * input: { name: 'test' },\n * });\n *\n * expect(result).toEqual({ output: { name: 'test' } });\n * ```\n *\n * @alpha\n */\nexport class MockActionsRegistry\n implements ActionsRegistryService, ActionsService\n{\n private constructor(private readonly logger: LoggerService) {}\n\n static create(opts: { logger: LoggerService }) {\n return new MockActionsRegistry(opts.logger);\n }\n\n readonly actions: Map<string, ActionsRegistryActionOptions<any, any>> =\n new Map();\n\n async list(): Promise<{ actions: ActionsServiceAction[] }> {\n return {\n actions: Array.from(this.actions.entries()).map(([id, action]) => ({\n id,\n name: action.name,\n title: action.title,\n description: action.description,\n attributes: {\n destructive: action.attributes?.destructive ?? true,\n idempotent: action.attributes?.idempotent ?? false,\n readOnly: action.attributes?.readOnly ?? false,\n },\n schema: {\n input: action.schema?.input\n ? zodToJsonSchema(action.schema.input(z))\n : zodToJsonSchema(z.object({})),\n output: action.schema?.output\n ? zodToJsonSchema(action.schema.output(z))\n : zodToJsonSchema(z.object({})),\n } as ActionsServiceAction['schema'],\n })),\n };\n }\n\n async invoke(opts: {\n id: string;\n input?: JsonObject;\n credentials?: BackstageCredentials;\n }): Promise<{ output: JsonValue }> {\n const action = this.actions.get(opts.id);\n\n if (!action) {\n const availableActionIds = Array.from(this.actions.keys()).join(', ');\n throw new NotFoundError(\n `Action \"${opts.id}\" not found, available actions: ${\n availableActionIds ? `\"${availableActionIds}\"` : 'none'\n }`,\n );\n }\n\n const input = action.schema?.input\n ? action.schema.input(z).safeParse(opts.input)\n : ({ success: true, data: undefined } as const);\n\n if (!input.success) {\n throw new InputError(`Invalid input to action \"${opts.id}\"`, input.error);\n }\n\n try {\n const result = await action.action({\n input: input.data,\n credentials: opts.credentials ?? mockCredentials.none(),\n logger: this.logger,\n });\n\n const output = action.schema?.output\n ? action.schema.output(z).safeParse(result?.output)\n : ({ success: true, data: result?.output } as const);\n\n if (!output.success) {\n throw new InputError(\n `Invalid output from action \"${opts.id}\"`,\n output.error,\n );\n }\n\n return { output: output.data };\n } catch (error) {\n throw new ForwardedError(\n `Failed execution of action \"${opts.id}\"`,\n error,\n );\n }\n }\n\n register<\n TInputSchema extends AnyZodObject,\n TOutputSchema extends AnyZodObject,\n >(options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>): void {\n // hardcode test: prefix similar to how the default actions registry does it\n // and other places around the testing ecosystem:\n // https://github.com/backstage/backstage/blob/a9219496d5c073aaa0b8caf32ece10455cf65e61/packages/backend-test-utils/src/next/services/mockServices.ts#L321\n // https://github.com/backstage/backstage/blob/861f162b4a39117b824669d67a951ed1db142e3d/packages/backend-test-utils/src/next/wiring/ServiceFactoryTester.ts#L99\n const id = `test:${options.name}`;\n\n if (this.actions.has(id)) {\n throw new Error(`Action with id \"${id}\" is already registered`);\n }\n\n this.actions.set(id, options);\n }\n}\n"],"names":["zodToJsonSchema","z","NotFoundError","InputError","mockCredentials","ForwardedError"],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
|
|
5
|
+
function simpleMock(ref, mockFactory) {
|
|
6
|
+
return (partialImpl) => {
|
|
7
|
+
const mock = mockFactory();
|
|
8
|
+
if (partialImpl) {
|
|
9
|
+
for (const [key, impl] of Object.entries(partialImpl)) {
|
|
10
|
+
if (typeof impl === "function") {
|
|
11
|
+
mock[key].mockImplementation(impl);
|
|
12
|
+
} else {
|
|
13
|
+
mock[key] = impl;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return Object.assign(mock, {
|
|
18
|
+
factory: backendPluginApi.createServiceFactory({
|
|
19
|
+
service: ref,
|
|
20
|
+
deps: {},
|
|
21
|
+
factory: () => mock
|
|
22
|
+
})
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
exports.simpleMock = simpleMock;
|
|
28
|
+
//# sourceMappingURL=simpleMock.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simpleMock.cjs.js","sources":["../../../src/alpha/services/simpleMock.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n createServiceFactory,\n ServiceFactory,\n ServiceRef,\n} from '@backstage/backend-plugin-api';\n\n/** @alpha */\nexport type ServiceMock<TService> = {\n factory: ServiceFactory<TService>;\n} & {\n [Key in keyof TService]: TService[Key] extends (\n ...args: infer Args\n ) => infer Return\n ? TService[Key] & jest.MockInstance<Return, Args>\n : TService[Key];\n};\n\n/** @internal */\nexport function simpleMock<TService>(\n ref: ServiceRef<TService, any>,\n mockFactory: () => jest.Mocked<TService>,\n): (partialImpl?: Partial<TService>) => ServiceMock<TService> {\n return partialImpl => {\n const mock = mockFactory();\n if (partialImpl) {\n for (const [key, impl] of Object.entries(partialImpl)) {\n if (typeof impl === 'function') {\n (mock as any)[key].mockImplementation(impl);\n } else {\n (mock as any)[key] = impl;\n }\n }\n }\n return Object.assign(mock, {\n factory: createServiceFactory({\n service: ref,\n deps: {},\n factory: () => mock,\n }),\n }) as ServiceMock<TService>;\n };\n}\n"],"names":["createServiceFactory"],"mappings":";;;;AAiCgB,SAAA,UAAA,CACd,KACA,WAC4D,EAAA;AAC5D,EAAA,OAAO,CAAe,WAAA,KAAA;AACpB,IAAA,MAAM,OAAO,WAAY,EAAA;AACzB,IAAA,IAAI,WAAa,EAAA;AACf,MAAA,KAAA,MAAW,CAAC,GAAK,EAAA,IAAI,KAAK,MAAO,CAAA,OAAA,CAAQ,WAAW,CAAG,EAAA;AACrD,QAAI,IAAA,OAAO,SAAS,UAAY,EAAA;AAC9B,UAAC,IAAa,CAAA,GAAG,CAAE,CAAA,kBAAA,CAAmB,IAAI,CAAA;AAAA,SACrC,MAAA;AACL,UAAC,IAAA,CAAa,GAAG,CAAI,GAAA,IAAA;AAAA;AACvB;AACF;AAEF,IAAO,OAAA,MAAA,CAAO,OAAO,IAAM,EAAA;AAAA,MACzB,SAASA,qCAAqB,CAAA;AAAA,QAC5B,OAAS,EAAA,GAAA;AAAA,QACT,MAAM,EAAC;AAAA,QACP,SAAS,MAAM;AAAA,OAChB;AAAA,KACF,CAAA;AAAA,GACH;AACF;;;;"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var ActionsRegistryServiceMock = require('./alpha/services/ActionsRegistryServiceMock.cjs.js');
|
|
4
|
+
var MockActionsRegistry = require('./alpha/services/MockActionsRegistry.cjs.js');
|
|
5
|
+
var ActionsServiceMock = require('./alpha/services/ActionsServiceMock.cjs.js');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Object.defineProperty(exports, "actionsRegistryServiceMock", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function () { return ActionsRegistryServiceMock.actionsRegistryServiceMock; }
|
|
12
|
+
});
|
|
13
|
+
exports.MockActionsRegistry = MockActionsRegistry.MockActionsRegistry;
|
|
14
|
+
Object.defineProperty(exports, "actionsServiceMock", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return ActionsServiceMock.actionsServiceMock; }
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=alpha.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alpha.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"}
|
package/dist/alpha.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
+
import { ServiceFactory, LoggerService, BackstageCredentials } from '@backstage/backend-plugin-api';
|
|
3
|
+
import { JsonObject, JsonValue } from '@backstage/types';
|
|
4
|
+
import { AnyZodObject } from 'zod';
|
|
5
|
+
import { ActionsRegistryService, ActionsService, ActionsRegistryActionOptions, ActionsServiceAction } from '@backstage/backend-plugin-api/alpha';
|
|
6
|
+
|
|
7
|
+
/** @alpha */
|
|
8
|
+
type ServiceMock<TService> = {
|
|
9
|
+
factory: ServiceFactory<TService>;
|
|
10
|
+
} & {
|
|
11
|
+
[Key in keyof TService]: TService[Key] extends (...args: infer Args) => infer Return ? TService[Key] & jest.MockInstance<Return, Args> : TService[Key];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A mock implementation of the ActionsRegistryService and ActionsService that can be used in tests.
|
|
16
|
+
*
|
|
17
|
+
* This is useful for testing actions that are registered with the ActionsRegistryService and ActionsService.
|
|
18
|
+
*
|
|
19
|
+
* The plugin ID is hardcoded to `testing` in the mock implementation.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const actionsRegistry = mockServices.actionsRegistry();
|
|
24
|
+
*
|
|
25
|
+
* actionsRegistry.register({
|
|
26
|
+
* name: 'test',
|
|
27
|
+
* title: 'Test',
|
|
28
|
+
* description: 'Test',
|
|
29
|
+
* schema: {
|
|
30
|
+
* input: z.object({ name: z.string() }),
|
|
31
|
+
* output: z.object({ name: z.string() }),
|
|
32
|
+
* },
|
|
33
|
+
* action: async ({ input }) => ({ output: { name: input.name } }),
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
*
|
|
37
|
+
* const result = await actionsRegistry.invoke({
|
|
38
|
+
* id: 'testing:test',
|
|
39
|
+
* input: { name: 'test' },
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* expect(result).toEqual({ output: { name: 'test' } });
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @alpha
|
|
46
|
+
*/
|
|
47
|
+
declare class MockActionsRegistry implements ActionsRegistryService, ActionsService {
|
|
48
|
+
private readonly logger;
|
|
49
|
+
private constructor();
|
|
50
|
+
static create(opts: {
|
|
51
|
+
logger: LoggerService;
|
|
52
|
+
}): MockActionsRegistry;
|
|
53
|
+
readonly actions: Map<string, ActionsRegistryActionOptions<any, any>>;
|
|
54
|
+
list(): Promise<{
|
|
55
|
+
actions: ActionsServiceAction[];
|
|
56
|
+
}>;
|
|
57
|
+
invoke(opts: {
|
|
58
|
+
id: string;
|
|
59
|
+
input?: JsonObject;
|
|
60
|
+
credentials?: BackstageCredentials;
|
|
61
|
+
}): Promise<{
|
|
62
|
+
output: JsonValue;
|
|
63
|
+
}>;
|
|
64
|
+
register<TInputSchema extends AnyZodObject, TOutputSchema extends AnyZodObject>(options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>): void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @alpha
|
|
69
|
+
*/
|
|
70
|
+
declare function actionsRegistryServiceMock(options?: {
|
|
71
|
+
logger: LoggerService;
|
|
72
|
+
}): MockActionsRegistry;
|
|
73
|
+
/**
|
|
74
|
+
* @alpha
|
|
75
|
+
*/
|
|
76
|
+
declare namespace actionsRegistryServiceMock {
|
|
77
|
+
const factory: () => _backstage_backend_plugin_api.ServiceFactory<ActionsRegistryService, "plugin", "singleton">;
|
|
78
|
+
const mock: (partialImpl?: Partial<ActionsRegistryService> | undefined) => ServiceMock<ActionsRegistryService>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @alpha
|
|
83
|
+
*/
|
|
84
|
+
declare namespace actionsServiceMock {
|
|
85
|
+
const factory: () => _backstage_backend_plugin_api.ServiceFactory<ActionsService, "plugin", "singleton">;
|
|
86
|
+
const mock: (partialImpl?: Partial<ActionsService> | undefined) => ServiceMock<ActionsService>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export { MockActionsRegistry, type ServiceMock, actionsRegistryServiceMock, actionsServiceMock };
|
|
@@ -134,11 +134,19 @@ class DependencyGraph {
|
|
|
134
134
|
*/
|
|
135
135
|
async parallelTopologicalTraversal(fn) {
|
|
136
136
|
const allProvided = this.#allProvided;
|
|
137
|
-
const producedSoFar = /* @__PURE__ */ new Set();
|
|
138
137
|
const waiting = new Set(this.#nodes.values());
|
|
139
138
|
const visited = /* @__PURE__ */ new Set();
|
|
140
139
|
const results = new Array();
|
|
141
140
|
let inFlight = 0;
|
|
141
|
+
const producedRemaining = /* @__PURE__ */ new Map();
|
|
142
|
+
for (const node of this.#nodes) {
|
|
143
|
+
for (const provided of node.provides) {
|
|
144
|
+
producedRemaining.set(
|
|
145
|
+
provided,
|
|
146
|
+
(producedRemaining.get(provided) ?? 0) + 1
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
142
150
|
async function processMoreNodes() {
|
|
143
151
|
if (waiting.size === 0) {
|
|
144
152
|
return;
|
|
@@ -147,7 +155,7 @@ class DependencyGraph {
|
|
|
147
155
|
for (const node of waiting) {
|
|
148
156
|
let ready = true;
|
|
149
157
|
for (const consumed of node.consumes) {
|
|
150
|
-
if (allProvided.has(consumed) &&
|
|
158
|
+
if (allProvided.has(consumed) && producedRemaining.get(consumed) !== 0) {
|
|
151
159
|
ready = false;
|
|
152
160
|
continue;
|
|
153
161
|
}
|
|
@@ -169,7 +177,15 @@ class DependencyGraph {
|
|
|
169
177
|
inFlight += 1;
|
|
170
178
|
const result = await fn(node.value);
|
|
171
179
|
results.push(result);
|
|
172
|
-
node.provides.forEach((produced) =>
|
|
180
|
+
node.provides.forEach((produced) => {
|
|
181
|
+
const remaining = producedRemaining.get(produced);
|
|
182
|
+
if (!remaining) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
`Internal error: Node provided superfluous dependency '${produced}'`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
producedRemaining.set(produced, remaining - 1);
|
|
188
|
+
});
|
|
173
189
|
inFlight -= 1;
|
|
174
190
|
await processMoreNodes();
|
|
175
191
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DependencyGraph.cjs.js","sources":["../../../../../backend-app-api/src/lib/DependencyGraph.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ninterface NodeInput<T> {\n value: T;\n consumes?: Iterable<string>;\n provides?: Iterable<string>;\n}\n\n/** @internal */\nclass Node<T> {\n static from<T>(input: NodeInput<T>) {\n return new Node<T>(\n input.value,\n input.consumes ? new Set(input.consumes) : new Set(),\n input.provides ? new Set(input.provides) : new Set(),\n );\n }\n\n private constructor(\n readonly value: T,\n readonly consumes: Set<string>,\n readonly provides: Set<string>,\n ) {}\n}\n\n/** @internal */\nclass CycleKeySet<T> {\n static from<T>(nodes: Array<Node<T>>) {\n return new CycleKeySet<T>(nodes);\n }\n\n #nodeIds: Map<T, number>;\n #cycleKeys: Set<string>;\n\n private constructor(nodes: Array<Node<T>>) {\n this.#nodeIds = new Map(nodes.map((n, i) => [n.value, i]));\n this.#cycleKeys = new Set<string>();\n }\n\n tryAdd(path: T[]): boolean {\n const cycleKey = this.#getCycleKey(path);\n if (this.#cycleKeys.has(cycleKey)) {\n return false;\n }\n this.#cycleKeys.add(cycleKey);\n return true;\n }\n\n #getCycleKey(path: T[]): string {\n return path\n .map(n => this.#nodeIds.get(n)!)\n .sort()\n .join(',');\n }\n}\n\n/**\n * Internal helper to help validate and traverse a dependency graph.\n * @internal\n */\nexport class DependencyGraph<T> {\n static fromMap(\n nodes: Record<string, Omit<NodeInput<unknown>, 'value'>>,\n ): DependencyGraph<string> {\n return this.fromIterable(\n Object.entries(nodes).map(([key, node]) => ({\n value: String(key),\n ...node,\n })),\n );\n }\n\n static fromIterable<T>(\n nodeInputs: Iterable<NodeInput<T>>,\n ): DependencyGraph<T> {\n const nodes = new Array<Node<T>>();\n for (const nodeInput of nodeInputs) {\n nodes.push(Node.from(nodeInput));\n }\n\n return new DependencyGraph(nodes);\n }\n\n #nodes: Array<Node<T>>;\n #allProvided: Set<string>;\n\n private constructor(nodes: Array<Node<T>>) {\n this.#nodes = nodes;\n this.#allProvided = new Set();\n\n for (const node of this.#nodes.values()) {\n for (const produced of node.provides) {\n this.#allProvided.add(produced);\n }\n }\n }\n\n /**\n * Find all nodes that consume dependencies that are not provided by any other node.\n */\n findUnsatisfiedDeps(): Array<{ value: T; unsatisfied: string[] }> {\n const unsatisfiedDependencies = [];\n for (const node of this.#nodes.values()) {\n const unsatisfied = Array.from(node.consumes).filter(\n id => !this.#allProvided.has(id),\n );\n if (unsatisfied.length > 0) {\n unsatisfiedDependencies.push({ value: node.value, unsatisfied });\n }\n }\n return unsatisfiedDependencies;\n }\n\n /**\n * Detect the first circular dependency within the graph, returning the path of nodes that\n * form a cycle, with the same node as the first and last element of the array.\n */\n detectCircularDependency(): T[] | undefined {\n return this.detectCircularDependencies().next().value;\n }\n\n /**\n * Detect circular dependencies within the graph, returning the path of nodes that\n * form a cycle, with the same node as the first and last element of the array.\n */\n *detectCircularDependencies(): Generator<T[], undefined> {\n const cycleKeys = CycleKeySet.from(this.#nodes);\n\n for (const startNode of this.#nodes) {\n const visited = new Set<Node<T>>();\n const stack = new Array<[node: Node<T>, path: T[]]>([\n startNode,\n [startNode.value],\n ]);\n\n while (stack.length > 0) {\n const [node, path] = stack.pop()!;\n if (visited.has(node)) {\n continue;\n }\n visited.add(node);\n for (const consumed of node.consumes) {\n const providerNodes = this.#nodes.filter(other =>\n other.provides.has(consumed),\n );\n for (const provider of providerNodes) {\n if (provider === startNode) {\n if (cycleKeys.tryAdd(path)) {\n yield [...path, startNode.value];\n }\n\n break;\n }\n if (!visited.has(provider)) {\n stack.push([provider, [...path, provider.value]]);\n }\n }\n }\n }\n }\n return undefined;\n }\n\n /**\n * Traverses the dependency graph in topological order, calling the provided\n * function for each node and waiting for it to resolve.\n *\n * The nodes are traversed in parallel, but in such a way that no node is\n * visited before all of its dependencies.\n *\n * Dependencies of nodes that are not produced by any other nodes will be ignored.\n */\n async parallelTopologicalTraversal<TResult>(\n fn: (value: T) => Promise<TResult>,\n ): Promise<TResult[]> {\n const allProvided = this.#allProvided;\n const producedSoFar = new Set<string>();\n const waiting = new Set(this.#nodes.values());\n const visited = new Set<Node<T>>();\n const results = new Array<TResult>();\n let inFlight = 0; // Keep track of how many callbacks are in flight, so that we know if we got stuck\n\n // Find all nodes that have no dependencies that have not already been produced by visited nodes\n async function processMoreNodes() {\n if (waiting.size === 0) {\n return;\n }\n const nodesToProcess = [];\n for (const node of waiting) {\n let ready = true;\n for (const consumed of node.consumes) {\n if (allProvided.has(consumed) && !producedSoFar.has(consumed)) {\n ready = false;\n continue;\n }\n }\n if (ready) {\n nodesToProcess.push(node);\n }\n }\n\n for (const node of nodesToProcess) {\n waiting.delete(node);\n }\n\n if (nodesToProcess.length === 0 && inFlight === 0) {\n // We expect the caller to check for circular dependencies before\n // traversal, so this error should never happen\n throw new Error('Circular dependency detected');\n }\n\n await Promise.all(nodesToProcess.map(processNode));\n }\n\n // Process an individual node, and then add its produced dependencies to the set of available products\n async function processNode(node: Node<T>) {\n visited.add(node);\n inFlight += 1;\n\n const result = await fn(node.value);\n results.push(result);\n\n node.provides.forEach(produced => producedSoFar.add(produced));\n inFlight -= 1;\n await processMoreNodes();\n }\n\n await processMoreNodes();\n\n return results;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DependencyGraph.cjs.js","sources":["../../../../../backend-app-api/src/lib/DependencyGraph.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ninterface NodeInput<T> {\n value: T;\n consumes?: Iterable<string>;\n provides?: Iterable<string>;\n}\n\n/** @internal */\nclass Node<T> {\n static from<T>(input: NodeInput<T>) {\n return new Node<T>(\n input.value,\n input.consumes ? new Set(input.consumes) : new Set(),\n input.provides ? new Set(input.provides) : new Set(),\n );\n }\n\n private constructor(\n readonly value: T,\n readonly consumes: Set<string>,\n readonly provides: Set<string>,\n ) {}\n}\n\n/** @internal */\nclass CycleKeySet<T> {\n static from<T>(nodes: Array<Node<T>>) {\n return new CycleKeySet<T>(nodes);\n }\n\n #nodeIds: Map<T, number>;\n #cycleKeys: Set<string>;\n\n private constructor(nodes: Array<Node<T>>) {\n this.#nodeIds = new Map(nodes.map((n, i) => [n.value, i]));\n this.#cycleKeys = new Set<string>();\n }\n\n tryAdd(path: T[]): boolean {\n const cycleKey = this.#getCycleKey(path);\n if (this.#cycleKeys.has(cycleKey)) {\n return false;\n }\n this.#cycleKeys.add(cycleKey);\n return true;\n }\n\n #getCycleKey(path: T[]): string {\n return path\n .map(n => this.#nodeIds.get(n)!)\n .sort()\n .join(',');\n }\n}\n\n/**\n * Internal helper to help validate and traverse a dependency graph.\n * @internal\n */\nexport class DependencyGraph<T> {\n static fromMap(\n nodes: Record<string, Omit<NodeInput<unknown>, 'value'>>,\n ): DependencyGraph<string> {\n return this.fromIterable(\n Object.entries(nodes).map(([key, node]) => ({\n value: String(key),\n ...node,\n })),\n );\n }\n\n static fromIterable<T>(\n nodeInputs: Iterable<NodeInput<T>>,\n ): DependencyGraph<T> {\n const nodes = new Array<Node<T>>();\n for (const nodeInput of nodeInputs) {\n nodes.push(Node.from(nodeInput));\n }\n\n return new DependencyGraph(nodes);\n }\n\n #nodes: Array<Node<T>>;\n #allProvided: Set<string>;\n\n private constructor(nodes: Array<Node<T>>) {\n this.#nodes = nodes;\n this.#allProvided = new Set();\n\n for (const node of this.#nodes.values()) {\n for (const produced of node.provides) {\n this.#allProvided.add(produced);\n }\n }\n }\n\n /**\n * Find all nodes that consume dependencies that are not provided by any other node.\n */\n findUnsatisfiedDeps(): Array<{ value: T; unsatisfied: string[] }> {\n const unsatisfiedDependencies = [];\n for (const node of this.#nodes.values()) {\n const unsatisfied = Array.from(node.consumes).filter(\n id => !this.#allProvided.has(id),\n );\n if (unsatisfied.length > 0) {\n unsatisfiedDependencies.push({ value: node.value, unsatisfied });\n }\n }\n return unsatisfiedDependencies;\n }\n\n /**\n * Detect the first circular dependency within the graph, returning the path of nodes that\n * form a cycle, with the same node as the first and last element of the array.\n */\n detectCircularDependency(): T[] | undefined {\n return this.detectCircularDependencies().next().value;\n }\n\n /**\n * Detect circular dependencies within the graph, returning the path of nodes that\n * form a cycle, with the same node as the first and last element of the array.\n */\n *detectCircularDependencies(): Generator<T[], undefined> {\n const cycleKeys = CycleKeySet.from(this.#nodes);\n\n for (const startNode of this.#nodes) {\n const visited = new Set<Node<T>>();\n const stack = new Array<[node: Node<T>, path: T[]]>([\n startNode,\n [startNode.value],\n ]);\n\n while (stack.length > 0) {\n const [node, path] = stack.pop()!;\n if (visited.has(node)) {\n continue;\n }\n visited.add(node);\n for (const consumed of node.consumes) {\n const providerNodes = this.#nodes.filter(other =>\n other.provides.has(consumed),\n );\n for (const provider of providerNodes) {\n if (provider === startNode) {\n if (cycleKeys.tryAdd(path)) {\n yield [...path, startNode.value];\n }\n\n break;\n }\n if (!visited.has(provider)) {\n stack.push([provider, [...path, provider.value]]);\n }\n }\n }\n }\n }\n return undefined;\n }\n\n /**\n * Traverses the dependency graph in topological order, calling the provided\n * function for each node and waiting for it to resolve.\n *\n * The nodes are traversed in parallel, but in such a way that no node is\n * visited before all of its dependencies.\n *\n * Dependencies of nodes that are not produced by any other nodes will be ignored.\n */\n async parallelTopologicalTraversal<TResult>(\n fn: (value: T) => Promise<TResult>,\n ): Promise<TResult[]> {\n const allProvided = this.#allProvided;\n const waiting = new Set(this.#nodes.values());\n const visited = new Set<Node<T>>();\n const results = new Array<TResult>();\n let inFlight = 0; // Keep track of how many callbacks are in flight, so that we know if we got stuck\n\n // This keeps track of a counter of how many providers there are still left\n // to be visited for each dependency. This needs to be a counter instead of\n // a flag for the special case where there are several providers of a given\n // value, even though there may be only one consumer of it.\n const producedRemaining = new Map<string, number>();\n for (const node of this.#nodes) {\n for (const provided of node.provides) {\n producedRemaining.set(\n provided,\n (producedRemaining.get(provided) ?? 0) + 1,\n );\n }\n }\n\n // Find all nodes that have no dependencies that have not already been produced by visited nodes\n async function processMoreNodes() {\n if (waiting.size === 0) {\n return;\n }\n const nodesToProcess = [];\n for (const node of waiting) {\n let ready = true;\n for (const consumed of node.consumes) {\n if (\n allProvided.has(consumed) &&\n producedRemaining.get(consumed) !== 0\n ) {\n ready = false;\n continue;\n }\n }\n if (ready) {\n nodesToProcess.push(node);\n }\n }\n\n for (const node of nodesToProcess) {\n waiting.delete(node);\n }\n\n if (nodesToProcess.length === 0 && inFlight === 0) {\n // We expect the caller to check for circular dependencies before\n // traversal, so this error should never happen\n throw new Error('Circular dependency detected');\n }\n\n await Promise.all(nodesToProcess.map(processNode));\n }\n\n // Process an individual node, and then add its produced dependencies to the set of available products\n async function processNode(node: Node<T>) {\n visited.add(node);\n inFlight += 1;\n\n const result = await fn(node.value);\n results.push(result);\n\n node.provides.forEach(produced => {\n const remaining = producedRemaining.get(produced);\n if (!remaining) {\n // This should be impossible, if the code that generates the map is correct\n throw new Error(\n `Internal error: Node provided superfluous dependency '${produced}'`,\n );\n }\n producedRemaining.set(produced, remaining - 1);\n });\n\n inFlight -= 1;\n await processMoreNodes();\n }\n\n await processMoreNodes();\n\n return results;\n }\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.cjs.js
CHANGED
|
@@ -4,10 +4,10 @@ var TestCaches = require('./cache/TestCaches.cjs.js');
|
|
|
4
4
|
var TestDatabases = require('./database/TestDatabases.cjs.js');
|
|
5
5
|
var registerMswTestHooks = require('./msw/registerMswTestHooks.cjs.js');
|
|
6
6
|
var MockDirectory = require('./filesystem/MockDirectory.cjs.js');
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
var
|
|
7
|
+
var mockServices = require('./services/mockServices.cjs.js');
|
|
8
|
+
var mockCredentials = require('./services/mockCredentials.cjs.js');
|
|
9
|
+
var ServiceFactoryTester = require('./wiring/ServiceFactoryTester.cjs.js');
|
|
10
|
+
var TestBackend = require('./wiring/TestBackend.cjs.js');
|
|
11
11
|
var errorHandler = require('./util/errorHandler.cjs.js');
|
|
12
12
|
|
|
13
13
|
|
|
@@ -16,8 +16,6 @@ exports.TestCaches = TestCaches.TestCaches;
|
|
|
16
16
|
exports.TestDatabases = TestDatabases.TestDatabases;
|
|
17
17
|
exports.registerMswTestHooks = registerMswTestHooks.registerMswTestHooks;
|
|
18
18
|
exports.createMockDirectory = MockDirectory.createMockDirectory;
|
|
19
|
-
exports.ServiceFactoryTester = ServiceFactoryTester.ServiceFactoryTester;
|
|
20
|
-
exports.startTestBackend = TestBackend.startTestBackend;
|
|
21
19
|
Object.defineProperty(exports, "mockServices", {
|
|
22
20
|
enumerable: true,
|
|
23
21
|
get: function () { return mockServices.mockServices; }
|
|
@@ -26,5 +24,7 @@ Object.defineProperty(exports, "mockCredentials", {
|
|
|
26
24
|
enumerable: true,
|
|
27
25
|
get: function () { return mockCredentials.mockCredentials; }
|
|
28
26
|
});
|
|
27
|
+
exports.ServiceFactoryTester = ServiceFactoryTester.ServiceFactoryTester;
|
|
28
|
+
exports.startTestBackend = TestBackend.startTestBackend;
|
|
29
29
|
exports.mockErrorHandler = errorHandler.mockErrorHandler;
|
|
30
30
|
//# sourceMappingURL=index.cjs.js.map
|