Skip to content
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

Interactive Graph: Extract validation out of scoring #1903

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
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
5 changes: 5 additions & 0 deletions .changeset/cold-badgers-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/perseus": minor
---

Introduces a validation function for the interactive graph widget (extracted from the scoring function).
7 changes: 5 additions & 2 deletions packages/perseus/src/validation.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,12 @@ export type PerseusInputNumberUserInput = {
currentValue: string;
};

export type PerseusInteractiveGraphRubric = {
export type PerseusInteractiveGraphScoringData = {
// TODO(LEMS-2344): make the type of `correct` more specific
correct: PerseusGraphCorrectType;
} & PerseusInteractiveGraphValidationData;

export type PerseusInteractiveGraphValidationData = {
graph: PerseusGraphType;
};

Expand Down Expand Up @@ -226,7 +229,7 @@ export type Rubric =
| PerseusGrapherRubric
| PerseusIFrameRubric
| PerseusInputNumberRubric
| PerseusInteractiveGraphRubric
| PerseusInteractiveGraphScoringData
| PerseusLabelImageRubric
| PerseusMatcherRubric
| PerseusMatrixRubric
Expand Down
4 changes: 2 additions & 2 deletions packages/perseus/src/widgets/interactive-graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import type {
SineCoefficient,
} from "../util/geometry";
import type {
PerseusInteractiveGraphRubric,
PerseusInteractiveGraphScoringData,
PerseusInteractiveGraphUserInput,
} from "../validation.types";
import type {InteractiveGraphPromptJSON} from "../widget-ai-utils/interactive-graph/interactive-graph-ai-utils";
Expand Down Expand Up @@ -119,7 +119,7 @@ const makeInvalidTypeError = (
};

type RenderProps = PerseusInteractiveGraphWidgetOptions; // There's no transform function in exports
type Props = WidgetProps<RenderProps, PerseusInteractiveGraphRubric>;
type Props = WidgetProps<RenderProps, PerseusInteractiveGraphScoringData>;
type State = any;
type DefaultProps = {
labels: Props["labels"];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,9 @@ import {clone} from "../../../../../testing/object-utils";
import scoreInteractiveGraph from "./score-interactive-graph";

import type {PerseusGraphType} from "../../perseus-types";
import type {PerseusInteractiveGraphRubric} from "../../validation.types";
import type {PerseusInteractiveGraphScoringData} from "../../validation.types";

describe("InteractiveGraph scoring on a segment question", () => {
it("marks the answer invalid if guess.coords is missing", () => {
const guess: PerseusGraphType = {type: "segment"};
const rubric: PerseusInteractiveGraphRubric = {
graph: {
type: "segment",
},
correct: {
type: "segment",
coords: [
[
[0, 0],
[1, 1],
],
],
},
};

const result = scoreInteractiveGraph(guess, rubric);

expect(result).toHaveInvalidInput();
});

it("does not award points if guess.coords is wrong", () => {
const guess: PerseusGraphType = {
type: "segment",
Expand All @@ -41,7 +19,7 @@ describe("InteractiveGraph scoring on a segment question", () => {
],
};

const rubric: PerseusInteractiveGraphRubric = {
const rubric: PerseusInteractiveGraphScoringData = {
graph: {type: "segment"},
correct: {
type: "segment",
Expand Down Expand Up @@ -70,7 +48,7 @@ describe("InteractiveGraph scoring on a segment question", () => {
],
};

const rubric: PerseusInteractiveGraphRubric = {
const rubric: PerseusInteractiveGraphScoringData = {
graph: {type: "segment"},
correct: {
type: "segment",
Expand Down Expand Up @@ -98,7 +76,7 @@ describe("InteractiveGraph scoring on a segment question", () => {
],
],
};
const rubric: PerseusInteractiveGraphRubric = {
const rubric: PerseusInteractiveGraphScoringData = {
graph: {type: "segment"},
correct: {
type: "segment",
Expand Down Expand Up @@ -127,7 +105,7 @@ describe("InteractiveGraph scoring on a segment question", () => {
],
};

const rubric: PerseusInteractiveGraphRubric = {
const rubric: PerseusInteractiveGraphScoringData = {
graph: {type: "segment"},
correct: {
type: "segment",
Expand Down Expand Up @@ -160,7 +138,7 @@ describe("InteractiveGraph scoring on a segment question", () => {
],
],
};
const rubric: PerseusInteractiveGraphRubric = {
const rubric: PerseusInteractiveGraphScoringData = {
graph: {type: "segment"},
correct: {
type: "segment",
Expand All @@ -187,45 +165,7 @@ describe("InteractiveGraph scoring on a segment question", () => {
});
});

describe("InteractiveGraph scoring on an angle question", () => {
it("marks the answer invalid if guess.coords is missing", () => {
const guess: PerseusGraphType = {type: "angle"};
const rubric: PerseusInteractiveGraphRubric = {
graph: {type: "angle"},
correct: {
type: "angle",
coords: [
[1, 1],
[0, 0],
[-1, -1],
],
allowReflexAngles: false,
match: "congruent",
},
};

const result = scoreInteractiveGraph(guess, rubric);

expect(result).toHaveInvalidInput();
});
});

describe("InteractiveGraph scoring on a point question", () => {
it("marks the answer invalid if guess.coords is missing", () => {
const guess: PerseusGraphType = {type: "point"};
const rubric: PerseusInteractiveGraphRubric = {
graph: {type: "point"},
correct: {
type: "point",
coords: [[0, 0]],
},
};

const result = scoreInteractiveGraph(guess, rubric);

expect(result).toHaveInvalidInput();
});

it("throws an exception if correct.coords is missing", () => {
// Characterization test: this might not be desirable behavior, but
// it's the current behavior as of 2024-09-25.
Expand All @@ -234,7 +174,7 @@ describe("InteractiveGraph scoring on a point question", () => {
coords: [[0, 0]],
};

const rubric: PerseusInteractiveGraphRubric = {
const rubric: PerseusInteractiveGraphScoringData = {
graph: {
type: "point",
},
Expand All @@ -252,7 +192,7 @@ describe("InteractiveGraph scoring on a point question", () => {
type: "point",
coords: [[9, 9]],
};
const rubric: PerseusInteractiveGraphRubric = {
const rubric: PerseusInteractiveGraphScoringData = {
graph: {type: "point"},
correct: {
type: "point",
Expand All @@ -270,7 +210,7 @@ describe("InteractiveGraph scoring on a point question", () => {
type: "point",
coords: [[7, 8]],
};
const rubric: PerseusInteractiveGraphRubric = {
const rubric: PerseusInteractiveGraphScoringData = {
graph: {type: "point"},
correct: {
type: "point",
Expand All @@ -291,7 +231,7 @@ describe("InteractiveGraph scoring on a point question", () => {
[5, 6],
],
};
const rubric: PerseusInteractiveGraphRubric = {
const rubric: PerseusInteractiveGraphScoringData = {
graph: {type: "point"},
correct: {
type: "point",
Expand All @@ -315,7 +255,7 @@ describe("InteractiveGraph scoring on a point question", () => {
[5, 6],
],
};
const rubric: PerseusInteractiveGraphRubric = {
const rubric: PerseusInteractiveGraphScoringData = {
graph: {type: "point"},
correct: {
type: "point",
Expand All @@ -341,7 +281,7 @@ describe("InteractiveGraph scoring on a point question", () => {
[5, 6],
],
};
const rubric: PerseusInteractiveGraphRubric = {
const rubric: PerseusInteractiveGraphScoringData = {
graph: {type: "point"},
correct: {
type: "point",
Expand Down
Loading