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

Add file input dialog #90

Merged
merged 13 commits into from
Oct 3, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

- Made text input box use a monospace font
- Disabled download buttons when there is no input/output.
- Added a dialog to the file input section.

### πŸ”§ Internal changes

Expand Down
62 changes: 42 additions & 20 deletions demo/src/MemoryModelsUserInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import {
Tooltip,
MenuItem,
Stack,
Dialog,
DialogActions,
DialogContent,
} from "@mui/material";
import DownloadJSONButton from "./DownloadJSONButton";
import MemoryModelsMenu from "./MemoryModelsMenu";
Expand Down Expand Up @@ -45,6 +48,10 @@ type MemoryModelsUserInputPropTypes = MemoryModelsFileInputPropTypes &

function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) {
const [uploadedFileString, setUploadedFileString] = useState("");
const [open, setOpen] = useState(false);

const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);

const onChange = (event) => {
try {
Expand All @@ -54,7 +61,6 @@ function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) {
fileReader.onload = (event) => {
const fileString = event.target.result as string;
setUploadedFileString(fileString);
props.setTextData(fileString);
};
} catch (error) {
const errorMessage = `Error reading uploaded file as text. Please ensure it's in UTF-8 encoding: ${error.message}`;
Expand All @@ -66,29 +72,45 @@ function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) {

const onLoadButtonClick = () => {
props.setTextData(uploadedFileString);
setOpen(false);
};

return (
<Stack direction={"row"} spacing={2}>
<Input
type="file"
onChange={onChange}
inputProps={{
accept: "application/JSON",
"data-testid": "file-input",
}}
disableUnderline={true}
/>
<Button
data-testid="file-input-reapply-button"
variant="contained"
disabled={!uploadedFileString}
onClick={onLoadButtonClick}
sx={{ textTransform: "none" }}
>
Load file data
<div>
<Button onClick={handleOpen} sx={{ textTransform: "none" }}>
Upload JSON File
</Button>
</Stack>
<Dialog
open={open}
onClose={handleClose}
data-testid="file-input-dialog"
>
<DialogContent>
<Input
type="file"
onChange={onChange}
inputProps={{
accept: "application/JSON",
"data-testid": "file-input",
}}
disableUnderline={true}
sx={{ alignSelf: "center" }}
/>
</DialogContent>
<DialogActions>
<Button
data-testid="file-input-reapply-button"
variant="contained"
color="primary"
disabled={!uploadedFileString}
onClick={onLoadButtonClick}
sx={{ textTransform: "none" }}
>
Load file data
</Button>
</DialogActions>
</Dialog>
</div>
);
}

Expand Down
25 changes: 19 additions & 6 deletions demo/src/__tests__/MemoryModelsUserInput.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import React from "react";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import {
fireEvent,
getByText,
render,
screen,
waitFor,
} from "@testing-library/react";
import MemoryModelsUserInput from "../MemoryModelsUserInput";

describe("MemoryModelsUserInput", () => {
Expand Down Expand Up @@ -127,7 +133,16 @@ describe("MemoryModelsUserInput", () => {
jest.restoreAllMocks();
});

it("does not render the dialog when the page first loads", () => {
const dialog = screen.queryByTestId("file-input-dialog");
expect(dialog).toBeNull();

const input: HTMLInputElement = screen.queryByTestId("file-input");
expect(input).toBeNull();
});

it("renders an enabled input and disabled reapply button", () => {
fireEvent.click(screen.getByText("Upload JSON File"));
const input: HTMLInputElement = screen.getByTestId("file-input");
expect(input).toHaveProperty("disabled", false);

Expand All @@ -149,6 +164,7 @@ describe("MemoryModelsUserInput", () => {
type: "application/json",
}
);
fireEvent.click(screen.getByText("Upload JSON File"));
const input: HTMLInputElement = screen.getByTestId("file-input");
await waitFor(() => {
// this needs to be awaited because of fileReader.onload being async
Expand All @@ -167,6 +183,7 @@ describe("MemoryModelsUserInput", () => {
let input: HTMLInputElement;

beforeEach(async () => {
fireEvent.click(screen.getByText("Upload JSON File"));
const file = new File([fileString], "test.json", {
type: "application/json",
});
Expand Down Expand Up @@ -195,13 +212,9 @@ describe("MemoryModelsUserInput", () => {
});

await waitFor(() => {
// once from reapplyBtn onChange, once from MemoryModelsTextInput handleTextFieldChange
// if put within the same waitFor block as fireEvent.click(reapplyBtn), this test always passes
// even with the wrong expect
expect(setTextDataMock).toHaveBeenNthCalledWith(
2,
fileString
);
expect(setTextDataMock).toHaveBeenCalledWith(fileString);
Copy link
Collaborator Author

@yoonieaj yoonieaj Oct 2, 2024

Choose a reason for hiding this comment

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

Previously, setTextData would be called called twice (once upon uploading the file, and again upon clicking the Load file data button). I made changes so that setTextData is only called once the button is clicked, and had to change this test to reflect that.

});
});
});
Expand Down
Loading