From 4d238358ecc89af36631bef1d86314b15b7d9df7 Mon Sep 17 00:00:00 2001 From: suryabulusu Date: Mon, 23 Oct 2023 18:21:22 +0530 Subject: [PATCH 1/3] lots of ui changes --- README.md | 4 ++ src/components/Omr/OmrItem.vue | 33 ++++++++-- src/components/Questions/Body.vue | 28 ++++++++- src/components/Questions/Footer.vue | 62 +++++++++---------- src/components/Questions/QuestionModal.vue | 2 +- tests/unit/components/Questions/Body.spec.ts | 28 ++++++++- .../unit/components/Questions/Footer.spec.ts | 8 +-- 7 files changed, 116 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index e55f18c..74e140c 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,10 @@ The actual deployment happens through Github Actions. Look at `.github/workflows ``` npm run test:unit ``` +To run unit tests for individual spec files (say, for Header component), use: +``` +npm run test:unit -- Header.spec.ts +``` ### Run the end-to-end tests diff --git a/src/components/Omr/OmrItem.vue b/src/components/Omr/OmrItem.vue index 8d743c6..f7621d5 100644 --- a/src/components/Omr/OmrItem.vue +++ b/src/components/Omr/OmrItem.vue @@ -55,14 +55,14 @@
+ +
+ Correct Answer: {{ correctAnswer }} +
@@ -192,6 +208,7 @@ export default defineComponent({ draftAnswer: props.submittedAnswer as DraftResponse, // answer for the current question nonGradedAnswerClass: "bg-gray-200", correctOptionClass: "text-white bg-green-500", + skippedCorrectOptionClass: "border-4 border-green-500", wrongOptionClass: "text-white bg-red-500", disabledOptionClass: "bg-gray-200", questionHeaderTextClass: @@ -242,7 +259,13 @@ export default defineComponent({ props.isGradedQuestion && props.correctAnswer.indexOf(optionIndex) != -1 ) { - return state.correctOptionClass + if (state.draftAnswer != null && + state.draftAnswer.indexOf(optionIndex) != -1) { + // if both correct and submitted option + return state.correctOptionClass + } + // if correct but not in submitted option + return state.skippedCorrectOptionClass } if ( (!isQuizAssessment.value || props.hasQuizEnded) && diff --git a/src/components/Questions/Body.vue b/src/components/Questions/Body.vue index c4bc339..6f7361f 100644 --- a/src/components/Questions/Body.vue +++ b/src/components/Questions/Body.vue @@ -127,6 +127,14 @@ {{ charactersLeft }}

+ +
+ Correct Answer: {{ correctAnswer }} +
+ +
+ Correct Answer: {{ correctAnswer }} +
@@ -296,6 +312,7 @@ export default defineComponent({ questionTypesWithOptions: new Set([questionType.SINGLE_CHOICE, questionType.MULTI_CHOICE]), nonGradedAnswerClass: "bg-gray-200", correctOptionClass: "text-white bg-green-500", + skippedCorrectOptionClass: "border-4 border-green-500", wrongOptionClass: "text-white bg-red-500", questionHeaderTextClass: "text-lg md:text-xl lg:text-2xl mx-4 m-2 text-center leading-tight whitespace-pre-wrap", @@ -328,10 +345,11 @@ export default defineComponent({ /** * returns the background class for an option * - * handles the 4 different cases: + * handles the 5 different cases: * - the given option has not been selected * - question is graded and given option is the right answer * - question is graded and given option is the wrong answer + * - question is graded and no option is given (skipped) * - question is non-graded and the given option has been selected * @param {Number} optionIndex - index of the option */ @@ -351,7 +369,13 @@ export default defineComponent({ props.isGradedQuestion && props.correctAnswer.indexOf(optionIndex) != -1 ) { - return state.correctOptionClass + if (props.submittedAnswer != null && + props.submittedAnswer.indexOf(optionIndex) != -1) { + // if both correct and submitted option + return state.correctOptionClass + } + // if correct but not in submitted option + return state.skippedCorrectOptionClass } if ( (!isQuizAssessment.value || props.hasQuizEnded) && diff --git a/src/components/Questions/Footer.vue b/src/components/Questions/Footer.vue index 9fbaf6f..d5b0494 100644 --- a/src/components/Questions/Footer.vue +++ b/src/components/Questions/Footer.vue @@ -6,20 +6,34 @@ 'bg-gray-200 py-4 px-2': isQuizAssessment, }" > -
+
+ +
- - -
@@ -63,19 +64,18 @@ @click="submitQuestion" data-test="submitButton" > - +
@@ -178,11 +178,6 @@ export default defineComponent({ iconClass: state.assessmentNavigationButtonIconClass, } as IconButtonIconConfig); - const nextQuestionButtonTitleConfig = ref({ - value: "Next", - class: "text-gray-600", - } as IconButtonTitleConfig); - const clearButtonClass = ref([ state.assessmentTextButtonClass, "bg-white hover:bg-gray-50", @@ -271,7 +266,6 @@ export default defineComponent({ ...toRefs(state), previousQuestionButtonIconConfig, nextQuestionButtonIconConfig, - nextQuestionButtonTitleConfig, clearButtonClass, saveAndNextButtonClass, clearButtonTitleConfig, diff --git a/src/components/Questions/QuestionModal.vue b/src/components/Questions/QuestionModal.vue index d7fe046..693e94e 100644 --- a/src/components/Questions/QuestionModal.vue +++ b/src/components/Questions/QuestionModal.vue @@ -392,7 +392,7 @@ To attempt this question, unselect an answer to another question in this section } } state.toast.success( - `You have answered ${attemptedQuestions} out of ${props.numQuestions} questions. Please verify your responses and click End Test button again to make final submission.`, + `You have answered ${attemptedQuestions} out of ${props.numQuestions} questions. Click on the Question Palette to review unanswered questions before submitting the test. Click the End Test button again to make the final submission.`, { position: POSITION.TOP_CENTER, timeout: 5000, diff --git a/tests/unit/components/Questions/Body.spec.ts b/tests/unit/components/Questions/Body.spec.ts index bbd98e3..7985e51 100644 --- a/tests/unit/components/Questions/Body.spec.ts +++ b/tests/unit/components/Questions/Body.spec.ts @@ -99,7 +99,7 @@ describe("Body.vue", () => { expect( wrapper.find(`[data-test="optionContainer-1"]`).classes() - ).toContain("bg-green-500"); + ).toContain("border-green-500"); expect( wrapper.find(`[data-test="optionContainer-0"]`).classes() ).toContain("bg-red-500"); @@ -202,7 +202,7 @@ describe("Body.vue", () => { expect( wrapper.find('[data-test="optionContainer-0"]').classes() - ).toContain("bg-green-500"); + ).toContain("border-green-500"); expect( wrapper.find('[data-test="optionContainer-1"]').classes() ).toContain("bg-green-500"); @@ -239,7 +239,7 @@ describe("Body.vue", () => { expect( wrapper.find('[data-test="optionContainer-0"]').classes() - ).not.toContain("bg-green-500"); + ).not.toContain("border-green-500"); expect( wrapper.find('[data-test="optionContainer-1"]').classes() ).not.toContain("bg-green-500"); @@ -391,6 +391,17 @@ describe("Body.vue", () => { .setValue(value); expect(wrapper.vm.subjectiveAnswer).toBe(value.slice(0, maxCharLimit)); }); + + it("shows correct answer when quiz has ended", async () => { + await wrapper.setProps({ + isAnswerSubmitted: true, + correctAnswer: "Answer", + hasQuizEnded: true + }); + + expect(wrapper.find('[data-test="subjectiveCorrectAnswer"').text()) + .toBe("Correct Answer: Answer") + }) }); describe("numerical integer questions", () => { const wrapper = mount(Body, { @@ -498,6 +509,17 @@ describe("Body.vue", () => { expect(emitted["numerical-answer-entered"][1]).toEqual([null]) }) + it("shows correct answer when quiz has ended", async () => { + await wrapper.setProps({ + isAnswerSubmitted: true, + correctAnswer: 10, + hasQuizEnded: true + }); + + expect(wrapper.find('[data-test="numericalCorrectAnswer"').text()) + .toBe("Correct Answer: 10") + }) + it("highlights correct/wrong answer for homework quizzes", async () => { let submittedAnswer = 7; let correctAnswer = 8; diff --git a/tests/unit/components/Questions/Footer.spec.ts b/tests/unit/components/Questions/Footer.spec.ts index e339e88..655bf38 100644 --- a/tests/unit/components/Questions/Footer.spec.ts +++ b/tests/unit/components/Questions/Footer.spec.ts @@ -10,8 +10,8 @@ describe("Footer.vue", () => { }); it("shows disabled submit button only by default", () => { expect( - wrapper.get('[data-test="previousQuestionButton"]').classes() - ).toContain("hidden"); + wrapper.get('[data-test="previousQuestionButton"]').attributes().disabled + ).toBeDefined(); const submitButton = wrapper.find('[data-test="submitButton"]'); expect(submitButton.exists()).toBeTruthy(); expect(submitButton.text()).toBe("Submit"); @@ -83,8 +83,8 @@ describe("Footer.vue", () => { }); it("shows next, disabled save & next and disabled clear buttons by default", () => { expect( - wrapper.get('[data-test="previousQuestionButton"]').classes() - ).toContain("invisible"); + wrapper.get('[data-test="previousQuestionButton"]').attributes().disabled + ).toBeDefined(); expect(wrapper.find('[data-test="submitButton"]').exists()).toBeFalsy(); expect( wrapper.find('[data-test="saveAndNextButton"]').exists() From 7be116385e029ab10b2963a9a4a7f766c4430a19 Mon Sep 17 00:00:00 2001 From: suryabulusu Date: Mon, 23 Oct 2023 18:44:46 +0530 Subject: [PATCH 2/3] changes txt color splash --- src/components/Splash.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Splash.vue b/src/components/Splash.vue index 4cd4a40..2ff1a98 100644 --- a/src/components/Splash.vue +++ b/src/components/Splash.vue @@ -181,7 +181,7 @@ export default defineComponent({ config.value = "Let's Start"; } else { if (props.hasQuizEnded && !props.reviewAnswers) { - config.class = "text-sm md:text-sm text-primary font-poppins-bold"; + config.class = "text-sm md:text-sm text-primary text-white font-poppins-bold"; config.value = "You cannot review answers now. Please come back after test ends."; if (props.sessionEndTimeText != "") { config.value += ` (${props.sessionEndTimeText})` From 08225854c2bcee1d9e188c6a93cdffa0935bdc84 Mon Sep 17 00:00:00 2001 From: suryabulusu Date: Mon, 23 Oct 2023 20:04:12 +0530 Subject: [PATCH 3/3] changes to splash and instr --- src/components/InstructionPage.vue | 30 +++++++++++++++--------------- src/components/Splash.vue | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/components/InstructionPage.vue b/src/components/InstructionPage.vue index 5e71e2e..087fa49 100644 --- a/src/components/InstructionPage.vue +++ b/src/components/InstructionPage.vue @@ -2,7 +2,7 @@

Test Paper Overview

- +
@@ -60,21 +60,21 @@
  • The countdown timer in the top right corner of screen will display the remaining time available for you to complete the test. When the timer reaches zero, the test will end by itself. You will not be required to end or submit your test.
  • You can click on the button on the top left corner of the page to expand the Question Palette.
  • The Question Palette will show the status of each question using one of the following symbols: -
    -
    - - You have answered the question -
    -
    - - You have not visited the question yet -
    -
    - - You have not answered the question -
    +
    +
    + + You have answered the question
    -
  • +
    + + You have not visited the question yet +
    +
    + + You have not answered the question +
    + +
  • You can click on the button again to collapse the Question Palette.
  • diff --git a/src/components/Splash.vue b/src/components/Splash.vue index 2ff1a98..9456a4c 100644 --- a/src/components/Splash.vue +++ b/src/components/Splash.vue @@ -63,7 +63,7 @@ :maxQuestionsAllowedToAttempt="maxQuestionsAllowedToAttempt" :quizTimeLimit="quizTimeLimit" :questionSetStates = "questionSetStates" - class="xl:mr-20 xl:ml-10 lg:mr-24 lg:ml-24 md:mr-48 md:ml-48 sm:mr-60 sm:ml-60" + class="mx-4 md:mx-40" > @@ -181,7 +181,7 @@ export default defineComponent({ config.value = "Let's Start"; } else { if (props.hasQuizEnded && !props.reviewAnswers) { - config.class = "text-sm md:text-sm text-primary text-white font-poppins-bold"; + config.class = "text-sm md:text-sm text-white font-poppins-bold"; config.value = "You cannot review answers now. Please come back after test ends."; if (props.sessionEndTimeText != "") { config.value += ` (${props.sessionEndTimeText})`
    Test Name