Skip to content
Open
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
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 30 additions & 1 deletion questionnaire/questionnaire-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@ defaults.createQuestionnaireDAL = require('./questionnaire-dal');

defaults.apiVersion = '2023-05-17';

defaults.createTaskRunner = require('./questionnaire/utils/taskRunner');
const sendNotifyMessageToSQS = require('./questionnaire/utils/taskRunner/tasks/postToNotify');
const sequential = require('./questionnaire/utils/taskRunner/tasks/sequential');

function createQuestionnaireService({
logger,
apiVersion = defaults.apiVersion,
ownerId,
createQuestionnaireDAL = defaults.createQuestionnaireDAL
createQuestionnaireDAL = defaults.createQuestionnaireDAL,
createTaskRunner = defaults.createTaskRunner
} = {}) {
const db = createQuestionnaireDAL({logger, ownerId});

Expand Down Expand Up @@ -109,6 +114,30 @@ function createQuestionnaireService({

await db.createQuestionnaire(questionnaire.id, questionnaire);

const taskImplementations = {
sendNotifyMessageToSQS
};

if (questionnaire.onCreate) {
const onCreateTaskDefinition = JSON.parse(JSON.stringify(questionnaire.onCreate));
const taskRunner = createTaskRunner({
taskImplementations: {
sequential,
...taskImplementations
},
context: {
logger,
questionnaireDef: questionnaire,
type: 'onCreate'
}
});
try {
await taskRunner.run(onCreateTaskDefinition);
} catch (error) {
logger.info(error);
}
}

if (ownerData.isAuthenticated) {
await updateExpiryForAuthenticatedOwner(questionnaire.id, ownerData.id);
}
Expand Down
73 changes: 72 additions & 1 deletion questionnaire/questionnaire-service.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ const failedSubmissionStatus = 'FAILED';
const originData = {
channel: 'telephone'
};
const onCreateTasks = {
id: 'task0',
type: 'sequential',
retries: 0,
data: [
{
id: 'task1',
type: 'sendNotifyMessageToSQS',
retries: 0,
data: {
questionnaire: '$.questionnaireDef',
logger: '$.logger'
}
}
]
};

beforeEach(() => {
jest.clearAllMocks();
Expand Down Expand Up @@ -209,6 +225,23 @@ jest.doMock('./utils/isQuestionnaireVersionCompatible', () => questionnaireVersi

const mockDalService = require('./questionnaire-dal')();

jest.doMock('./templates/templates', () => ({
templateService: {
getTemplateAsJson: async (name, version) => {
const realTemplateService = jest.requireActual('./templates/templates');
const templateAsJson = await realTemplateService.templateService.getTemplateAsJson(
name,
version
);
const template = JSON.parse(templateAsJson);
return JSON.stringify({
...template,
onCreate: onCreateTasks
});
}
}
}));

const createQuestionnaireService = require('./questionnaire-service');

describe('Questionnaire Service', () => {
Expand All @@ -227,7 +260,11 @@ describe('Questionnaire Service', () => {
});
describe('DCS API Version 2023-05-17', () => {
const questionnaireService = createQuestionnaireService({
logger: () => 'Logged from createQuestionnaire test',
logger: {
info: jest.fn(() => {
return 'Logged from createQuestionnaire test';
})
},
apiVersion,
ownerId
});
Expand Down Expand Up @@ -351,6 +388,40 @@ describe('Questionnaire Service', () => {
questionnaireService.createQuestionnaire(templatename, ownerData)
).rejects.toThrow('Owner data must be defined');
});

it('Should run any onCreate tasks defined in the questionnaire', async () => {
const runMock = jest.fn(() => 'ok!');
const questionnaireService = createQuestionnaireService({
logger: () => 'Logged from createQuestionnaire test',
apiVersion,
createTaskRunner: () => {
return {run: runMock};
}
});
await questionnaireService.createQuestionnaire(templatename, ownerData);
expect(runMock).toHaveBeenCalledWith(onCreateTasks);
});

it('Should log an error but still return if any onCreate tasks fail', async () => {
const failError = new Error('Task failed to run');
const runMock = jest.fn(() => {
throw failError;
});
const loggerMock = {info: jest.fn()};
const questionnaireService = createQuestionnaireService({
logger: loggerMock,
apiVersion,
createTaskRunner: () => {
return {run: runMock};
}
});

await expect(
questionnaireService.createQuestionnaire(templatename, ownerData)
).resolves.not.toThrow();
expect(runMock).toHaveBeenCalledWith(onCreateTasks);
expect(loggerMock.info).toHaveBeenCalledWith(failError);
});
});

describe('getProgressEntries', () => {
Expand Down
6 changes: 3 additions & 3 deletions questionnaire/questionnaire/questionnaire.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ function createQuestionnaire({
if (sectionDefinitionVars !== undefined && allowSummary === true) {
const resolvedVars = getResolvedVars(sectionId, sectionDefinitionVars);
if (resolvedVars.summary) {
if (sectionDefinition.schema.options) {
if (sectionDefinition.schema.options?.ordering) {
const sortingInstructions = sectionDefinition.schema.options.ordering;
resolvedVars.summary = sortThemedAnswers(
resolvedVars.summary,
Expand Down Expand Up @@ -346,8 +346,8 @@ function createQuestionnaire({
return undefined;
}

function getPermittedActions() {
const actions = questionnaireDefinition?.meta?.onComplete?.actions;
function getPermittedActions(type = 'onComplete') {
const actions = questionnaireDefinition?.meta?.[type]?.actions;

if (actions) {
const answersAndRoles = {
Expand Down
39 changes: 39 additions & 0 deletions questionnaire/questionnaire/questionnaire.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1260,4 +1260,43 @@ describe('Questionnaire', () => {
});
});
});
describe('Given both "onComplete" and "onCreate" actions definitions', () => {
it('should return actions of the correct type', () => {
const questionnaire = createQuestionnaire({
questionnaireDefinition: {
meta: {
onComplete: {
actions: [
{
type: 'actionA'
},
{
type: 'actionD'
}
]
},
onCreate: {
actions: [
{
type: 'actionC'
},
{
type: 'actionB'
}
]
}
}
}
});
const completeActions = questionnaire.getPermittedActions('onComplete');
const completeActionTypes = completeActions.map(action => action.type);
expect(completeActionTypes.length).toEqual(2);
expect(completeActionTypes).toEqual(['actionA', 'actionD']);

const createActions = questionnaire.getPermittedActions('onCreate');
const createActionTypes = createActions.map(action => action.type);
expect(createActionTypes.length).toEqual(2);
expect(createActionTypes).toEqual(['actionC', 'actionB']);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
const createSqsService = require('../../../../../../services/sqs/index');
const createQuestionnaireHelper = require('../../../../questionnaire');

async function sendNotifyMessageToSQS({questionnaire, logger}) {
async function sendNotifyMessageToSQS({questionnaire, logger, type}) {
const questionnaireId = questionnaire.id;
logger.info(`Sending notify message to SQS for questionnaire with id ${questionnaireId}`);
const sqsService = createSqsService({logger});
const questionnaireDef = createQuestionnaireHelper({questionnaireDefinition: questionnaire});
const permittedActions = questionnaireDef.getPermittedActions();
const permittedActions = questionnaireDef.getPermittedActions(type);
let sqsResponse = {MessageId: 'MessageId'};

await Promise.all(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,26 @@ describe('Post to Notify task', () => {
expect(sendMock).toHaveBeenCalledTimes(1);
expect(mockLogger.info).toHaveBeenCalledTimes(1);
});

it('Should complete onCreate actions if the type is onCreate', async () => {
sendMock = mockSqsService.mockImplementation(() => ({
send: payload => payload
}));
const data = {
questionnaire: questionnaireWithEmail,
logger: mockLogger,
type: 'onCreate'
};
const messageResult = await sendNotifyMessageToSQS(data);
expect(sendMock).toHaveBeenCalledTimes(1);
expect(messageResult).toEqual({
reference: null,
templateId: '00000000-aaaa-0000-aaaa-000000000000',
emailAddress: 'foo@bar.com',
personalisation: {
caseReference: '12/34567',
content: undefined
}
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,22 @@
}
]
},
"onCreate": {
"actions": [
{
"data": {
"reference": null,
"templateId": "00000000-aaaa-0000-aaaa-000000000000",
"emailAddress": "foo@bar.com",
"personalisation": {
"caseReference": "12/34567"
}
},
"type": "sendEmail",
"description": "Notification email - applicant:adult"
}
]
},
"questionnaireDocumentVersion": "4.2.0"
},
"type": "apply-for-compensation",
Expand Down
8 changes: 7 additions & 1 deletion questionnaire/routes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,13 @@ describe('Openapi version 2023-05-17 validation', () => {
`Resource /api/questionnaires/${id}/sections/${section}/answers does not exist`
);
}
return 'ok';
return {
data: {
type: 'answers',
id: 'id',
attributes: 'coerced answers'
}
};
}),
updateQuestionnaireSubmissionStatus: jest.fn(() => {
return 'ok';
Expand Down
3 changes: 2 additions & 1 deletion questionnaire/submissions/submissions-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ function createSubmissionService({
},
context: {
logger,
questionnaireDef: questionnaireDefinition
questionnaireDef: questionnaireDefinition,
type: 'onComplete'
}
});

Expand Down
Loading