From 9cca11b7854ef3814940bdef77c0fbdc410481c2 Mon Sep 17 00:00:00 2001
From: "Ziyuan (Jerry) Zhang" <ziyuanzhang2019@gmail.com>
Date: Fri, 23 Feb 2024 16:49:33 -0500
Subject: [PATCH] Add prop types, error boundary tests

---
 demo/src/App.tsx                              | 10 ++++-
 demo/src/MemoryModels.tsx                     | 10 ++++-
 demo/src/SvgDisplay.tsx                       |  6 ++-
 demo/src/__tests__/App.spec.tsx               | 44 +++++++++++++++++++
 .../__tests__/MemoryModelsUserInput.spec.tsx  |  1 +
 demo/src/__tests__/SvgDisplay.spec.tsx        |  2 +-
 6 files changed, 68 insertions(+), 5 deletions(-)
 create mode 100644 demo/src/__tests__/App.spec.tsx

diff --git a/demo/src/App.tsx b/demo/src/App.tsx
index 7d80a2e7..aedec23b 100644
--- a/demo/src/App.tsx
+++ b/demo/src/App.tsx
@@ -12,7 +12,7 @@ export default function App() {
         try {
             setJsonResult(JSON.parse(formData));
         } catch (error) {
-            console.error("Error parsing inputted JSON: ", error);
+            console.error(`Error parsing inputted JSON: ${error.message}`);
             setJsonResult(null);
         }
     };
@@ -26,7 +26,13 @@ export default function App() {
             />
             <section>
                 <h2>Output</h2>
-                <ErrorBoundary fallback={<div>Something went wrong</div>}>
+                <ErrorBoundary
+                    fallback={
+                        <div data-testid="svg-display-error-boundary">
+                            Something went wrong
+                        </div>
+                    }
+                >
                     <SvgDisplay jsonResult={jsonResult} />
                 </ErrorBoundary>
             </section>
diff --git a/demo/src/MemoryModels.tsx b/demo/src/MemoryModels.tsx
index 404369c2..70b647ac 100644
--- a/demo/src/MemoryModels.tsx
+++ b/demo/src/MemoryModels.tsx
@@ -1,7 +1,15 @@
 import React from "react";
 import { Button, Card, CardContent, TextField, Grid } from "@mui/material";
 
-export default function MemoryModelsUserInput(props) {
+type MemoryModelsUserInputPropTypes = {
+    onSubmit: (event: React.MouseEvent<HTMLFormElement>) => void;
+    setFormData: React.Dispatch<React.SetStateAction<string>>;
+    formData: string;
+};
+
+export default function MemoryModelsUserInput(
+    props: MemoryModelsUserInputPropTypes
+) {
     const handleTextFieldChange = (event) => {
         props.setFormData(event.target.value);
     };
diff --git a/demo/src/SvgDisplay.tsx b/demo/src/SvgDisplay.tsx
index dd4d10d0..c993e54d 100644
--- a/demo/src/SvgDisplay.tsx
+++ b/demo/src/SvgDisplay.tsx
@@ -1,7 +1,11 @@
 import React, { useRef, useEffect } from "react";
 import mem from "../../src/index"; // TODO: replace with import of the package after it's been published
 
-export default function SvgDisplay(props) {
+type SvgDisplayPropTypes = {
+    jsonResult: object;
+};
+
+export default function SvgDisplay(props: SvgDisplayPropTypes) {
     const canvasRef = useRef(null);
 
     useEffect(() => {
diff --git a/demo/src/__tests__/App.spec.tsx b/demo/src/__tests__/App.spec.tsx
new file mode 100644
index 00000000..769beb4f
--- /dev/null
+++ b/demo/src/__tests__/App.spec.tsx
@@ -0,0 +1,44 @@
+import React from "react";
+import { fireEvent, render, screen } from "@testing-library/react";
+import App from "../App";
+
+describe("App", () => {
+    beforeEach(() => {
+        render(<App />);
+    });
+
+    it("renders Output heading", () => {
+        expect(screen.getByText("Output").nodeName).toEqual("H2");
+    });
+
+    it("renders ErrorBoundary fallback element when draw function throws error", () => {
+        jest.mock("../../../src/index", () => ({
+            draw: jest.fn(() => {
+                throw new Error();
+            }),
+        }));
+        const input = screen.getByLabelText("Enter memory model JSON here");
+        // In order to get to draw function, input has to be valid json otherwise JSON.parse fails
+        fireEvent.change(input, { target: { value: "[{}]" } });
+        const button = screen.getByTestId("input-submit-button");
+        fireEvent.click(button);
+
+        const errorBoundary = screen.getByTestId("svg-display-error-boundary");
+        expect(errorBoundary.textContent).toEqual("Something went wrong");
+    });
+
+    it("calls console error when the input is not valid JSON", () => {
+        const consoleErrorSpy = jest
+            .spyOn(console, "error")
+            .mockImplementation();
+
+        const input = screen.getByLabelText("Enter memory model JSON here");
+        fireEvent.change(input, { target: { value: "*&#*#(@(!(" } });
+        const button = screen.getByTestId("input-submit-button");
+        fireEvent.click(button);
+
+        expect(consoleErrorSpy).toHaveBeenCalledWith(
+            expect.stringMatching(/^Error parsing inputted JSON: /)
+        );
+    });
+});
diff --git a/demo/src/__tests__/MemoryModelsUserInput.spec.tsx b/demo/src/__tests__/MemoryModelsUserInput.spec.tsx
index e4f59d1b..d4f799e9 100644
--- a/demo/src/__tests__/MemoryModelsUserInput.spec.tsx
+++ b/demo/src/__tests__/MemoryModelsUserInput.spec.tsx
@@ -30,6 +30,7 @@ describe("MemoryModelsUserInput", () => {
 
         render(
             <MemoryModelsUserInput
+                onSubmit={onSubmitMock}
                 setFormData={setFormDataMock}
                 formData={formDataMock}
             />
diff --git a/demo/src/__tests__/SvgDisplay.spec.tsx b/demo/src/__tests__/SvgDisplay.spec.tsx
index cfd649b9..7fb48f7d 100644
--- a/demo/src/__tests__/SvgDisplay.spec.tsx
+++ b/demo/src/__tests__/SvgDisplay.spec.tsx
@@ -1,5 +1,5 @@
 import React from "react";
-import { cleanup, render, screen } from "@testing-library/react";
+import { render, screen } from "@testing-library/react";
 import SvgDisplay from "../SvgDisplay";
 import mem from "../../../src/index";
 const { draw } = mem;