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

[Interactive Graph] Add example function area for locked function settings #1600

Merged
5 changes: 5 additions & 0 deletions .changeset/few-boats-retire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/perseus-editor": minor
---

Interactive Graph - Add example functions for copy/paste to locked functions settings
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import {render, screen} from "@testing-library/react";
import {userEvent as userEventLib} from "@testing-library/user-event";
import * as React from "react";

// Disabling the following linting error because the import is needed for mocking purposes.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import examples from "../graph-locked-figures/locked-function-examples";
import LockedFunctionSettings from "../graph-locked-figures/locked-function-settings";
import {getDefaultFigureForType} from "../util";

Expand All @@ -16,6 +19,14 @@ const defaultProps = {
onRemove: () => {},
} as Props;

const exampleEquationsMock = {
foo: ["bar", "zot"],
};
jest.mock("../graph-locked-figures/locked-function-examples", () => ({
__esModule: true,
default: exampleEquationsMock,
}));

describe("Locked Function Settings", () => {
let userEvent: UserEvent;
const onChangeProps = jest.fn();
Expand Down Expand Up @@ -222,7 +233,6 @@ describe("Locked Function Settings", () => {

test("calls 'onChangeProps' when directional axis is changed", async () => {
// Arrange
const onChangeProps = jest.fn();
render(
<LockedFunctionSettings
{...defaultProps}
Expand All @@ -244,7 +254,7 @@ describe("Locked Function Settings", () => {
expect(onChangeProps).toHaveBeenCalledWith({directionalAxis: "y"});
});

describe("Domain interactions", () => {
describe("Domain/Range interactions", () => {
test("valid entries update component properties", async () => {
// Arrange
render(
Expand Down Expand Up @@ -363,6 +373,138 @@ describe("Locked Function Settings", () => {
domain: [3, Infinity],
});
});

test("restriction labels reflect the directional axis specified", async () => {
// Arrange
render(
<LockedFunctionSettings
{...defaultProps}
directionalAxis="x"
expanded={true}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

// Assert - "x" axis means "domain"
let minField = screen.getByText("domain min");
expect(minField).toBeInTheDocument();

// Arrange
render(
<LockedFunctionSettings
{...defaultProps}
directionalAxis="y"
expanded={true}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

// Assert - "y" axis means "range"
Copy link
Contributor

Choose a reason for hiding this comment

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

I like your system of adding extra context to the arrange/act/assert comments. I'm gonna start doing this too.

minField = screen.getByText("range min");
expect(minField).toBeInTheDocument();
});
});

describe("Example equation interactions", () => {
test("shows example equations based upon the category chosen", async () => {
// Arrange
render(
<LockedFunctionSettings
{...defaultProps}
expanded={true}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

// Assert - initial state (no category selected)
let copyButtons = screen.queryAllByLabelText("copy example");
expect(copyButtons.length).toEqual(0);

// Act - choose a category of examples
const categoryDropdown =
screen.getByLabelText("Choose a category");
await userEvent.click(categoryDropdown);
const categoryOption = screen.getAllByRole("option")[0];
await userEvent.click(categoryOption);

// Assert - modified state
copyButtons = screen.queryAllByLabelText("copy example");
expect(copyButtons.length).toBeGreaterThan(0);
});

test("example equation is copied to the clipboard when 'copy' icon button is activated", async () => {
// Arrange
const writeTextMock = jest.fn();
const clipboardFnMock = jest.fn();
jest.spyOn(
global.navigator,
"clipboard",
"get",
).mockReturnValue({
// Only interested in the "writeText" function.
writeText: writeTextMock,
// The other functions are here to avoid TS from complaining.
read: clipboardFnMock,
readText: clipboardFnMock,
write: clipboardFnMock,
addEventListener: clipboardFnMock,
dispatchEvent: clipboardFnMock,
removeEventListener: clipboardFnMock,
});

render(
<LockedFunctionSettings
{...defaultProps}
expanded={true}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

// Act - choose a category to get a listing of examples
const categoryDropdown =
screen.getByLabelText("Choose a category");
await userEvent.click(categoryDropdown);
const categoryOption = screen.getAllByRole("option")[0];
await userEvent.click(categoryOption);

// Act - click the copy button for the first example
const copyButton = screen.getAllByLabelText("copy example")[0];
await userEvent.click(copyButton);

// Assert - clipboard receives example text
expect(writeTextMock).toHaveBeenCalledWith("bar");
});

test("example equation is copied to the equation field when 'paste' icon button is activated", async () => {
// Arrange
render(
<LockedFunctionSettings
{...defaultProps}
expanded={true}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

// Act - choose a category to get a listing of examples
const categoryDropdown =
screen.getByLabelText("Choose a category");
await userEvent.click(categoryDropdown);
const categoryOption = screen.getAllByRole("option")[0];
await userEvent.click(categoryOption);

// Act - click the copy button for the first example
const pasteButton =
screen.getAllByLabelText("paste example")[0];
await userEvent.click(pasteButton);

// Assert - clipboard receives example text
expect(onChangeProps).toHaveBeenCalledWith({equation: "bar"});
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const examples: {[k: string]: string[]} = {
linear: ["x + 5", "1/2x - 2"],
polynomial: ["1/2x^2 + 3x - 4", "(1/3)x^3 - 2x^2 + 3x - 4"],
trigonometric: ["sin(x) * 3", "arctan(2x) + 4"],
};

export default examples;
Loading