Skip to content

Commit

Permalink
Create helper to build public widget options for Radio (#2183)
Browse files Browse the repository at this point in the history
## Summary:
Adds a function that takes Radio's full widget options and filters out answer data. It also adds this function to Radio's widget export and adds a test confirming the function does what is expected.

Issue: LEMS-2754

## Test plan:
- Confirm all checks pass
- Confirm Radio still works as expected

Author: Myranae

Reviewers: Myranae, benchristel, jeremywiebe, handeyeco

Required Reviewers:

Approved By: benchristel

Checks: ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x)

Pull Request URL: #2183
  • Loading branch information
Myranae authored Feb 3, 2025
1 parent 37bc455 commit cac3901
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .changeset/smart-months-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@khanacademy/perseus": minor
"@khanacademy/perseus-core": minor
---

Implement a widget export function to filter out rubric data from widget options for the Radio widget
1 change: 1 addition & 0 deletions packages/perseus-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,4 @@ export {default as getSorterPublicWidgetOptions} from "./widgets/sorter/sorter-u
export {default as getDropdownPublicWidgetOptions} from "./widgets/dropdown/dropdown-util";
export {default as getNumericInputPublicWidgetOptions} from "./widgets/numeric-input/numeric-input-util";
export {default as getNumberLinePublicWidgetOptions} from "./widgets/number-line/number-line-util";
export {default as getRadioPublicWidgetOptions} from "./widgets/radio/radio-util";
88 changes: 88 additions & 0 deletions packages/perseus-core/src/widgets/radio/radio-util.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import {getRadioPublicWidgetOptions} from "@khanacademy/perseus-core";

import type {PerseusRadioWidgetOptions} from "../../data-schema";

describe("getRadioPublicWidgetOptions", () => {
it("should return the correct public options without any answer data", () => {
// Arrange
const options: PerseusRadioWidgetOptions = {
choices: [
{
content: "$-8$ and $8$",
correct: false,
clue: "The square root operation ($\\sqrt{\\phantom{x}}$)...",
widgets: {},
},
{
content: "$-8$",
correct: false,
clue: "While $(-8)^2=64$, the square root operation...",
widgets: {},
},
{
content: "There is no such input value.",
isNoneOfTheAbove: true,
correct: true,
clue: "This is a none of the above option.",
widgets: {
"sorter 1": {
type: "sorter",
options: {
correct: ["test"],
padding: true,
layout: "horizontal",
},
},
},
},
],
hasNoneOfTheAbove: false,
countChoices: false,
randomize: false,
multipleSelect: false,
deselectEnabled: false,
onePerLine: false,
displayCount: null,
noneOfTheAbove: false,
};

// Act
const publicWidgetOptions = getRadioPublicWidgetOptions(options);

// Assert
expect(publicWidgetOptions).toEqual({
choices: [
{
content: "$-8$ and $8$",
widgets: {},
},
{
content: "$-8$",
widgets: {},
},
{
content: "There is no such input value.",
isNoneOfTheAbove: true,
widgets: {
"sorter 1": {
type: "sorter",
options: {
correct: ["test"],
padding: true,
layout: "horizontal",
},
},
},
},
],
hasNoneOfTheAbove: false,
countChoices: false,
randomize: false,
multipleSelect: false,
deselectEnabled: false,
onePerLine: false,
displayCount: null,
noneOfTheAbove: false,
});
});
});
58 changes: 58 additions & 0 deletions packages/perseus-core/src/widgets/radio/radio-util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type {
PerseusRadioChoice,
PerseusRadioWidgetOptions,
} from "@khanacademy/perseus-core";

/**
* For details on the individual options, see the
* PerseusRadioWidgetOptions type
*/
type RadioPublicWidgetOptions = {
choices: ReadonlyArray<RadioChoicePublicData>;
hasNoneOfTheAbove?: PerseusRadioWidgetOptions["hasNoneOfTheAbove"];
countChoices?: PerseusRadioWidgetOptions["countChoices"];
randomize?: PerseusRadioWidgetOptions["randomize"];
multipleSelect?: PerseusRadioWidgetOptions["multipleSelect"];
deselectEnabled?: PerseusRadioWidgetOptions["deselectEnabled"];
onePerLine?: PerseusRadioWidgetOptions["onePerLine"];
displayCount?: PerseusRadioWidgetOptions["displayCount"];
noneOfTheAbove?: PerseusRadioWidgetOptions["noneOfTheAbove"];
};

/**
* Only the options from each Radio choice that should be exposed to the client.
*/
type RadioChoicePublicData = Pick<
PerseusRadioChoice,
"content" | "isNoneOfTheAbove" | "widgets"
>;

/**
* Given a PerseusRadioChoice object, return a new object with only the public
* data that should be included in the Radio public widget options.
*/
function getRadioChoicePublicData(
choice: PerseusRadioChoice,
): RadioChoicePublicData {
const {content, isNoneOfTheAbove, widgets} = choice;
return {
content,
isNoneOfTheAbove,
widgets,
};
}

/**
* Given a PerseusRadioWidgetOptions object, return a new object with only
* the public options that should be exposed to the client.
*/
function getRadioPublicWidgetOptions(
options: PerseusRadioWidgetOptions,
): RadioPublicWidgetOptions {
return {
...options,
choices: options.choices.map(getRadioChoicePublicData),
};
}

export default getRadioPublicWidgetOptions;
2 changes: 2 additions & 0 deletions packages/perseus/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
getDropdownPublicWidgetOptions,
getNumericInputPublicWidgetOptions,
getNumberLinePublicWidgetOptions,
getRadioPublicWidgetOptions,
} from "@khanacademy/perseus-core";
import type {LinterContextProps} from "@khanacademy/perseus-linter";
import type {
Expand Down Expand Up @@ -516,6 +517,7 @@ export type WidgetTransform = (
* A union type of all the functions that provide public widget options.
*/
export type PublicWidgetOptionsFunction =
| typeof getRadioPublicWidgetOptions
| typeof getNumericInputPublicWidgetOptions
| typeof getDropdownPublicWidgetOptions
| typeof getCategorizerPublicWidgetOptions
Expand Down
2 changes: 2 additions & 0 deletions packages/perseus/src/widgets/radio/radio.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
radioLogic,
type PerseusRadioWidgetOptions,
getRadioPublicWidgetOptions,
} from "@khanacademy/perseus-core";
import _ from "underscore";

Expand Down Expand Up @@ -137,4 +138,5 @@ export default {
version: radioLogic.version,
propUpgrades: radioLogic.widgetOptionsUpgrades,
isLintable: true,
getPublicWidgetOptions: getRadioPublicWidgetOptions,
} satisfies WidgetExports<typeof Radio>;

0 comments on commit cac3901

Please sign in to comment.