Skip to content

Commit

Permalink
Merge pull request #157 from UserOfficeProject/763-fix-generic-templa…
Browse files Browse the repository at this point in the history
…te-questions-for-cloned-proposal

fix: generic template questions for cloned proposal
  • Loading branch information
mutambaraf authored Feb 8, 2023
2 parents 1fef9b8 + 614e965 commit 43cb770
Show file tree
Hide file tree
Showing 6 changed files with 387 additions and 49 deletions.
251 changes: 251 additions & 0 deletions apps/user-office-frontend-e2e/cypress/integration/generic_templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ context('GenericTemplates tests', () => {
const addButtonLabel = twoFakes(2);
const genericTemplateTitle = faker.lorem.words(3);
const genericTemplateQuestionaryQuestion = twoFakes(3);
const genericTemplateTitleAnswers = [
faker.lorem.words(3),
faker.lorem.words(3),
faker.lorem.words(3),
faker.lorem.words(3),
];
const proposalWorkflow = {
name: faker.random.words(3),
description: faker.random.words(5),
Expand Down Expand Up @@ -150,6 +156,106 @@ context('GenericTemplates tests', () => {
}
});
};
const createGenericTemplates = (count: number) => {
const genericTemaplates: number[] = [];
for (let index = 0; index <= count; index++)
cy.createTemplate({
name: faker.lorem.word(5),
groupId: TemplateGroupId.GENERIC_TEMPLATE,
}).then((result) => {
if (result.createTemplate.template) {
const genericTemplateID = result.createTemplate.template.templateId;
const topicId =
result.createTemplate.template.steps[
result.createTemplate.template.steps.length - 1
].topic.id;
cy.createQuestion({
categoryId: TemplateCategoryId.GENERIC_TEMPLATE,
dataType: DataType.TEXT_INPUT,
}).then((questionResult) => {
const createdQuestion = questionResult.createQuestion.question;
if (createdQuestion) {
cy.updateQuestion({
id: createdQuestion.id,
question: faker.lorem.words(5),
naturalKey: faker.lorem.word(5),
config: `{"required":true,"multiline":false}`,
});
cy.createQuestionTemplateRelation({
questionId: createdQuestion.id,
templateId: genericTemplateID,
sortOrder: 1,
topicId: topicId,
});
}
});

genericTemaplates.push(genericTemplateID);
}
});

return genericTemaplates;
};
const createProposalTemplateWithSubTemplate = (
genericSubTemplateIds: number[]
) => {
cy.createTemplate({
name: faker.lorem.words(3),
groupId: TemplateGroupId.PROPOSAL,
}).then((result) => {
if (result.createTemplate.template) {
const proposalTemplateId = result.createTemplate.template.templateId;
for (let index = 0; index < genericSubTemplateIds.length - 1; index++) {
cy.createTopic({
templateId: proposalTemplateId,
sortOrder: index + 1,
}).then((topicResult) => {
if (!topicResult.createTopic.template) {
throw new Error('Can not create topic');
}
const topicId =
topicResult.createTopic.template.steps[
topicResult.createTopic.template.steps.length - 1
].topic.id;
cy.updateTopic({
title: faker.lorem.words(4),
templateId: proposalTemplateId,
sortOrder: index + 1,
topicId,
});
cy.createQuestion({
categoryId: TemplateCategoryId.PROPOSAL_QUESTIONARY,
dataType: DataType.GENERIC_TEMPLATE,
}).then((questionResult) => {
if (questionResult.createQuestion.question) {
const createdQuestion1Id =
questionResult.createQuestion.question.id;

cy.updateQuestion({
id: createdQuestion1Id,
question: genericTemplateQuestion[index],
config: `{"addEntryButtonLabel":"${addButtonLabel[index]}","minEntries":"1","maxEntries":"2","templateId":${genericSubTemplateIds[index]},"templateCategory":"GENERIC_TEMPLATE","required":false,"small_label":""}`,
});

cy.createQuestionTemplateRelation({
questionId: createdQuestion1Id,
templateId: proposalTemplateId,
sortOrder: index + 1,
topicId: topicId,
});
}
});
});
}
cy.updateCall({
id: initialDBData.call.id,
...updatedCall,
templateId: proposalTemplateId,
proposalWorkflowId: workflowId,
});
}
});
};

beforeEach(() => {
// NOTE: Stop the web application and clearly separate the end-to-end tests by visiting the blank about page before each test.
Expand Down Expand Up @@ -564,4 +670,149 @@ context('GenericTemplates tests', () => {
cy.contains(proposalTitle[1]).should('not.exist');
});
});

describe('Generic template cloning tests', () => {
beforeEach(() => {
cy.createProposalWorkflow(proposalWorkflow).then((result) => {
if (result.createProposalWorkflow.proposalWorkflow) {
workflowId = result.createProposalWorkflow.proposalWorkflow.id;
const genericTemplates = createGenericTemplates(2);
createProposalTemplateWithSubTemplate(genericTemplates);
cy.createProposal({ callId: initialDBData.call.id }).then(
(result) => {
if (result.createProposal.proposal) {
const proposalPK = result.createProposal.proposal.primaryKey;
const questionarySteps =
result.createProposal.proposal.questionary.steps;
const proposal = result.createProposal.proposal;
cy.updateProposal({
proposalPk: result.createProposal.proposal.primaryKey,
title: proposalTitle[1],
abstract: faker.lorem.words(3),
proposerId: initialDBData.users.user1.id,
});

for (let index = 1; index < questionarySteps.length; index++) {
cy.createGenericTemplate({
proposalPk: result.createProposal.proposal.primaryKey,
title: genericTemplateTitleAnswers[index - 1],
questionId:
result.createProposal.proposal.questionary.steps[index]
.fields[0].question.id,
templateId: genericTemplates[index - 1],
}).then((templateResult) => {
if (
templateResult.createGenericTemplate.genericTemplate
?.questionaryId
) {
cy.answerTopic({
isPartialSave: false,
questionaryId:
templateResult.createGenericTemplate.genericTemplate
.questionaryId,
topicId:
templateResult.createGenericTemplate.genericTemplate
.questionary.steps[0].topic.id,
answers: [
{
questionId:
templateResult.createGenericTemplate
.genericTemplate.questionary.steps[0].fields[1]
.question.id,
value: '{"value":"answer"}',
},
],
});
}
});
cy.answerTopic({
questionaryId: proposal.questionaryId,
topicId: questionarySteps[index].topic.id,
isPartialSave: false,
answers: [],
});
}
cy.cloneProposals({
callId: initialDBData.call.id,
proposalsToClonePk: [proposalPK],
});
}
}
);
} else {
throw new Error('Workflow creation failed');
}
});
});
it('User should be able to modify and submit cloned proposal with generic templates', () => {
cy.login('user1');
cy.visit('/');

cy.finishedLoading();

cy.contains(`Copy of ${proposalTitle[1]}`)
.parent()
.find('[aria-label="Edit proposal"]')
.click();

cy.finishedLoading();

cy.contains('New proposal', { matchCase: true }).click();

cy.get('[data-cy=title] input').clear().type(faker.lorem.word(5));

cy.get('[data-cy=abstract] textarea').first().type(faker.lorem.words(2));

cy.contains('Save and continue').click();

cy.finishedLoading();

cy.contains(genericTemplateTitleAnswers[0]).click();

cy.get('[data-cy=title-input] textarea')
.first()
.clear()
.type(genericTemplateTitleAnswers[2])
.should('have.value', genericTemplateTitleAnswers[2])
.blur();

cy.get(
'[data-cy=genericTemplate-declaration-modal] [data-cy=save-and-continue-button]'
).click();

cy.finishedLoading();

cy.contains(genericTemplateTitleAnswers[2]);

cy.contains('Save and continue').click();

cy.finishedLoading();

cy.contains(genericTemplateTitleAnswers[1]).click();

cy.get('[data-cy=title-input] textarea')
.first()
.clear()
.type(genericTemplateTitleAnswers[3])
.should('have.value', genericTemplateTitleAnswers[3])
.blur();

cy.get(
'[data-cy=genericTemplate-declaration-modal] [data-cy=save-and-continue-button]'
).click();

cy.finishedLoading();

cy.contains(genericTemplateTitleAnswers[3]);

cy.contains('Save and continue').click();

cy.contains('Submit').click();

cy.contains('OK').click();

cy.contains(genericTemplateTitleAnswers[2]);
cy.contains(genericTemplateTitleAnswers[3]);
});
});
});
12 changes: 12 additions & 0 deletions apps/user-office-frontend-e2e/cypress/support/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import {
CreateTemplateMutation,
CreateTemplateMutationVariables,
CreateTopicMutation,
UpdateTopicMutation,
CreateTopicMutationVariables,
UpdateQuestionMutation,
UpdateQuestionMutationVariables,
UpdateQuestionTemplateRelationSettingsMutation,
UpdateQuestionTemplateRelationSettingsMutationVariables,
UpdateTopicMutationVariables,
} from '@user-office-software-libs/shared-types';

import { getE2EApi } from './utils';
Expand All @@ -43,6 +45,15 @@ const createTopic = (
return cy.wrap(request);
};

const updateTopic = (
updateTopicInput: UpdateTopicMutationVariables
): Cypress.Chainable<UpdateTopicMutation> => {
const api = getE2EApi();
const request = api.updateTopic(updateTopicInput);

return cy.wrap(request);
};

const answerTopic = (
answerTopicInput: AnswerTopicMutationVariables
): Cypress.Chainable<AnswerTopicMutation> => {
Expand Down Expand Up @@ -549,6 +560,7 @@ Cypress.Commands.add('createGenericTemplate', createGenericTemplate);
Cypress.Commands.add('navigateToTemplatesSubmenu', navigateToTemplatesSubmenu);

Cypress.Commands.add('createTopic', createTopic);
Cypress.Commands.add('updateTopic', updateTopic);
Cypress.Commands.add('answerTopic', answerTopic);

Cypress.Commands.add('createQuestion', createQuestion);
Expand Down
13 changes: 13 additions & 0 deletions apps/user-office-frontend-e2e/cypress/types/template.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
CreateQuestionTemplateRelationMutation,
CreateQuestionTemplateRelationMutationVariables,
CreateTopicMutation,
UpdateTopicMutation,
CreateGenericTemplateMutationVariables,
CreateGenericTemplateMutation,
AnswerTopicMutationVariables,
Expand Down Expand Up @@ -279,6 +280,18 @@ declare global {
createTopicInput: CreateTopicMutationVariables
) => Cypress.Chainable<CreateTopicMutation>;

/**
* Updates topic in template
*
* @returns {typeof updateTopic}
* @memberof Chainable
* @example
* cy.updateTopic(updateTopicInput: UpdateTopicMutationVariables)
*/
updateTopic: (
updateTopicInput: UpdateTopicMutationVariables
) => Cypress.Chainable<UpdateTopicMutation>;

/**
* Answers topic in proposal template
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { ProposalSubmissionState } from 'models/questionary/proposal/ProposalSub
import { ProposalWithQuestionary } from 'models/questionary/proposal/ProposalWithQuestionary';
import {
Event,
GENERIC_TEMPLATE_EVENT,
QuestionarySubmissionModel,
} from 'models/questionary/QuestionarySubmissionState';
import useEventHandlers from 'models/questionary/useEventHandlers';
Expand Down Expand Up @@ -61,8 +62,35 @@ export default function ProposalContainer(props: ProposalContainerProps) {
draftState.proposal.samples = action.newItems;
draftState.isDirty = true;
break;
case 'GENERIC_TEMPLATE_ITEMS_MODIFIED':
draftState.proposal.genericTemplates = action.newItems;
case GENERIC_TEMPLATE_EVENT.ITEMS_MODIFIED:
if (action.newItems) {
if (state.proposal.genericTemplates) {
const questionIds = action.newItems.map((value) => value.id);
draftState.proposal.genericTemplates = [
...state.proposal.genericTemplates.filter(
(value) => !questionIds.some((id) => id === value.id)
),
...action.newItems,
];
} else {
draftState.proposal.genericTemplates = action.newItems;
}
}
draftState.isDirty = true;
break;

case GENERIC_TEMPLATE_EVENT.ITEMS_DELETED:
if (action.newItems) {
if (state.proposal.genericTemplates) {
const questionIds = action.newItems.map((value) => value.id);
draftState.proposal.genericTemplates = [
...state.proposal.genericTemplates.filter(
(value) => !questionIds.some((id) => id === value.id)
),
];
action.newItems = [];
}
}
draftState.isDirty = true;
break;
}
Expand Down
Loading

0 comments on commit 43cb770

Please sign in to comment.