Skip to content

Commit

Permalink
Tmi2 364/add redirection logic for new mandatory question journey (#89)
Browse files Browse the repository at this point in the history
* initial commit

* add redirection logic, and mock page for new journey

* add test coverage

* ignore temporary snyk dependency check, rename page

* fix indentation

* update snyk ignore policy

* update snyk rule

* fix start page url

* add more test coverage, in case of error we now redirect to an error page
  • Loading branch information
a-lor-cab authored Oct 11, 2023
1 parent f7fcbb6 commit babc124
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 2 deletions.
2 changes: 1 addition & 1 deletion packages/admin/.snyk
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ ignore:
Dev dependency - upgrade requires migration to next 13
expires: 2023-10-09T14:10:46.319Z
created: 2023-12-09T14:10:46.321Z
patch: {}
patch: {}
2 changes: 1 addition & 1 deletion packages/applicant/.snyk
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ ignore:
Dev dependency - upgrade requires migration to next 13
expires: 2023-10-09T14:10:46.319Z
created: 2023-12-09T14:10:46.321Z
patch: {}
patch: {}
125 changes: 125 additions & 0 deletions packages/applicant/src/pages/api/redirect-from-find.page.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { merge } from 'lodash';
import { AdvertDto, getAdvertBySlug } from '../../services/GrantAdvertService';
import { getJwtFromCookies } from '../../utils/jwt';
import handler from './redirect-from-find.page';

// Mock the getAdvertBySlug function (you may need to adjust this based on your actual implementation)
jest.mock('../../services/GrantAdvertService');
jest.mock('../../utils/jwt');
const mockedRedirect = jest.fn();
const mockedSetHeader = jest.fn();
const mockedSend = jest.fn();

const req = (overrides: any = {}) =>
merge({
query: {
slug: 'slug',
},
});

const res = (overrides: any = {}) =>
merge(
{
redirect: mockedRedirect,
setHeader: mockedSetHeader,
send: mockedSend,
},
overrides
);

describe('API Handler Tests', () => {
beforeEach(() => {
process.env.HOST = 'http://localhost';
jest.resetAllMocks();
});
it('should redirect to /applications/<applicationId> when advert is version 1 and have internal application', async () => {
const advertDTO: AdvertDto = {
id: '123',
version: 1,
grantApplicationId: 123,
isInternal: true,
grantSchemeId: 456,
externalSubmissionUrl: 'http://example.com',
};

(getAdvertBySlug as jest.Mock).mockResolvedValue(advertDTO);
(getJwtFromCookies as jest.Mock).mockReturnValue('testJwt');
await handler(req(), res());

expect(mockedRedirect).toHaveBeenCalledWith(
'http://localhost/applications/123'
);
});
it('should redirect to the external Submission Url when advert is version 1 and have internal application', async () => {
const advertDTO: AdvertDto = {
id: '123',
version: 1,
grantApplicationId: 123,
isInternal: false,
grantSchemeId: 456,
externalSubmissionUrl: 'http://example.com',
};

(getAdvertBySlug as jest.Mock).mockResolvedValue(advertDTO);
(getJwtFromCookies as jest.Mock).mockReturnValue('testJwt');
await handler(req(), res());

expect(mockedRedirect).toHaveBeenCalledWith('http://example.com');
});

it('should redirect to the new Mandatory Question journey start page when advert is version 2 and have internal application', async () => {
const advertDTO: AdvertDto = {
id: '123',
version: 2,
grantApplicationId: 123,
isInternal: true,
grantSchemeId: 456,
externalSubmissionUrl: 'http://example.com',
};

(getAdvertBySlug as jest.Mock).mockResolvedValue(advertDTO);
(getJwtFromCookies as jest.Mock).mockReturnValue('testJwt');
await handler(req(), res());

expect(mockedRedirect).toHaveBeenCalledWith(
'http://localhost/mandatory-questions/start?schemeId=456'
);
});

it('should redirect to the new Mandatory Question journey start page when advert is version 2 and have external application', async () => {
const advertDTO: AdvertDto = {
id: '123',
version: 2,
grantApplicationId: 123,
isInternal: false,
grantSchemeId: 456,
externalSubmissionUrl: 'http://example.com',
};

(getAdvertBySlug as jest.Mock).mockResolvedValue(advertDTO);
(getJwtFromCookies as jest.Mock).mockReturnValue('testJwt');
await handler(req(), res());

expect(mockedRedirect).toHaveBeenCalledWith(
'http://localhost/mandatory-questions/start?schemeId=456'
);
});
it('should redirect to the service Error when there is an error in the call to the backend', async () => {
(getAdvertBySlug as jest.Mock).mockRejectedValue(new Error('error'));
(getJwtFromCookies as jest.Mock).mockReturnValue('testJwt');
await handler(req(), res());
const serviceErrorProps = {
errorInformation: 'There was an error in the service',
linkAttributes: {
href: '/dashboard',
linkText: 'Go back to your dashboard',
linkInformation: '',
},
};
expect(mockedRedirect).toHaveBeenCalledWith(
`http://localhost/service-error?serviceErrorProps=${JSON.stringify(
serviceErrorProps
)}`
);
});
});
47 changes: 47 additions & 0 deletions packages/applicant/src/pages/api/redirect-from-find.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { NextApiRequest, NextApiResponse } from 'next';
import { getAdvertBySlug } from '../../services/GrantAdvertService';
import { getJwtFromCookies } from '../../utils/jwt';
import { routes } from '../../utils/routes';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const slug = req.query.slug as string;
try {
const {
externalSubmissionUrl,
version,
grantApplicationId,
isInternal,
grantSchemeId,
} = await getAdvertBySlug(getJwtFromCookies(req), slug);

if (version === 1) {
const redirectUrl = isInternal
? `${process.env.HOST}${routes.applications}/${grantApplicationId}`
: externalSubmissionUrl;
res.redirect(redirectUrl);
}

if (version === 2) {
res.redirect(
`${process.env.HOST}${routes.mandatoryQuestions.startPage(
grantSchemeId.toString()
)}`
);
}
} catch (e) {
const serviceErrorProps = {
errorInformation: 'There was an error in the service',
linkAttributes: {
href: routes.dashboard,
linkText: 'Go back to your dashboard',
linkInformation: '',
},
};
console.log(e);
res.redirect(
`${process.env.HOST}${routes.serviceError(serviceErrorProps)}`
);
}
}
17 changes: 17 additions & 0 deletions packages/applicant/src/pages/mandatory-questions/start.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Layout from '../../components/partials/Layout';
import Meta from '../../components/partials/Meta';
import { routes } from '../../utils/routes';

const FirstMandatoryQuestion = () => {
return (
<>
<Meta title="View my applications - Apply for a grant" />

<Layout backBtnUrl={routes.dashboard}>
<>NEW PAGE</>
</Layout>
</>
);
};

export default FirstMandatoryQuestion;
48 changes: 48 additions & 0 deletions packages/applicant/src/services/GrantAdvertService.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import axios from 'axios';
import { AdvertDto, getAdvertBySlug } from './GrantAdvertService';

jest.mock('axios');

const BACKEND_HOST = process.env.BACKEND_HOST + '/grant-adverts';
const advertDTO: AdvertDto = {
id: '123',
version: 2,
grantApplicationId: 123,
isInternal: true,
grantSchemeId: 456,
externalSubmissionUrl: 'http://example.com',
};
describe('GrantAdvert Service', () => {
beforeEach(() => {
jest.resetAllMocks();
});

describe('getGrantBeneficiary', () => {
it('Should call axios', async () => {
(axios.get as jest.Mock).mockResolvedValue({});

await getAdvertBySlug('testJwt', 'slug');

expect(axios.get as jest.Mock).toHaveBeenNthCalledWith(
1,
`${BACKEND_HOST}?contentfulSlug=slug`,
{
headers: {
Accept: 'application/json',
Authorization: 'Bearer testJwt',
},
}
);
});

it('Should return a GrantBeneficiary', async () => {
(axios.get as jest.Mock).mockResolvedValue({
data: advertDTO,
});

const response = await getAdvertBySlug('testJwt', 'slug');

expect(response).toStrictEqual(advertDTO);
});
});
});
26 changes: 26 additions & 0 deletions packages/applicant/src/services/GrantAdvertService.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import axios from 'axios';
import getConfig from 'next/config';
import { axiosConfig } from '../utils/jwt';

const { serverRuntimeConfig } = getConfig();
const BACKEND_HOST = serverRuntimeConfig.backendHost;

export async function getAdvertBySlug(
jwt: string,
slug: string
): Promise<AdvertDto> {
const { data } = await axios.get<AdvertDto>(
`${BACKEND_HOST}/grant-adverts?contentfulSlug=${slug}`,
axiosConfig(jwt)
);
return data;
}

export interface AdvertDto {
id: string;
externalSubmissionUrl: string;
version: number;
grantApplicationId: number | null;
isInternal: boolean;
grantSchemeId: number;
}
6 changes: 6 additions & 0 deletions packages/applicant/src/utils/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export const routes = {
name: '/organisation/name',
type: '/organisation/type',
},
mandatoryQuestions: {
startPage: (schemeId: string) =>
`/mandatory-questions/start?schemeId=${schemeId}`,
},
applications: '/applications',
submissions: {
index: '/submissions',
Expand All @@ -33,6 +37,8 @@ export const routes = {
`/submissions/${grantSubmissionId}/submission-confirmation`,
},
findAGrant: publicRuntimeConfig.FIND_A_GRANT_URL,
serviceError: (serviceErrorProps) =>
`/service-error?serviceErrorProps=${JSON.stringify(serviceErrorProps)}`,
api: {
submissions: {
section: (grantSubmissionId: string, sectionId: string) =>
Expand Down

0 comments on commit babc124

Please sign in to comment.