Signed-off-by: bnechyporenko <bnechyporenko@bol.com>
This commit is contained in:
bnechyporenko
2024-02-23 21:56:11 +01:00
committed by blam
parent 813d6dbbb2
commit 0458575373
2 changed files with 142 additions and 67 deletions
@@ -0,0 +1,57 @@
---
id: writing-tests-for-actions
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.
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.
Example how to use it:
```typescript
import { createMockActionContext } from '@backstage/scaffolder-test-utils';
const mockContext = createMockActionContext({
input: { repoUrl: 'dev.azure.com?repo=repo&owner=owner&organization=org' },
});
await action.handler(mockContext);
expect(mockContext.output).toHaveBeenCalledWith(
'remoteUrl',
'https://dev.azure.com/organization/project/_git/repo',
);
```
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:
```typescript
describe('github:autolinks:create', async () => {
const workspacePath = createMockDirectory().resolve('workspace');
// ...
it('should call the githubApis for creating alphanumeric autolink reference', async () => {
// ...
await action.handler(
createMockActionContext({
input: {
repoUrl: 'github.com?repo=repo&owner=owner',
keyPrefix: 'TICKET-',
urlTemplate: 'https://example.com/TICKET?query=<num>',
},
workspacePath,
}),
);
//...
});
});
```
@@ -213,79 +213,97 @@ export function createPublishGithubAction(options: {
requiredCommitSigning = false,
} = ctx.input;
const octokitOptions = await getOctokitOptions({
integrations,
credentialsProvider: githubCredentialsProvider,
token: providedToken,
repoUrl: repoUrl,
});
const client = new Octokit(octokitOptions);
const { _commitHash, _remoteUrl, _repoContentsUrl } =
await ctx.checkpoint?.(
'repo.create',
async (): Promise<{
_commitHash: string;
_remoteUrl: string;
_repoContentsUrl: string;
}> => {
const octokitOptions = await getOctokitOptions({
integrations,
credentialsProvider: githubCredentialsProvider,
token: providedToken,
repoUrl: repoUrl,
});
const client = new Octokit(octokitOptions);
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
if (!owner) {
throw new InputError('Invalid repository owner provided in repoUrl');
}
if (!owner) {
throw new InputError(
'Invalid repository owner provided in repoUrl',
);
}
const newRepo = await createGithubRepoWithCollaboratorsAndTopics(
client,
repo,
owner,
repoVisibility,
description,
homepage,
deleteBranchOnMerge,
allowMergeCommit,
allowSquashMerge,
squashMergeCommitTitle,
squashMergeCommitMessage,
allowRebaseMerge,
allowAutoMerge,
access,
collaborators,
hasProjects,
hasWiki,
hasIssues,
topics,
repoVariables,
secrets,
oidcCustomization,
ctx.logger,
);
const newRepo = await createGithubRepoWithCollaboratorsAndTopics(
client,
repo,
owner,
repoVisibility,
description,
homepage,
deleteBranchOnMerge,
allowMergeCommit,
allowSquashMerge,
squashMergeCommitTitle,
squashMergeCommitMessage,
allowRebaseMerge,
allowAutoMerge,
access,
collaborators,
hasProjects,
hasWiki,
hasIssues,
topics,
repoVariables,
secrets,
oidcCustomization,
ctx.logger,
);
const remoteUrl = newRepo.clone_url;
const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`;
const remoteUrl = newRepo.clone_url;
const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`;
const commitResult = await initRepoPushAndProtect(
remoteUrl,
octokitOptions.auth,
ctx.workspacePath,
ctx.input.sourcePath,
defaultBranch,
protectDefaultBranch,
protectEnforceAdmins,
owner,
client,
repo,
requireCodeOwnerReviews,
bypassPullRequestAllowances,
requiredApprovingReviewCount,
restrictions,
requiredStatusCheckContexts,
requireBranchesToBeUpToDate,
requiredConversationResolution,
config,
ctx.logger,
gitCommitMessage,
gitAuthorName,
gitAuthorEmail,
dismissStaleReviews,
requiredCommitSigning,
);
const commitResult = await initRepoPushAndProtect(
remoteUrl,
octokitOptions.auth,
ctx.workspacePath,
ctx.input.sourcePath,
defaultBranch,
protectDefaultBranch,
protectEnforceAdmins,
owner,
client,
repo,
requireCodeOwnerReviews,
bypassPullRequestAllowances,
requiredApprovingReviewCount,
restrictions,
requiredStatusCheckContexts,
requireBranchesToBeUpToDate,
requiredConversationResolution,
config,
ctx.logger,
gitCommitMessage,
gitAuthorName,
gitAuthorEmail,
dismissStaleReviews,
requiredCommitSigning,
);
ctx.output('commitHash', commitResult?.commitHash);
ctx.output('remoteUrl', remoteUrl);
ctx.output('repoContentsUrl', repoContentsUrl);
return {
_commitHash: commitResult?.commitHash,
_remoteUrl: remoteUrl,
_repoContentsUrl: repoContentsUrl,
};
},
)!!;
ctx.output('commitHash', _commitHash);
ctx.output('remoteUrl', _remoteUrl);
ctx.output('repoContentsUrl', _repoContentsUrl);
},
});
}