From 774f40733235c3171ef25eb2f111181834d7cd11 Mon Sep 17 00:00:00 2001 From: Matthew Curtis Date: Tue, 26 Nov 2024 09:50:07 -0600 Subject: [PATCH 1/7] expression --- .../widgets/expression/expression.test.tsx | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/packages/perseus/src/widgets/expression/expression.test.tsx b/packages/perseus/src/widgets/expression/expression.test.tsx index be8d76b63c..3a35cdaa96 100644 --- a/packages/perseus/src/widgets/expression/expression.test.tsx +++ b/packages/perseus/src/widgets/expression/expression.test.tsx @@ -523,4 +523,33 @@ 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 result = ExpressionWidgetExport.propUpgrades["1"](v0props); + + expect(result).toEqual({ + times: false, + buttonSets: ["basic"], + functions: [], + answerForms: [ + { + considered: "correct", + form: false, + simplify: false, + value: "42", + }, + ], + }); + }); + }); }); From 65c06c19b4afa5056bf2e2f64917b1a60c0bab43 Mon Sep 17 00:00:00 2001 From: Matthew Curtis Date: Tue, 26 Nov 2024 09:59:50 -0600 Subject: [PATCH 2/7] measurer --- .../src/widgets/measurer/measurer.test.tsx | 39 +++++++++++++++++++ .../perseus/src/widgets/measurer/measurer.tsx | 22 +++++------ 2 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 packages/perseus/src/widgets/measurer/measurer.test.tsx diff --git a/packages/perseus/src/widgets/measurer/measurer.test.tsx b/packages/perseus/src/widgets/measurer/measurer.test.tsx new file mode 100644 index 0000000000..c55c786209 --- /dev/null +++ b/packages/perseus/src/widgets/measurer/measurer.test.tsx @@ -0,0 +1,39 @@ +import MeasurerWidgetExport from "./measurer"; + +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 result = MeasurerWidgetExport.propUpgrades["1"](v0props); + + expect(result).toEqual({ + image: { + url: "url", + top: 42, + left: 42, + }, + showProtractor: false, + showRuler: false, + rulerLabel: "test", + rulerTicks: 4, + rulerPixels: 4, + rulerLength: 4, + box: [4, 4], + static: false, + }); + }); + }); +}); diff --git a/packages/perseus/src/widgets/measurer/measurer.tsx b/packages/perseus/src/widgets/measurer/measurer.tsx index 4347ec677e..9e3f676ac5 100644 --- a/packages/perseus/src/widgets/measurer/measurer.tsx +++ b/packages/perseus/src/widgets/measurer/measurer.tsx @@ -183,18 +183,16 @@ class Measurer extends React.Component 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; + const {imageUrl, imageTop, imageLeft, ...rest} = v0props; + + return { + ...rest, + image: { + url: imageUrl, + top: imageTop, + left: imageLeft, + }, + }; }, } as const; From 250f67e4afd8742a50d2dc3b30889d700b3d914b Mon Sep 17 00:00:00 2001 From: Matthew Curtis Date: Tue, 26 Nov 2024 10:19:29 -0600 Subject: [PATCH 3/7] radio --- .../src/widgets/radio/__tests__/radio.test.ts | 27 +++++++++++++++++++ packages/perseus/src/widgets/radio/radio.ts | 13 +++++---- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/packages/perseus/src/widgets/radio/__tests__/radio.test.ts b/packages/perseus/src/widgets/radio/__tests__/radio.test.ts index 4eeb1de264..0eb7393801 100644 --- a/packages/perseus/src/widgets/radio/__tests__/radio.test.ts +++ b/packages/perseus/src/widgets/radio/__tests__/radio.test.ts @@ -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 { @@ -984,3 +985,29 @@ describe("scoring", () => { expect(renderer).toHaveBeenAnsweredIncorrectly(); }); }); + +describe("propsUpgrade", () => { + it("can upgrade from v0 to v1", () => { + const v0props = { + choices: [{content: "Choice 1"}, {content: "Choice 2"}], + }; + + const result = RadioWidgetExport.propUpgrades["1"](v0props); + + expect(result).toEqual({ + choices: [{content: "Choice 1"}, {content: "Choice 2"}], + hasNoneOfTheAbove: false, + }); + }); + + 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", + ); + }); +}); diff --git a/packages/perseus/src/widgets/radio/radio.ts b/packages/perseus/src/widgets/radio/radio.ts index 815320c5e5..d41e084f9f 100644 --- a/packages/perseus/src/widgets/radio/radio.ts +++ b/packages/perseus/src/widgets/radio/radio.ts @@ -127,10 +127,12 @@ const transform = ( const propUpgrades = { "1": (v0props: any): any => { + const {noneOfTheAbove, ...rest} = v0props; + let choices; let hasNoneOfTheAbove; - if (!v0props.noneOfTheAbove) { + if (!noneOfTheAbove) { choices = v0props.choices; hasNoneOfTheAbove = false; } else { @@ -139,10 +141,11 @@ const propUpgrades = { ); } - return _.extend(_.omit(v0props, "noneOfTheAbove"), { - choices: choices, - hasNoneOfTheAbove: hasNoneOfTheAbove, - }); + return { + ...rest, + choices, + hasNoneOfTheAbove, + }; }, } as const; From b2859e90cb0ae91abc899aea93ceb620531caf37 Mon Sep 17 00:00:00 2001 From: Matthew Curtis Date: Tue, 26 Nov 2024 10:24:32 -0600 Subject: [PATCH 4/7] changeset --- .changeset/two-feet-care.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/two-feet-care.md diff --git a/.changeset/two-feet-care.md b/.changeset/two-feet-care.md new file mode 100644 index 0000000000..3a774776ad --- /dev/null +++ b/.changeset/two-feet-care.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/perseus": patch +--- + +Add tests for propUpgrades functions (and remove underscore usage) From febaac0bda40abd5a57ffdde3fcd8c16a0ba9891 Mon Sep 17 00:00:00 2001 From: Matthew Curtis Date: Tue, 26 Nov 2024 10:32:59 -0600 Subject: [PATCH 5/7] cleanup --- packages/perseus/src/widgets/radio/radio.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/perseus/src/widgets/radio/radio.ts b/packages/perseus/src/widgets/radio/radio.ts index d41e084f9f..2b80459b27 100644 --- a/packages/perseus/src/widgets/radio/radio.ts +++ b/packages/perseus/src/widgets/radio/radio.ts @@ -129,13 +129,7 @@ const propUpgrades = { "1": (v0props: any): any => { const {noneOfTheAbove, ...rest} = v0props; - let choices; - let hasNoneOfTheAbove; - - if (!noneOfTheAbove) { - choices = v0props.choices; - hasNoneOfTheAbove = false; - } else { + if (noneOfTheAbove) { throw new Error( "radio widget v0 no longer supports auto noneOfTheAbove", ); @@ -143,8 +137,7 @@ const propUpgrades = { return { ...rest, - choices, - hasNoneOfTheAbove, + hasNoneOfTheAbove: false, }; }, } as const; From bbcfde0d3dbfc406547deaff00f68350fb40d119 Mon Sep 17 00:00:00 2001 From: Matthew Curtis Date: Tue, 26 Nov 2024 15:50:10 -0600 Subject: [PATCH 6/7] respond to Jeremys feedback --- .../src/widgets/expression/expression.test.tsx | 15 ++++++++++----- .../src/widgets/measurer/measurer.test.tsx | 12 ++++++++---- .../src/widgets/radio/__tests__/radio.test.ts | 15 ++++++++++----- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/packages/perseus/src/widgets/expression/expression.test.tsx b/packages/perseus/src/widgets/expression/expression.test.tsx index 3a35cdaa96..d0e102f4dd 100644 --- a/packages/perseus/src/widgets/expression/expression.test.tsx +++ b/packages/perseus/src/widgets/expression/expression.test.tsx @@ -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 ( @@ -535,9 +538,7 @@ describe("Expression Widget", function () { value: "42", }; - const result = ExpressionWidgetExport.propUpgrades["1"](v0props); - - expect(result).toEqual({ + const expected: PerseusExpressionWidgetOptions = { times: false, buttonSets: ["basic"], functions: [], @@ -549,7 +550,11 @@ describe("Expression Widget", function () { value: "42", }, ], - }); + }; + + const result = ExpressionWidgetExport.propUpgrades["1"](v0props); + + expect(result).toEqual(expected); }); }); }); diff --git a/packages/perseus/src/widgets/measurer/measurer.test.tsx b/packages/perseus/src/widgets/measurer/measurer.test.tsx index c55c786209..70ec179f24 100644 --- a/packages/perseus/src/widgets/measurer/measurer.test.tsx +++ b/packages/perseus/src/widgets/measurer/measurer.test.tsx @@ -1,5 +1,7 @@ import MeasurerWidgetExport from "./measurer"; +import type {PerseusMeasurerWidgetOptions} from "../../perseus-types"; + describe("measurer", () => { describe("propUpgrades", () => { it("can upgrade from v0 to v1", () => { @@ -17,9 +19,7 @@ describe("measurer", () => { static: false, }; - const result = MeasurerWidgetExport.propUpgrades["1"](v0props); - - expect(result).toEqual({ + const expected: PerseusMeasurerWidgetOptions = { image: { url: "url", top: 42, @@ -33,7 +33,11 @@ describe("measurer", () => { rulerLength: 4, box: [4, 4], static: false, - }); + }; + + const result = MeasurerWidgetExport.propUpgrades["1"](v0props); + + expect(result).toEqual(expected); }); }); }); diff --git a/packages/perseus/src/widgets/radio/__tests__/radio.test.ts b/packages/perseus/src/widgets/radio/__tests__/radio.test.ts index 0eb7393801..02b8b72a32 100644 --- a/packages/perseus/src/widgets/radio/__tests__/radio.test.ts +++ b/packages/perseus/src/widgets/radio/__tests__/radio.test.ts @@ -18,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"; @@ -992,12 +995,14 @@ describe("propsUpgrade", () => { choices: [{content: "Choice 1"}, {content: "Choice 2"}], }; - const result = RadioWidgetExport.propUpgrades["1"](v0props); - - expect(result).toEqual({ + const expected: PerseusRadioWidgetOptions = { choices: [{content: "Choice 1"}, {content: "Choice 2"}], hasNoneOfTheAbove: false, - }); + }; + + const result = RadioWidgetExport.propUpgrades["1"](v0props); + + expect(result).toEqual(expected); }); it("throws from noneOfTheAbove", () => { From c12b3f64fe96ec5b6cc55d366b6425c86c00e731 Mon Sep 17 00:00:00 2001 From: Matthew Curtis Date: Tue, 26 Nov 2024 15:57:47 -0600 Subject: [PATCH 7/7] add more types --- packages/perseus/src/widgets/expression/expression.test.tsx | 3 ++- packages/perseus/src/widgets/measurer/measurer.test.tsx | 3 ++- packages/perseus/src/widgets/measurer/measurer.tsx | 2 +- packages/perseus/src/widgets/radio/__tests__/radio.test.ts | 3 ++- packages/perseus/src/widgets/radio/radio.ts | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/perseus/src/widgets/expression/expression.test.tsx b/packages/perseus/src/widgets/expression/expression.test.tsx index d0e102f4dd..2f5ee2a239 100644 --- a/packages/perseus/src/widgets/expression/expression.test.tsx +++ b/packages/perseus/src/widgets/expression/expression.test.tsx @@ -552,7 +552,8 @@ describe("Expression Widget", function () { ], }; - const result = ExpressionWidgetExport.propUpgrades["1"](v0props); + const result: PerseusExpressionWidgetOptions = + ExpressionWidgetExport.propUpgrades["1"](v0props); expect(result).toEqual(expected); }); diff --git a/packages/perseus/src/widgets/measurer/measurer.test.tsx b/packages/perseus/src/widgets/measurer/measurer.test.tsx index 70ec179f24..6a35c0ca4c 100644 --- a/packages/perseus/src/widgets/measurer/measurer.test.tsx +++ b/packages/perseus/src/widgets/measurer/measurer.test.tsx @@ -35,7 +35,8 @@ describe("measurer", () => { static: false, }; - const result = MeasurerWidgetExport.propUpgrades["1"](v0props); + const result: PerseusMeasurerWidgetOptions = + MeasurerWidgetExport.propUpgrades["1"](v0props); expect(result).toEqual(expected); }); diff --git a/packages/perseus/src/widgets/measurer/measurer.tsx b/packages/perseus/src/widgets/measurer/measurer.tsx index 9e3f676ac5..db4b00a07b 100644 --- a/packages/perseus/src/widgets/measurer/measurer.tsx +++ b/packages/perseus/src/widgets/measurer/measurer.tsx @@ -182,7 +182,7 @@ class Measurer extends React.Component implements Widget { } const propUpgrades = { - "1": (v0props: any): any => { + "1": (v0props: any): PerseusMeasurerWidgetOptions => { const {imageUrl, imageTop, imageLeft, ...rest} = v0props; return { diff --git a/packages/perseus/src/widgets/radio/__tests__/radio.test.ts b/packages/perseus/src/widgets/radio/__tests__/radio.test.ts index 02b8b72a32..593f5a94c4 100644 --- a/packages/perseus/src/widgets/radio/__tests__/radio.test.ts +++ b/packages/perseus/src/widgets/radio/__tests__/radio.test.ts @@ -1000,7 +1000,8 @@ describe("propsUpgrade", () => { hasNoneOfTheAbove: false, }; - const result = RadioWidgetExport.propUpgrades["1"](v0props); + const result: PerseusRadioWidgetOptions = + RadioWidgetExport.propUpgrades["1"](v0props); expect(result).toEqual(expected); }); diff --git a/packages/perseus/src/widgets/radio/radio.ts b/packages/perseus/src/widgets/radio/radio.ts index 2b80459b27..528514e7c9 100644 --- a/packages/perseus/src/widgets/radio/radio.ts +++ b/packages/perseus/src/widgets/radio/radio.ts @@ -126,7 +126,7 @@ const transform = ( }; const propUpgrades = { - "1": (v0props: any): any => { + "1": (v0props: any): PerseusRadioWidgetOptions => { const {noneOfTheAbove, ...rest} = v0props; if (noneOfTheAbove) {