Skip to content

Commit

Permalink
Add tests for propUpgrades functions (#1914)
Browse files Browse the repository at this point in the history
## Summary:
Only 3 widgets seem to use the `propUpgrades` mechanism:
- Radio
- Expression
- Measurer

None of them seemed to have tests (at least not direct tests), so this adds them.

I also took out underscore after I wrote the tests.

## Test plan:
This is the test plan

Author: handeyeco

Reviewers: jeremywiebe, handeyeco

Required Reviewers:

Approved By: jeremywiebe

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), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ gerald

Pull Request URL: #1914
  • Loading branch information
handeyeco authored Nov 27, 2024
1 parent ee09e9f commit 3e98b7c
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 27 deletions.
5 changes: 5 additions & 0 deletions .changeset/two-feet-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/perseus": patch
---

Add tests for propUpgrades functions (and remove underscore usage)
37 changes: 36 additions & 1 deletion packages/perseus/src/widgets/expression/expression.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import {
expressionItemWithLabels,
} from "./expression.testdata";

import type {PerseusItem} from "../../perseus-types";
import type {
PerseusExpressionWidgetOptions,
PerseusItem,
} from "../../perseus-types";
import type {UserEvent} from "@testing-library/user-event";

const renderAndAnswer = async (
Expand Down Expand Up @@ -523,4 +526,36 @@ describe("Expression Widget", function () {
).toBeNull();
});
});

describe("propUpgrades", () => {
it("can upgrade from v0 to v1", () => {
const v0props = {
times: false,
buttonSets: ["basic"],
functions: [],
form: false,
simplify: false,
value: "42",
};

const expected: PerseusExpressionWidgetOptions = {
times: false,
buttonSets: ["basic"],
functions: [],
answerForms: [
{
considered: "correct",
form: false,
simplify: false,
value: "42",
},
],
};

const result: PerseusExpressionWidgetOptions =
ExpressionWidgetExport.propUpgrades["1"](v0props);

expect(result).toEqual(expected);
});
});
});
44 changes: 44 additions & 0 deletions packages/perseus/src/widgets/measurer/measurer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import MeasurerWidgetExport from "./measurer";

import type {PerseusMeasurerWidgetOptions} from "../../perseus-types";

describe("measurer", () => {
describe("propUpgrades", () => {
it("can upgrade from v0 to v1", () => {
const v0props = {
imageUrl: "url",
imageTop: 42,
imageLeft: 42,
showProtractor: false,
showRuler: false,
rulerLabel: "test",
rulerTicks: 4,
rulerPixels: 4,
rulerLength: 4,
box: [4, 4],
static: false,
};

const expected: PerseusMeasurerWidgetOptions = {
image: {
url: "url",
top: 42,
left: 42,
},
showProtractor: false,
showRuler: false,
rulerLabel: "test",
rulerTicks: 4,
rulerPixels: 4,
rulerLength: 4,
box: [4, 4],
static: false,
};

const result: PerseusMeasurerWidgetOptions =
MeasurerWidgetExport.propUpgrades["1"](v0props);

expect(result).toEqual(expected);
});
});
});
24 changes: 11 additions & 13 deletions packages/perseus/src/widgets/measurer/measurer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,17 @@ class Measurer extends React.Component<Props> implements Widget {
}

const propUpgrades = {
"1": (v0props: any): any => {
const v1props = _(v0props)
.chain()
.omit("imageUrl", "imageTop", "imageLeft")
.extend({
image: {
url: v0props.imageUrl,
top: v0props.imageTop,
left: v0props.imageLeft,
},
})
.value();
return v1props;
"1": (v0props: any): PerseusMeasurerWidgetOptions => {
const {imageUrl, imageTop, imageLeft, ...rest} = v0props;

return {
...rest,
image: {
url: imageUrl,
top: imageTop,
left: imageLeft,
},
};
},
} as const;

Expand Down
35 changes: 34 additions & 1 deletion packages/perseus/src/widgets/radio/__tests__/radio.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as Dependencies from "../../../dependencies";
import {mockStrings} from "../../../strings";
import {renderQuestion} from "../../__testutils__/renderQuestion";
import PassageWidget from "../../passage";
import RadioWidgetExport from "../radio";
import scoreRadio from "../score-radio";

import {
Expand All @@ -17,7 +18,10 @@ import {
shuffledNoneQuestion,
} from "./radio.testdata";

import type {PerseusRenderer} from "../../../perseus-types";
import type {
PerseusRadioWidgetOptions,
PerseusRenderer,
} from "../../../perseus-types";
import type {APIOptions} from "../../../types";
import type {PerseusRadioUserInput} from "../../../validation.types";
import type {UserEvent} from "@testing-library/user-event";
Expand Down Expand Up @@ -984,3 +988,32 @@ describe("scoring", () => {
expect(renderer).toHaveBeenAnsweredIncorrectly();
});
});

describe("propsUpgrade", () => {
it("can upgrade from v0 to v1", () => {
const v0props = {
choices: [{content: "Choice 1"}, {content: "Choice 2"}],
};

const expected: PerseusRadioWidgetOptions = {
choices: [{content: "Choice 1"}, {content: "Choice 2"}],
hasNoneOfTheAbove: false,
};

const result: PerseusRadioWidgetOptions =
RadioWidgetExport.propUpgrades["1"](v0props);

expect(result).toEqual(expected);
});

it("throws from noneOfTheAbove", () => {
const v0props = {
choices: [{content: "Choice 1"}, {content: "Choice 2"}],
noneOfTheAbove: true,
};

expect(() => RadioWidgetExport.propUpgrades["1"](v0props)).toThrow(
"radio widget v0 no longer supports auto noneOfTheAbove",
);
});
});
20 changes: 8 additions & 12 deletions packages/perseus/src/widgets/radio/radio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,23 +126,19 @@ const transform = (
};

const propUpgrades = {
"1": (v0props: any): any => {
let choices;
let hasNoneOfTheAbove;

if (!v0props.noneOfTheAbove) {
choices = v0props.choices;
hasNoneOfTheAbove = false;
} else {
"1": (v0props: any): PerseusRadioWidgetOptions => {
const {noneOfTheAbove, ...rest} = v0props;

if (noneOfTheAbove) {
throw new Error(
"radio widget v0 no longer supports auto noneOfTheAbove",
);
}

return _.extend(_.omit(v0props, "noneOfTheAbove"), {
choices: choices,
hasNoneOfTheAbove: hasNoneOfTheAbove,
});
return {
...rest,
hasNoneOfTheAbove: false,
};
},
} as const;

Expand Down

0 comments on commit 3e98b7c

Please sign in to comment.