From 37e9d81ca9db300bc865679355548631f10b8c07 Mon Sep 17 00:00:00 2001
From: SeboMyr <80338167+Seborider@users.noreply.github.com>
Date: Sun, 29 Oct 2023 14:26:42 +0100
Subject: [PATCH] react missions
---
.prettierignore | 1 +
.prettierrc | 1 +
package-lock.json | 18 +++++++
package.json | 3 ++
public/index.html | 2 +-
src/App.test.tsx | 40 +++++++++++---
src/App.tsx | 32 +++++------
src/components/items-list/items-list.css | 23 ++++++++
src/components/items-list/items-list.test.tsx | 54 +++++++++++++++++++
src/components/items-list/items-list.tsx | 46 ++++++++++++++++
src/index.css | 6 +--
src/index.tsx | 16 +++---
src/services/items-api/items-api-service.ts | 14 +++++
src/setupTests.ts | 5 --
tsconfig.json | 10 +---
15 files changed, 221 insertions(+), 50 deletions(-)
create mode 100644 .prettierignore
create mode 100644 .prettierrc
create mode 100644 src/components/items-list/items-list.css
create mode 100644 src/components/items-list/items-list.test.tsx
create mode 100644 src/components/items-list/items-list.tsx
create mode 100644 src/services/items-api/items-api-service.ts
delete mode 100644 src/setupTests.ts
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..b512c09
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1 @@
+{}
diff --git a/package-lock.json b/package-lock.json
index 3032566..2f9ebae 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -20,6 +20,9 @@
"react-scripts": "5.0.1",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
+ },
+ "devDependencies": {
+ "prettier": "3.0.3"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -13810,6 +13813,21 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prettier": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
+ "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
"node_modules/pretty-bytes": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
diff --git a/package.json b/package.json
index 8f9a736..dcf3e06 100644
--- a/package.json
+++ b/package.json
@@ -39,5 +39,8 @@
"last 1 firefox version",
"last 1 safari version"
]
+ },
+ "devDependencies": {
+ "prettier": "3.0.3"
}
}
diff --git a/public/index.html b/public/index.html
index aa069f2..e65acb3 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1,4 +1,4 @@
-
+
diff --git a/src/App.test.tsx b/src/App.test.tsx
index 6b51971..c84d720 100644
--- a/src/App.test.tsx
+++ b/src/App.test.tsx
@@ -1,10 +1,34 @@
-import React from "react"
-import { render, screen } from "@testing-library/react"
-import App from "./App"
+import React from "react";
+import { render, screen, fireEvent, waitFor } from "@testing-library/react";
+import "@testing-library/jest-dom";
+import App from "./App";
-test("renders learn react link", () => {
- render()
- const linkElement = screen.getByText(/Click here/i)
- expect(linkElement).toBeInTheDocument()
-})
+describe("App component", () => {
+ test("renders App with ItemsList component", async () => {
+ render();
+ const button = screen.getByText(/click here/i);
+ expect(button).toBeInTheDocument();
+ await waitFor(() => screen.getByText(/Times clicked/));
+ });
+
+ test("clicking button in ItemsList increases count", async () => {
+ render();
+
+ const button = screen.getByText(/click here/i);
+
+ expect(screen.getByText("0 Times clicked")).toBeInTheDocument();
+
+ await waitFor(() => {
+ fireEvent.click(button);
+ });
+
+ expect(screen.getByText("1 Times clicked")).toBeInTheDocument();
+
+ await waitFor(() => {
+ fireEvent.click(button);
+ });
+
+ expect(screen.getByText("2 Times clicked")).toBeInTheDocument();
+ });
+});
diff --git a/src/App.tsx b/src/App.tsx
index 5936e14..07f2c13 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,23 +1,19 @@
-import React, { useEffect, useState } from "react"
-import "./App.css"
+import React, { useState } from "react";
+import "./App.css";
+import ItemsList from "./components/items-list/items-list";
+
+const App: React.FC = () => {
+ const [count, setCount] = useState(0);
+
+ const handleIncrement = () => {
+ setCount((prevCount) => prevCount + 1);
+ };
-function App() {
- const [message, setMessage] = useState("")
- const [count, setCount] = useState(0)
- useEffect(() => {
- setMessage(`${count} Times clicked`)
- })
- const onClick = () => {
- setCount(count + 1)
- }
return (
- )
-}
+ );
+};
-export default App
+export default App;
diff --git a/src/components/items-list/items-list.css b/src/components/items-list/items-list.css
new file mode 100644
index 0000000..3b73f7f
--- /dev/null
+++ b/src/components/items-list/items-list.css
@@ -0,0 +1,23 @@
+.page-container {
+ display: flex;
+ flex-direction: column;
+ padding: 20px;
+}
+
+.items-container {
+ margin: 20px;
+ padding: 20px;
+ border: 1px solid #cccccc;
+ border-radius: 4px;
+}
+
+.items-container ul {
+ list-style-type: none;
+ padding: 0;
+}
+
+.button-message-container {
+ display: flex;
+ gap: 1rem;
+ padding: 20px;
+}
diff --git a/src/components/items-list/items-list.test.tsx b/src/components/items-list/items-list.test.tsx
new file mode 100644
index 0000000..831c460
--- /dev/null
+++ b/src/components/items-list/items-list.test.tsx
@@ -0,0 +1,54 @@
+jest.mock("../../services/items-api/items-api-service");
+
+import React from "react";
+import { render, screen, fireEvent } from "@testing-library/react";
+import "@testing-library/jest-dom";
+import ItemsList from "./items-list";
+import { fetchItems } from "../../services/items-api/items-api-service";
+import { act } from "react-dom/test-utils";
+describe("ItemsList component", () => {
+ let promise: Promise<{ id: string; label: string }[]>;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ promise = Promise.resolve([{ id: "1", label: "Item 1" }]);
+
+ (fetchItems as jest.Mock).mockReturnValue(promise);
+ });
+
+ test("fetches and renders items", async () => {
+ act(() => {
+ render( {}} />);
+ });
+
+ await act(() => promise);
+
+ expect(screen.getByText(/Item 1 with ID: 1/)).toBeInTheDocument();
+ });
+
+ test("displays the correct click count message", async () => {
+ act(() => {
+ render( {}} />);
+ });
+
+ await act(() => promise);
+
+ const message = screen.getByText("3 Times clicked");
+ expect(message).toBeInTheDocument();
+ });
+
+ test("button click calls onIncrement", async () => {
+ const handleIncrement = jest.fn();
+
+ act(() => {
+ render();
+ });
+
+ await act(() => promise);
+
+ fireEvent.click(screen.getByText("Click here"));
+
+ expect(handleIncrement).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/src/components/items-list/items-list.tsx b/src/components/items-list/items-list.tsx
new file mode 100644
index 0000000..91519b8
--- /dev/null
+++ b/src/components/items-list/items-list.tsx
@@ -0,0 +1,46 @@
+import React, { useEffect, useState } from "react";
+import {
+ fetchItems,
+ IListItem,
+} from "../../services/items-api/items-api-service";
+import "./items-list.css";
+
+interface ItemsListProps {
+ count: number;
+ onIncrement: () => void;
+}
+
+const ItemsList: React.FC = ({ count, onIncrement }) => {
+ const [items, setItems] = useState([]);
+ const [message, setMessage] = useState("");
+
+ useEffect(() => {
+ setMessage(`${count} Times clicked`);
+ }, [count]);
+
+ useEffect(() => {
+ fetchItems().then((data) => setItems(data));
+ }, []);
+
+ return (
+
+
+
+ {items.map((item) => (
+ -
+ {item.label} with ID: {item.id}
+
+ ))}
+
+
+
+
+
{message}
+
+
+ );
+};
+
+export default ItemsList;
diff --git a/src/index.css b/src/index.css
index ec2585e..4a1df4d 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,13 +1,13 @@
body {
margin: 0;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
- 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
+ "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
- font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
diff --git a/src/index.tsx b/src/index.tsx
index f50b6dd..e36f828 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,11 +1,13 @@
-import React from "react"
-import ReactDOM from "react-dom/client"
-import "./index.css"
-import App from "./App"
+import React from "react";
+import ReactDOM from "react-dom/client";
+import "./index.css";
+import App from "./App";
-const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
+const root = ReactDOM.createRoot(
+ document.getElementById("root") as HTMLElement,
+);
root.render(
-
-)
+ ,
+);
diff --git a/src/services/items-api/items-api-service.ts b/src/services/items-api/items-api-service.ts
new file mode 100644
index 0000000..f56abff
--- /dev/null
+++ b/src/services/items-api/items-api-service.ts
@@ -0,0 +1,14 @@
+export interface IListItem {
+ id: number;
+ label: string;
+}
+
+export const fetchItems = (): Promise => {
+ return Promise.resolve([
+ { id: 1, label: "Some label 1" },
+ { id: 2, label: "Some label 2" },
+ { id: 3, label: "Some label 3" },
+ { id: 4, label: "Some label 4" },
+ { id: 5, label: "Some label 5" },
+ ]);
+};
diff --git a/src/setupTests.ts b/src/setupTests.ts
deleted file mode 100644
index 8f2609b..0000000
--- a/src/setupTests.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-// jest-dom adds custom jest matchers for asserting on DOM nodes.
-// allows you to do things like:
-// expect(element).toHaveTextContent(/react/i)
-// learn more: https://github.com/testing-library/jest-dom
-import '@testing-library/jest-dom';
diff --git a/tsconfig.json b/tsconfig.json
index a273b0c..9d379a3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,11 +1,7 @@
{
"compilerOptions": {
"target": "es5",
- "lib": [
- "dom",
- "dom.iterable",
- "esnext"
- ],
+ "lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
@@ -20,7 +16,5 @@
"noEmit": true,
"jsx": "react-jsx"
},
- "include": [
- "src"
- ]
+ "include": ["src"]
}