Skip to content

Commit

Permalink
Revert "Expose a way to get user input from ServerItemRenderer (#1753)"
Browse files Browse the repository at this point in the history
This reverts commit c1ba55f.
  • Loading branch information
SonicScrewdriver committed Nov 22, 2024
1 parent 37cc5e6 commit d7d4833
Show file tree
Hide file tree
Showing 18 changed files with 76 additions and 234 deletions.
11 changes: 1 addition & 10 deletions dev/flipbook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {useEffect, useMemo, useReducer, useRef, useState} from "react";

import {Renderer} from "../packages/perseus/src";
import {SvgImage} from "../packages/perseus/src/components";
import {scorePerseusItem} from "../packages/perseus/src/renderer-util";
import {mockStrings} from "../packages/perseus/src/strings";
import {isCorrect} from "../packages/perseus/src/util";
import {trueForAllMafsSupportedGraphTypes} from "../packages/perseus/src/widgets/interactive-graphs/mafs-supported-graph-types";
Expand Down Expand Up @@ -320,15 +319,7 @@ function GradableRenderer(props: QuestionRendererProps) {
leftContent={
<Button
onClick={() => {
if (rendererRef.current) {
const score = scorePerseusItem(
question,
rendererRef.current.getUserInputMap(),
mockStrings,
"en",
);
setScore(score);
}
setScore(rendererRef.current?.score());
clearScoreTimeout.set();
}}
>
Expand Down
12 changes: 8 additions & 4 deletions packages/perseus/src/components/__tests__/sorter.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,15 @@ describe("sorter widget", () => {
const {renderer} = renderQuestion(question1, apiOptions);
const sorter = renderer.findWidgets("sorter 1")[0];

// Act
// Put the options in the correct order

["$0.005$ kilograms", "$15$ grams", "$55$ grams"].forEach((option) => {
act(() => sorter.moveOptionToIndex(option, 3));
});
// Act
renderer.guessAndScore();

// Assert
// assert
expect(renderer).toHaveBeenAnsweredCorrectly();
});
it("can be answered incorrectly", () => {
Expand All @@ -93,15 +95,17 @@ describe("sorter widget", () => {
const {renderer} = renderQuestion(question1, apiOptions);
const sorter = renderer.findWidgets("sorter 1")[0];

// Act
// Put the options in the reverse order
["$0.005$ kilograms", "$15$ grams", "$55$ grams"].forEach(
(option, index) => {
act(() => sorter.moveOptionToIndex(option, 0));
},
);

// Assert
// Act
renderer.guessAndScore();

// assert
expect(renderer).toHaveBeenAnsweredIncorrectly();
});
});
2 changes: 0 additions & 2 deletions packages/perseus/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export {default as ServerItemRenderer} from "./server-item-renderer";
export {default as HintsRenderer} from "./hints-renderer";
export {default as HintRenderer} from "./hint-renderer";
export {default as Renderer} from "./renderer";
export {scorePerseusItem} from "./renderer-util";

/**
* Widgets
Expand Down Expand Up @@ -228,7 +227,6 @@ export type {
PerseusWidgetsMap,
MultiItem,
} from "./perseus-types";
export type {UserInputMap} from "./validation.types";
export type {Coord} from "./interactive2/types";
export type {MarkerType} from "./widgets/label-image/types";

Expand Down
51 changes: 1 addition & 50 deletions packages/perseus/src/renderer-util.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import {screen} from "@testing-library/react";
import {userEvent as userEventLib} from "@testing-library/user-event";

import {
emptyWidgetsFunctional,
scorePerseusItem,
scoreWidgetsFunctional,
} from "./renderer-util";
import {emptyWidgetsFunctional, scoreWidgetsFunctional} from "./renderer-util";
import {mockStrings} from "./strings";
import {registerAllWidgetsForTesting} from "./util/register-all-widgets-for-testing";
import {renderQuestion} from "./widgets/__testutils__/renderQuestion";
import {question1} from "./widgets/group/group.testdata";

import type {DropdownWidget, PerseusWidgetsMap} from "./perseus-types";
import type {UserInputMap} from "./validation.types";
import type {UserEvent} from "@testing-library/user-event";

const testDropdownWidget: DropdownWidget = {
type: "dropdown",
Expand Down Expand Up @@ -479,42 +469,3 @@ describe("scoreWidgetsFunctional", () => {
expect(result["group 1"]).toHaveBeenAnsweredIncorrectly();
});
});

describe("scorePerseusItem", () => {
let userEvent: UserEvent;
beforeEach(() => {
userEvent = userEventLib.setup({
advanceTimers: jest.advanceTimersByTime,
});
});

it("should return score from contained Renderer", async () => {
// Arrange
const {renderer} = renderQuestion(question1);
// Answer all widgets correctly
await userEvent.click(screen.getAllByRole("radio")[4]);
// Note(jeremy): If we don't tab away from the radio button in this
// test, it seems like the userEvent typing doesn't land in the first
// text field.
await userEvent.tab();
await userEvent.type(
screen.getByRole("textbox", {name: /nearest ten/}),
"230",
);
await userEvent.type(
screen.getByRole("textbox", {name: /nearest hundred/}),
"200",
);
const userInput = renderer.getUserInputMap();
const score = scorePerseusItem(question1, userInput, mockStrings, "en");

// Assert
expect(score).toHaveBeenAnsweredCorrectly();
expect(score).toEqual({
earned: 3,
message: null,
total: 3,
type: "points",
});
});
});
31 changes: 3 additions & 28 deletions packages/perseus/src/renderer-util.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import Util from "./util";
import {getWidgetIdsFromContent} from "./widget-type-utils";
import {getWidgetScorer} from "./widgets";

import type {PerseusRenderer, PerseusWidgetsMap} from "./perseus-types";
import type {PerseusWidgetsMap} from "./perseus-types";
import type {PerseusStrings} from "./strings";
import type {PerseusScore} from "./types";
import type {UserInput, UserInputMap} from "./validation.types";
Expand Down Expand Up @@ -51,35 +50,11 @@ export function emptyWidgetsFunctional(
});
}

// TODO: combine scorePerseusItem with scoreWidgetsFunctional
// once scorePerseusItem is the only one calling scoreWidgetsFunctional
export function scorePerseusItem(
perseusRenderData: PerseusRenderer,
userInputMap: UserInputMap,
// TODO(LEMS-2461,LEMS-2391): these probably
// need to be removed before we move this to the server
strings: PerseusStrings,
locale: string,
): PerseusScore {
// There seems to be a chance that PerseusRenderer.widgets might include
// widget data for widgets that are not in PerseusRenderer.content,
// so this checks that the widgets are being used before scoring them
const usedWidgetIds = getWidgetIdsFromContent(perseusRenderData.content);
const scores = scoreWidgetsFunctional(
perseusRenderData.widgets,
usedWidgetIds,
userInputMap,
strings,
locale,
);
return Util.flattenScores(scores);
}

export function scoreWidgetsFunctional(
widgets: PerseusWidgetsMap,
// This is a port of old code, I'm not sure why
// we need widgetIds vs the keys of the widgets object
widgetIds: ReadonlyArray<string>,
widgetIds: Array<string>,
userInputMap: UserInputMap,
strings: PerseusStrings,
locale: string,
Expand All @@ -104,7 +79,7 @@ export function scoreWidgetsFunctional(
if (widget.type === "group") {
const scores = scoreWidgetsFunctional(
widget.options.widgets,
getWidgetIdsFromContent(widget.options.content),
Object.keys(widget.options.widgets),
userInputMap[id] as UserInputMap,
strings,
locale,
Expand Down
38 changes: 21 additions & 17 deletions packages/perseus/src/renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,7 @@ class Renderer
// /cry(aria)
this._foundTextNodes = true;

if (this.widgetIds.includes(node.id)) {
if (_.contains(this.widgetIds, node.id)) {
// We don't want to render a duplicate widget key/ref,
// as this causes problems with react (for obvious
// reasons). Instead we just notify the
Expand Down Expand Up @@ -1510,15 +1510,15 @@ class Renderer

getInputPaths: () => ReadonlyArray<FocusPath> = () => {
const inputPaths: Array<FocusPath> = [];
this.widgetIds.forEach((widgetId: string) => {
_.each(this.widgetIds, (widgetId: string) => {
const widget = this.getWidgetInstance(widgetId);
if (widget && widget.getInputPaths) {
// Grab all input paths and add widgetID to the front
const widgetInputPaths = widget.getInputPaths();
// Prefix paths with their widgetID and add to collective
// list of paths.
// @ts-expect-error - TS2345 - Argument of type '(inputPath: string) => void' is not assignable to parameter of type 'CollectionIterator<FocusPath, void, readonly FocusPath[]>'.
widgetInputPaths.forEach((inputPath: string) => {
_.each(widgetInputPaths, (inputPath: string) => {
const relativeInputPath = [widgetId].concat(inputPath);
inputPaths.push(relativeInputPath);
});
Expand Down Expand Up @@ -1742,42 +1742,46 @@ class Renderer
}

/**
* Scores the content.
*
* @deprecated use scorePerseusItem
* Returns an object mapping from widget ID to perseus-style score.
* The keys of this object are the values of the array returned
* from `getWidgetIds`.
*/
score(): PerseusScore {
const scores = scoreWidgetsFunctional(
scoreWidgets(): {[widgetId: string]: PerseusScore} {
return scoreWidgetsFunctional(
this.state.widgetInfo,
this.widgetIds,
this.getUserInputMap(),
this.props.strings,
this.context.locale,
);
const combinedScore = Util.flattenScores(scores);
return combinedScore;
}

/**
* @deprecated use scorePerseusItem
* Grades the content.
*/
guessAndScore: () => [UserInputArray, PerseusScore] = () => {
score(): PerseusScore {
const scores = this.scoreWidgets();
const combinedScore = Util.flattenScores(scores);
return combinedScore;
}

guessAndScore(): [UserInputArray, PerseusScore] {
const totalGuess = this.getUserInput();
const totalScore = this.score();

return [totalGuess, totalScore];
};
}

examples: () => ReadonlyArray<string> | null | undefined = () => {
const widgetIds = this.widgetIds;
const examples = widgetIds
.map((widgetId) => {
const examples = _.compact(
_.map(widgetIds, (widgetId) => {
const widget = this.getWidgetInstance(widgetId);
return widget != null && widget.examples
? widget.examples()
: null;
})
.filter(Boolean);
}),
);

// no widgets with examples
if (!examples.length) {
Expand Down
Loading

0 comments on commit d7d4833

Please sign in to comment.