feat: add epic scope tests

Signed-off-by: Elaine Mattos <elaine.mattos@gmail.com>
This commit is contained in:
Elaine De-Mattos-Silva-Bezerra
2023-12-18 22:58:58 +01:00
committed by Elaine Mattos
parent 31904c79e4
commit 40dcabc994
4 changed files with 204 additions and 61 deletions
@@ -37,7 +37,7 @@ jest.mock('@gitbeaker/rest', () => ({
describe('gitlab:issues:create', () => {
beforeEach(() => {
jest.clearAllMocks();
advanceTo(new Date(1990, 9, 24, 12, 0, 0)); // Set the desired date and time
advanceTo(new Date(1988, 5, 3, 12, 0, 0)); // Set the desired date and time
});
afterEach(() => {
@@ -157,4 +157,61 @@ describe('gitlab:issues:create', () => {
'https://gitlab.com/hangar18-/issues/42',
);
});
it('should return a Gitlab issue when called with several input params', async () => {
const mockContext = {
input: {
repoUrl: 'gitlab.com?repo=repo&owner=owner',
projectId: 123,
issueType: 'incident',
title: 'Computer banks to rule the world',
description:
'this issue should kickstart research on instruments to sight the stars',
dueDate: '1990-08-20T23:59:59Z',
token: 'myAwesomeToken',
assignees: [3, 14, 15],
labels: 'operation:mindcrime',
},
workspacePath: 'seen2much',
logger: getVoidLogger(),
logStream: new PassThrough(),
output: jest.fn(),
createTemporaryDirectory: jest.fn(),
};
mockGitlabClient.Issues.create.mockResolvedValue({
id: 42,
web_url: 'https://gitlab.com/hangar18-/issues/42',
});
await action.handler({
...mockContext,
});
expect(mockGitlabClient.Issues.create).toHaveBeenCalledWith(
123,
'Computer banks to rule the world',
{
issueType: 'incident',
description:
'this issue should kickstart research on instruments to sight the stars',
assigneeIds: [3, 14, 15],
confidential: false,
epicId: undefined,
labels: 'operation:mindcrime',
createdAt: new Date().toISOString(),
dueDate: '1990-08-20T23:59:59.000Z',
discussionToResolve: '',
mergeRequestToResolveDiscussionsOf: undefined,
milestoneId: undefined,
weight: undefined,
},
);
expect(mockContext.output).toHaveBeenCalledWith('issueId', 42);
expect(mockContext.output).toHaveBeenCalledWith(
'issueUrl',
'https://gitlab.com/hangar18-/issues/42',
);
});
});
@@ -177,7 +177,6 @@ export const createGitlabIssueAction = (options: {
);
}
}
console.log('After epic test');
const mappedCreatedAt = convertDate(
String(createdAt),
new Date().toISOString(),
@@ -200,11 +199,6 @@ export const createGitlabIssueAction = (options: {
milestoneId,
weight,
};
console.log('After setting issues options');
console.log({ issueOptions });
console.log(`Other options: ${projectId}, ${title}`);
console.log({ token });
const response = (await api.Issues.create(
projectId,
@@ -212,14 +206,14 @@ export const createGitlabIssueAction = (options: {
issueOptions,
)) as IssueSchema;
console.log('After calling the issues endpoint');
ctx.output('issueId', response.id);
ctx.output('issueUrl', response.web_url);
} catch (error: any) {
if (error instanceof z.ZodError) {
// Handling Zod validation errors
throw new InputError(`Validation error: ${error.message}`);
throw new InputError(`Validation error: ${error.message}`, {
validationErrors: error.errors,
});
}
// Handling other errors
throw new InputError(`Failed to create GitLab issue: ${error.message}`);
@@ -19,24 +19,26 @@ import { Gitlab, GroupSchema } from '@gitbeaker/rest';
import { InputError } from '@backstage/errors';
// Mock the Gitlab client and its methods
const setupGitlabMock = () => {
jest.mock('@gitbeaker/rest', () => {
return {
Gitlab: jest.fn().mockImplementation(() => ({
Groups: {
show: jest.fn(),
},
Projects: {
show: jest.fn(),
},
Epics: {
all: jest.fn(),
},
})),
};
});
const mockGitlabClient = {
Groups: {
show: jest.fn(),
},
Projects: {
show: jest.fn(),
},
Epics: {
all: jest.fn(),
},
};
jest.mock('@gitbeaker/rest', () => ({
Gitlab: class {
constructor() {
return mockGitlabClient;
}
},
}));
const mockConfig = {
gitlab: [
{
@@ -51,10 +53,6 @@ const mockConfig = {
],
};
describe('getTopLevelParentGroup', () => {
beforeEach(() => {
setupGitlabMock();
});
afterEach(() => jest.resetAllMocks());
// Mocked nested groups
@@ -149,7 +147,7 @@ describe('getTopLevelParentGroup', () => {
it('should return the top-level parent group if the input group has a parent in the hierarchy', async () => {
// Instance with token
const mockGitlabClient = new Gitlab({
const apiClient = new Gitlab({
host: mockConfig.gitlab[0].host,
token: mockConfig.gitlab[0].token!,
});
@@ -166,7 +164,7 @@ describe('getTopLevelParentGroup', () => {
},
);
const action = util.getTopLevelParentGroup(mockGitlabClient, 123);
const action = util.getTopLevelParentGroup(apiClient, 123);
const result = await action;
expect(result).toEqual(mockTopParentGroup);
@@ -174,7 +172,7 @@ describe('getTopLevelParentGroup', () => {
it('should return the input group if it has no parents in the hierarchy', async () => {
// Instance with token
const mockGitlabClient = new Gitlab({
const apiClient = new Gitlab({
host: mockConfig.gitlab[0].host,
token: mockConfig.gitlab[0].token!,
});
@@ -191,7 +189,7 @@ describe('getTopLevelParentGroup', () => {
},
);
const action = util.getTopLevelParentGroup(mockGitlabClient, 789);
const action = util.getTopLevelParentGroup(apiClient, 789);
const result = await action;
expect(result).toEqual(mockTopParentGroup);
@@ -201,8 +199,8 @@ describe('getTopLevelParentGroup', () => {
describe('checkEpicScope', () => {
afterEach(() => jest.resetAllMocks());
it('should return true if the project and epic are found', async () => {
const mockGitlabClient = new Gitlab({
it('should return true if the project is inside the epic scope', async () => {
const apiClient = new Gitlab({
host: mockConfig.gitlab[0].host,
token: mockConfig.gitlab[0].token!,
});
@@ -210,17 +208,25 @@ describe('checkEpicScope', () => {
const projectId = 123;
const epicId = 456;
// Mock project and top-level parent group
const mockProject = { namespace: { id: 789 } };
const mockTopParentGroup = { id: 789, name: 'MockGroup' };
// Mock project, top-level parent group, and epic
const mockProject = {
id: 123,
name: 'You learn',
namespace: { id: 789 },
path_with_namespace: 'at-once/you-learn',
};
const mockTopParentGroup = {
id: 789,
name: 'LivingTwice',
full_path: 'at-once/you-learn',
};
const mockEpic = { id: epicId, group_id: 789 };
mockGitlabClient.Projects.show.mockResolvedValue(mockProject);
mockGitlabClient.Groups.show.mockResolvedValue(mockTopParentGroup);
mockGitlabClient.Epics.all.mockResolvedValue([
{ id: epicId, group_id: 789 },
]);
mockGitlabClient.Epics.all.mockResolvedValue([mockEpic]);
const result = await checkEpicScope(mockGitlabClient, projectId, epicId);
const result = await util.checkEpicScope(apiClient, projectId, epicId);
expect(result).toBe(true);
expect(mockGitlabClient.Projects.show).toHaveBeenCalledWith(projectId);
@@ -232,26 +238,116 @@ describe('checkEpicScope', () => {
);
});
it('should throw InputError if the project is not found', async () => {
const mockClient = new Gitlab();
it('should return false if the project is not inside the epic scope', async () => {
const apiClient = new Gitlab({
host: mockConfig.gitlab[0].host,
token: mockConfig.gitlab[0].token!,
});
const projectId = 123;
const epicId = 45;
// Mock project, top-level parent group, and epic
const mockProject = {
id: 123,
name: 'You learn',
namespace: { id: 32 },
path_with_namespace: 'at-once/you-learn',
};
const mockTopParentGroup = {
id: 32,
name: 'TheWalls',
full_path: 'you-built/within',
};
const mockEpic = { id: epicId, group_id: 32 };
mockGitlabClient.Projects.show.mockResolvedValue(mockProject);
mockGitlabClient.Groups.show.mockResolvedValue(mockTopParentGroup);
mockGitlabClient.Epics.all.mockResolvedValue([mockEpic]);
const result = await util.checkEpicScope(apiClient, projectId, epicId);
expect(result).toBe(false);
expect(mockGitlabClient.Projects.show).toHaveBeenCalledWith(projectId);
expect(mockGitlabClient.Groups.show).toHaveBeenCalledWith(
mockProject.namespace.id,
);
expect(mockGitlabClient.Epics.all).toHaveBeenCalledWith(
mockTopParentGroup.id,
);
});
it('should throw an InputError if the project is not found', async () => {
const apiClient = new Gitlab({
host: mockConfig.gitlab[0].host,
token: mockConfig.gitlab[0].token!,
});
const projectId = 123;
const epicId = 456;
// Mocking the absence of the project
mockClient.Projects.show.mockResolvedValue(null);
mockGitlabClient.Projects.show.mockResolvedValue(null);
await expect(checkEpicScope(mockClient, projectId, epicId)).rejects.toThrow(
new InputError(
`Project with id ${projectId} not found. Check your GitLab instance.`,
),
);
expect(mockClient.Projects.show).toHaveBeenCalledWith(projectId);
expect(mockClient.Groups.show).not.toHaveBeenCalled();
expect(mockClient.Epics.all).not.toHaveBeenCalled();
await expect(
util.checkEpicScope(apiClient, projectId, epicId),
).rejects.toThrow(InputError);
expect(mockGitlabClient.Projects.show).toHaveBeenCalledWith(projectId);
});
// Add more test cases as needed for different scenarios
it('should throw an InputError if the top-level parent group is not found', async () => {
const apiClient = new Gitlab({
host: mockConfig.gitlab[0].host,
token: mockConfig.gitlab[0].token!,
});
const projectId = 123;
const epicId = 456;
mockGitlabClient.Projects.show.mockResolvedValue({
id: 123,
name: 'You learn',
namespace: { id: 789 },
path_with_namespace: 'at-once/you-learn',
});
mockGitlabClient.Groups.show.mockResolvedValue(null);
await expect(
util.checkEpicScope(apiClient, projectId, epicId),
).rejects.toThrow(InputError);
expect(mockGitlabClient.Projects.show).toHaveBeenCalledWith(projectId);
expect(mockGitlabClient.Groups.show).toHaveBeenCalledWith(789);
});
it('should throw an InputError if the epic is not found', async () => {
const apiClient = new Gitlab({
host: mockConfig.gitlab[0].host,
token: mockConfig.gitlab[0].token!,
});
const projectId = 123;
const epicId = 456;
mockGitlabClient.Projects.show.mockResolvedValue({
id: 123,
name: 'You learn',
namespace: { id: 789 },
path_with_namespace: 'at-once/you-learn',
});
mockGitlabClient.Groups.show.mockResolvedValue({
id: 789,
name: 'LivingTwice',
full_path: 'at-once/you-learn',
});
mockGitlabClient.Epics.all.mockResolvedValue([]);
await expect(
util.checkEpicScope(apiClient, projectId, epicId),
).rejects.toThrow(InputError);
expect(mockGitlabClient.Projects.show).toHaveBeenCalledWith(projectId);
expect(mockGitlabClient.Groups.show).toHaveBeenCalledWith(789);
expect(mockGitlabClient.Epics.all).toHaveBeenCalledWith(789);
});
});
describe('convertDate', () => {
@@ -120,7 +120,6 @@ export function getClient(props: {
};
gitlabOptions[tokenType] = requestToken;
console.log({ gitlabOptions });
return new Gitlab(gitlabOptions);
}
@@ -177,12 +176,10 @@ export async function checkEpicScope(
if (!topParentGroup) {
throw new InputError(`Couldn't find a suitable top-level parent group.`);
}
// Get the epic
const epic = (await client.Epics.all(topParentGroup.id)).find(
(x: any) => x.id === epicId,
);
if (!epic) {
throw new InputError(
`Epic with id ${epicId} not found in the top-level parent group ${topParentGroup.name}.`,
@@ -191,7 +188,6 @@ export async function checkEpicScope(
const epicGroup = await client.Groups.show(epic.group_id as number);
const projectNamespace: string = project.path_with_namespace as string;
return projectNamespace.startsWith(epicGroup.full_path as string);
} catch (error: any) {
throw new InputError(`Could not find epic scope: ${error.message}`);