Skip to content

Commit

Permalink
Update Sorter's public widget option function to use custom seed gene…
Browse files Browse the repository at this point in the history
…ration for shuffle (#2215)

## Summary:
To shuffle server-side, we need to set up a seed other than the problemNum. We decided just to use Random.math for the seed. Once Sorter is receiving public widget options from the server, we can remove the client-side shuffle to ensure answer data is not transmitted to the client.

Issue: LEMS-2846

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

Author: Myranae

Reviewers: benchristel, Myranae, 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 builds for changes in size (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x)

Pull Request URL: #2215
  • Loading branch information
Myranae authored Feb 18, 2025
1 parent cbd5a65 commit 62ed407
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 9 deletions.
6 changes: 6 additions & 0 deletions .changeset/tender-eels-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@khanacademy/perseus": patch
"@khanacademy/perseus-core": minor
---

Update Sorter's public widget option function to use Math.random and shuffle
11 changes: 5 additions & 6 deletions packages/perseus-core/src/widgets/sorter/sorter-util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import getSorterPublicWidgetOptions from "./sorter-util";
import type {PerseusSorterWidgetOptions} from "../../data-schema";

describe("getSorterPublicWidgetOptions", () => {
it("should return the correct public options without any answer data", () => {
it("should return options without any answer data due to the shuffled state of the correct field", () => {
// Arrange
const options: PerseusSorterWidgetOptions = {
correct: ["$15$ grams", "$55$ grams", "$0.005$ kilograms"],
Expand All @@ -15,10 +15,9 @@ describe("getSorterPublicWidgetOptions", () => {
const publicWidgetOptions = getSorterPublicWidgetOptions(options);

// Assert
expect(publicWidgetOptions).toEqual({
correct: ["$0.005$ kilograms", "$15$ grams", "$55$ grams"],
layout: "horizontal",
padding: true,
});
expect(new Set(publicWidgetOptions.correct)).toEqual(
new Set(options.correct),
);
expect(publicWidgetOptions.correct).not.toEqual(options.correct);
});
});
18 changes: 15 additions & 3 deletions packages/perseus-core/src/widgets/sorter/sorter-util.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {shuffle} from "@khanacademy/perseus-core";

import type {PerseusSorterWidgetOptions} from "@khanacademy/perseus-core";

/**
Expand All @@ -8,6 +10,7 @@ type SorterPublicWidgetOptions = {
correct: PerseusSorterWidgetOptions["correct"];
padding: PerseusSorterWidgetOptions["padding"];
layout: PerseusSorterWidgetOptions["layout"];
isCorrectShuffled: boolean;
};

/**
Expand All @@ -17,13 +20,22 @@ type SorterPublicWidgetOptions = {
function getSorterPublicWidgetOptions(
options: PerseusSorterWidgetOptions,
): SorterPublicWidgetOptions {
const shuffledCorrect = shuffle(
options.correct,
Math.random,
/* ensurePermuted */ true,
);

return {
...options,
// Note(Tamara): This does not provide correct answer information any longer.
// To maintain compatibility with the original widget options, we are
// keeping the key the same. Represents initial state of the cards here.
correct: options.correct.slice().sort(),
padding: options.padding,
layout: options.layout,
correct: shuffledCorrect,
// Note(Tamara): This new key is only added here with "true". There isn't
// a place where it is set to false. It indicates that the correct field
// has been shuffled and no longer contains correct answer info.
isCorrectShuffled: true,
};
}

Expand Down
4 changes: 4 additions & 0 deletions packages/perseus/src/widgets/sorter/sorter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ class Sorter extends React.Component<Props, State> implements Widget {
};

render(): React.ReactNode {
// TODO(LEMS-2841): Remove client-side shuffle once receiving public
// options. The correct field will already be shuffled.
// Probably easiest to replace "options" with "this.props.correct" when
// setting up Sortable below. Or use the assignment to rename for clarity.
const options = shuffle(
this.props.correct,
this.props.problemNum as number,
Expand Down

0 comments on commit 62ed407

Please sign in to comment.