diff --git a/README.md b/README.md new file mode 100644 index 0000000..7545d10 --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +# TP CI/CD + +A Node.js application providing a simple greeting service with a REST API. It includes a server built with Express, greeting logic, and comprehensive test +suites (unit, integration, and end-to-end). + +## Features + +- **Greeting Functionality**: Generates personalized greetings via `src/greeting.js`. +- **REST API Server**: Built with Express in `src/server.js`, supporting GET and POST endpoints for greetings. +- **Testing**: Full test coverage with Jest: + - Unit tests in `tests/unit/greeting.test.js`. + - Integration tests in `tests/integration/app.test.js`. + - End-to-end tests in `tests/e2e/e2e.test.js`. +- **Linting**: Configured with ESLint (via `.eslintrc.js` and `.eslintignore`). +- **Node.js Version Management**: Uses `.nvmrc` to specify Node.js v22.19.0. + +## Prerequisites + +- Node.js ≥22.19.0 (use `.nvmrc` with nvm: `nvm use`). +- npm (included with Node.js). + +## Installation + +1. Fork the repository: +2. Install dependencies: + +``` +npm install +``` + +## Usage + +Start the server: + +``` +npm start +``` + +The server runs on port 3000 (or `process.env.PORT`). Endpoints: + +- `GET /hello/:name?`: Returns a greeting (e.g., "Hello world!" or "Hello world! From [name]"). +- `POST /hello`: Expects `x-name` header for the name. + +## Testing + +Run tests with Jest: + +- All tests: `npm test` +- Unit tests: `npm run test:unit` (if defined; otherwise, use `npm test -- tests/unit/`) +- Integration tests: `npm run test:integration` (if defined; otherwise, use `npm test -- tests/integration/`) +- E2E tests: `npm run test:e2e` (if defined; otherwise, use `npm test -- tests/e2e/`) + +## Linting + +Check code quality: + +``` +npm run lint +``` + +## Project Structure + +- `src/greeting.js`: Core greeting logic. +- `src/server.js`: Express server setup. +- `tests/`: Test suites (unit, integration, e2e). +- `.eslintrc.js`: ESLint configuration. +- `.eslintignore`: Files/directories excluded from linting. +- `.nvmrc`: Node.js version specification. +- `package.json`: Project metadata, dependencies, and scripts. + +## Dependencies + +- **Runtime**: Express (web server), Axios (HTTP client), Supertest (testing utility). +- **Dev**: ESLint (linting), Jest (testing). + +## Contributing + +1. Fork the repo. +2. Create a feature branch. +3. Run tests and linting. +4. Submit a pull request. diff --git a/package.json b/package.json index 670ad58..ab6ee2b 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "private": true, "scripts": { "lint": "eslint .", - "test": "jest" + "test": "jest", + "start": "node src/server.js" }, "dependencies": { "express": "^4.18.2", diff --git a/src/greeting.js b/src/greeting.js index 1c8a2a1..943acf7 100644 --- a/src/greeting.js +++ b/src/greeting.js @@ -1,5 +1,13 @@ -function getGreeting() { - return 'Hello world'; +function getGreeting(name) { + const greeting = `Hello world!`; + + if (name) { + const wisher = `From ${name}`; + + return `${greeting} ${wisher}`; + } + + return greeting; } module.exports = { getGreeting }; diff --git a/src/server.js b/src/server.js index a9c5c59..2dcc9ed 100644 --- a/src/server.js +++ b/src/server.js @@ -1,11 +1,19 @@ -const express = require('express'); -const { getGreeting } = require('./greeting'); +const express = require("express"); +const { getGreeting } = require("./greeting"); const app = express(); const PORT = process.env.PORT || 3000; -app.get('/hello', (req, res) => { - res.send(getGreeting()); +app.get("/hello/:name?", (req, res) => { + const name = req.params.name; + + res.send(getGreeting(name)); +}); + +app.post("/hello", (req, res) => { + const name = req.headers["x-name"]; + + res.send(getGreeting(name)); }); if (require.main === module) { diff --git a/tests/e2e/e2e.test.js b/tests/e2e/e2e.test.js index cee3eea..c4e43d1 100644 --- a/tests/e2e/e2e.test.js +++ b/tests/e2e/e2e.test.js @@ -1,9 +1,9 @@ -const axios = require('axios'); -const app = require('../../src/server'); +const axios = require("axios"); +const app = require("../../src/server"); let server; let baseURL; -beforeAll(done => { +beforeAll((done) => { server = app.listen(0, () => { const { port } = server.address(); baseURL = `http://127.0.0.1:${port}`; @@ -11,14 +11,14 @@ beforeAll(done => { }); }); -afterAll(done => { +afterAll((done) => { server.close(done); }); -describe('E2E GET /hello', () => { - it('responds with Hello world', async () => { +describe("E2E GET /hello", () => { + it("responds with Hello world", async () => { const res = await axios.get(`${baseURL}/hello`); expect(res.status).toBe(200); - expect(res.data).toBe('Hello world'); + expect(res.data).toBe("Hello world!"); }); }); diff --git a/tests/integration/app.test.js b/tests/integration/app.test.js index bb10075..20bc570 100644 --- a/tests/integration/app.test.js +++ b/tests/integration/app.test.js @@ -1,10 +1,10 @@ -const request = require('supertest'); -const app = require('../../src/server'); +const request = require("supertest"); +const app = require("../../src/server"); -describe('GET /hello', () => { - it('should return Hello world', async () => { - const res = await request(app).get('/hello'); +describe("GET /hello", () => { + it("should return Hello world", async () => { + const res = await request(app).get("/hello"); expect(res.statusCode).toBe(200); - expect(res.text).toBe('Hello world'); + expect(res.text).toBe("Hello world!"); }); }); diff --git a/tests/unit/greeting.test.js b/tests/unit/greeting.test.js index 779c26e..46204e3 100644 --- a/tests/unit/greeting.test.js +++ b/tests/unit/greeting.test.js @@ -1,7 +1,7 @@ -const { getGreeting } = require('../../src/greeting'); +const { getGreeting } = require("../../src/greeting"); -describe('getGreeting', () => { - it('returns the hello world message', () => { - expect(getGreeting()).toBe('Hello world'); +describe("getGreeting", () => { + it("returns the hello world message", () => { + expect(getGreeting()).toBe("Hello world!"); }); });