-
Notifications
You must be signed in to change notification settings - Fork 350
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refine Radio's Rubric and UserInput types #1758
Changes from 4 commits
fba00dc
2c2df85
7d37ff7
6950cc8
4ede900
480e653
1652070
277954c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@khanacademy/perseus": patch | ||
--- | ||
|
||
Refine Radio's Rubric type |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,13 +2,18 @@ import {mockStrings} from "../../strings"; | |
|
||
import radioValidator from "./radio-validator"; | ||
|
||
import type { | ||
PerseusRadioRubric, | ||
PerseusRadioUserInput, | ||
} from "../../validation.types"; | ||
|
||
describe("radioValidator", () => { | ||
it("is invalid when no options are selected", () => { | ||
const userInput = { | ||
const userInput: PerseusRadioUserInput = { | ||
choicesSelected: [false, false, false, false], | ||
}; | ||
|
||
const rubric = { | ||
const rubric: PerseusRadioRubric = { | ||
choices: [ | ||
{content: "Choice 1"}, | ||
{content: "Choice 2"}, | ||
|
@@ -23,12 +28,12 @@ describe("radioValidator", () => { | |
}); | ||
|
||
it("is invalid when number selected does not match number correct", () => { | ||
const userInput = { | ||
const userInput: PerseusRadioUserInput = { | ||
numCorrect: 2, | ||
choicesSelected: [true, false, false, false], | ||
}; | ||
|
||
const rubric = { | ||
const rubric: PerseusRadioRubric = { | ||
choices: [ | ||
{content: "Choice 1", correct: true}, | ||
{content: "Choice 2", correct: true}, | ||
|
@@ -43,20 +48,19 @@ describe("radioValidator", () => { | |
}); | ||
|
||
it("is invalid when none of the above and an answer are both selected", () => { | ||
const userInput = { | ||
const userInput: PerseusRadioUserInput = { | ||
noneOfTheAboveSelected: true, | ||
choicesSelected: [true, false, false, false, true], | ||
}; | ||
|
||
const rubric = { | ||
const rubric: PerseusRadioRubric = { | ||
choices: [ | ||
{content: "Choice 1", correct: true}, | ||
{content: "Choice 2", correct: false}, | ||
{content: "Choice 3", correct: false}, | ||
{content: "Choice 4", correct: false}, | ||
{content: "None of the above", correct: false}, | ||
], | ||
hasNoneOfTheAbove: true, | ||
}; | ||
|
||
const result = radioValidator(userInput, rubric, mockStrings); | ||
|
@@ -65,11 +69,11 @@ describe("radioValidator", () => { | |
}); | ||
|
||
it("can handle single correct answer", () => { | ||
const userInput = { | ||
const userInput: PerseusRadioUserInput = { | ||
choicesSelected: [true, false, false, false], | ||
}; | ||
|
||
const rubric = { | ||
const rubric: PerseusRadioRubric = { | ||
choices: [ | ||
{content: "Choice 1", correct: true}, | ||
{content: "Choice 2", correct: false}, | ||
|
@@ -84,11 +88,11 @@ describe("radioValidator", () => { | |
}); | ||
|
||
it("can handle single incorrect answer", () => { | ||
const userInput = { | ||
const userInput: PerseusRadioUserInput = { | ||
choicesSelected: [false, false, false, true], | ||
}; | ||
|
||
const rubric = { | ||
const rubric: PerseusRadioRubric = { | ||
choices: [ | ||
{content: "Choice 1", correct: true}, | ||
{content: "Choice 2", correct: false}, | ||
|
@@ -103,11 +107,11 @@ describe("radioValidator", () => { | |
}); | ||
|
||
it("can handle multiple correct answer", () => { | ||
const userInput = { | ||
const userInput: PerseusRadioUserInput = { | ||
choicesSelected: [true, true, false, false], | ||
}; | ||
|
||
const rubric = { | ||
const rubric: PerseusRadioRubric = { | ||
choices: [ | ||
{content: "Choice 1", correct: true}, | ||
{content: "Choice 2", correct: true}, | ||
|
@@ -122,11 +126,11 @@ describe("radioValidator", () => { | |
}); | ||
|
||
it("can handle multiple incorrect answer", () => { | ||
const userInput = { | ||
const userInput: PerseusRadioUserInput = { | ||
choicesSelected: [true, false, false, true], | ||
}; | ||
|
||
const rubric = { | ||
const rubric: PerseusRadioRubric = { | ||
choices: [ | ||
{content: "Choice 1", correct: true}, | ||
{content: "Choice 2", correct: true}, | ||
|
@@ -141,13 +145,13 @@ describe("radioValidator", () => { | |
}); | ||
|
||
it("can handle none of the above correct answer", () => { | ||
const userInput = { | ||
const userInput: PerseusRadioUserInput = { | ||
choicesSelected: [false, false, false, false, true], | ||
noneOfTheAboveSelected: true, | ||
noneOfTheAboveIndex: 4, | ||
}; | ||
|
||
const rubric = { | ||
const rubric: PerseusRadioRubric = { | ||
choices: [ | ||
{content: "Choice 1", correct: false}, | ||
{content: "Choice 2", correct: false}, | ||
|
@@ -162,13 +166,13 @@ describe("radioValidator", () => { | |
}); | ||
|
||
it("can handle none of the above incorrect answer", () => { | ||
const userInput = { | ||
const userInput: PerseusRadioUserInput = { | ||
choicesSelected: [false, false, false, false, true], | ||
noneOfTheAboveSelected: true, | ||
noneOfTheAboveIndex: 4, | ||
}; | ||
|
||
const rubric = { | ||
const rubric: PerseusRadioRubric = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I love all this typing. Thank you! |
||
choices: [ | ||
{content: "Choice 1", correct: true}, | ||
{content: "Choice 2", correct: false}, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,7 @@ function radioValidator( | |
}; | ||
} | ||
|
||
// TODO: should numCorrect actually be on the rubric | ||
// TODO(LEMS-2541): should numCorrect actually be on the rubric | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for filing this ticket. I think |
||
// instead of the userInput? | ||
if ( | ||
userInput.numCorrect && | ||
|
@@ -35,7 +35,7 @@ function radioValidator( | |
// If NOTA and some other answer are checked, ... | ||
} | ||
|
||
// TODO: should noneOfTheAboveSelected be replaced with a | ||
// TODO(LEMS-2541): should noneOfTheAboveSelected be replaced with a | ||
// combination of choicesSelected and noneOfTheAboveIndex? | ||
if (userInput.noneOfTheAboveSelected && numSelected > 1) { | ||
return { | ||
|
@@ -46,7 +46,7 @@ function radioValidator( | |
|
||
const correct = userInput.choicesSelected.every((selected, i) => { | ||
let isCorrect: boolean; | ||
// TODO: should noneOfTheAboveIndex actually be on the rubric | ||
// TODO(LEMS-2541): should noneOfTheAboveIndex actually be on the rubric | ||
// instead of the userInput? | ||
if (userInput.noneOfTheAboveIndex === i) { | ||
isCorrect = rubric.choices.every((choice, j) => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So one way to look at the overall problem of RenderProps vs UserInput vs Rubric: is the thing in question used in the validator? Since
countChoices
isn't in the validator (or any of the functionality that the validator uses), it can't be in the Rubric (which is stuff we need from KA to validate the answer) or UserInput (which is stuff we need from the leaner to validate the answer). It's rendering logic, so RenderProps.Then like
numCorrect
is a weird one:numCorrect
and if so would that affect their score? No, so it's not UserInput.numCorrect
something KA determines and is it used to score? Yes, so it's part of the Rubric.numCorrect
something that determines how we render the component? Yes, so it needs to be part of RenderProps.There's some overlap between all of this, but that's okay. What's important (for this leg of the work) is that we know exactly what shape the Rubric and UserInput is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally makes sense. I wanted to fix the UserInput so countChoices is not included, but that requires some logic refactoring, which is why I created a separate ticket for it. Should I just do the refactoring as part of the type update here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went through the code to see where removing
countChoices
from Radio's user input would require a refactor, but didn't see it. I asked Jeremy to follow-up on this today so you have coverage while I'm gone.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I was getting some weird errors the first time, but I was able to follow through with removing
countChoices
from theUserInput
type, so that's been added here.