Compare commits
3 Commits
v1.0.0
...
9ad33b98e7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ad33b98e7 | ||
|
|
4502c7aef0 | ||
|
|
b7ce3dbc21 |
1638
react-advanced-tag1/package-lock.json
generated
1638
react-advanced-tag1/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,12 @@
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"test": "vitest",
|
||||
"test:watch": "vitest --watch",
|
||||
"test:coverage": "vitest --coverage",
|
||||
"test:coverage:report": "vitest --coverage --reporter=html",
|
||||
"test:coverage:report:open": "vitest --coverage --reporter=html && open coverage/index.html"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^19.0.0",
|
||||
@@ -16,13 +21,17 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.21.0",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@types/react": "^19.0.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"@vitest/coverage-v8": "^3.1.1",
|
||||
"@vitest/ui": "^3.1.1",
|
||||
"eslint": "^9.21.0",
|
||||
"eslint-plugin-react-hooks": "^5.1.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"globals": "^15.15.0",
|
||||
"jsdom": "^26.0.0",
|
||||
"typescript": "~5.7.2",
|
||||
"typescript-eslint": "^8.24.1",
|
||||
"vite": "^6.2.0",
|
||||
|
||||
@@ -7,18 +7,21 @@ import UsersPage from './routes/UsersPage'
|
||||
import EffectExercisesPage from './routes/EffectExercisesPage'
|
||||
import FormsPage from './routes/FormsPage'
|
||||
import MemoCallbackPage from './routes/MemoCallbackPage'
|
||||
import ComponentWrapperPage from './routes/ComponentWrapperPage'
|
||||
|
||||
function App() {
|
||||
|
||||
return <MainLayout>
|
||||
<Routes>
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/user" element={<UsersPage />} />
|
||||
<Route path="/effect" element={<EffectExercisesPage />} />
|
||||
<Route path="/forms" element={<FormsPage />} />
|
||||
<Route path="/memocallback" element={<MemoCallbackPage />} />
|
||||
</Routes>
|
||||
</MainLayout>
|
||||
<Routes>
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/user" element={<UsersPage />} />
|
||||
<Route path="/effect" element={<EffectExercisesPage />} />
|
||||
<Route path="/forms" element={<FormsPage />} />
|
||||
<Route path="/memocallback" element={<MemoCallbackPage />} />
|
||||
<Route path="/componentwrapper" element={<ComponentWrapperPage />} />
|
||||
|
||||
</Routes>
|
||||
</MainLayout>
|
||||
}
|
||||
|
||||
export default App
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
.component-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
background-color: #1a1a1a;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.component-content {
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
background-color: #888;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import './ComponentWrapper.css'
|
||||
|
||||
interface ComponentWrapperProps {
|
||||
title?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
export default function ComponentWrapper({ children, title }: ComponentWrapperProps): React.ReactElement {
|
||||
console.log("ComponentWrapper rendered");
|
||||
return (
|
||||
<div className='component-wrapper'>
|
||||
{title && <h2>{title}</h2>}
|
||||
<div className='component-content'>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
10
react-advanced-tag1/src/common/components/Footer.test.tsx
Normal file
10
react-advanced-tag1/src/common/components/Footer.test.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import Footer from "./Footer";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
describe("Footer Component", () => {
|
||||
it("should render the footer with correct content", () => {
|
||||
render(<Footer />);
|
||||
expect(screen.getByText(/© 2025 Your Company/i)).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,7 @@ export default function Navigation () {
|
||||
<li><a href="/effect">Effects</a></li>
|
||||
<li><a href="/forms">Forms</a></li>
|
||||
<li><a href="/memocallback">Memo und Callback</a></li>
|
||||
<li><a href="/componentwrapper">Component Wrapper</a></li>
|
||||
</ul>
|
||||
</nav>);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import MemoCallback from "./index";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { users } from "../../../utils/shuffle";
|
||||
|
||||
|
||||
|
||||
describe("MemoCallback Component", () => {
|
||||
it("should render the component with initial users", () => {
|
||||
render(<MemoCallback />);
|
||||
users.forEach((user) => {
|
||||
expect(screen.getByText(user)).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should filter users based on search input", () => {
|
||||
render(<MemoCallback />);
|
||||
const searchInput = screen.getByPlaceholderText(/search/i);
|
||||
|
||||
fireEvent.change(searchInput, { target: { value: "a" } });
|
||||
const filteredUsers = users.filter((user) => user.toLowerCase().includes("a"));
|
||||
filteredUsers.forEach((user) => {
|
||||
expect(screen.getByText(user)).toBeDefined();
|
||||
});
|
||||
|
||||
const nonMatchingUsers = users.filter((user) => !user.toLowerCase().includes("a"));
|
||||
nonMatchingUsers.forEach((user) => {
|
||||
expect(screen.queryByText(user)).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should shuffle users when the shuffle button is clicked", () => {
|
||||
render(<MemoCallback />);
|
||||
const shuffleButton = screen.getByText(/shuffle/i);
|
||||
|
||||
const initialOrder = screen.getAllByText(/./).map((el) => el.textContent);
|
||||
fireEvent.click(shuffleButton);
|
||||
const shuffledOrder = screen.getAllByText(/./).map((el) => el.textContent);
|
||||
|
||||
expect(initialOrder).not.toEqual(shuffledOrder);
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { shuffleArray, users } from "../../../utils/shuffle";
|
||||
import Search from "./Search";
|
||||
import { users, shuffleArray } from "../../../utils/shuffle";
|
||||
|
||||
export default function MemoCallback() {
|
||||
console.log("MemoCallback rendered");
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import Footer from "../components/Footer";
|
||||
import Header from "../components/Header";
|
||||
import './MainLayout.css'
|
||||
import Footer from "../common/components/Footer";
|
||||
import Header from "../common/components/Header";
|
||||
|
||||
export default function MainLayout({children}: {children: React.ReactNode | React.ReactElement | React.ReactElement[]}): React.ReactElement {
|
||||
|
||||
|
||||
15
react-advanced-tag1/src/routes/ComponentWrapperPage.tsx
Normal file
15
react-advanced-tag1/src/routes/ComponentWrapperPage.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import ComponentWrapper from "../common/components/ComponentWrapper/ComponentWrapper";
|
||||
import EffectExercises from "../common/components/exercises/EffectExercises";
|
||||
|
||||
export default function ComponentWrapperPage() {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '3rem' }}>
|
||||
<ComponentWrapper title='Komponenten Wrapper Test'>
|
||||
<h1>Hallo</h1>
|
||||
</ComponentWrapper>
|
||||
<ComponentWrapper title='Komponenten Wrapper Test2'>
|
||||
<EffectExercises />
|
||||
</ComponentWrapper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import EffectExercises from "../components/exercises/EffectExercises";
|
||||
import Heading from "../components/globals/Heading"
|
||||
import EffectExercises from "../common/components/exercises/EffectExercises";
|
||||
import Heading from "../common/components/globals/Heading";
|
||||
|
||||
|
||||
export default function EffectExercisesPage() {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import RefExercise from "../components/exercises/RefExercise";
|
||||
import Heading from "../components/globals/Heading";
|
||||
import RefExercise from "../common/components/exercises/RefExercise";
|
||||
import Heading from "../common/components/globals/Heading";
|
||||
|
||||
export default function FormsPage() {
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Heading from "../components/globals/Heading"
|
||||
import Heading from "../common/components/globals/Heading";
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import MemoCallback from "../components/exercises/MemoCallback";
|
||||
import Heading from "../components/globals/Heading";
|
||||
import MemoCallback from "../common/components/exercises/MemoCallback";
|
||||
import Heading from "../common/components/globals/Heading";
|
||||
|
||||
export default function MemoCallbackPage() {
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import UserEffect from "../components/exercises/UserEffect";
|
||||
import { UserOverview } from "../components/exercises/UserOverview";
|
||||
import Heading from "../components/globals/Heading";
|
||||
import UserEffect from "../common/components/exercises/UserEffect";
|
||||
import { UserOverview } from "../common/components/exercises/UserOverview";
|
||||
import Heading from "../common/components/globals/Heading";
|
||||
|
||||
export default function UsersPage() {
|
||||
return (
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import { defineConfig, UserConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
})
|
||||
test: {
|
||||
// 👋 add the line below to add jsdom to vite
|
||||
environment: 'jsdom',
|
||||
}
|
||||
} as UserConfig)
|
||||
|
||||
Reference in New Issue
Block a user