From faae99aed621447319f2603cce154546dfe6eed7 Mon Sep 17 00:00:00 2001 From: FORGE Date: Fri, 10 Apr 2026 05:08:32 +0000 Subject: [PATCH 1/4] feat: Set Up Vite React Project Run: 0e6f20d3-cd3c-4214-ae92-540af6ac4d2f Task: 5f9ba066-0226-4611-af62-8414195d41aa Agent: builder --- RUNNING.md | 88 ++++++++++++++++++++++++++----- index.html | 12 +++++ package.json | 26 +++++++++ src/App.css | 25 +++++++++ src/App.jsx | 23 ++++++++ src/components/Counter.jsx | 93 +++++++++++++++++++++++++++++++++ src/components/Counter.test.jsx | 84 +++++++++++++++++++++++++++++ src/main.jsx | 14 +++++ src/setupTests.js | 6 +++ vite.config.js | 17 ++++++ 10 files changed, 376 insertions(+), 12 deletions(-) create mode 100644 index.html create mode 100644 package.json create mode 100644 src/App.css create mode 100644 src/App.jsx create mode 100644 src/components/Counter.jsx create mode 100644 src/components/Counter.test.jsx create mode 100644 src/main.jsx create mode 100644 src/setupTests.js create mode 100644 vite.config.js diff --git a/RUNNING.md b/RUNNING.md index 77896cf..6c08dcd 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -1,33 +1,97 @@ -# Running the Todo API +# React Counter App + +A minimal Vite + React application featuring a Counter component with increment and decrement functionality. + +## TEAM_BRIEF + +stack: TypeScript/React+Vite +test_runner: npx vitest run +lint_tool: none +coverage_tool: none +coverage_threshold: 0 +coverage_applies: false ## Prerequisites -- Python 3.10 or later +- Node.js 18+ and npm +- Docker (optional, for containerised setup) -## Install dependencies +## Local Setup ```bash -pip install fastapi uvicorn pydantic +# Install dependencies +npm install + +# Start development server +npm run dev + +# Run tests +npm test + +# Build for production +npm run build + +# Preview production build +npm run preview ``` -For running the test suite you will also need: +## Docker Setup + +### Development ```bash -pip install httpx pytest +# Build the Docker image +docker build -t react-counter-app . + +# Run the container (development mode) +docker run -it --rm -p 5173:5173 react-counter-app npm run dev -- --host 0.0.0.0 + +# Run tests inside container +docker run -it --rm react-counter-app npm test ``` -## Start the server +### Using Docker Compose (if available) ```bash -uvicorn main:app --reload --host 0.0.0.0 --port 8000 +docker compose up ``` -The API will be available at . +## Project Structure + +``` +. +├── index.html # HTML entry point +├── package.json # Dependencies and scripts +├── vite.config.js # Vite configuration with React plugin +├── src/ +│ ├── main.jsx # React entry point +│ ├── App.jsx # Root component +│ ├── App.css # Centering styles +│ ├── setupTests.js # Test setup (jest-dom matchers) +│ └── components/ +│ ├── Counter.jsx # Counter component with state +│ └── Counter.test.jsx # Counter component tests +└── RUNNING.md # This file +``` -Interactive docs are served at . +## Testing -## Run the tests +Tests use **Vitest** with **@testing-library/react** and **@testing-library/jest-dom**. ```bash -pytest tests/ +# Run tests once +npm test + +# Run tests in watch mode +npm run test:watch ``` + +## Scripts + +| Script | Description | +| -------------- | ------------------------------------ | +| `npm run dev` | Start Vite dev server with HMR | +| `npm run build`| Build for production | +| `npm run preview` | Preview production build locally | +| `npm test` | Run tests with Vitest | +| `npm run test:watch` | Run tests in watch mode | diff --git a/index.html b/index.html new file mode 100644 index 0000000..0a39fde --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + + React Counter App + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..f904a92 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "react-counter-app", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "test": "vitest run", + "test:watch": "vitest" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.2.1", + "vite": "^5.1.0", + "vitest": "^1.3.0", + "@testing-library/react": "^14.2.1", + "@testing-library/jest-dom": "^6.4.2", + "@testing-library/user-event": "^14.5.2", + "jsdom": "^24.0.0" + } +} diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..a07df9c --- /dev/null +++ b/src/App.css @@ -0,0 +1,25 @@ +/** + * Base styling to center the Counter component + * both vertically and horizontally on the page. + */ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html, body, #root { + height: 100%; + width: 100%; +} + +.app-container { + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, + Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + background-color: #f5f5f5; +} diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 0000000..948d769 --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,23 @@ +/** + * Root application component. + * + * Layouts and centers the Counter component on the page. + */ +import React from 'react'; +import Counter from './components/Counter.jsx'; +import './App.css'; + +/** + * App component that serves as the root layout. + * + * @returns {JSX.Element} The rendered application. + */ +function App() { + return ( +
+ +
+ ); +} + +export default App; diff --git a/src/components/Counter.jsx b/src/components/Counter.jsx new file mode 100644 index 0000000..f185106 --- /dev/null +++ b/src/components/Counter.jsx @@ -0,0 +1,93 @@ +/** + * Counter component. + * + * Displays a count value with increment and decrement buttons. + * Uses React useState hook to manage count state. + */ +import React, { useState } from 'react'; + +/** + * Counter functional component. + * + * Renders the current count centered within its container, + * along with increment and decrement buttons. + * + * @returns {JSX.Element} The rendered counter UI. + */ +function Counter() { + const [count, setCount] = useState(0); + + /** + * Increment the count by 1. + */ + const handleIncrement = () => { + setCount((prev) => prev + 1); + }; + + /** + * Decrement the count by 1. + */ + const handleDecrement = () => { + setCount((prev) => prev - 1); + }; + + return ( +
+

Counter

+

+ {count} +

+
+ + +
+
+ ); +} + +export default Counter; diff --git a/src/components/Counter.test.jsx b/src/components/Counter.test.jsx new file mode 100644 index 0000000..c0c2cb3 --- /dev/null +++ b/src/components/Counter.test.jsx @@ -0,0 +1,84 @@ +/** + * Unit and UI tests for the Counter component. + * + * Tests cover: + * - Initial count display renders 0 + * - Increment button increases count by 1 + * - Decrement button decreases count by 1 + * - Count display is centered via text-align style + */ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { describe, it, expect } from 'vitest'; +import Counter from './Counter.jsx'; + +describe('Counter component', () => { + it('renders initial count of 0', () => { + render(); + const countDisplay = screen.getByTestId('count-display'); + expect(countDisplay).toHaveTextContent('0'); + }); + + it('increments count when increment button is clicked', () => { + render(); + const incrementButton = screen.getByRole('button', { name: /increment/i }); + const countDisplay = screen.getByTestId('count-display'); + + fireEvent.click(incrementButton); + expect(countDisplay).toHaveTextContent('1'); + + fireEvent.click(incrementButton); + expect(countDisplay).toHaveTextContent('2'); + }); + + it('decrements count when decrement button is clicked', () => { + render(); + const decrementButton = screen.getByRole('button', { name: /decrement/i }); + const countDisplay = screen.getByTestId('count-display'); + + fireEvent.click(decrementButton); + expect(countDisplay).toHaveTextContent('-1'); + + fireEvent.click(decrementButton); + expect(countDisplay).toHaveTextContent('-2'); + }); + + it('count display is centered via text-align style', () => { + render(); + const countDisplay = screen.getByTestId('count-display'); + expect(countDisplay).toHaveStyle({ textAlign: 'center' }); + }); + + it('handles rapid increment and decrement clicks correctly', () => { + render(); + const incrementButton = screen.getByRole('button', { name: /increment/i }); + const decrementButton = screen.getByRole('button', { name: /decrement/i }); + const countDisplay = screen.getByTestId('count-display'); + + // Rapid increments + for (let i = 0; i < 10; i++) { + fireEvent.click(incrementButton); + } + expect(countDisplay).toHaveTextContent('10'); + + // Rapid decrements + for (let i = 0; i < 5; i++) { + fireEvent.click(decrementButton); + } + expect(countDisplay).toHaveTextContent('5'); + }); + + it('renders both increment and decrement buttons', () => { + render(); + const incrementButton = screen.getByRole('button', { name: /increment/i }); + const decrementButton = screen.getByRole('button', { name: /decrement/i }); + expect(incrementButton).toBeInTheDocument(); + expect(decrementButton).toBeInTheDocument(); + }); + + it('renders the Counter heading', () => { + render(); + const heading = screen.getByRole('heading', { name: /counter/i }); + expect(heading).toBeInTheDocument(); + }); +}); diff --git a/src/main.jsx b/src/main.jsx new file mode 100644 index 0000000..8f70054 --- /dev/null +++ b/src/main.jsx @@ -0,0 +1,14 @@ +/** + * React entry point. + * + * Renders the root App component into the #root div. + */ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App.jsx'; + +ReactDOM.createRoot(document.getElementById('root')).render( + + + +); diff --git a/src/setupTests.js b/src/setupTests.js new file mode 100644 index 0000000..4c6922a --- /dev/null +++ b/src/setupTests.js @@ -0,0 +1,6 @@ +/** + * Test setup file for Vitest. + * + * Imports jest-dom matchers so they are available in all test files. + */ +import '@testing-library/jest-dom'; diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..32d311b --- /dev/null +++ b/vite.config.js @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +/** + * Vite configuration for React application. + * + * Uses the official React plugin for Fast Refresh and JSX support. + * Test configuration uses jsdom for DOM environment simulation. + */ +export default defineConfig({ + plugins: [react()], + test: { + environment: 'jsdom', + globals: true, + setupFiles: './src/setupTests.js', + }, +}); From 747b46e7fbfd3c6487794ce96688fbacaf94dbf8 Mon Sep 17 00:00:00 2001 From: FORGE Date: Fri, 10 Apr 2026 05:09:26 +0000 Subject: [PATCH 2/4] feat: Implement Counter Component Run: 0e6f20d3-cd3c-4214-ae92-540af6ac4d2f Task: 96fa15b5-1adc-49fe-b536-e4544df7ab17 Agent: builder --- RUNNING.md | 71 +++++++++++----------------- index.html | 2 +- package.json | 15 +++--- src/App.css | 9 +--- src/App.jsx | 10 +--- src/components/Counter.jsx | 60 ++++-------------------- src/components/Counter.module.css | 51 ++++++++++++++++++++ src/components/Counter.test.jsx | 78 ++++++++++++++++--------------- src/main.jsx | 5 -- src/setupTests.js | 5 -- vite.config.js | 6 --- 11 files changed, 139 insertions(+), 173 deletions(-) create mode 100644 src/components/Counter.module.css diff --git a/RUNNING.md b/RUNNING.md index 6c08dcd..3171804 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -1,9 +1,6 @@ -# React Counter App - -A minimal Vite + React application featuring a Counter component with increment and decrement functionality. +# Mini React Counter App ## TEAM_BRIEF - stack: TypeScript/React+Vite test_runner: npx vitest run lint_tool: none @@ -16,7 +13,7 @@ coverage_applies: false - Node.js 18+ and npm - Docker (optional, for containerised setup) -## Local Setup +## Local Development ```bash # Install dependencies @@ -25,73 +22,57 @@ npm install # Start development server npm run dev -# Run tests -npm test - # Build for production npm run build -# Preview production build -npm run preview +# Run tests +npm test + +# Run tests in watch mode +npm run test:watch ``` ## Docker Setup -### Development +### Build and run ```bash # Build the Docker image -docker build -t react-counter-app . +docker build -t counter-app . -# Run the container (development mode) -docker run -it --rm -p 5173:5173 react-counter-app npm run dev -- --host 0.0.0.0 +# Run the container (development server on port 5173) +docker run -p 5173:5173 counter-app -# Run tests inside container -docker run -it --rm react-counter-app npm test +# Run tests inside Docker +docker run --rm counter-app npm test ``` -### Using Docker Compose (if available) +### Using docker-compose (if available) ```bash -docker compose up +docker-compose up ``` ## Project Structure ``` -. -├── index.html # HTML entry point -├── package.json # Dependencies and scripts -├── vite.config.js # Vite configuration with React plugin -├── src/ -│ ├── main.jsx # React entry point -│ ├── App.jsx # Root component -│ ├── App.css # Centering styles -│ ├── setupTests.js # Test setup (jest-dom matchers) -│ └── components/ -│ ├── Counter.jsx # Counter component with state -│ └── Counter.test.jsx # Counter component tests -└── RUNNING.md # This file +src/ +├── main.jsx # React entry point +├── App.jsx # Root component +├── App.css # Global centering styles +├── setupTests.js # Test setup (jest-dom) +└── components/ + ├── Counter.jsx # Counter component + ├── Counter.module.css # Counter scoped styles + └── Counter.test.jsx # Counter unit tests ``` ## Testing -Tests use **Vitest** with **@testing-library/react** and **@testing-library/jest-dom**. +Tests are written using Vitest and @testing-library/react. ```bash -# Run tests once npm test - -# Run tests in watch mode -npm run test:watch ``` -## Scripts - -| Script | Description | -| -------------- | ------------------------------------ | -| `npm run dev` | Start Vite dev server with HMR | -| `npm run build`| Build for production | -| `npm run preview` | Preview production build locally | -| `npm test` | Run tests with Vitest | -| `npm run test:watch` | Run tests in watch mode | +This runs all `*.test.jsx` files via `vitest run`. diff --git a/index.html b/index.html index 0a39fde..4642756 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - React Counter App + Counter App
diff --git a/package.json b/package.json index f904a92..b01081d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "react-counter-app", - "private": true, + "name": "mini-react-counter", "version": "1.0.0", + "private": true, "type": "module", "scripts": { "dev": "vite", @@ -15,12 +15,11 @@ "react-dom": "^18.2.0" }, "devDependencies": { + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^14.3.1", "@vitejs/plugin-react": "^4.2.1", - "vite": "^5.1.0", - "vitest": "^1.3.0", - "@testing-library/react": "^14.2.1", - "@testing-library/jest-dom": "^6.4.2", - "@testing-library/user-event": "^14.5.2", - "jsdom": "^24.0.0" + "jsdom": "^24.0.0", + "vite": "^5.4.19", + "vitest": "^1.6.0" } } diff --git a/src/App.css b/src/App.css index a07df9c..8dbb83c 100644 --- a/src/App.css +++ b/src/App.css @@ -1,8 +1,3 @@ -/** - * Base styling to center the Counter component - * both vertically and horizontally on the page. - */ - * { margin: 0; padding: 0; @@ -19,7 +14,7 @@ html, body, #root { justify-content: center; align-items: center; min-height: 100vh; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, - Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + width: 100%; + font-family: Arial, Helvetica, sans-serif; background-color: #f5f5f5; } diff --git a/src/App.jsx b/src/App.jsx index 948d769..d99234f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,16 +1,10 @@ -/** - * Root application component. - * - * Layouts and centers the Counter component on the page. - */ import React from 'react'; import Counter from './components/Counter.jsx'; import './App.css'; /** - * App component that serves as the root layout. - * - * @returns {JSX.Element} The rendered application. + * Root application component. + * Renders the Counter component centered on the page. */ function App() { return ( diff --git a/src/components/Counter.jsx b/src/components/Counter.jsx index f185106..6adc8f8 100644 --- a/src/components/Counter.jsx +++ b/src/components/Counter.jsx @@ -1,18 +1,11 @@ -/** - * Counter component. - * - * Displays a count value with increment and decrement buttons. - * Uses React useState hook to manage count state. - */ import React, { useState } from 'react'; +import styles from './Counter.module.css'; /** - * Counter functional component. - * - * Renders the current count centered within its container, - * along with increment and decrement buttons. + * Counter component. * - * @returns {JSX.Element} The rendered counter UI. + * Displays the current count value with increment and decrement buttons. + * The count starts at 0 and can go negative. */ function Counter() { const [count, setCount] = useState(0); @@ -32,56 +25,23 @@ function Counter() { }; return ( -
-

Counter

-

+

+

Counter

+

{count}

-
+
diff --git a/src/components/Counter.module.css b/src/components/Counter.module.css new file mode 100644 index 0000000..d30c495 --- /dev/null +++ b/src/components/Counter.module.css @@ -0,0 +1,51 @@ +.counter { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 2rem 3rem; + background-color: #ffffff; + border-radius: 12px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + text-align: center; +} + +.title { + font-size: 1.5rem; + font-weight: 600; + margin-bottom: 1rem; + color: #333; +} + +.count { + font-size: 3rem; + font-weight: 700; + margin-bottom: 1.5rem; + color: #111; +} + +.buttons { + display: flex; + gap: 1rem; +} + +.button { + font-size: 1.25rem; + font-weight: 600; + padding: 0.5rem 1.5rem; + border: 2px solid #333; + border-radius: 8px; + background-color: #fff; + color: #333; + cursor: pointer; + transition: background-color 0.15s ease, color 0.15s ease; +} + +.button:hover { + background-color: #333; + color: #fff; +} + +.button:active { + transform: scale(0.96); +} diff --git a/src/components/Counter.test.jsx b/src/components/Counter.test.jsx index c0c2cb3..b6698b9 100644 --- a/src/components/Counter.test.jsx +++ b/src/components/Counter.test.jsx @@ -1,12 +1,3 @@ -/** - * Unit and UI tests for the Counter component. - * - * Tests cover: - * - Initial count display renders 0 - * - Increment button increases count by 1 - * - Decrement button decreases count by 1 - * - Count display is centered via text-align style - */ import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; @@ -21,64 +12,75 @@ describe('Counter component', () => { it('increments count when increment button is clicked', () => { render(); - const incrementButton = screen.getByRole('button', { name: /increment/i }); + const incrementBtn = screen.getByRole('button', { name: /increment/i }); const countDisplay = screen.getByTestId('count-display'); - fireEvent.click(incrementButton); + fireEvent.click(incrementBtn); expect(countDisplay).toHaveTextContent('1'); - fireEvent.click(incrementButton); + fireEvent.click(incrementBtn); expect(countDisplay).toHaveTextContent('2'); }); it('decrements count when decrement button is clicked', () => { render(); - const decrementButton = screen.getByRole('button', { name: /decrement/i }); + const decrementBtn = screen.getByRole('button', { name: /decrement/i }); const countDisplay = screen.getByTestId('count-display'); - fireEvent.click(decrementButton); + fireEvent.click(decrementBtn); expect(countDisplay).toHaveTextContent('-1'); - fireEvent.click(decrementButton); + fireEvent.click(decrementBtn); expect(countDisplay).toHaveTextContent('-2'); }); - it('count display is centered via text-align style', () => { - render(); - const countDisplay = screen.getByTestId('count-display'); - expect(countDisplay).toHaveStyle({ textAlign: 'center' }); - }); - it('handles rapid increment and decrement clicks correctly', () => { render(); - const incrementButton = screen.getByRole('button', { name: /increment/i }); - const decrementButton = screen.getByRole('button', { name: /decrement/i }); + const incrementBtn = screen.getByRole('button', { name: /increment/i }); + const decrementBtn = screen.getByRole('button', { name: /decrement/i }); const countDisplay = screen.getByTestId('count-display'); - // Rapid increments - for (let i = 0; i < 10; i++) { - fireEvent.click(incrementButton); - } - expect(countDisplay).toHaveTextContent('10'); - - // Rapid decrements + // Click increment 5 times for (let i = 0; i < 5; i++) { - fireEvent.click(decrementButton); + fireEvent.click(incrementBtn); } expect(countDisplay).toHaveTextContent('5'); + + // Click decrement 3 times + for (let i = 0; i < 3; i++) { + fireEvent.click(decrementBtn); + } + expect(countDisplay).toHaveTextContent('2'); + }); + + it('renders the counter container with centered alignment', () => { + render(); + const container = screen.getByTestId('counter-container'); + expect(container).toBeInTheDocument(); + }); + + it('renders the Counter title', () => { + render(); + const title = screen.getByText('Counter'); + expect(title).toBeInTheDocument(); }); it('renders both increment and decrement buttons', () => { render(); - const incrementButton = screen.getByRole('button', { name: /increment/i }); - const decrementButton = screen.getByRole('button', { name: /decrement/i }); - expect(incrementButton).toBeInTheDocument(); - expect(decrementButton).toBeInTheDocument(); + const incrementBtn = screen.getByRole('button', { name: /increment/i }); + const decrementBtn = screen.getByRole('button', { name: /decrement/i }); + expect(incrementBtn).toBeInTheDocument(); + expect(decrementBtn).toBeInTheDocument(); }); - it('renders the Counter heading', () => { + it('allows count to go negative', () => { render(); - const heading = screen.getByRole('heading', { name: /counter/i }); - expect(heading).toBeInTheDocument(); + const decrementBtn = screen.getByRole('button', { name: /decrement/i }); + const countDisplay = screen.getByTestId('count-display'); + + fireEvent.click(decrementBtn); + fireEvent.click(decrementBtn); + fireEvent.click(decrementBtn); + expect(countDisplay).toHaveTextContent('-3'); }); }); diff --git a/src/main.jsx b/src/main.jsx index 8f70054..6f4d655 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -1,8 +1,3 @@ -/** - * React entry point. - * - * Renders the root App component into the #root div. - */ import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App.jsx'; diff --git a/src/setupTests.js b/src/setupTests.js index 4c6922a..7b0828b 100644 --- a/src/setupTests.js +++ b/src/setupTests.js @@ -1,6 +1 @@ -/** - * Test setup file for Vitest. - * - * Imports jest-dom matchers so they are available in all test files. - */ import '@testing-library/jest-dom'; diff --git a/vite.config.js b/vite.config.js index 32d311b..53d9d0c 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,12 +1,6 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; -/** - * Vite configuration for React application. - * - * Uses the official React plugin for Fast Refresh and JSX support. - * Test configuration uses jsdom for DOM environment simulation. - */ export default defineConfig({ plugins: [react()], test: { From 417c8be64e04cbd0cbdf86ce139f5a112a1983bf Mon Sep 17 00:00:00 2001 From: FORGE Date: Fri, 10 Apr 2026 05:10:11 +0000 Subject: [PATCH 3/4] feat: Implement Main App Page Run: 0e6f20d3-cd3c-4214-ae92-540af6ac4d2f Task: 8184d6b6-4f60-4d58-88f5-d9314ced4a23 Agent: builder --- RUNNING.md | 94 +++++++++++++++++++-------------- index.html | 2 +- package.json | 14 ++--- src/App.css | 10 ++-- src/App.jsx | 4 +- src/components/Counter.jsx | 55 +++++++++++++++---- src/components/Counter.test.jsx | 76 ++++++++++---------------- 7 files changed, 144 insertions(+), 111 deletions(-) diff --git a/RUNNING.md b/RUNNING.md index 3171804..0fd33c5 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -1,4 +1,6 @@ -# Mini React Counter App +# React Counter App + +A minimal React application featuring a Counter component centered on the page. ## TEAM_BRIEF stack: TypeScript/React+Vite @@ -10,69 +12,81 @@ coverage_applies: false ## Prerequisites -- Node.js 18+ and npm -- Docker (optional, for containerised setup) +- Node.js >= 18 +- npm >= 9 -## Local Development +## Setup ```bash -# Install dependencies npm install +``` -# Start development server +## Running the App + +```bash npm run dev +``` -# Build for production +The app will be available at `http://localhost:5173` by default. + +## Building for Production + +```bash npm run build +npm run preview +``` -# Run tests +## Running Tests + +```bash npm test +``` -# Run tests in watch mode +Or in watch mode: + +```bash npm run test:watch ``` ## Docker Setup -### Build and run +### Dockerfile -```bash -# Build the Docker image -docker build -t counter-app . +Create a `Dockerfile` at the project root: -# Run the container (development server on port 5173) -docker run -p 5173:5173 counter-app +```dockerfile +FROM node:18-alpine AS base +WORKDIR /app +COPY package.json ./ +RUN npm install +COPY . . -# Run tests inside Docker -docker run --rm counter-app npm test -``` - -### Using docker-compose (if available) +# Run tests +FROM base AS test +RUN npm test -```bash -docker-compose up +# Build for production +FROM base AS build +RUN npm run build + +# Serve with a lightweight server +FROM nginx:alpine AS production +COPY --from=build /app/dist /usr/share/nginx/html +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] ``` -## Project Structure - -``` -src/ -├── main.jsx # React entry point -├── App.jsx # Root component -├── App.css # Global centering styles -├── setupTests.js # Test setup (jest-dom) -└── components/ - ├── Counter.jsx # Counter component - ├── Counter.module.css # Counter scoped styles - └── Counter.test.jsx # Counter unit tests -``` +### Running with Docker -## Testing +```bash +# Build and run tests +docker build --target test -t counter-app-test . -Tests are written using Vitest and @testing-library/react. +# Build production image +docker build --target production -t counter-app . -```bash -npm test +# Run production container +docker run -p 8080:80 counter-app ``` -This runs all `*.test.jsx` files via `vitest run`. +The production app will be available at `http://localhost:8080`. diff --git a/index.html b/index.html index 4642756..0a39fde 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - Counter App + React Counter App
diff --git a/package.json b/package.json index b01081d..81b8bfd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "mini-react-counter", - "version": "1.0.0", + "name": "react-counter-app", "private": true, + "version": "1.0.0", "type": "module", "scripts": { "dev": "vite", @@ -15,11 +15,11 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@testing-library/jest-dom": "^6.6.3", - "@testing-library/react": "^14.3.1", + "@testing-library/jest-dom": "^6.1.4", + "@testing-library/react": "^14.1.2", "@vitejs/plugin-react": "^4.2.1", - "jsdom": "^24.0.0", - "vite": "^5.4.19", - "vitest": "^1.6.0" + "jsdom": "^23.0.1", + "vite": "^5.0.8", + "vitest": "^1.1.0" } } diff --git a/src/App.css b/src/App.css index 8dbb83c..06c7834 100644 --- a/src/App.css +++ b/src/App.css @@ -1,7 +1,8 @@ -* { +/* Reset */ +*, *::before, *::after { + box-sizing: border-box; margin: 0; padding: 0; - box-sizing: border-box; } html, body, #root { @@ -9,12 +10,15 @@ html, body, #root { width: 100%; } +/* Center the Counter component both vertically and horizontally */ .app-container { display: flex; justify-content: center; align-items: center; min-height: 100vh; width: 100%; - font-family: Arial, Helvetica, sans-serif; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; background-color: #f5f5f5; } diff --git a/src/App.jsx b/src/App.jsx index d99234f..dde55e9 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -4,7 +4,9 @@ import './App.css'; /** * Root application component. - * Renders the Counter component centered on the page. + * + * Renders the Counter component centered on the page using a + * flexbox-based container layout. */ function App() { return ( diff --git a/src/components/Counter.jsx b/src/components/Counter.jsx index 6adc8f8..ae7db13 100644 --- a/src/components/Counter.jsx +++ b/src/components/Counter.jsx @@ -1,47 +1,80 @@ import React, { useState } from 'react'; -import styles from './Counter.module.css'; /** * Counter component. * - * Displays the current count value with increment and decrement buttons. - * The count starts at 0 and can go negative. + * Displays a numeric count with increment and decrement buttons. + * The count state is managed locally via useState and can go negative. */ function Counter() { const [count, setCount] = useState(0); /** - * Increment the count by 1. + * Increment the counter by 1. */ const handleIncrement = () => { setCount((prev) => prev + 1); }; /** - * Decrement the count by 1. + * Decrement the counter by 1. */ const handleDecrement = () => { setCount((prev) => prev - 1); }; return ( -
-

Counter

-

+

+

Counter

+

{count}

-
+
diff --git a/src/components/Counter.test.jsx b/src/components/Counter.test.jsx index b6698b9..c1123b4 100644 --- a/src/components/Counter.test.jsx +++ b/src/components/Counter.test.jsx @@ -6,81 +6,61 @@ import Counter from './Counter.jsx'; describe('Counter component', () => { it('renders initial count of 0', () => { render(); - const countDisplay = screen.getByTestId('count-display'); - expect(countDisplay).toHaveTextContent('0'); + const display = screen.getByTestId('count-display'); + expect(display).toHaveTextContent('0'); }); it('increments count when increment button is clicked', () => { render(); const incrementBtn = screen.getByRole('button', { name: /increment/i }); - const countDisplay = screen.getByTestId('count-display'); - - fireEvent.click(incrementBtn); - expect(countDisplay).toHaveTextContent('1'); - fireEvent.click(incrementBtn); - expect(countDisplay).toHaveTextContent('2'); + expect(screen.getByTestId('count-display')).toHaveTextContent('1'); }); it('decrements count when decrement button is clicked', () => { render(); const decrementBtn = screen.getByRole('button', { name: /decrement/i }); - const countDisplay = screen.getByTestId('count-display'); - fireEvent.click(decrementBtn); - expect(countDisplay).toHaveTextContent('-1'); - - fireEvent.click(decrementBtn); - expect(countDisplay).toHaveTextContent('-2'); + expect(screen.getByTestId('count-display')).toHaveTextContent('-1'); }); - it('handles rapid increment and decrement clicks correctly', () => { + it('handles multiple increments correctly', () => { render(); const incrementBtn = screen.getByRole('button', { name: /increment/i }); - const decrementBtn = screen.getByRole('button', { name: /decrement/i }); - const countDisplay = screen.getByTestId('count-display'); - - // Click increment 5 times - for (let i = 0; i < 5; i++) { - fireEvent.click(incrementBtn); - } - expect(countDisplay).toHaveTextContent('5'); - - // Click decrement 3 times - for (let i = 0; i < 3; i++) { - fireEvent.click(decrementBtn); - } - expect(countDisplay).toHaveTextContent('2'); - }); - - it('renders the counter container with centered alignment', () => { - render(); - const container = screen.getByTestId('counter-container'); - expect(container).toBeInTheDocument(); + fireEvent.click(incrementBtn); + fireEvent.click(incrementBtn); + fireEvent.click(incrementBtn); + expect(screen.getByTestId('count-display')).toHaveTextContent('3'); }); - it('renders the Counter title', () => { + it('handles multiple decrements correctly', () => { render(); - const title = screen.getByText('Counter'); - expect(title).toBeInTheDocument(); + const decrementBtn = screen.getByRole('button', { name: /decrement/i }); + fireEvent.click(decrementBtn); + fireEvent.click(decrementBtn); + expect(screen.getByTestId('count-display')).toHaveTextContent('-2'); }); - it('renders both increment and decrement buttons', () => { + it('handles mixed increment and decrement clicks', () => { render(); const incrementBtn = screen.getByRole('button', { name: /increment/i }); const decrementBtn = screen.getByRole('button', { name: /decrement/i }); - expect(incrementBtn).toBeInTheDocument(); - expect(decrementBtn).toBeInTheDocument(); + fireEvent.click(incrementBtn); + fireEvent.click(incrementBtn); + fireEvent.click(decrementBtn); + expect(screen.getByTestId('count-display')).toHaveTextContent('1'); }); - it('allows count to go negative', () => { + it('renders the count display centered (text-align: center)', () => { render(); - const decrementBtn = screen.getByRole('button', { name: /decrement/i }); - const countDisplay = screen.getByTestId('count-display'); + const display = screen.getByTestId('count-display'); + expect(display.style.textAlign).toBe('center'); + }); - fireEvent.click(decrementBtn); - fireEvent.click(decrementBtn); - fireEvent.click(decrementBtn); - expect(countDisplay).toHaveTextContent('-3'); + it('renders the counter container with centered alignment', () => { + const { container } = render(); + const counterDiv = container.querySelector('.counter'); + expect(counterDiv).not.toBeNull(); + expect(counterDiv.style.alignItems).toBe('center'); }); }); From 011cb0569718f38e1ea2f772aae3ebd960f9f3b6 Mon Sep 17 00:00:00 2001 From: FORGE Date: Fri, 10 Apr 2026 05:11:12 +0000 Subject: [PATCH 4/4] feat: Write Complete Test Suite Run: 0e6f20d3-cd3c-4214-ae92-540af6ac4d2f Task: c10c2b22-95ae-4f2a-af92-0a92683c8562 Agent: builder --- Dockerfile | 12 +++ RUNNING.md | 103 ++++++++++---------- package.json | 13 +-- src/App.css | 64 ++++++++++--- src/App.jsx | 6 +- src/components/Counter.jsx | 58 +++-------- src/components/Counter.test.jsx | 165 +++++++++++++++++++++++++------- vite.config.js | 3 +- 8 files changed, 272 insertions(+), 152 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a74ca12 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:18-alpine + +WORKDIR /app + +COPY package.json ./ +RUN npm install + +COPY . . + +EXPOSE 5173 + +CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"] diff --git a/RUNNING.md b/RUNNING.md index 0fd33c5..d6559a1 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -1,6 +1,6 @@ # React Counter App -A minimal React application featuring a Counter component centered on the page. +A minimal React counter application built with Vite, featuring increment and decrement buttons with a comprehensive test suite. ## TEAM_BRIEF stack: TypeScript/React+Vite @@ -12,81 +12,80 @@ coverage_applies: false ## Prerequisites -- Node.js >= 18 -- npm >= 9 +- Node.js 18+ and npm +- Docker (optional, for containerized setup) -## Setup +## Local Setup ```bash +# Install dependencies npm install -``` - -## Running the App -```bash +# Start development server npm run dev -``` -The app will be available at `http://localhost:5173` by default. - -## Building for Production +# Run tests +npm test -```bash +# Build for production npm run build -npm run preview ``` -## Running Tests +## Docker Setup + +### Build and Run ```bash -npm test +# Build the Docker image +docker build -t react-counter-app . + +# Run the container (development server on port 5173) +docker run -p 5173:5173 react-counter-app ``` -Or in watch mode: +### Run Tests in Docker ```bash -npm run test:watch +# Run the test suite inside a container +docker run --rm react-counter-app npm test ``` -## Docker Setup - -### Dockerfile - -Create a `Dockerfile` at the project root: - -```dockerfile -FROM node:18-alpine AS base -WORKDIR /app -COPY package.json ./ -RUN npm install -COPY . . - -# Run tests -FROM base AS test -RUN npm test +## Project Structure -# Build for production -FROM base AS build -RUN npm run build - -# Serve with a lightweight server -FROM nginx:alpine AS production -COPY --from=build /app/dist /usr/share/nginx/html -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] +``` +├── index.html # HTML entry point +├── package.json # Dependencies and scripts +├── vite.config.js # Vite + Vitest configuration +├── src/ +│ ├── main.jsx # React entry point +│ ├── App.jsx # Root App component +│ ├── App.css # Global and centering styles +│ ├── setupTests.js # Test setup (jest-dom matchers) +│ └── components/ +│ ├── Counter.jsx # Counter component +│ └── Counter.test.jsx # Test suite for Counter and App ``` -### Running with Docker +## Testing -```bash -# Build and run tests -docker build --target test -t counter-app-test . +Tests are written using [Vitest](https://vitest.dev/) and [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro/). -# Build production image -docker build --target production -t counter-app . +```bash +# Run all tests +npm test -# Run production container -docker run -p 8080:80 counter-app +# Run tests in watch mode +npm run test:watch ``` -The production app will be available at `http://localhost:8080`. +### Test Coverage + +- Initial count renders as 0 +- Increment button increases count by 1 +- Decrement button decreases count by 1 +- Mixed increment/decrement sequences +- Count can go negative +- Rapid clicking updates correctly +- Accessibility labels and aria-live region +- Centering classes are applied +- App renders Counter within centered container diff --git a/package.json b/package.json index 81b8bfd..240e22b 100644 --- a/package.json +++ b/package.json @@ -15,11 +15,12 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@testing-library/jest-dom": "^6.1.4", - "@testing-library/react": "^14.1.2", - "@vitejs/plugin-react": "^4.2.1", - "jsdom": "^23.0.1", - "vite": "^5.0.8", - "vitest": "^1.1.0" + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.1.0", + "@testing-library/user-event": "^14.5.2", + "@vitejs/plugin-react": "^4.3.4", + "jsdom": "^25.0.1", + "vite": "^5.4.11", + "vitest": "^2.1.8" } } diff --git a/src/App.css b/src/App.css index 06c7834..770ef01 100644 --- a/src/App.css +++ b/src/App.css @@ -1,24 +1,62 @@ -/* Reset */ -*, *::before, *::after { - box-sizing: border-box; +* { margin: 0; padding: 0; + box-sizing: border-box; } -html, body, #root { - height: 100%; - width: 100%; -} - -/* Center the Counter component both vertically and horizontally */ .app-container { display: flex; justify-content: center; align-items: center; min-height: 100vh; - width: 100%; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, - Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: Arial, Helvetica, sans-serif; background-color: #f5f5f5; } + +.counter-wrapper { + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + padding: 2rem; + background: #ffffff; + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + text-align: center; +} + +.counter-wrapper h1 { + font-size: 1.5rem; + color: #333; +} + +.count-display { + font-size: 3rem; + font-weight: bold; + color: #111; + min-width: 100px; + text-align: center; +} + +.counter-buttons { + display: flex; + gap: 1rem; +} + +.counter-buttons button { + font-size: 1.25rem; + padding: 0.5rem 1.5rem; + border: 2px solid #333; + border-radius: 8px; + background: #fff; + cursor: pointer; + transition: background-color 0.15s ease; +} + +.counter-buttons button:hover { + background-color: #e0e0e0; +} + +.counter-buttons button:active { + background-color: #ccc; +} diff --git a/src/App.jsx b/src/App.jsx index dde55e9..24c9f47 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -4,13 +4,11 @@ import './App.css'; /** * Root application component. - * - * Renders the Counter component centered on the page using a - * flexbox-based container layout. + * Renders the Counter component centered on the page. */ function App() { return ( -
+
); diff --git a/src/components/Counter.jsx b/src/components/Counter.jsx index ae7db13..83bb56d 100644 --- a/src/components/Counter.jsx +++ b/src/components/Counter.jsx @@ -1,80 +1,50 @@ import React, { useState } from 'react'; /** - * Counter component. + * Counter component with increment and decrement functionality. * - * Displays a numeric count with increment and decrement buttons. - * The count state is managed locally via useState and can go negative. + * Displays the current count value and provides buttons to + * increase or decrease the count by one. */ function Counter() { const [count, setCount] = useState(0); /** - * Increment the counter by 1. + * Increment the count by one. */ const handleIncrement = () => { setCount((prev) => prev + 1); }; /** - * Decrement the counter by 1. + * Decrement the count by one. */ const handleDecrement = () => { setCount((prev) => prev - 1); }; return ( -
-

Counter

-

+

Counter

+
{count} -

-
+
+
diff --git a/src/components/Counter.test.jsx b/src/components/Counter.test.jsx index c1123b4..3e9a750 100644 --- a/src/components/Counter.test.jsx +++ b/src/components/Counter.test.jsx @@ -1,66 +1,167 @@ import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { describe, it, expect } from 'vitest'; import Counter from './Counter.jsx'; +import App from '../App.jsx'; describe('Counter component', () => { - it('renders initial count of 0', () => { + it('renders with an initial count of 0', () => { render(); const display = screen.getByTestId('count-display'); expect(display).toHaveTextContent('0'); }); - it('increments count when increment button is clicked', () => { + it('renders the heading text "Counter"', () => { render(); - const incrementBtn = screen.getByRole('button', { name: /increment/i }); - fireEvent.click(incrementBtn); - expect(screen.getByTestId('count-display')).toHaveTextContent('1'); + const heading = screen.getByRole('heading', { name: /counter/i }); + expect(heading).toBeInTheDocument(); }); - it('decrements count when decrement button is clicked', () => { + it('renders increment and decrement buttons', () => { render(); - const decrementBtn = screen.getByRole('button', { name: /decrement/i }); - fireEvent.click(decrementBtn); - expect(screen.getByTestId('count-display')).toHaveTextContent('-1'); + const incrementBtn = screen.getByTestId('increment-button'); + const decrementBtn = screen.getByTestId('decrement-button'); + expect(incrementBtn).toBeInTheDocument(); + expect(decrementBtn).toBeInTheDocument(); }); - it('handles multiple increments correctly', () => { + it('increments the count when increment button is clicked', async () => { + const user = userEvent.setup(); render(); - const incrementBtn = screen.getByRole('button', { name: /increment/i }); - fireEvent.click(incrementBtn); - fireEvent.click(incrementBtn); - fireEvent.click(incrementBtn); - expect(screen.getByTestId('count-display')).toHaveTextContent('3'); + const incrementBtn = screen.getByTestId('increment-button'); + const display = screen.getByTestId('count-display'); + + await user.click(incrementBtn); + expect(display).toHaveTextContent('1'); + + await user.click(incrementBtn); + expect(display).toHaveTextContent('2'); }); - it('handles multiple decrements correctly', () => { + it('decrements the count when decrement button is clicked', async () => { + const user = userEvent.setup(); render(); - const decrementBtn = screen.getByRole('button', { name: /decrement/i }); - fireEvent.click(decrementBtn); - fireEvent.click(decrementBtn); - expect(screen.getByTestId('count-display')).toHaveTextContent('-2'); + const decrementBtn = screen.getByTestId('decrement-button'); + const display = screen.getByTestId('count-display'); + + await user.click(decrementBtn); + expect(display).toHaveTextContent('-1'); + + await user.click(decrementBtn); + expect(display).toHaveTextContent('-2'); + }); + + it('handles a mix of increment and decrement clicks correctly', async () => { + const user = userEvent.setup(); + render(); + const incrementBtn = screen.getByTestId('increment-button'); + const decrementBtn = screen.getByTestId('decrement-button'); + const display = screen.getByTestId('count-display'); + + await user.click(incrementBtn); + await user.click(incrementBtn); + await user.click(incrementBtn); + expect(display).toHaveTextContent('3'); + + await user.click(decrementBtn); + expect(display).toHaveTextContent('2'); + + await user.click(decrementBtn); + await user.click(decrementBtn); + expect(display).toHaveTextContent('0'); + }); + + it('allows count to go negative', async () => { + const user = userEvent.setup(); + render(); + const decrementBtn = screen.getByTestId('decrement-button'); + const display = screen.getByTestId('count-display'); + + await user.click(decrementBtn); + await user.click(decrementBtn); + await user.click(decrementBtn); + expect(display).toHaveTextContent('-3'); }); - it('handles mixed increment and decrement clicks', () => { + it('handles rapid clicks correctly', async () => { + const user = userEvent.setup(); + render(); + const incrementBtn = screen.getByTestId('increment-button'); + const display = screen.getByTestId('count-display'); + + // Rapid-fire 10 clicks + for (let i = 0; i < 10; i++) { + await user.click(incrementBtn); + } + expect(display).toHaveTextContent('10'); + }); + + it('has accessible button labels', () => { render(); const incrementBtn = screen.getByRole('button', { name: /increment/i }); const decrementBtn = screen.getByRole('button', { name: /decrement/i }); - fireEvent.click(incrementBtn); - fireEvent.click(incrementBtn); - fireEvent.click(decrementBtn); - expect(screen.getByTestId('count-display')).toHaveTextContent('1'); + expect(incrementBtn).toBeInTheDocument(); + expect(decrementBtn).toBeInTheDocument(); + }); + + it('has an aria-live region for the count display', () => { + render(); + const display = screen.getByTestId('count-display'); + expect(display).toHaveAttribute('aria-live', 'polite'); }); - it('renders the count display centered (text-align: center)', () => { + it('count display is centered within the counter wrapper (text-align)', () => { render(); + const wrapper = screen.getByTestId('counter-wrapper'); + expect(wrapper).toHaveClass('counter-wrapper'); + // The counter-wrapper class applies text-align: center and align-items: center + // Verify the wrapper element has the centering class applied const display = screen.getByTestId('count-display'); - expect(display.style.textAlign).toBe('center'); + expect(display).toHaveClass('count-display'); + }); +}); + +describe('App component', () => { + it('renders the Counter component inside a centered container', () => { + render(); + const appContainer = screen.getByTestId('app-container'); + expect(appContainer).toBeInTheDocument(); + expect(appContainer).toHaveClass('app-container'); + }); + + it('displays the Counter inside the App', () => { + render(); + const counterWrapper = screen.getByTestId('counter-wrapper'); + expect(counterWrapper).toBeInTheDocument(); + }); + + it('shows initial count of 0 when App renders', () => { + render(); + const display = screen.getByTestId('count-display'); + expect(display).toHaveTextContent('0'); + }); + + it('increment and decrement work through the App', async () => { + const user = userEvent.setup(); + render(); + const incrementBtn = screen.getByTestId('increment-button'); + const decrementBtn = screen.getByTestId('decrement-button'); + const display = screen.getByTestId('count-display'); + + await user.click(incrementBtn); + await user.click(incrementBtn); + expect(display).toHaveTextContent('2'); + + await user.click(decrementBtn); + expect(display).toHaveTextContent('1'); }); - it('renders the counter container with centered alignment', () => { - const { container } = render(); - const counterDiv = container.querySelector('.counter'); - expect(counterDiv).not.toBeNull(); - expect(counterDiv.style.alignItems).toBe('center'); + it('app container uses flex centering class', () => { + render(); + const appContainer = screen.getByTestId('app-container'); + // Verify the container has the app-container class which provides + // display:flex, justify-content:center, align-items:center + expect(appContainer).toHaveClass('app-container'); }); }); diff --git a/vite.config.js b/vite.config.js index 53d9d0c..aa0f24d 100644 --- a/vite.config.js +++ b/vite.config.js @@ -6,6 +6,7 @@ export default defineConfig({ test: { environment: 'jsdom', globals: true, - setupFiles: './src/setupTests.js', + setupFiles: ['./src/setupTests.js'], + css: true, }, });