diff --git a/jest.init.ts b/jest.init.ts index decc871..750fd09 100644 --- a/jest.init.ts +++ b/jest.init.ts @@ -7,12 +7,33 @@ import { config } from "@vue/test-utils"; import VueClickAway from "vue3-click-away"; +// Mock window.matchMedia +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: (query: string) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + }), +}); + +// Mock window.scrollTo +Object.defineProperty(window, 'scrollTo', { + writable: true, + value: jest.fn(), +}); + // inline-svg stub const InlineSvg = { template: "", }; config.global.stubs = { - InlineSvg: InlineSvg, + InlineSvg, }; config.global.plugins = [VueClickAway]; diff --git a/src/components/InstructionPage.vue b/src/components/InstructionPage.vue index 4f5289a..4f4e700 100644 --- a/src/components/InstructionPage.vue +++ b/src/components/InstructionPage.vue @@ -54,27 +54,48 @@

General Instructions

    -
  1. 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.
  2. -
  3. You can click on the button on the top left corner of the page to expand the Question Palette.
  4. -
  5. The Question Palette will show the status of each question using one of the following symbols: +
  6. + The countdown timer in the top right corner of the 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. +
  7. +
  8. + You can click on the + + + + button on the top left corner of the page to expand the Question Palette. +
  9. +
  10. + 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 marked the question for review + NEW +
  11. -
  12. You can click on the button again to collapse the Question Palette.
  13. +
  14. + You can click on the + + + + button again to collapse the Question Palette. +
+

Answering a Question:

@@ -84,7 +105,11 @@
  • To select you answer, click on the button of one of the options.
  • To deselect your chosen answer, click on the button of the chosen option again or click on the Clear button.
  • To change your chosen answer, click on the button of another option.
  • -
  • To save your answer, you MUST click on the Save & Next button.
  • +
  • To save your answer, you MUST click on the "Save & Next" button.
  • +
  • + To review a question later, you can click on the "Review >" button. This action will not save your answer. + NEW +
  • To change your answer to a question that has already been answered, first select that question for answering and then follow the procedure for answering that type of question.
  • @@ -92,7 +117,7 @@
    !
    -
    Note that selecting an option does NOT save your answer to the current question. Click on Save & Next to save your answer for the current question and then go to the next question.
    +
    Note that selecting an option DOES NOT save your answer to the current question. Click on "Save & Next" to save your answer for the current question and then go to the next question.
    @@ -103,6 +128,7 @@ import BaseIcon from "./UI/Icons/BaseIcon.vue"; import Success from "./Questions/Palette/Success.vue"; import Error from "./Questions/Palette/Error.vue"; import Neutral from "./Questions/Palette/Neutral.vue"; +import Review from "./Questions/Palette/Review.vue"; import { quizTitleType, testFormat, questionSetPalette, TimeLimit } from "../types"; export default defineComponent({ name: "InstructionPage", @@ -110,7 +136,8 @@ export default defineComponent({ BaseIcon, Success, Error, - Neutral + Neutral, + Review }, props: { title: { diff --git a/src/components/Omr/OmrModal.vue b/src/components/Omr/OmrModal.vue index 4aa9234..f5bbe2b 100644 --- a/src/components/Omr/OmrModal.vue +++ b/src/components/Omr/OmrModal.vue @@ -426,7 +426,9 @@ export default defineComponent({ _id: response._id, question_id: response.question_id, answer: response.answer, - visited: response.visited + visited: response.visited, + time_spent: response.time_spent, + marked_for_review: response.marked_for_review } ) }) diff --git a/src/components/Questions/Body.vue b/src/components/Questions/Body.vue index 9726ab0..85af4b7 100644 --- a/src/components/Questions/Body.vue +++ b/src/components/Questions/Body.vue @@ -271,6 +271,15 @@ + +
    + MARKED FOR REVIEW + ANSWERED + NOT ANSWERED +
    + + +
    @@ -95,6 +107,8 @@ import { toRefs, computed, PropType, + onMounted, + onBeforeUnmount } from "vue"; export default defineComponent({ @@ -108,6 +122,10 @@ export default defineComponent({ default: false, type: Boolean, }, + isMarkedForReview: { + default: false, + type: Boolean, + }, isPreviousButtonShown: { default: false, type: Boolean, @@ -139,6 +157,10 @@ export default defineComponent({ }, setup(props, context) { const isQuizAssessment = computed(() => props.quizType == "assessment" || props.quizType == "omr-assessment"); + const isSmallScreen = ref(false); + const updateScreenSize = () => { + isSmallScreen.value = window.matchMedia("(max-width: 500px)").matches; + }; const state = reactive({ assessmentNavigationButtonIconClass: [ { @@ -149,7 +171,7 @@ export default defineComponent({ "fill-current", ], assessmentTextButtonTitleClass: - "text-sm bp-500:text-md lg:text-lg xl:text-xl font-bold", + "text-xs bp-500:text-sm lg:text-base xl:text-lg font-bold", assessmentNavigationButtonClass: [ { "bg-yellow-500 hover:bg-yellow-600 ring-yellow-500 px-6 bp-500:px-8 rounded-2xl": @@ -183,6 +205,11 @@ export default defineComponent({ "bg-white hover:bg-gray-50", ]); + const markForReviewButtonClass = ref([ + state.assessmentTextButtonClass, + "bg-white hover:bg-gray-50", + ]); + const saveAndNextButtonClass = ref([ state.assessmentTextButtonClass, "bg-white hover:bg-gray-50", @@ -193,6 +220,11 @@ export default defineComponent({ class: [state.assessmentTextButtonTitleClass, "text-gray-600"], } as IconButtonTitleConfig); + const markForReviewButtonTitleConfig = computed(() => ({ + value: isSmallScreen.value ? "Review >" : "Mark For Review & Next", + class: ["text-xxs bp-500:text-sm lg:text-base xl:text-lg font-bold", "text-violet-500"], + } as IconButtonTitleConfig)); + const saveAndNextButtonTitleConfig = ref({ value: "Save & Next", class: [state.assessmentTextButtonTitleClass, "text-emerald-500"], @@ -216,6 +248,19 @@ export default defineComponent({ context.emit("clear"); } + function toggleMarkForReview() { + if (!props.isMarkedForReview) { + context.emit("mark-for-review"); + // wait for processing to be done and answer to be submitted + const checkProcessingDone = setInterval(() => { + if (!props.isSessionAnswerRequestProcessing) { + if (props.continueAfterAnswerSubmit) context.emit("continue"); + clearInterval(checkProcessingDone); + } + }, 100); // check every 100ms + } + } + function goToPreviousQuestion() { context.emit("previous"); } @@ -262,19 +307,32 @@ export default defineComponent({ "p-4 px-8 bp-500:p-6 bp-500:px-12 rounded-2xl shadow-xl disabled:opacity-50 disabled:cursor-not-allowed", ]); + // Setup listeners for screen size changes + onMounted(() => { + updateScreenSize(); + window.addEventListener("resize", updateScreenSize); + }); + + onBeforeUnmount(() => { + window.removeEventListener("resize", updateScreenSize); + }); + return { ...toRefs(state), previousQuestionButtonIconConfig, nextQuestionButtonIconConfig, clearButtonClass, + markForReviewButtonClass, saveAndNextButtonClass, clearButtonTitleConfig, + markForReviewButtonTitleConfig, saveAndNextButtonTitleConfig, saveAndNextButtonIconConfig, submitQuestion, goToPreviousQuestion, goToNextQuestion, clearAnswer, + toggleMarkForReview, saveQuestionAndProceed, submitButtonTitleConfig, submitButtonIconConfig, @@ -282,6 +340,6 @@ export default defineComponent({ isQuizAssessment, }; }, - emits: ["submit", "previous", "continue", "clear"], + emits: ["submit", "previous", "continue", "clear", "mark-for-review"], }); diff --git a/src/components/Questions/Palette/Item.vue b/src/components/Questions/Palette/Item.vue index 4271e13..cff2c5b 100644 --- a/src/components/Questions/Palette/Item.vue +++ b/src/components/Questions/Palette/Item.vue @@ -20,6 +20,11 @@ :hasQuizEnded="hasQuizEnded" data-test="neutral" > +

    +

    + +
    @@ -78,6 +84,7 @@ import Success from "./Success.vue"; import PartialSuccess from "./PartialSuccess.vue"; import Error from "./Error.vue"; import Neutral from "./Neutral.vue"; +import Review from "./Review.vue"; import PaletteItem from "./Item.vue"; import InstructionPage from "@/components/InstructionPage.vue"; import { TimeLimit, questionSetPalette, quizTitleType, testFormat } from "@/types"; @@ -89,6 +96,7 @@ export default defineComponent({ PartialSuccess, Error, Neutral, + Review, PaletteItem, InstructionPage }, diff --git a/src/components/Questions/Palette/Review.vue b/src/components/Questions/Palette/Review.vue new file mode 100644 index 0000000..7c55868 --- /dev/null +++ b/src/components/Questions/Palette/Review.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/components/Questions/Palette/Utils.ts b/src/components/Questions/Palette/Utils.ts index 7a0db84..f355e81 100644 --- a/src/components/Questions/Palette/Utils.ts +++ b/src/components/Questions/Palette/Utils.ts @@ -1,8 +1,8 @@ // classes for the icon of each key in the legend of the question palette export const legendKeyIconClass = - "w-6 h-6 bp-420:w-10 bp-420:h-10 border-1 rounded-md place-self-center"; + "w-6 h-6 bp-420:w-10 bp-420:h-10 border-1 rounded-md place-self-center flex-shrink-0"; // classes for the text of each key in the legend of the question palette export const legendKeyTextClass = "place-self-center text-sm sm:text-base font-bold"; // classes for the container of each key in the legend of the question palette -export const legendKeyContainerClass = "flex space-x-2 lg:space-x-4"; +export const legendKeyContainerClass = "flex space-x-2 lg:space-x-4 items-centers"; diff --git a/src/components/Questions/QuestionModal.vue b/src/components/Questions/QuestionModal.vue index 2735a98..7f9b570 100644 --- a/src/components/Questions/QuestionModal.vue +++ b/src/components/Questions/QuestionModal.vue @@ -47,6 +47,8 @@ :draftAnswer="draftResponses[currentQuestionIndex]" :submittedAnswer="currentQuestionResponseAnswer" :isAnswerSubmitted="isAnswerSubmitted" + :isMarkedForReview="isMarkedForReview" + :isSessionAnswerRequestProcessing="$props.isSessionAnswerRequestProcessing" :isPaletteVisible="isPaletteVisible" :isDraftAnswerCleared="isDraftAnswerCleared" :quizType="quizType" @@ -72,6 +74,7 @@ >
    @@ -247,12 +251,13 @@ export default defineComponent({ watch( () => props.currentQuestionIndex, (newValue: Number) => { + console.log(state.localResponses[props.currentQuestionIndex].answer, state.localResponses[props.currentQuestionIndex].marked_for_review) state.localCurrentQuestionIndex = newValue.valueOf() if (!props.hasQuizEnded && optionalLimitReached.value && currentQuestionResponseAnswer.value == null) { state.toast.warning( `You have already attempted maximum allowed (${props.maxQuestionsAllowedToAttempt}) questions in current section (Q.${props.qsetIndexLimits.low + 1} - Q.${props.qsetIndexLimits.high}). -To attempt this question, unselect an answer to another question in this section. +To attempt Q.${props.currentQuestionIndex + 1}, unselect an answer to another question in this section. `, { position: POSITION.TOP_CENTER, @@ -320,9 +325,12 @@ To attempt this question, unselect an answer to another question in this section function submitQuestion() { if (!state.localResponses.length) return - state.previousLocalResponse = clonedeep(state.localResponses[props.currentQuestionIndex]); state.localResponses[props.currentQuestionIndex].answer = state.draftResponses[props.currentQuestionIndex] + if (state.draftResponses[props.currentQuestionIndex] != null) { + // question is answered => set review to false + state.localResponses[props.currentQuestionIndex].marked_for_review = false; + } context.emit("submit-question") } @@ -332,6 +340,27 @@ To attempt this question, unselect an answer to another question in this section state.isDraftAnswerCleared = true } + function markForReviewQuestion() { + state.previousLocalResponse = clonedeep(state.localResponses[props.currentQuestionIndex]); + state.localResponses[props.currentQuestionIndex].marked_for_review = true; + let markForReviewInfoText = `Question ${props.currentQuestionIndex + 1} is marked for review.` + if (state.localResponses[props.currentQuestionIndex].answer != null) { + markForReviewInfoText += `\nAnswer to Question ${props.currentQuestionIndex + 1} is cleared!` + clearAnswer() + submitQuestion() + } else if (state.draftResponses[props.currentQuestionIndex] != null) { + markForReviewInfoText += "\nThis action does not save your answer!" + } + state.toast.info( + markForReviewInfoText, + { + position: POSITION.TOP_LEFT, + timeout: 3500, + } + ) + context.emit("update-review-status") + } + function showNextQuestion() { // It toggles the reRenderKey from 0 to 1 or 1 to 0. And changing the reRender key, re-renders the component. // we reRender the whole component as textarea is holding the details which is not getting updated @@ -378,7 +407,7 @@ To attempt this question, unselect an answer to another question in this section currentQuestionResponseAnswer.value } state.isDraftAnswerCleared = false - state.toast.clear() // if toast exists in current state, clear when you switch state + // state.toast.clear() // if toast exists in current state, clear when you switch state } function numericalAnswerUpdated(answer: number | null) { @@ -393,16 +422,24 @@ To attempt this question, unselect an answer to another question in this section function endTest() { if (!props.hasQuizEnded && state.hasEndTestBeenClickedOnce) { let attemptedQuestions = 0; + let markedForReviewAndUnansweredQuestions = 0; for (const response of props.responses) { if (response.answer != null) { attemptedQuestions += 1; } + if (response.marked_for_review == true && response.answer == null) { + markedForReviewAndUnansweredQuestions += 1 + } } state.toast.success( - `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.`, + `Total Questions: ${props.numQuestions} +Questions Answered: ${attemptedQuestions} +Questions Marked for Review and Unanswered: ${markedForReviewAndUnansweredQuestions} +\nUse the Question Palette to review all questions. +For final submission, click the End Test button again.`, { position: POSITION.TOP_CENTER, - timeout: 5000, + timeout: 6000, draggablePercent: 0.4 } ) @@ -483,6 +520,10 @@ To attempt this question, unselect an answer to another question in this section return true }) + const isMarkedForReview = computed(() => { + return currentQuestionResponse.value.marked_for_review; + }) + const isAttemptValid = computed(() => { if (optionalLimitReached.value && currentQuestionResponseAnswer.value == null) { // this cannot be answered @@ -546,6 +587,7 @@ To attempt this question, unselect an answer to another question in this section showPreviousQuestion, subjectiveAnswerUpdated, clearAnswer, + markForReviewQuestion, endTest, endTestByTime, navigateToQuestion, @@ -556,6 +598,7 @@ To attempt this question, unselect an answer to another question in this section isGradedQuestion, currentQuestionResponseAnswer, isAnswerSubmitted, + isMarkedForReview, isAttemptValid, isQuizAssessment, optionalLimitReached, @@ -572,7 +615,8 @@ To attempt this question, unselect an answer to another question in this section "end-test", "fetch-question-bucket", "test-warning-shown", - "test-optional-warning-shown" + "test-optional-warning-shown", + "update-review-status" ], }); diff --git a/src/services/API/Session.ts b/src/services/API/Session.ts index 4e65b00..d7a5597 100644 --- a/src/services/API/Session.ts +++ b/src/services/API/Session.ts @@ -54,6 +54,7 @@ export default { total_correct: 0, total_wrong: 0, total_partially_correct: 0, + total_marked_for_review: 0, total_marks: 0, }; @@ -67,6 +68,7 @@ export default { num_correct: metric.correctlyAnswered, num_wrong: metric.wronglyAnswered, num_partially_correct: metric.partiallyAnswered, + num_marked_for_review: metric.numQuestionsMarkedForReview, attempt_rate: Math.round(metric.attemptRate * 100) / 100, accuracy_rate: Math.round(metric.accuracyRate * 100) / 100, }; @@ -77,6 +79,7 @@ export default { sessionMetrics.total_correct += metric.correctlyAnswered; sessionMetrics.total_wrong += metric.wronglyAnswered; sessionMetrics.total_partially_correct += metric.partiallyAnswered; + sessionMetrics.total_marked_for_review += metric.numQuestionsMarkedForReview; sessionMetrics.total_marks += metric.marksScored; }); diff --git a/src/types.ts b/src/types.ts index 1754888..c3d0e53 100644 --- a/src/types.ts +++ b/src/types.ts @@ -61,6 +61,7 @@ export interface SubmittedResponse { answer: submittedAnswer; visited: boolean; time_spent?: number; // time spent on question in seconds + marked_for_review: boolean; } interface ScorecardMetricIcon { @@ -83,6 +84,7 @@ export interface QuestionSetMetric { correctlyAnswered: number, partiallyAnswered: number, wronglyAnswered: number, + numQuestionsMarkedForReview: number, attemptRate: number, accuracyRate: number } @@ -223,6 +225,7 @@ export interface QuestionSetMetricPayload { num_correct: number; num_wrong: number; num_partially_correct: number; + num_marked_for_review: number; attempt_rate: number; accuracy_rate: number; } @@ -234,6 +237,7 @@ export interface SessionMetricsPayload { total_correct: number; total_wrong: number; total_partially_correct: number; + total_marked_for_review: number; total_marks: number; } export interface UpdateSessionAPIResponse { @@ -248,6 +252,7 @@ export interface UpdateSessionAnswerAPIPayload { answer?: submittedAnswer; visited?: boolean; time_spent?: number; // time spent on question in seconds + marked_for_review?: boolean; } export type TimeSpentEntry = { @@ -264,7 +269,7 @@ export interface answerEvaluation { isPartiallyCorrect?: boolean; // whether question has been partially answered for multi answer } -export type questionState = "success" | "error" | "neutral" | "partial-success"; +export type questionState = "success" | "error" | "neutral" | "partial-success" | "review"; export interface paletteItemState { index: number; // index of the corresponding question in the list of questions value: questionState; diff --git a/src/views/Player.vue b/src/views/Player.vue index 387ac17..52483d5 100644 --- a/src/views/Player.vue +++ b/src/views/Player.vue @@ -84,6 +84,7 @@ v-model:responses="responses" v-model:previousResponse="previousResponse" @submit-question="submitQuestion" + @update-review-status="updateQuestionResponse" @end-test="endTest" @fetch-question-bucket="fetchQuestionBucket" v-if="isQuestionShown && !isOmrMode" @@ -203,6 +204,7 @@ export default defineComponent({ numWrong: 0, // number of wrongly answered questions numPartiallyCorrect: 0, // number of partially correct questions numSkipped: 0, // number of skipped questions + numMarkedForReview: 0, // number of questions marked for review marksScored: 0, maxMarks: 0, // maximum marks that can be scored isScorecardShown: false, // to show the scorecard or not @@ -238,7 +240,7 @@ export default defineComponent({ }); const isQuizLoaded = computed(() => numQuestions.value > 0); const scorecardResult = computed(() => ({ - title: isQuizAssessment.value ? "Score" : "Accuracy", + title: isQuizAssessment.value ? "Score" : "Score %", value: scorecardResultValue.value, })); @@ -475,13 +477,44 @@ export default defineComponent({ await createSession(); } + /** updates the session answer once marked for review */ + async function updateQuestionResponse() { + state.isSessionAnswerRequestProcessing = true; + const itemResponse = state.responses[state.currentQuestionIndex]; + const payload: UpdateSessionAnswerAPIPayload = { + marked_for_review: itemResponse.marked_for_review + } + const response = await SessionAPIService.updateSessionAnswer( // response.data + state.sessionId, + state.currentQuestionIndex, + payload + ); + state.timeSpentOnQuestion[state.currentQuestionIndex].hasSynced = true; + if (response.status != 200) { + state.toast.error( + `Review Status for Q.${state.currentQuestionIndex + 1} not saved. Please try to mark for review again or refresh the page.`, + { + position: POSITION.TOP_LEFT, + timeout: 4000, + draggablePercent: 0.4 + } + ) + state.responses[state.currentQuestionIndex] = state.previousResponse; // previous value?! + } else { + // successful response + state.continueAfterAnswerSubmit = true; + } + state.isSessionAnswerRequestProcessing = false; + } + /** updates the session answer once a response is submitted */ async function submitQuestion() { state.isSessionAnswerRequestProcessing = true; state.continueAfterAnswerSubmit = false; const itemResponse = state.responses[state.currentQuestionIndex]; const payload: UpdateSessionAnswerAPIPayload = { - answer: itemResponse.answer + answer: itemResponse.answer, + marked_for_review: itemResponse.marked_for_review } if (!isQuizAssessment.value) { // we update time spent for homework immediately when answer is submitted @@ -690,6 +723,7 @@ export default defineComponent({ state.numCorrect = 0; state.numWrong = 0; state.numPartiallyCorrect = 0; + state.numMarkedForReview = 0; state.marksScored = 0; // Initialize metrics for each question set @@ -702,6 +736,7 @@ export default defineComponent({ correctlyAnswered: 0, wronglyAnswered: 0, partiallyAnswered: 0, + numQuestionsMarkedForReview: 0, attemptRate: 0, accuracyRate: 0 })); @@ -710,6 +745,10 @@ export default defineComponent({ const [currentQsetIndex] = getQsetLimits(questionIndex); const qsetMetricsObj = state.qsetMetrics[currentQsetIndex]; if (!questionDetail.graded) qsetMetricsObj.maxQuestionsAllowedToAttempt -= 1 + if (state.responses[index].marked_for_review === true) { + qsetMetricsObj.numQuestionsMarkedForReview += 1; + state.numMarkedForReview += 1; + } updateQuestionMetrics(questionDetail, state.responses[index].answer, qsetMetricsObj); if (qsetMetricsObj.numAnswered != 0) qsetMetricsObj.accuracyRate = (qsetMetricsObj.correctlyAnswered + 0.5 * qsetMetricsObj.partiallyAnswered) / qsetMetricsObj.numAnswered; state.qsetMetrics[currentQsetIndex].attemptRate = qsetMetricsObj.numAnswered / qsetMetricsObj.maxQuestionsAllowedToAttempt; @@ -846,6 +885,7 @@ export default defineComponent({ qstate = "neutral" } else { if (state.responses[qindex].answer != null) qstate = "success" + else if (state.responses[qindex].marked_for_review) qstate = "review" else qstate = "error" } } else qstate = "error" @@ -921,6 +961,7 @@ export default defineComponent({ startQuiz, getQsetLimits, submitQuestion, + updateQuestionResponse, submitOmrQuestion, goToPreviousQuestion, endTest, diff --git a/tailwind.config.js b/tailwind.config.js index cd2e87b..05778c5 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -13,6 +13,9 @@ module.exports = { borderWidth: { 1: "1px", }, + fontSize: { + xxs: "0.80rem", + }, }, screens: { "bp-320": "320px", diff --git a/tests/e2e/specs/renders-player-to-check-timed.js b/tests/e2e/specs/renders-player-to-check-timed.js index e7cd95c..3d0404c 100644 --- a/tests/e2e/specs/renders-player-to-check-timed.js +++ b/tests/e2e/specs/renders-player-to-check-timed.js @@ -167,6 +167,7 @@ describe("Player for Assessment Timed quizzes", () => { num_correct: 0, num_wrong: 0, num_partially_correct: 0, + num_marked_for_review: 0, attempt_rate: 0, accuracy_rate: 0, }, @@ -176,6 +177,7 @@ describe("Player for Assessment Timed quizzes", () => { total_correct: 0, total_wrong: 0, total_partially_correct: 0, + total_marked_for_review: 0, total_marks: 0, }, }); @@ -340,6 +342,7 @@ describe("Player for Homework Quizzes", () => { .should("deep.equal", { answer: [0], time_spent: 3, + marked_for_review: false, }); }); @@ -363,6 +366,7 @@ describe("Player for Homework Quizzes", () => { .should("deep.equal", { answer: [0], time_spent: 0, + marked_for_review: false, }); // click submit again to continue cy.get('[data-test="modal"]') @@ -403,6 +407,7 @@ describe("Player for Homework Quizzes", () => { .should("deep.equal", { answer: [1], time_spent: 3, // not 6 + marked_for_review: false, }); }); }); diff --git a/tests/unit/components/Omr/OmrModal.spec.ts b/tests/unit/components/Omr/OmrModal.spec.ts index 411e2e5..2884e19 100644 --- a/tests/unit/components/Omr/OmrModal.spec.ts +++ b/tests/unit/components/Omr/OmrModal.spec.ts @@ -236,6 +236,7 @@ describe("OmrModal.vue", () => { question_id: question._id, answer: null, visited: false, + marked_for_review: false, time_spent: 0 }) ); @@ -324,6 +325,7 @@ describe("OmrModal.vue", () => { question_id: questions[questionIndex]._id, answer: [0], visited: false, + marked_for_review: false, time_spent: 0 }); expect(wrapper.emitted()).toHaveProperty("submit-omr-question"); @@ -415,6 +417,7 @@ describe("OmrModal.vue", () => { question_id: questions[questionIndex]._id, answer: [0, 1], visited: false, + marked_for_review: false, time_spent: 0 }); expect(wrapper.emitted()).toHaveProperty("submit-omr-question"); diff --git a/tests/unit/components/Questions/QuestionModal.spec.ts b/tests/unit/components/Questions/QuestionModal.spec.ts index 4b4aabf..5e4040b 100644 --- a/tests/unit/components/Questions/QuestionModal.spec.ts +++ b/tests/unit/components/Questions/QuestionModal.spec.ts @@ -218,6 +218,7 @@ describe("QuestionModal.vue", () => { question_id: question._id, answer: null, visited: false, + marked_for_review: false, time_spent: 0 }) ); @@ -472,6 +473,7 @@ describe("QuestionModal.vue", () => { question_id: questions[questionIndex]._id, answer: [0], visited: false, + marked_for_review: false, time_spent: 0 }); expect(wrapper.emitted()).toHaveProperty("submit-question"); @@ -574,6 +576,7 @@ describe("QuestionModal.vue", () => { question_id: questions[questionIndex]._id, answer: [0, 1], visited: false, + marked_for_review: false, time_spent: 0 }); expect(wrapper.emitted()).toHaveProperty("submit-question"); @@ -656,6 +659,7 @@ describe("QuestionModal.vue", () => { question_id: questions[questionIndex]._id, answer, visited: false, + marked_for_review: false, time_spent: 0 }); expect(wrapper.emitted()).toHaveProperty("submit-question"); @@ -758,6 +762,7 @@ describe("QuestionModal.vue", () => { question_id: questions[questionIndex]._id, answer, visited: false, + marked_for_review: false, time_spent: 0 }); expect(wrapper.emitted()).toHaveProperty("submit-question");