From 971c996387b89349ea45cd7a8a3256aed6a7a90d Mon Sep 17 00:00:00 2001 From: FORGE Date: Fri, 10 Apr 2026 14:08:10 +0000 Subject: [PATCH 1/3] feat: Setup project with package.json and Vite config Run: d8851c62-0093-491a-9b28-79311e2b8dbd Task: d17be6fe-c3f5-4277-a2a7-99bd3d877172 Agent: builder --- Dockerfile | 23 ++++++++++++++ RUNNING.md | 63 ++++++++++++++++++++++++++++---------- docker-compose.yml | 10 ++++++ index.html | 12 ++++++++ package.json | 27 ++++++++++++++++ src/App.module.css | 13 ++++++++ src/App.tsx | 18 +++++++++++ src/__tests__/App.test.tsx | 31 +++++++++++++++++++ src/__tests__/setup.ts | 1 + src/main.css | 9 ++++++ src/main.tsx | 15 +++++++++ src/vite-env.d.ts | 9 ++++++ tsconfig.json | 21 +++++++++++++ vite.config.ts | 25 +++++++++++++++ 14 files changed, 260 insertions(+), 17 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 index.html create mode 100644 package.json create mode 100644 src/App.module.css create mode 100644 src/App.tsx create mode 100644 src/__tests__/App.test.tsx create mode 100644 src/__tests__/setup.ts create mode 100644 src/main.css create mode 100644 src/main.tsx create mode 100644 src/vite-env.d.ts create mode 100644 tsconfig.json create mode 100644 vite.config.ts diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6cd8ac4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM node:18-alpine AS builder + +WORKDIR /app + +COPY package.json ./ +RUN npm install + +COPY . . +RUN npm run build + +# --- production stage --- +FROM node:18-alpine + +WORKDIR /app + +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/package.json ./ +COPY --from=builder /app/vite.config.ts ./ + +EXPOSE 5173 + +CMD ["npx", "vite", "preview", "--host", "0.0.0.0", "--port", "5173"] diff --git a/RUNNING.md b/RUNNING.md index 77896cf..3a59d38 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -1,33 +1,62 @@ -# Running the Todo API +# Yellow World — Running Instructions + +## 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 +- **npm** ≥ 9 +- **Docker** and **Docker Compose** (for containerised usage) -## Install dependencies +## Local Development ```bash -pip install fastapi uvicorn pydantic -``` +# Install dependencies +npm install -For running the test suite you will also need: +# Start the dev server (http://localhost:5173) +npm run dev -```bash -pip install httpx pytest -``` +# Run tests +npm test -## Start the server +# Build for production +npm run build -```bash -uvicorn main:app --reload --host 0.0.0.0 --port 8000 +# Preview the production build +npm run preview ``` -The API will be available at . +## Docker -Interactive docs are served at . +```bash +# Build and start the container +docker compose up --build -## Run the tests +# The app is available at http://localhost:5173 +``` -```bash -pytest tests/ +## Project Structure + +``` +├── index.html # HTML entry point +├── src/ +│ ├── main.tsx # React bootstrap +│ ├── main.css # Global styles +│ ├── App.tsx # Main App component +│ ├── App.module.css # Scoped styles for App +│ └── __tests__/ +│ ├── setup.ts # Test setup (jest-dom) +│ └── App.test.tsx # App component tests +├── vite.config.ts # Vite configuration +├── tsconfig.json # TypeScript configuration +├── package.json # Dependencies and scripts +├── Dockerfile # Multi-stage Docker build +└── docker-compose.yml # Compose orchestration ``` diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..816b053 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +version: "3.8" + +services: + frontend: + build: + context: . + dockerfile: Dockerfile + ports: + - "5173:5173" + restart: unless-stopped diff --git a/index.html b/index.html new file mode 100644 index 0000000..21bddb7 --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + + Yellow World + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..26e7698 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "yellow-world", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "test": "vitest run" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.1.4", + "@testing-library/react": "^14.1.2", + "@types/react": "^18.2.43", + "@types/react-dom": "^18.2.17", + "@vitejs/plugin-react": "^4.2.1", + "jsdom": "^23.0.1", + "typescript": "^5.3.3", + "vite": "^5.0.8", + "vitest": "^1.1.0" + } +} diff --git a/src/App.module.css b/src/App.module.css new file mode 100644 index 0000000..0f7d793 --- /dev/null +++ b/src/App.module.css @@ -0,0 +1,13 @@ +.container { + display: flex; + align-items: center; + justify-content: center; + min-height: 100vh; + background-color: #ffd700; +} + +.heading { + font-size: 3rem; + color: #333; + font-family: Arial, Helvetica, sans-serif; +} diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..52dca39 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import styles from "./App.module.css"; + +/** + * Main application component. + * + * Renders a heading with the text "yellow world" using yellow-themed + * styling provided by CSS modules. + */ +const App: React.FC = () => { + return ( +
+

yellow world

+
+ ); +}; + +export default App; diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx new file mode 100644 index 0000000..a750c5f --- /dev/null +++ b/src/__tests__/App.test.tsx @@ -0,0 +1,31 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { describe, it, expect } from "vitest"; +import App from "../App"; + +describe("App component", () => { + it("renders 'yellow world' text", () => { + render(); + const heading = screen.getByText("yellow world"); + expect(heading).toBeInTheDocument(); + }); + + it("renders the app container with correct class", () => { + render(); + const container = screen.getByTestId("app-container"); + expect(container).toBeInTheDocument(); + expect(container).toHaveClass("container"); + }); + + it("renders heading with correct class", () => { + render(); + const heading = screen.getByText("yellow world"); + expect(heading).toHaveClass("heading"); + }); + + it("heading is an h1 element", () => { + render(); + const heading = screen.getByRole("heading", { level: 1 }); + expect(heading).toHaveTextContent("yellow world"); + }); +}); diff --git a/src/__tests__/setup.ts b/src/__tests__/setup.ts new file mode 100644 index 0000000..d0de870 --- /dev/null +++ b/src/__tests__/setup.ts @@ -0,0 +1 @@ +import "@testing-library/jest-dom"; diff --git a/src/main.css b/src/main.css new file mode 100644 index 0000000..0f5ad9c --- /dev/null +++ b/src/main.css @@ -0,0 +1,9 @@ +* { + box-sizing: border-box; +} + +body { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..66c07b9 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import "./main.css"; + +/** + * Application bootstrap. + * + * Mounts the root component into the #root DOM element. + */ +ReactDOM.createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..d5c843c --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,9 @@ +/// + +/** + * Type declarations for CSS module imports. + */ +declare module "*.module.css" { + const classes: { readonly [key: string]: string }; + export default classes; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e05cb43 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vitest/globals"] + }, + "include": ["src"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..d7f53f3 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,25 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +/// +export default defineConfig({ + plugins: [react()], + server: { + host: "0.0.0.0", + port: 5173, + }, + preview: { + host: "0.0.0.0", + port: 5173, + }, + test: { + environment: "jsdom", + globals: true, + setupFiles: ["./src/__tests__/setup.ts"], + css: { + modules: { + classNameStrategy: "non-scoped", + }, + }, + }, +}); From 7400b3973edb58024464bac7165760d7a7162ed2 Mon Sep 17 00:00:00 2001 From: FORGE Date: Fri, 10 Apr 2026 14:09:00 +0000 Subject: [PATCH 2/3] feat: Create main App component and global styles Run: d8851c62-0093-491a-9b28-79311e2b8dbd Task: 643ade76-cddd-4dc9-b523-0485530ac973 Agent: builder --- Dockerfile | 3 ++- RUNNING.md | 34 +++++++++------------------------- index.html | 2 +- package.json | 8 ++++---- src/App.module.css | 11 +++++++++-- src/__tests__/App.test.tsx | 25 ++++++++++++++++++------- src/__tests__/setup.ts | 6 ++++++ src/main.css | 19 ++++++++++++++----- src/main.tsx | 7 ++++--- src/vite-env.d.ts | 3 +++ vite.config.ts | 17 +++++++---------- 11 files changed, 77 insertions(+), 58 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6cd8ac4..dd8eefd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ +# Stage 1: Build FROM node:18-alpine AS builder WORKDIR /app @@ -8,7 +9,7 @@ RUN npm install COPY . . RUN npm run build -# --- production stage --- +# Stage 2: Serve FROM node:18-alpine WORKDIR /app diff --git a/RUNNING.md b/RUNNING.md index 3a59d38..4272a3c 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -10,9 +10,8 @@ coverage_applies: false ## Prerequisites -- **Node.js** ≥ 18 -- **npm** ≥ 9 -- **Docker** and **Docker Compose** (for containerised usage) +- Node.js 18+ (or Docker) +- npm ## Local Development @@ -20,7 +19,7 @@ coverage_applies: false # Install dependencies npm install -# Start the dev server (http://localhost:5173) +# Start development server npm run dev # Run tests @@ -29,34 +28,19 @@ npm test # Build for production npm run build -# Preview the production build +# Preview production build npm run preview ``` ## Docker ```bash -# Build and start the container +# Build and run with Docker Compose docker compose up --build -# The app is available at http://localhost:5173 +# Or build manually +docker build -t yellow-world . +docker run -p 5173:5173 yellow-world ``` -## Project Structure - -``` -├── index.html # HTML entry point -├── src/ -│ ├── main.tsx # React bootstrap -│ ├── main.css # Global styles -│ ├── App.tsx # Main App component -│ ├── App.module.css # Scoped styles for App -│ └── __tests__/ -│ ├── setup.ts # Test setup (jest-dom) -│ └── App.test.tsx # App component tests -├── vite.config.ts # Vite configuration -├── tsconfig.json # TypeScript configuration -├── package.json # Dependencies and scripts -├── Dockerfile # Multi-stage Docker build -└── docker-compose.yml # Compose orchestration -``` +Open http://localhost:5173 in your browser. diff --git a/index.html b/index.html index 21bddb7..4f63111 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,4 @@ - + diff --git a/package.json b/package.json index 26e7698..8aeed4d 100644 --- a/package.json +++ b/package.json @@ -14,14 +14,14 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@testing-library/jest-dom": "^6.1.4", - "@testing-library/react": "^14.1.2", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.1.0", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", "@vitejs/plugin-react": "^4.2.1", - "jsdom": "^23.0.1", + "jsdom": "^25.0.1", "typescript": "^5.3.3", "vite": "^5.0.8", - "vitest": "^1.1.0" + "vitest": "^2.1.8" } } diff --git a/src/App.module.css b/src/App.module.css index 0f7d793..6b14755 100644 --- a/src/App.module.css +++ b/src/App.module.css @@ -1,3 +1,9 @@ +/** + * Encapsulated CSS module for the App component. + * + * Provides yellow-themed background and text styling. + */ + .container { display: flex; align-items: center; @@ -7,7 +13,8 @@ } .heading { + color: #8b7500; font-size: 3rem; - color: #333; - font-family: Arial, Helvetica, sans-serif; + font-weight: 700; + text-align: center; } diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx index a750c5f..58e3a05 100644 --- a/src/__tests__/App.test.tsx +++ b/src/__tests__/App.test.tsx @@ -3,29 +3,40 @@ import { render, screen } from "@testing-library/react"; import { describe, it, expect } from "vitest"; import App from "../App"; -describe("App component", () => { +/** + * Unit tests for the App component. + * + * Verifies that the component renders the expected text and applies + * the correct yellow-themed CSS module classes. + */ +describe("App", () => { it("renders 'yellow world' text", () => { render(); const heading = screen.getByText("yellow world"); expect(heading).toBeInTheDocument(); }); - it("renders the app container with correct class", () => { + it("renders the heading as an h1 element", () => { + render(); + const heading = screen.getByText("yellow world"); + expect(heading.tagName).toBe("H1"); + }); + + it("applies container class to the wrapper div", () => { render(); const container = screen.getByTestId("app-container"); - expect(container).toBeInTheDocument(); expect(container).toHaveClass("container"); }); - it("renders heading with correct class", () => { + it("applies heading class to the h1 element", () => { render(); const heading = screen.getByText("yellow world"); expect(heading).toHaveClass("heading"); }); - it("heading is an h1 element", () => { + it("has a data-testid attribute on the container", () => { render(); - const heading = screen.getByRole("heading", { level: 1 }); - expect(heading).toHaveTextContent("yellow world"); + const container = screen.getByTestId("app-container"); + expect(container).toBeInTheDocument(); }); }); diff --git a/src/__tests__/setup.ts b/src/__tests__/setup.ts index d0de870..149b658 100644 --- a/src/__tests__/setup.ts +++ b/src/__tests__/setup.ts @@ -1 +1,7 @@ +/** + * Vitest setup file. + * + * Extends expect with jest-dom matchers for DOM assertion helpers + * such as toBeInTheDocument() and toHaveClass(). + */ import "@testing-library/jest-dom"; diff --git a/src/main.css b/src/main.css index 0f5ad9c..705b730 100644 --- a/src/main.css +++ b/src/main.css @@ -1,9 +1,18 @@ -* { - box-sizing: border-box; -} +/** + * Global base styles. + * + * Resets body margin and defines the default font family for the + * entire application. + */ body { margin: 0; - padding: 0; - font-family: Arial, Helvetica, sans-serif; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + "Helvetica Neue", Arial, sans-serif; +} + +*, +*::before, +*::after { + box-sizing: border-box; } diff --git a/src/main.tsx b/src/main.tsx index 66c07b9..25df5ef 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -4,12 +4,13 @@ import App from "./App"; import "./main.css"; /** - * Application bootstrap. + * Application entry point. * - * Mounts the root component into the #root DOM element. + * Imports global styles and renders the root App component into the + * #root element defined in index.html. */ ReactDOM.createRoot(document.getElementById("root")!).render( - , + ); diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index d5c843c..9974dff 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -2,6 +2,9 @@ /** * Type declarations for CSS module imports. + * + * Allows TypeScript to understand `import styles from '*.module.css'` + * and treat the default export as a record of class name strings. */ declare module "*.module.css" { const classes: { readonly [key: string]: string }; diff --git a/vite.config.ts b/vite.config.ts index d7f53f3..3f987d1 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,20 +1,17 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; -/// +/** + * Vite configuration for the Yellow World React/TypeScript project. + * + * Enables the React plugin and configures Vitest for unit testing + * with jsdom as the DOM environment. + */ export default defineConfig({ plugins: [react()], - server: { - host: "0.0.0.0", - port: 5173, - }, - preview: { - host: "0.0.0.0", - port: 5173, - }, test: { - environment: "jsdom", globals: true, + environment: "jsdom", setupFiles: ["./src/__tests__/setup.ts"], css: { modules: { From 53e63cce57f0239113299566ce8e63ead1bc4111 Mon Sep 17 00:00:00 2001 From: FORGE Date: Fri, 10 Apr 2026 14:09:54 +0000 Subject: [PATCH 3/3] feat: Write complete test suite for Yellow World Web App Run: d8851c62-0093-491a-9b28-79311e2b8dbd Task: 6d7f6539-5183-4fdf-add5-6a03850365e8 Agent: builder --- Dockerfile | 14 +++---- RUNNING.md | 50 ++++++++++++++++++++---- SETUP.md | 21 +++++----- docker-compose.yml | 4 +- package.json | 8 ++-- src/App.module.css | 12 +++--- src/App.tsx | 12 +++--- src/__tests__/App.test.tsx | 80 +++++++++++++++++++++++++++----------- src/main.css | 22 ++++------- src/main.tsx | 16 ++++---- src/setupTests.ts | 5 +++ tsconfig.json | 5 +-- vite-env.d.ts | 1 + vite.config.ts | 23 ++++++----- 14 files changed, 169 insertions(+), 104 deletions(-) create mode 100644 src/setupTests.ts create mode 100644 vite-env.d.ts diff --git a/Dockerfile b/Dockerfile index dd8eefd..0d79f8d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,4 @@ -# Stage 1: Build -FROM node:18-alpine AS builder +FROM node:18-alpine AS build WORKDIR /app @@ -9,15 +8,14 @@ RUN npm install COPY . . RUN npm run build -# Stage 2: Serve -FROM node:18-alpine +FROM node:18-alpine AS production WORKDIR /app -COPY --from=builder /app/dist ./dist -COPY --from=builder /app/node_modules ./node_modules -COPY --from=builder /app/package.json ./ -COPY --from=builder /app/vite.config.ts ./ +COPY --from=build /app/dist ./dist +COPY --from=build /app/node_modules ./node_modules +COPY --from=build /app/package.json ./ +COPY --from=build /app/vite.config.ts ./ EXPOSE 5173 diff --git a/RUNNING.md b/RUNNING.md index 4272a3c..ef1efc7 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -1,4 +1,6 @@ -# Yellow World — Running Instructions +# Yellow World Web App + +A minimal React/Vite/TypeScript application that displays "yellow world" with yellow-themed styling. ## TEAM_BRIEF stack: TypeScript/React+Vite @@ -10,8 +12,8 @@ coverage_applies: false ## Prerequisites -- Node.js 18+ (or Docker) -- npm +- Node.js 18+ and npm +- Docker and Docker Compose (for containerised run) ## Local Development @@ -19,7 +21,7 @@ coverage_applies: false # Install dependencies npm install -# Start development server +# Start dev server npm run dev # Run tests @@ -38,9 +40,41 @@ npm run preview # Build and run with Docker Compose docker compose up --build -# Or build manually -docker build -t yellow-world . -docker run -p 5173:5173 yellow-world +# Open in browser +# http://localhost:5173 +``` + +## Project Structure + +``` +├── index.html # HTML entry point +├── src/ +│ ├── main.tsx # React entry point +│ ├── main.css # Global styles +│ ├── App.tsx # Main App component +│ ├── App.module.css # Yellow-themed CSS module +│ ├── setupTests.ts # Test setup (jest-dom matchers) +│ └── __tests__/ +│ └── App.test.tsx # App component test suite +├── vite.config.ts # Vite + Vitest configuration +├── tsconfig.json # TypeScript configuration +├── package.json # Dependencies and scripts +├── Dockerfile # Multi-stage Docker build +└── docker-compose.yml # Docker Compose config ``` -Open http://localhost:5173 in your browser. +## Testing + +Tests use Vitest with React Testing Library and jest-dom matchers. +The test suite verifies: + +1. The "yellow world" text is rendered in the DOM +2. The text appears inside an `

` element +3. CSS module classes (`container`, `heading`) are correctly applied +4. The DOM structure is correct (div wrapping h1) + +Run tests: + +```bash +npm test +``` diff --git a/SETUP.md b/SETUP.md index 643c59c..5704866 100644 --- a/SETUP.md +++ b/SETUP.md @@ -1,25 +1,24 @@ # Setup Instructions -## Install Dependencies +This project uses npm for dependency management. Lock files are generated +by the package manager and must not be hand-written. -```bash -pip install -r requirements.txt -``` - -## Install Test Dependencies +## Generate lock file and install dependencies ```bash -pip install pytest httpx +npm install ``` -## Run Tests +This will create `package-lock.json` and populate `node_modules/`. + +## Run tests ```bash -pytest tests/ -v +npm test ``` -## Run the Application +## Build ```bash -uvicorn main:app --reload +npm run build ``` diff --git a/docker-compose.yml b/docker-compose.yml index 816b053..226cc1d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ -version: "3.8" +version: "3.9" services: - frontend: + yellow-world: build: context: . dockerfile: Dockerfile diff --git a/package.json b/package.json index 8aeed4d..26e7698 100644 --- a/package.json +++ b/package.json @@ -14,14 +14,14 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@testing-library/jest-dom": "^6.6.3", - "@testing-library/react": "^16.1.0", + "@testing-library/jest-dom": "^6.1.4", + "@testing-library/react": "^14.1.2", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", "@vitejs/plugin-react": "^4.2.1", - "jsdom": "^25.0.1", + "jsdom": "^23.0.1", "typescript": "^5.3.3", "vite": "^5.0.8", - "vitest": "^2.1.8" + "vitest": "^1.1.0" } } diff --git a/src/App.module.css b/src/App.module.css index 6b14755..c7afee3 100644 --- a/src/App.module.css +++ b/src/App.module.css @@ -1,8 +1,4 @@ -/** - * Encapsulated CSS module for the App component. - * - * Provides yellow-themed background and text styling. - */ +/* Yellow-themed styling for the App component */ .container { display: flex; @@ -15,6 +11,10 @@ .heading { color: #8b7500; font-size: 3rem; - font-weight: 700; + font-weight: bold; text-align: center; + padding: 2rem; + background-color: #ffecb3; + border-radius: 12px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } diff --git a/src/App.tsx b/src/App.tsx index 52dca39..cf67e23 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,16 +1,18 @@ -import React from "react"; -import styles from "./App.module.css"; +import React from 'react'; +import styles from './App.module.css'; /** * Main application component. * - * Renders a heading with the text "yellow world" using yellow-themed - * styling provided by CSS modules. + * Renders a "yellow world" heading inside a yellow-themed container. + * Styling is applied via CSS modules defined in App.module.css. */ const App: React.FC = () => { return (
-

yellow world

+

+ yellow world +

); }; diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx index 58e3a05..81fc837 100644 --- a/src/__tests__/App.test.tsx +++ b/src/__tests__/App.test.tsx @@ -1,42 +1,78 @@ -import React from "react"; -import { render, screen } from "@testing-library/react"; -import { describe, it, expect } from "vitest"; -import App from "../App"; +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { describe, it, expect } from 'vitest'; +import App from '../App'; /** - * Unit tests for the App component. + * Test suite for the App component. * - * Verifies that the component renders the expected text and applies - * the correct yellow-themed CSS module classes. + * Verifies that the 'yellow world' text is rendered in the DOM and + * that the correct yellow-themed CSS module class names are applied + * to the container and heading elements. */ -describe("App", () => { - it("renders 'yellow world' text", () => { +describe('App Component', () => { + it('renders the yellow world text', () => { render(); - const heading = screen.getByText("yellow world"); + const heading = screen.getByText('yellow world'); expect(heading).toBeInTheDocument(); }); - it("renders the heading as an h1 element", () => { + it('renders the yellow world text in an h1 element', () => { render(); - const heading = screen.getByText("yellow world"); - expect(heading.tagName).toBe("H1"); + const heading = screen.getByRole('heading', { level: 1 }); + expect(heading).toBeInTheDocument(); + expect(heading).toHaveTextContent('yellow world'); }); - it("applies container class to the wrapper div", () => { + it('applies the container CSS module class to the wrapper div', () => { render(); - const container = screen.getByTestId("app-container"); - expect(container).toHaveClass("container"); + const container = screen.getByTestId('app-container'); + expect(container).toBeInTheDocument(); + expect(container.className).toContain('container'); }); - it("applies heading class to the h1 element", () => { + it('applies the heading CSS module class to the h1 element', () => { render(); - const heading = screen.getByText("yellow world"); - expect(heading).toHaveClass("heading"); + const heading = screen.getByTestId('app-heading'); + expect(heading).toBeInTheDocument(); + expect(heading.className).toContain('heading'); }); - it("has a data-testid attribute on the container", () => { + it('renders the heading inside the container', () => { render(); - const container = screen.getByTestId("app-container"); - expect(container).toBeInTheDocument(); + const container = screen.getByTestId('app-container'); + const heading = screen.getByTestId('app-heading'); + expect(container).toContainElement(heading); + }); + + it('renders exactly one h1 element', () => { + const { container } = render(); + const headings = container.querySelectorAll('h1'); + expect(headings).toHaveLength(1); + }); + + it('has the correct text content without extra whitespace', () => { + render(); + const heading = screen.getByTestId('app-heading'); + expect(heading.textContent?.trim()).toBe('yellow world'); + }); + + it('container and heading have distinct CSS module classes', () => { + render(); + const container = screen.getByTestId('app-container'); + const heading = screen.getByTestId('app-heading'); + expect(container.className).not.toBe(heading.className); + }); + + it('container element is a div', () => { + render(); + const container = screen.getByTestId('app-container'); + expect(container.tagName).toBe('DIV'); + }); + + it('heading element is an h1', () => { + render(); + const heading = screen.getByTestId('app-heading'); + expect(heading.tagName).toBe('H1'); }); }); diff --git a/src/main.css b/src/main.css index 705b730..8d492b3 100644 --- a/src/main.css +++ b/src/main.css @@ -1,18 +1,12 @@ -/** - * Global base styles. - * - * Resets body margin and defines the default font family for the - * entire application. - */ +/* Global reset and base styles */ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, - "Helvetica Neue", Arial, sans-serif; +* { + box-sizing: border-box; } -*, -*::before, -*::after { - box-sizing: border-box; +body { + margin: 0; + padding: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + 'Helvetica Neue', Arial, sans-serif; } diff --git a/src/main.tsx b/src/main.tsx index 25df5ef..c806033 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,16 +1,14 @@ -import React from "react"; -import ReactDOM from "react-dom/client"; -import App from "./App"; -import "./main.css"; +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; +import './main.css'; /** * Application entry point. - * - * Imports global styles and renders the root App component into the - * #root element defined in index.html. + * Mounts the root component into the #root DOM element. */ -ReactDOM.createRoot(document.getElementById("root")!).render( +ReactDOM.createRoot(document.getElementById('root')!).render( - + , ); diff --git a/src/setupTests.ts b/src/setupTests.ts new file mode 100644 index 0000000..c416b59 --- /dev/null +++ b/src/setupTests.ts @@ -0,0 +1,5 @@ +/** + * Test setup file loaded before each test suite. + * Imports jest-dom matchers for enhanced DOM assertions. + */ +import '@testing-library/jest-dom'; diff --git a/tsconfig.json b/tsconfig.json index e05cb43..863f64f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,8 +14,7 @@ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "types": ["vitest/globals"] + "noFallthroughCasesInSwitch": true }, - "include": ["src"] + "include": ["src", "vite-env.d.ts"] } diff --git a/vite-env.d.ts b/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/vite.config.ts b/vite.config.ts index 3f987d1..e1ca860 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,22 +1,21 @@ -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; -/** - * Vite configuration for the Yellow World React/TypeScript project. - * - * Enables the React plugin and configures Vitest for unit testing - * with jsdom as the DOM environment. - */ export default defineConfig({ plugins: [react()], + css: { + modules: { + localsConvention: 'camelCase', + }, + }, test: { globals: true, - environment: "jsdom", - setupFiles: ["./src/__tests__/setup.ts"], + environment: 'jsdom', + setupFiles: ['./src/setupTests.ts'], css: { modules: { - classNameStrategy: "non-scoped", + classNameStrategy: 'non-scoped', }, }, }, -}); +} as any);