-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add tests, coverage, and Codecov CI setup #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| node_modules | ||
| npm-debug.log | ||
| tests | ||
| .git | ||
| .github | ||
| .gitignore | ||
| *.md | ||
| jest.config.js |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,7 +1,17 @@ | ||||||
| FROM node:18-alpine | ||||||
|
|
||||||
| WORKDIR /app | ||||||
|
|
||||||
| COPY package*.json ./ | ||||||
| RUN npm install | ||||||
| COPY . . | ||||||
|
|
||||||
| RUN npm ci --only=production && npm cache clean --force | ||||||
|
|
||||||
| COPY src/ ./src/ | ||||||
| COPY index.js ./ | ||||||
|
|
||||||
| EXPOSE 8080 | ||||||
| ENTRYPOINT ["node", "index.js"] | ||||||
|
|
||||||
| HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ | ||||||
| CMD node -e "require('http').get('http://localhost:8080/health', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})" | ||||||
|
||||||
| CMD node -e "require('http').get('http://localhost:8080/health', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})" | |
| CMD node -e "const http = require('http'); const req = http.get('http://localhost:8080/health', (r) => { r.resume(); process.exit(r.statusCode === 200 ? 0 : 1); }); req.on('error', () => process.exit(1)); req.setTimeout(2500, () => { req.destroy(); process.exit(1); });" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| # Mon Service | ||
|
|
||
| Service Node.js avec architecture modulaire (Entities, Services, Controllers) | ||
|
|
||
| ## Structure du projet | ||
|
|
||
| ``` | ||
| mon-service/ | ||
| ├── src/ | ||
| │ ├── entities/ # Modèles de données (User.js) | ||
| │ ├── services/ # Logique métier (UserService.js) | ||
| │ ├── controllers/ # Gestion des routes (UserController.js) | ||
| ├── tests/ | ||
| │ ├── unit/ # Tests unitaires | ||
| │ ├── web/ # Tests d'intégration web | ||
| ├── index.js # Point d'entrée | ||
| ├── package.json # Dépendances | ||
| ├── Dockerfile # Configuration Docker | ||
| └── jest.config.js # Configuration Jest | ||
| ``` | ||
|
|
||
| ## Installation | ||
|
|
||
| ```bash | ||
| npm install | ||
| ``` | ||
|
|
||
| ## Scripts disponibles | ||
|
|
||
| ```bash | ||
| # Lancer tous les tests avec couverture | ||
| npm test | ||
|
|
||
| # Lancer uniquement les tests unitaires | ||
| npm run test:unit | ||
|
|
||
| # Lancer uniquement les tests web/intégration | ||
| npm run test:web | ||
|
|
||
| # Lancer les tests en mode watch | ||
| npm run test:watch | ||
|
|
||
| # Démarrer le serveur | ||
| npm start | ||
| ``` | ||
|
|
||
| ## Tests | ||
|
|
||
| Le projet inclut : | ||
| - **Tests unitaires** : Validation des entités et logique des services | ||
| - **Tests d'intégration** : Vérification des endpoints API via HTTP | ||
|
|
||
| Couverture minimale requise : 70% | ||
|
|
||
| ### Couverture de code (Jest + Codecov) | ||
|
|
||
| Ce projet est en **Node.js**, donc l'equivalent de JaCoCo est la couverture native de **Jest** (Istanbul). | ||
|
|
||
| - Rapport local HTML : `coverage/lcov-report/index.html` | ||
| - Rapport local machine-readable : `coverage/lcov.info` | ||
|
|
||
| #### Generer un rapport localement | ||
|
|
||
| ```bash | ||
| npm test | ||
| ``` | ||
|
|
||
| Puis ouvrir : | ||
|
|
||
| - `coverage/lcov-report/index.html` | ||
|
|
||
| Vous y verrez : | ||
|
|
||
| - couverture globale (statements, branches, functions, lines) | ||
| - details par fichier | ||
| - lignes couvertes/non couvertes | ||
|
|
||
| #### Upload automatique vers Codecov (GitHub Actions) | ||
|
|
||
| Le workflow `.github/workflows/action.yml` : | ||
|
|
||
| - execute les tests avec couverture | ||
| - upload `coverage/lcov.info` vers Codecov | ||
| - fonctionne sur `push` et `pull_request` (branches `master` et `develop`) | ||
|
|
||
| Pour activer Codecov : | ||
|
|
||
| 1. Connectez le repository sur https://app.codecov.io. | ||
| 2. Si le repo est prive, ajoutez le secret GitHub `CODECOV_TOKEN`. | ||
| 3. Verifiez dans une PR que le statut/rapport de couverture apparait. | ||
|
|
||
| #### Bonnes pratiques | ||
|
|
||
| - Viser au moins 80% en production | ||
| - Tester les cas de succes et d'erreur | ||
| - Ne pas gonfler artificiellement la couverture avec des tests sans valeur | ||
| - Utiliser la couverture comme indicateur, pas comme seul objectif | ||
|
|
||
| ### Lancer les tests | ||
|
|
||
| ```bash | ||
| # Tous les tests | ||
| npm test | ||
|
|
||
| # Uniquement unitaires | ||
| npm run test:unit | ||
|
|
||
| # Uniquement web | ||
| npm run test:web | ||
| ``` | ||
|
|
||
| ## API Endpoints | ||
|
|
||
| | Méthode | Route | Description | | ||
| |---------|-------|-------------| | ||
| | GET | `/` | Message de bienvenue | | ||
| | GET | `/health` | Vérification de santé du service | | ||
| | GET | `/users` | Récupérer tous les utilisateurs | | ||
| | GET | `/users/:id` | Récupérer un utilisateur | | ||
| | POST | `/users` | Créer un utilisateur | | ||
| | PUT | `/users/:id` | Mettre à jour un utilisateur | | ||
| | DELETE | `/users/:id` | Supprimer un utilisateur | | ||
|
Comment on lines
+114
to
+122
|
||
|
|
||
| ### Exemples | ||
|
|
||
| ```bash | ||
| # Créer un utilisateur | ||
| curl -X POST http://localhost:8080/users \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{"name":"John Doe","email":"john@example.com"}' | ||
|
|
||
| # Récupérer les utilisateurs | ||
| curl http://localhost:8080/users | ||
|
|
||
| # Vérifier la santé | ||
| curl http://localhost:8080/health | ||
| ``` | ||
|
|
||
| ## Docker | ||
|
|
||
| ### Build | ||
|
|
||
| ```bash | ||
| docker build -t mon-service:1 . | ||
| ``` | ||
|
|
||
| ### Run | ||
|
|
||
| ```bash | ||
| docker run -p 8080:8080 mon-service:1 | ||
| ``` | ||
|
|
||
| ## CI/CD | ||
|
|
||
| Les tests s'exécutent automatiquement via GitHub Actions pour chaque push et PR. | ||
|
|
||
| Voir `.github/workflows/action.yml` pour la configuration complète. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,41 @@ | ||
| const express = require('express'); | ||
| const UserService = require('./src/services/UserService'); | ||
| const UserController = require('./src/controllers/UserController'); | ||
|
|
||
| const app = express(); | ||
| const PORT = process.env.PORT || 8080; | ||
|
|
||
| // Middleware | ||
| app.use(express.json()); | ||
|
|
||
| // Initialize services and controllers | ||
| const userService = new UserService(); | ||
| const userController = new UserController(userService); | ||
|
|
||
| // Routes | ||
| app.get('/', (req, res) => { | ||
| res.send('Hello from Docker!'); | ||
| res.json({ message: 'Welcome to mon-service API' }); | ||
| }); | ||
|
|
||
| app.get('/health', (req, res) => userController.getHealth(req, res)); | ||
|
|
||
| // User routes | ||
| app.get('/users', (req, res) => userController.getAllUsers(req, res)); | ||
| app.get('/users/:id', (req, res) => userController.getUserById(req, res)); | ||
| app.post('/users', (req, res) => userController.createUser(req, res)); | ||
| app.put('/users/:id', (req, res) => userController.updateUser(req, res)); | ||
| app.delete('/users/:id', (req, res) => userController.deleteUser(req, res)); | ||
|
|
||
| // Error handling | ||
| app.use((req, res) => { | ||
| res.status(404).json({ error: 'Not found' }); | ||
| }); | ||
|
|
||
| app.listen(8080, () => { | ||
| console.log('Server running on port 8080'); | ||
| }); | ||
| // Start server only when running this file directly. | ||
| if (require.main === module) { | ||
| app.listen(PORT, () => { | ||
| console.log(`Server running on port ${PORT}`); | ||
| }); | ||
| } | ||
|
|
||
| module.exports = app; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| module.exports = { | ||
| testEnvironment: 'node', | ||
| collectCoverageFrom: [ | ||
| 'src/**/*.js', | ||
| '!src/**/*.test.js' | ||
| ], | ||
| coveragePathIgnorePatterns: [ | ||
| '/node_modules/', | ||
| '/tests/' | ||
| ], | ||
| coverageThreshold: { | ||
| global: { | ||
| branches: 70, | ||
| functions: 70, | ||
| lines: 70, | ||
| statements: 70 | ||
| } | ||
| }, | ||
| testMatch: [ | ||
| '**/tests/**/*.test.js' | ||
| ] | ||
| }; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CI runs the test suite multiple times (unit, web, then all again for coverage), which increases duration and compute cost. Consider running only
npm test(coverage) and, if you still want separate visibility, use Jest projects/groups or split bytestMatchwhile generating coverage once.