Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ntrnl 317 create a form for the addition of a git hub repo request #22

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const ADD_TEAM = 'add-team';
export const TEAM_REQUEST = 'team-request';
export const ADD_TEAM_MEMBER = 'add-team-member';
export const ADD_REPO = 'add-repo';
export const REPO_REQUEST = 'repo-request';

// Routing paths

Expand All @@ -36,6 +37,7 @@ export const ADD_TEAM_URL = '/add-team';
export const TEAM_REQUEST_URL = '/team-request';
export const ADD_TEAM_MEMBER_URL = '/add-team-member';
export const ADD_REPO_URL = '/add-repo';
export const REPO_REQUEST_URL = '/repo-request';

export const SERVICE_URL = `${BASE_URL}${CONFIRMATION_URL}`;

Expand Down
18 changes: 18 additions & 0 deletions src/controller/repo-request.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Request, Response } from 'express';
import { log } from '../utils/logger';
import * as config from '../config';

export const get = (_req: Request, res: Response) => {
return res.render(config.REPO_REQUEST);
};

export const post = (req: Request, res: Response) => {

const repoName = req.body.repo_name;

// validation middleware and data assignment to be implemented

log.info(`Repository Name: ${repoName}`);

return res.redirect(config.LANDING);
};
2 changes: 2 additions & 0 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import removeMemberRouter from './remove-member';
import teamRequestRouter from './team-request';
import addTeamMemberRouter from './add-team-member';
import memberRequestRouter from './member-request';
import repoRequestRouter from './repo-request';

const router = Router();

Expand All @@ -29,5 +30,6 @@ router.use(removeMemberRouter);
router.use(teamRequestRouter);
router.use(addTeamMemberRouter);
router.use(memberRequestRouter);
router.use(repoRequestRouter);

export default router;
13 changes: 13 additions & 0 deletions src/routes/repo-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Router } from 'express';

import { authentication } from '../middleware/authentication.middleware';

import { get, post } from '../controller/repo-request.controller';
import * as config from '../config';

const addRepoRouter = Router();

addRepoRouter.get(config.REPO_REQUEST_URL, authentication, get);
addRepoRouter.post(config.REPO_REQUEST_URL, authentication, post);

export default addRepoRouter;
2 changes: 1 addition & 1 deletion src/views/landing-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ <h2 class="govuk-heading-s">Repo requests</h2>
<a class="govuk-link" href="/add-repo">Add Repo</a>
</li>
<li>
<a class="govuk-link" href="#">Additional Repo Requests (e.g permission changes)</a>
<a class="govuk-link" href="/repo-request">Additional Repo Requests (e.g permission changes)</a>
</li>
</ul>
</div>
Expand Down
43 changes: 43 additions & 0 deletions src/views/repo-request.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{% extends "layout.html" %}

{% block beforeContent %}
{% include "include/back-link.html" %}
{% endblock %}

{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-l">Additional Repository Requests</h1>

<p class="govuk-body">
To request a more specific repository request that is not covered by the other options, such as permission changes.
<form method="post" novalidate>

{{ govukInput({
label: {
text: "Repository name",
classes: "govuk-label--m"
},
classes: "govuk-input--width-10",
id: "repo-name",
name: "repo_name"
}) }}
{{ govukTextarea({
name: "description",
id: "description",
label: {
text: "Description - (e.g. Permission changes) ",
classes: "govuk-label--m",
isPageHeading: true
},
hint: {
text: "Include a description of the request you would like to have completed."
}
}) }}

{% include "include/save-button.html" %}

</form>
</div>
</div>
{% endblock %}
58 changes: 58 additions & 0 deletions test/integration/routes/repo-request.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
jest.mock('../../../src/middleware/logger.middleware');
jest.mock('../../../src/middleware/authentication.middleware');
jest.mock('../../../src/utils/logger');

import { jest, beforeEach, describe, expect, test } from '@jest/globals';
import { Request, Response, NextFunction } from 'express';
import request from 'supertest';

import app from '../../../src/app';
import * as config from '../../../src/config';
import { logger } from '../../../src/middleware/logger.middleware';
import { log } from '../../../src/utils/logger';
import { authentication } from '../../../src/middleware/authentication.middleware';

import { MOCK_REDIRECT_MESSAGE, MOCK_GET_REPO_REQUEST_RESPONSE, MOCK_POST_REPO_REQUEST_RESPONSE } from '../../mock/text.mock';
import { MOCK_POST_REPO_REQUEST } from '../../mock/data';

const mockedLogger = logger as jest.Mock<typeof logger>;
mockedLogger.mockImplementation((_req: Request, _res: Response, next: NextFunction) => next());
const mockedAuth = authentication as jest.Mock<typeof authentication>;
mockedAuth.mockImplementation((_req: Request, _res: Response, next: NextFunction) => next());

describe('repo-request endpoint integration tests', () => {
beforeEach(() => {
jest.clearAllMocks();
});

describe('GET tests', () => {
test('renders the repo-request page', async () => {
const res = await request(app).get(config.REPO_REQUEST_URL);

expect(res.status).toEqual(200);
expect(res.text).toContain(MOCK_GET_REPO_REQUEST_RESPONSE);
expect(mockedLogger).toHaveBeenCalledTimes(1);
expect(mockedAuth).toHaveBeenCalledTimes(1);
});
});
describe('POST tests', () => {
test('Should redirect to landing page after POST request', async () => {
const res = await request(app).post(config.REPO_REQUEST_URL).send(MOCK_POST_REPO_REQUEST);

expect(res.status).toEqual(302);
expect(res.text).toContain(MOCK_REDIRECT_MESSAGE);
expect(mockedLogger).toHaveBeenCalledTimes(1);
expect(mockedAuth).toHaveBeenCalledTimes(1);
});
test('Should log the repository name and description on POST request', async () => {
const res = await request(app).post(config.REPO_REQUEST_URL).send(MOCK_POST_REPO_REQUEST);

const mockLog = log.info as jest.Mock;

expect(mockLog).toBeCalledWith(MOCK_POST_REPO_REQUEST_RESPONSE);
expect(res.text).toContain(MOCK_REDIRECT_MESSAGE);
expect(mockedLogger).toHaveBeenCalledTimes(1);
expect(mockedAuth).toHaveBeenCalledTimes(1);
});
});
});
1 change: 1 addition & 0 deletions test/mock/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const MOCK_POST_TEAM_REQUEST = { team_name: 'team1' };
export const MOCK_POST_MEMBER_REQUEST = { github_handle: 'example' };

export const MOCK_POST_ADD_TEAM_MEMBER = { team_name: 'team1', team_member_github_handle: 'joe' };
export const MOCK_POST_REPO_REQUEST = { repo_name: 'repo1' };

export const MOCK_CORS_VALUE = {
origin: [config.CDN_HOST, config.BASE_URL],
Expand Down
3 changes: 3 additions & 0 deletions test/mock/text.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ export const MOCK_POST_MEMBER_REQUEST_RESPONSE = 'GitHub Handle: example';
export const MOCK_GET_ADD_TEAM_MEMBER_RESPONSE = 'Add a GitHub member to a team';
export const MOCK_POST_ADD_TEAM_MEMBER_RESPONSE = 'Team Name: team1, Team Member GitHub Handle: joe';

export const MOCK_GET_REPO_REQUEST_RESPONSE = 'Additional Repository Requests';
export const MOCK_POST_REPO_REQUEST_RESPONSE = 'Repository Name: repo1';

export const MOCK_NOT_FOUND_RESPONSE = 'Page not found';
export const MOCK_SERVICE_UNAVAILABLE = 'Sorry, there is a problem with the service';
export const MOCK_SERVER_ERROR = 'Pipe 3000 requires elevated privileges';
Expand Down
58 changes: 58 additions & 0 deletions test/unit/controller/repo-request.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
jest.mock('../../../src/utils/logger');
import { describe, expect, afterEach, test, jest } from '@jest/globals';
import { Request, Response } from 'express';

import { get, post } from '../../../src/controller/repo-request.controller';
import * as config from '../../../src/config';
import { log } from '../../../src/utils/logger';

import { MOCK_POST_REPO_REQUEST } from '../../mock/data';
import { MOCK_POST_REPO_REQUEST_RESPONSE } from '../../mock/text.mock';

const req = {
body: MOCK_POST_REPO_REQUEST
} as Request;

const mockResponse = () => {
const res = {} as Response;
res.render = jest.fn().mockReturnValue(res) as any;
res.redirect = jest.fn().mockReturnValue(res) as any;
return res;
};

describe('repo-request controller test suites', () => {
afterEach(() => {
jest.resetAllMocks();
});

describe('repo-request GET tests', () => {

test('should render repo request page', () => {
const res = mockResponse();

get(req, res);

expect(res.render).toHaveBeenCalledWith(config.REPO_REQUEST);
});
});

describe('repo-request POST tests', () => {

test('should redirect to landing-page on POST request', () => {
const res = mockResponse();

post(req, res);

expect(res.redirect).toBeCalledWith(config.LANDING);
});
test('should log Repository Name on POST request', () => {
const res = mockResponse();

const mockLogInfo = log.info as jest.Mock;

post(req, res);

expect(mockLogInfo).toHaveBeenCalledWith(MOCK_POST_REPO_REQUEST_RESPONSE);
});
});
});
Loading