Skip to content

Commit

Permalink
Spike: swap input-number with numeric-input 😈
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremywiebe committed Mar 24, 2023
1 parent e05504d commit 63e4cac
Show file tree
Hide file tree
Showing 34 changed files with 1,135 additions and 1,103 deletions.
5 changes: 5 additions & 0 deletions .changeset/hungry-llamas-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/perseus": minor
---

Configure Perseus to render numeric-input widgets in place of input-number
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import Editor from "../editor.jsx";
import {registerAllWidgetsAndEditorsForTesting} from "../util/register-all-widgets-and-editors-for-testing.js";

export default {
title: "Perseus/Editor",
title: "Perseus/Editor/Demo",
};

export const Rational = (): React.Node => {
export const Unified = (): React.Node => {
registerAllWidgetsAndEditorsForTesting();
Dependencies.getDependencies().shouldUseFutureKaTeX(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Story = {|
|};

export default ({
title: "Perseus Editor/Widgets/Section Control Button",
title: "Perseus/Editor/Section Control Button",
}: Story);

export const ButtonForEditingSectionsOfContentWithInArticleEditor = (
Expand Down
29 changes: 18 additions & 11 deletions packages/perseus-editor/src/__testdata__/input-number_testdata.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
// @flow
import type {PerseusRenderer, InputNumberWidget} from "@khanacademy/perseus";
import type {PerseusRenderer, NumericInputWidget} from "@khanacademy/perseus";

export const question1: PerseusRenderer = {
content:
"A sequence is defined recursively as follows:\n\n\n$\\qquad\\displaystyle{{a}_{n}}=-\\frac{1}{a_{n-1}-1} \n~~~~~~\\text{ with}\\qquad\\displaystyle{{a}_{0}}=\\frac{1}{2}\\,$\n\n\nFind the term $a_3$ in the sequence.\n\n[[\u2603 input-number 1]]",
content: "$5008 \\div 4 =$ [[\u2603 numeric-input 1]] ",
images: {},
widgets: {
"input-number 1": ({
"numeric-input 1": ({
graded: true,
version: {
major: 0,
minor: 0,
},
static: false,
type: "input-number",
type: "numeric-input",
options: {
maxError: 0.1,
inexact: false,
value: 0.5,
simplify: "required",
answerType: "number",
coefficient: false,
static: false,
answers: [
{
status: "correct",
maxError: null,
strict: false,
value: 1252,
simplify: "required",
message: "",
},
],
labelText: "",
size: "normal",
},
alignment: "default",
}: InputNumberWidget),
}: NumericInputWidget),
},
};
57 changes: 37 additions & 20 deletions packages/perseus-editor/src/__tests__/editor_test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ describe("Editor", () => {
);
});

describe("input-number widget", () => {
describe("numeric-input widget", () => {
beforeEach(async () => {
const [InputNumberWidget, InputNumberEditor] = await Promise.all([
import("@khanacademy/perseus").then((m) => m.InputNumber),
import("../widgets/input-number-editor.jsx").then(
const [NumericInput, NumericInputEditor] = await Promise.all([
import("@khanacademy/perseus").then((m) => m.NumericInput),
import("../widgets/numeric-input-editor.jsx").then(
(m) => m.default,
),
]);
Widgets.registerWidgets([InputNumberWidget]);
Widgets.registerEditors([InputNumberEditor]);
Widgets.registerWidgets([NumericInput]);
Widgets.registerEditors([NumericInputEditor]);
});

test("clicking on the widget editor should open it", async () => {
Expand All @@ -51,13 +51,14 @@ describe("Editor", () => {

// Act
const widgetDisclosure = screen.getByRole("link", {
name: "input-number 1",
name: "numeric-input 1",
});
userEvent.click(widgetDisclosure);
const correctAnswerInput = screen.getByLabelText("Correct answer:");

// Assert
expect(correctAnswerInput).toHaveValue("0.5");
expect(
screen.getByText("Message shown to user on attempt"),
).toBeVisible();
});

it("should update values", async () => {
Expand All @@ -68,7 +69,7 @@ describe("Editor", () => {
<Editor
apiOptions={ApiOptions.defaults}
content={question1.content}
placeholder=""
placeholder="Hello World"
widgets={question1.widgets}
images={question1.images}
disabled={false}
Expand All @@ -84,33 +85,49 @@ describe("Editor", () => {

// Act
const widgetDisclosure = screen.getByRole("link", {
name: "input-number 1",
name: "numeric-input 1",
});
userEvent.click(widgetDisclosure);
const correctAnswerInput = screen.getByLabelText("Correct answer:");

const correctAnswerInput = screen.getByPlaceholderText("answer");
userEvent.clear(correctAnswerInput);
userEvent.paste(correctAnswerInput, "0.75");
userEvent.tab(); // blurring the input triggers onChange to be called

const messageInput = screen.getByPlaceholderText(
"Why is this answer correct? (reinforce the user's understanding)",
);
userEvent.clear(messageInput);
userEvent.type(messageInput, "Because its 0.75");
userEvent.tab();

// Assert
expect(changeFn).toHaveBeenCalledWith(
{
widgets: {
"input-number 1": {
"numeric-input 1": {
graded: true,
version: {major: 0, minor: 0},
static: false,
type: "input-number",
type: "numeric-input",
options: {
value: 0.75,
simplify: "required",
answers: [
{
maxError: null,
message: "",
simplify: "required",
status: "correct",
strict: false,
value: 0.75,
},
],
coefficient: false,
size: "normal",
inexact: false,
maxError: 0.1,
answerType: "number",
multipleNumberInput: false,
labelText: "",
rightAlign: false,
static: false,
},
static: false,
alignment: "default",
},
},
Expand Down
69 changes: 44 additions & 25 deletions packages/perseus-editor/src/__tests__/traversal_test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import _ from "underscore";

import {registerAllWidgetsAndEditorsForTesting} from "../util/register-all-widgets-and-editors-for-testing.js";

const missingOptions = {
import type {PerseusRenderer} from "@khanacademy/perseus";

const missingOptions: PerseusRenderer = {
content: "[[☃ radio 1]]\n\n",
images: {},
widgets: {
Expand Down Expand Up @@ -35,28 +37,44 @@ const missingOptions = {

const clonedMissingOptions = JSON.parse(JSON.stringify(missingOptions));

const sampleOptions = {
content: "[[☃ input-number 1]]",
const sampleOptions: PerseusRenderer = {
content: "[[☃ numeric-input 1]]",
images: {},
widgets: {
"input-number 1": {
type: "input-number",
"numeric-input 1": {
version: {
major: 0,
minor: 0,
},
type: "numeric-input",
graded: true,
alignment: "default",
static: false,
options: {
value: "0",
simplify: "required",
answers: [
{
message: "That's correct!",
value: 0.3333333333333333,
status: "correct",
answerForms: ["integer", "proper", "improper", "mixed"],
strict: true,
maxError: 0.1,
simplify: "optional",
},
],
answerForms: [
{name: "integer", simplify: "required"},
{name: "proper", simplify: "required"},
{name: "improper", simplify: "required"},
{name: "mixed", simplify: "required"},
],
size: "normal",
inexact: false,
maxError: 0.1,
answerType: "number",
coefficient: false,
multipleNumberInput: false,
rightAlign: false,
static: false,
labelText: "Enter the decimal value of 1/3",
},
version: {
major: 0,
minor: 0,
},
alignment: "default",
},
},
};
Expand Down Expand Up @@ -259,19 +277,18 @@ describe("Traversal", () => {
readContent = content;
});

expect(readContent).toBe("[[☃ input-number 1]]");
expect(readContent).toBe("[[☃ numeric-input 1]]");
assertNonMutative();
});

it("should be able to modify root level content", () => {
const newOptions = traverse(sampleOptions, (content) => {
return "new content text";
});
expect(newOptions).toEqual(
_.extend({}, sampleOptions, {
content: "new content text",
}),
);
expect(newOptions).toEqual({
...sampleOptions,
content: "new content text",
});
assertNonMutative();
});

Expand All @@ -281,7 +298,7 @@ describe("Traversal", () => {
widgetMap[widgetInfo.type] = (widgetMap[widgetInfo.type] || 0) + 1;
});
expect(widgetMap).toEqual({
"input-number": 1,
"numeric-input": 1,
});
assertNonMutative();
});
Expand All @@ -295,9 +312,9 @@ describe("Traversal", () => {
expect(newOptions).toEqual(
_.extend({}, sampleOptions, {
widgets: {
"input-number 1": _.extend(
"numeric-input 1": _.extend(
{},
sampleOptions.widgets["input-number 1"],
sampleOptions.widgets["numeric-input 1"],
{graded: false},
),
},
Expand All @@ -312,7 +329,9 @@ describe("Traversal", () => {
content: `${options.content}\n\nnew content!`,
});
});
expect(newOptions.content).toBe("[[☃ input-number 1]]\n\nnew content!");
expect(newOptions.content).toBe(
"[[☃ numeric-input 1]]\n\nnew content!",
);
expect(newOptions.widgets).toEqual(sampleOptions.widgets);
assertNonMutative();
});
Expand Down
2 changes: 0 additions & 2 deletions packages/perseus-editor/src/all-editors.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import GrapherEditor from "./widgets/grapher-editor.jsx";
import GroupEditor from "./widgets/group-editor.jsx";
import IframeEditor from "./widgets/iframe-editor.jsx";
import ImageEditor from "./widgets/image-editor.jsx";
import InputNumberEditor from "./widgets/input-number-editor.jsx";
import InteractionEditor from "./widgets/interaction-editor.jsx";
import InteractiveGraphEditor from "./widgets/interactive-graph-editor.jsx";
import LabelImageEditor from "./widgets/label-image-editor.jsx";
Expand Down Expand Up @@ -56,7 +55,6 @@ export default [
GroupEditor,
IframeEditor,
ImageEditor,
InputNumberEditor,
InteractionEditor,
InteractiveGraphEditor,
LabelImageEditor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ describe("Registering all widgets and editors", () => {

expect(allWidgetsTypes).not.toContain("undefined");

for (const widgetType of allWidgetsTypes) {
for (const widgetType of allWidgetsTypes.filter(
// `input-number` is gone, but we register the type so that we can
// redirect data that references it to the input-number widget.
(widgetType) => widgetType !== "input-number",
)) {
expect(Widgets.getEditor(widgetType)).toBeTruthy();
}
});
Expand Down

0 comments on commit 63e4cac

Please sign in to comment.