Skip to content

Commit

Permalink
[Locked Figure Labels] Add/edit/delete locked vector labels (#1652)
Browse files Browse the repository at this point in the history
## Summary:
Add the ability to add/edit/delete labels for locked vectors
within the interactive graph editor.

Issue: https://khanacademy.atlassian.net/browse/LEMS-2348

## Test plan:
- Go to http://localhost:6006/?path=/story/perseuseditor-widgets-interactive-graph--mafs-with-locked-vector-labels-flag
- Go to locked figures
- Open the locked vector settings
- Confirm that the label settings are there
- Play around with the label settings and confirm that it moves
  and updates with the vector

<img width="335" alt="image" src="https://github.com/user-attachments/assets/78e0bba8-981f-46c4-8158-6df89517c53e">

Author: nishasy

Reviewers: benchristel, mark-fitzgerald, catandthemachines, anakaren-rojas

Required Reviewers:

Approved By: benchristel

Checks: ✅ codecov/patch, ✅ codecov/project, ✅ Upload Coverage (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Jest Coverage (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), ✅ gerald

Pull Request URL: #1652
  • Loading branch information
nishasy authored Sep 24, 2024
1 parent 03cddb6 commit 1ed0455
Show file tree
Hide file tree
Showing 3 changed files with 316 additions and 4 deletions.
6 changes: 6 additions & 0 deletions .changeset/modern-sheep-bathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@khanacademy/perseus": minor
"@khanacademy/perseus-editor": minor
---

[Locked Figure Labels] Add/edit/delete locked vector labels
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,30 @@ import {render, screen} from "@testing-library/react";
import {userEvent as userEventLib} from "@testing-library/user-event";
import * as React from "react";

import {flags} from "../../../__stories__/flags-for-api-options";

import LockedVectorSettings from "./locked-vector-settings";
import {getDefaultFigureForType} from "./util";

import type {Props} from "./locked-vector-settings";
import type {UserEvent} from "@testing-library/user-event";

const defaultProps = {
flags: {
...flags,
mafs: {
...flags.mafs,
"locked-line-settings": true,
},
},
...getDefaultFigureForType("vector"),
onChangeProps: () => {},
onMove: () => {},
onRemove: () => {},
} as Props;

const defaultLabel = getDefaultFigureForType("label");

describe("Locked Vector Settings", () => {
let userEvent: UserEvent;
beforeEach(() => {
Expand Down Expand Up @@ -104,7 +115,10 @@ describe("Locked Vector Settings", () => {
await userEvent.click(colorOption);

// Assert
expect(onChangeProps).toHaveBeenCalledWith({color: "green"});
expect(onChangeProps).toHaveBeenCalledWith({
color: "green",
labels: [],
});
});

test("shows an error when the vector length is zero", () => {
Expand Down Expand Up @@ -176,4 +190,184 @@ describe("Locked Vector Settings", () => {
}
});
});

describe("Labels", () => {
test("Updates the label coords when the vector coords change", async () => {
// Arrange
const onChangeProps = jest.fn();
render(
<LockedVectorSettings
{...defaultProps}
points={[
[0, 0],
[2, 2],
]}
labels={[
{
...defaultLabel,
// Offset by 0.5, 0.5 from the line's midpoint
// of [1, 1].
coord: [1.5, 1.5],
},
]}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

// Act
const point1XInput = screen.getAllByLabelText("x coord")[1];
// Change the x coord of the second point to 20
await userEvent.type(point1XInput, "0");

// Assert
expect(onChangeProps).toHaveBeenCalledWith({
points: [
[0, 0],
[20, 2],
],
labels: [
{
...defaultLabel,
coord: [10.5, 1.5],
},
],
});
});

test("Updates the label color when the vector color changes", async () => {
// Arrange
const onChangeProps = jest.fn();
render(
<LockedVectorSettings
{...defaultProps}
color="green"
labels={[
{
...defaultLabel,
color: "green",
},
]}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

// Act
const colorSelect = screen.getByLabelText("color");
await userEvent.click(colorSelect);
const colorOption = screen.getByText("pink");
await userEvent.click(colorOption);

// Assert
expect(onChangeProps).toHaveBeenCalledWith({
color: "pink",
labels: [
{
...defaultLabel,
color: "pink",
},
],
});
});

test("Updates the label when the label text changes", async () => {
// Arrange
const onChangeProps = jest.fn();
render(
<LockedVectorSettings
{...defaultProps}
labels={[
{
...defaultLabel,
text: "label text",
},
]}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

// Act
const labelText = screen.getByLabelText("TeX");
await userEvent.type(labelText, "!");

// Assert
expect(onChangeProps).toHaveBeenCalledWith({
labels: [{...defaultLabel, text: "label text!"}],
});
});

test("Removes label when delete button is clicked", async () => {
// Arrange
const onChangeProps = jest.fn();
render(
<LockedVectorSettings
{...defaultProps}
labels={[
{
...defaultLabel,
text: "label text",
},
]}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

// Act
const deleteButton = screen.getByRole("button", {
name: "Delete locked label",
});
await userEvent.click(deleteButton);

// Assert
expect(onChangeProps).toHaveBeenCalledWith({
labels: [],
});
});

test("Adds a new label when the add label button is clicked", async () => {
// Arrange
const onChangeProps = jest.fn();
render(
<LockedVectorSettings
{...defaultProps}
labels={[
{
...defaultLabel,
text: "label text",
},
]}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

// Act
const addLabelButtons = screen.getAllByRole("button", {
name: "Add visible label",
});
// The last button is the one for the whole line, not for
// the points the define the line.
const addLabelButton = addLabelButtons[addLabelButtons.length - 1];
await userEvent.click(addLabelButton);

// Assert
expect(onChangeProps).toHaveBeenCalledWith({
labels: [
{
...defaultLabel,
text: "label text",
},
{
...defaultLabel,
// Midpoint of line [[0, 0], [2, 2]] is [1, 1].
// Offset 1 down vertically for each preceding label.
coord: [1, 0],
},
],
});
});
});
});
Loading

0 comments on commit 1ed0455

Please sign in to comment.