diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index 1e289d2409..d8e6feb559 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -734,7 +734,7 @@ an entity reference, such as the `kind`, `namespace`, and `name`. ### pick -This `pick` filter allows you to select specific properties from an object. +This `pick` filter allows you to select specific properties (`kind`, `namespace`, `name`) from an object. **Usage Example** diff --git a/docs/features/software-templates/writing-tests-for-actions.md b/docs/features/software-templates/writing-tests-for-actions.md index 0c92811b6f..0bfd97e49f 100644 --- a/docs/features/software-templates/writing-tests-for-actions.md +++ b/docs/features/software-templates/writing-tests-for-actions.md @@ -4,15 +4,13 @@ title: Writing Tests For Actions description: How to write tests for actions --- -Once you created a new action, your own custom one, or you would like to contribute new actions, you have to cover it with -Unit tests to be sure that your actions do what they suppose to do. +# Unit Testing Custom Actions -Make sure that you cover the most of scenario's, which could happen with the action. -One of indispensable part of the test is to supply the context to a handler of action for the execution. -We encourage you to use a utility method for that, so your tests are immune to structural changes of context. -What is inevitably going to happen during the time. +Unit tests help prevent regressions in custom action functionality. The `createTemplateAction` function that is the core of a custom action can be difficult to mock. There are helper methods that can assist. -Example how to use it: +## Mocking the Context + +The `handler` property of the `createTemplateAction` input object expects a context. You can create a mock context using the code below: ```typescript import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; @@ -29,10 +27,11 @@ expect(mockContext.output).toHaveBeenCalledWith( ); ``` +### Mocking a Workspace within the Context object + One thing to be aware about: if you would like to call `createMockActionContext` inside `it`, you have to provide a `workspacePath`. By default, `createMockActionContext` uses -`import { createMockDirectory } from '@backstage/backend-test-utils';` to create it for you. -This implementation contains a hook inside which creates this limitation. So in this case you can do then: +`import { createMockDirectory } from '@backstage/backend-test-utils';` to create it for you. You can use the code below to customize the `workspacePath` without using the default workspace of the `createMockActionContext` function. ```typescript describe('github:autolinks:create', async () => { @@ -55,3 +54,63 @@ describe('github:autolinks:create', async () => { }); }); ``` + +## Mocking a Config Core Service + +If your custom Action requires the Config Core Service within execution of the `handler(ctx)` such as the custom action below, mocking the context object can be done by building a `mockContext` with the `ConfigReader` function within the `@backstage/config` package. + +```typescript +// custom-action.ts +import { Config } from '@backstage/config'; + +export const customActionRequiringConfigCoreService = (config: Config) => { + const fieldRequiringValueFromConfig = config.getString('app.service.url'); + return createTemplateAction({ + ... + async handler(ctx) { + // Some code requiring the config const + ctx.logger.info(fieldRequiringValueFromConfig); + } + }) +} +``` + +```typescript +// custom-action.test.ts +import { ConfigReader } from '@backstage/config'; +import { customActionRequiringConfigCoreService } from './custom-action.ts'; +... +const mockConfig = new ConfigReader({ + app: { + service: { + url: 'https://api.service.io/graphql', + apiKeyId: '123', + apiKeySecret: '123abc', + }, + }, +}); +... +const action = customActionRequiringConfigCoreService(mockConfig); +await action.handler({ + ...mockContext +}) +``` + +## Mocking a Cache Core Service + +Similar to the `Mocking a Config Core Service` section above, if your custom action expects a Cache Core Service Object as part of the function input, you can mock it out with the following: + +```typescript +import { CacheService } from '@backstage/backend-plugin-api'; + +const mockCacheServiceMethods = { + get: jest.fn(), + set: jest.fn(), + delete: jest.fn(), +}; + +const mockCacheService = mockCacheServiceMethods as unknown as CacheService; + +const action = customActionRequiringCacheCoreService(mockCacheService); +... +```