Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mock Widget for cleaning up Tests #2072

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

SonicScrewdriver
Copy link
Contributor

@SonicScrewdriver SonicScrewdriver commented Jan 6, 2025

Summary:

This work was done as part of the Numeric Input project.

This PR introduces a new Mock Widget to be used for any tests that doesn't require testing the capabilities of a specific widget. I have updated as many tests and/or testdatas as I could find, except for a few key situations:

  • The test requires that we test a specific widget, such as extract-perseus-data. (Although I would like to recommend that we break up and move these tests into the individual widget tests as all we need to do is import a single function.)
  • The testdata is being used for storybook

I have also updated as many occurrences of any remaining uses of input-number in our tests to numeric-input, in order to help smooth the path forward for the eventual return to the Input Number Conversion project.

I have opted not to include the widget in our extra-widgets / general registration for now as it would require that I also create an editor for it, but a caveat of this approach means that this widget is not accessible for Webapp tests. I would be happy to hear any thoughts regarding this approach, as I wasn't sure if I should be globally registering this widget.

Issue: LEMS-2615

Test plan:

  • ensure all tests pass

@SonicScrewdriver SonicScrewdriver self-assigned this Jan 6, 2025
@SonicScrewdriver SonicScrewdriver changed the title Fixing up tons of merge conflicts from changes performed over the holidays Mock Widget for cleaning up Tests Jan 6, 2025
@@ -235,6 +235,14 @@ export type PerseusTableRubric = {

export type PerseusTableUserInput = ReadonlyArray<ReadonlyArray<string>>;

export type PerseusMockWidgetRubric = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: I should ensure these are ordered alphabetically

@@ -330,6 +331,8 @@ export type MoleculeRendererWidget = WidgetOptions<'molecule-renderer', PerseusM
export type RefTargetWidget = WidgetOptions<'passage-ref-target', PerseusPassageRefTargetWidgetOptions>;
// prettier-ignore
export type VideoWidget = WidgetOptions<'video', PerseusVideoWidgetOptions>;
// prettier-ignore
export type MockWidget = WidgetOptions<'mock-widget', MockWidgetOptions>;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: I should ensure these are ordered alphabetically

Copy link
Contributor

github-actions bot commented Jan 6, 2025

npm Snapshot: Published

Good news!! We've packaged up the latest commit from this PR (ce9ff1e) and published it to npm. You
can install it using the tag PR2072.

Example:

yarn add @khanacademy/perseus@PR2072

If you are working in Khan Academy's webapp, you can run:

./dev/tools/bump_perseus_version.sh -t PR2072

Copy link
Contributor

github-actions bot commented Jan 6, 2025

Size Change: -2 B (0%)

Total Size: 1.27 MB

Filename Size Change
packages/perseus-editor/dist/es/index.js 688 kB -2 B (0%)
ℹ️ View Unchanged
Filename Size
packages/kas/dist/es/index.js 39 kB
packages/keypad-context/dist/es/index.js 760 B
packages/kmath/dist/es/index.js 4.27 kB
packages/math-input/dist/es/index.js 78 kB
packages/math-input/dist/es/strings.js 1.79 kB
packages/perseus-core/dist/es/index.js 1.48 kB
packages/perseus-linter/dist/es/index.js 22.2 kB
packages/perseus/dist/es/index.js 419 kB
packages/perseus/dist/es/strings.js 4.64 kB
packages/pure-markdown/dist/es/index.js 3.66 kB
packages/simple-markdown/dist/es/index.js 12.5 kB

compressed-size-action

@@ -0,0 +1,38 @@
import KhanAnswerTypes from "../../util/answer-types";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will probably end up getting moved, or possible removed, as part of the Server Side Scoring project - which is fine!

@SonicScrewdriver SonicScrewdriver marked this pull request as ready for review January 8, 2025 22:59
Copy link
Collaborator

@jeremywiebe jeremywiebe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love this! Moving away from using production widgets for tests that aren't testing that widget should make for much less churn as we maintain/improve each widget!


/**
* This is a Mock Perseus widget, which is used for our various rendering tests
* across both Perseus and Webapp. It is a simple widget that renders an interactable
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove the reference to webapp (private repo)? I think it's enough to say it's for unit testing (both internally and in consuming projects)?

*
* Please use this widget for all tests that are not specifically testing the
* functionality of a particular widget, such as testing the rendering components.
* This allows us to more easily update our widget schemas without needing to
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* This allows us to more easily update our widget schemas without needing to
* This allows us to more easily update our widget schemas and behaviour without needing to

arg2: string,
arg3?: () => unknown | null | undefined,
) => void = (path, newValue, cb) => {
/* c8 ignore next */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this comment. We originally added these comments in a few, select places where we couldn't (or chose not to) unit test a line or block of code... this comment prevents the block from counting towards code coverage. I don't think we'll be too worried about test coverage of this mock widget as a whole.

getInputPaths: () => ReadonlyArray<ReadonlyArray<string>> = () => {
// The widget itself is an input, so we return a single empty list to
// indicate this.
/* c8 ignore next */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/* c8 ignore next */


const styles = StyleSheet.create({
widgetContainer: {
color: "red",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea to make this kinda blatantly non-production!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. I like the idea of moving these together under this folder.

// Act
const input = "40";
const textbox = screen.getByRole("textbox");
await userEvent.click(textbox);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove the .click() call when using .type() (it does that for you unless explicitly disabled)

https://testing-library.com/docs/user-event/utility/#type

@@ -223,6 +223,7 @@ export type {
CollinearTuple,
MathFormat,
InputNumberWidget, // TODO(jeremy): remove?
NumericInputWidget,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is needing this export? In a perfect world, we wouldn't export any of our widgets and usage of them would all be funnelled through a Renderer.

Comment on lines +1 to +28
import type {PerseusRenderer} from "../../perseus-types";

export default {
question: {
content: "[[☃ mock-widget 1]] [[☃ mock-widget 2]]",
images: {},
widgets: {
"mock-widget 1": {
type: "mock-widget",
graded: true,
options: {
value: "5",
},
},
"mock-widget 2": {
type: "mock-widget",
graded: true,
options: {
value: "6",
},
},
},
} as PerseusRenderer,
answerArea: {
calculator: false,
},
hints: [] as ReadonlyArray<any>,
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of casting the question to PerseusRenderer, can you type the entire thing as a PerseusItem using satisfies?

Suggested change
import type {PerseusRenderer} from "../../perseus-types";
export default {
question: {
content: "[[☃ mock-widget 1]] [[☃ mock-widget 2]]",
images: {},
widgets: {
"mock-widget 1": {
type: "mock-widget",
graded: true,
options: {
value: "5",
},
},
"mock-widget 2": {
type: "mock-widget",
graded: true,
options: {
value: "6",
},
},
},
} as PerseusRenderer,
answerArea: {
calculator: false,
},
hints: [] as ReadonlyArray<any>,
};
import type {PerseusItem} from "../../perseus-types";
export default {
question: {
content: "[[☃ mock-widget 1]] [[☃ mock-widget 2]]",
images: {},
widgets: {
"mock-widget 1": {
type: "mock-widget",
graded: true,
options: {
value: "5",
},
},
"mock-widget 2": {
type: "mock-widget",
graded: true,
options: {
value: "6",
},
},
},
},
answerArea: {
calculator: false,
},
hints: [] as ReadonlyArray<any>,
} satisfies PerseusItem;

static: true,
},
},
});
const cb = jest.fn();

// Act
act(() => renderer.setInputValue(["input-number 2"], "1000", cb));
act(() => renderer.setInputValue(["mock-widget 2"], "1000", cb));
act(() => jest.runOnlyPendingTimers());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With a simpler widget, we may be able to remove these jest.runOnlyPendingTimers() calls. Might be worth a try to simplify these tests slightly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants