From c38a6c4e63dc1682839df49b9ad93788447cec15 Mon Sep 17 00:00:00 2001 From: Fred <98240+farnoux@users.noreply.github.com> Date: Tue, 22 Oct 2024 11:05:30 +0200 Subject: [PATCH 1/2] refac(backend): Make Configuration a separate module --- backend/src/app.module.ts | 13 ++++----- backend/src/auth/auth.module.ts | 2 ++ backend/src/auth/guards/auth.guard.ts | 12 ++++----- backend/src/common/common.module.ts | 9 +++---- .../services/backend-configuration.service.ts | 27 ------------------- .../src/common/services/database.service.ts | 22 ++++++--------- .../src/common/services/supabase.service.ts | 15 +++++------ .../configuration.model.ts} | 0 backend/src/config/configuration.module.ts | 10 +++++++ backend/src/config/configuration.service.ts | 21 +++++++++++++++ backend/src/config/configuration.ts | 5 ++++ .../controllers/fiches-action.controller.ts | 16 +++++------ backend/src/indicateurs/indicateurs.module.ts | 4 ++- .../trajectoires-spreadsheet.service.ts | 16 +++++------ .../services/trajectoires-xlsx.service.ts | 10 +++---- 15 files changed, 88 insertions(+), 94 deletions(-) delete mode 100644 backend/src/common/services/backend-configuration.service.ts rename backend/src/{common/models/backend-configuration.models.ts => config/configuration.model.ts} (100%) create mode 100644 backend/src/config/configuration.module.ts create mode 100644 backend/src/config/configuration.service.ts create mode 100644 backend/src/config/configuration.ts diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index 38b4409e02..c4435911c0 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -3,29 +3,30 @@ import { ConfigModule } from '@nestjs/config'; import { AuthModule } from './auth/auth.module'; import { CollectivitesModule } from './collectivites/collectivites.module'; import { CommonModule } from './common/common.module'; -import { validateBackendConfiguration } from './common/services/backend-configuration.service'; +import configuration from './config/configuration'; import { FichesActionModule } from './fiches/fiches-action.module'; import { IndicateursModule } from './indicateurs/indicateurs.module'; import { SheetModule } from './spreadsheets/sheet.module'; -import { TrpcRouter } from './trpc.router'; import { TrpcModule } from './trpc/trpc.module'; +import { ConfigurationModule } from './config/configuration.module'; +import { TrpcRouter } from './trpc.router'; @Module({ imports: [ ConfigModule.forRoot({ ignoreEnvFile: process.env.NODE_ENV === 'production', // In production, environment variables are set by the deployment - validate: validateBackendConfiguration, + // validate: validateBackendConfiguration, + load: [configuration], }), - TrpcModule, + ConfigurationModule, CommonModule, + TrpcModule, SheetModule, CollectivitesModule, IndicateursModule, AuthModule, FichesActionModule, ], - controllers: [], - exports: [TrpcRouter], providers: [TrpcRouter], }) export class AppModule {} diff --git a/backend/src/auth/auth.module.ts b/backend/src/auth/auth.module.ts index 268948c6d4..1ac7a4ea71 100644 --- a/backend/src/auth/auth.module.ts +++ b/backend/src/auth/auth.module.ts @@ -4,6 +4,7 @@ import { JwtModule } from '@nestjs/jwt'; import { CommonModule } from '../common/common.module'; import { AuthGuard } from './guards/auth.guard'; import { AuthService } from './services/auth.service'; +import { ConfigurationModule } from '../config/configuration.module'; @Module({ imports: [ @@ -11,6 +12,7 @@ import { AuthService } from './services/auth.service'; global: true, secret: process.env.SUPABASE_JWT_SECRET, }), + ConfigurationModule, CommonModule, ], providers: [ diff --git a/backend/src/auth/guards/auth.guard.ts b/backend/src/auth/guards/auth.guard.ts index 7a0b9eeaa0..f7dbcb06b2 100644 --- a/backend/src/auth/guards/auth.guard.ts +++ b/backend/src/auth/guards/auth.guard.ts @@ -8,7 +8,7 @@ import { import { Reflector } from '@nestjs/core'; import { JwtService } from '@nestjs/jwt'; import { Request } from 'express'; -import BackendConfigurationService from '../../common/services/backend-configuration.service'; +import BackendConfigurationService from '../../config/configuration.service'; import { getErrorMessage } from '../../common/services/errors.helper'; import { PublicEndpoint } from '../decorators/public-endpoint.decorator'; import { SupabaseJwtPayload } from '../models/auth.models'; @@ -19,7 +19,7 @@ export class AuthGuard implements CanActivate { constructor( private jwtService: JwtService, private reflector: Reflector, - private backendConfigurationService: BackendConfigurationService, + private configService: BackendConfigurationService ) {} async canActivate(context: ExecutionContext): Promise { @@ -27,7 +27,7 @@ export class AuthGuard implements CanActivate { const publicEndpoint = this.reflector.get( PublicEndpoint, - context.getHandler(), + context.getHandler() ); if (publicEndpoint) { @@ -43,10 +43,8 @@ export class AuthGuard implements CanActivate { const payload: SupabaseJwtPayload = await this.jwtService.verifyAsync( token, { - secret: - this.backendConfigurationService.getBackendConfiguration() - .SUPABASE_JWT_SECRET, - }, + secret: this.configService.get('SUPABASE_JWT_SECRET'), + } ); // 💡 We're assigning the payload to the request object here // so that we can access it in our route handlers diff --git a/backend/src/common/common.module.ts b/backend/src/common/common.module.ts index 4df1b08705..8be8ff11d0 100644 --- a/backend/src/common/common.module.ts +++ b/backend/src/common/common.module.ts @@ -1,13 +1,12 @@ import { Module } from '@nestjs/common'; -import { ConfigModule } from '@nestjs/config'; +import { ConfigurationModule } from '../config/configuration.module'; import { VersionController } from './controllers/version.controller'; -import BackendConfigurationService from './services/backend-configuration.service'; import DatabaseService from './services/database.service'; @Module({ - imports: [ConfigModule], - providers: [ConfigModule, BackendConfigurationService, DatabaseService], - exports: [DatabaseService, BackendConfigurationService], + imports: [ConfigurationModule], + providers: [DatabaseService], + exports: [DatabaseService], controllers: [VersionController], }) export class CommonModule {} diff --git a/backend/src/common/services/backend-configuration.service.ts b/backend/src/common/services/backend-configuration.service.ts deleted file mode 100644 index 13cc7f5864..0000000000 --- a/backend/src/common/services/backend-configuration.service.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { - backendConfigurationSchema, - BackendConfigurationType, -} from '../models/backend-configuration.models'; - -@Injectable() -export default class BackendConfigurationService { - private readonly logger = new Logger(BackendConfigurationService.name); - - constructor(private readonly configService: ConfigService) {} - - getBackendConfiguration(): BackendConfigurationType { - return backendConfiguration; - } -} - -const logger = new Logger(BackendConfigurationService.name); -let backendConfiguration: BackendConfigurationType; -export const validateBackendConfiguration = ( - config: Record, -) => { - logger.log('Validating backend configuration'); - backendConfiguration = backendConfigurationSchema.parse(config); - return config; -}; diff --git a/backend/src/common/services/database.service.ts b/backend/src/common/services/database.service.ts index 317d853f54..cfee8d3ff8 100644 --- a/backend/src/common/services/database.service.ts +++ b/backend/src/common/services/database.service.ts @@ -1,7 +1,7 @@ import { Injectable, Logger, OnApplicationShutdown } from '@nestjs/common'; import { drizzle, PostgresJsDatabase } from 'drizzle-orm/postgres-js'; import { default as postgres } from 'postgres'; -import BackendConfigurationService from './backend-configuration.service'; +import ConfigurationService from '../../config/configuration.service'; @Injectable() export default class DatabaseService implements OnApplicationShutdown { @@ -9,20 +9,14 @@ export default class DatabaseService implements OnApplicationShutdown { public readonly db: PostgresJsDatabase; private readonly client: postgres.Sql; - constructor( - private readonly backendConfigurationService: BackendConfigurationService - ) { + constructor(private readonly configService: ConfigurationService) { this.logger.log(`Initializing database service`); - this.client = postgres( - backendConfigurationService.getBackendConfiguration() - .SUPABASE_DATABASE_URL, - { - prepare: false, - connection: { - application_name: `Backend ${process.env.APPLICATION_VERSION}`, - }, - } - ); + this.client = postgres(this.configService.get('SUPABASE_DATABASE_URL'), { + prepare: false, + connection: { + application_name: `Backend ${process.env.APPLICATION_VERSION}`, + }, + }); this.db = drizzle(this.client); } diff --git a/backend/src/common/services/supabase.service.ts b/backend/src/common/services/supabase.service.ts index bd0b03eaf3..a4fa8b4d5e 100644 --- a/backend/src/common/services/supabase.service.ts +++ b/backend/src/common/services/supabase.service.ts @@ -1,6 +1,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { createClient } from '@supabase/supabase-js'; -import BackendConfigurationService from './backend-configuration.service'; +import ConfigurationService from '../../config/configuration.service'; import { Database, DBClient } from '@tet/api'; @Injectable() @@ -9,15 +9,12 @@ export default class SupabaseService { public readonly client: DBClient; - constructor(backendConfigurationService: BackendConfigurationService) { - const backendConfiguration = - backendConfigurationService.getBackendConfiguration(); - this.logger.log( - `Initializing supabase service with url: ${backendConfiguration.SUPABASE_URL}` - ); + constructor(configService: ConfigurationService) { + const supabaseUrl = configService.get('SUPABASE_URL'); + this.logger.log(`Initializing supabase service with url: ${supabaseUrl}`); this.client = createClient( - backendConfiguration.SUPABASE_URL, - backendConfiguration.SUPABASE_SERVICE_ROLE_KEY + supabaseUrl, + configService.get('SUPABASE_SERVICE_ROLE_KEY') ); } } diff --git a/backend/src/common/models/backend-configuration.models.ts b/backend/src/config/configuration.model.ts similarity index 100% rename from backend/src/common/models/backend-configuration.models.ts rename to backend/src/config/configuration.model.ts diff --git a/backend/src/config/configuration.module.ts b/backend/src/config/configuration.module.ts new file mode 100644 index 0000000000..f6a34547f9 --- /dev/null +++ b/backend/src/config/configuration.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import ConfigurationService from './configuration.service'; + +@Module({ + imports: [ConfigModule.forRoot()], + providers: [ConfigurationService], + exports: [ConfigurationService], +}) +export class ConfigurationModule {} diff --git a/backend/src/config/configuration.service.ts b/backend/src/config/configuration.service.ts new file mode 100644 index 0000000000..be71207cdb --- /dev/null +++ b/backend/src/config/configuration.service.ts @@ -0,0 +1,21 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { BackendConfigurationType } from './configuration.model'; + +@Injectable() +export default class ConfigurationService { + private readonly logger = new Logger(ConfigurationService.name); + + constructor( + private readonly configService: ConfigService< + BackendConfigurationType, + true + > + ) { + this.logger.log(`Initializing configuration service`); + } + + get(key: keyof BackendConfigurationType) { + return this.configService.get(key); + } +} diff --git a/backend/src/config/configuration.ts b/backend/src/config/configuration.ts new file mode 100644 index 0000000000..30a257cd1b --- /dev/null +++ b/backend/src/config/configuration.ts @@ -0,0 +1,5 @@ +import { backendConfigurationSchema } from './configuration.model'; + +export default () => ({ + ...backendConfigurationSchema.parse(process.env), +}); diff --git a/backend/src/fiches/controllers/fiches-action.controller.ts b/backend/src/fiches/controllers/fiches-action.controller.ts index 6a219b05c8..e33b1915c5 100644 --- a/backend/src/fiches/controllers/fiches-action.controller.ts +++ b/backend/src/fiches/controllers/fiches-action.controller.ts @@ -2,7 +2,7 @@ import { createZodDto } from '@anatine/zod-nestjs'; import { Controller, Get, Param, Query } from '@nestjs/common'; import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { TokenInfo } from '../../auth/decorators/token-info.decorators'; -import { SupabaseJwtPayload } from '../../auth/models/auth.models'; +import type { SupabaseJwtPayload } from '../../auth/models/auth.models'; import { getFichesActionSyntheseSchema } from '../models/get-fiches-action-synthese.response'; import { getFichesActionFilterRequestSchema } from '../models/get-fiches-actions-filter.request'; import FichesActionSyntheseService from '../services/fiches-action-synthese.service'; @@ -11,17 +11,17 @@ import FichesActionSyntheseService from '../services/fiches-action-synthese.serv * CrĂ©ation des classes de rĂ©ponse Ă  partir du schema pour gĂ©nĂ©rer automatiquement la documentation OpenAPI */ export class GetFichesActionSyntheseResponseClass extends createZodDto( - getFichesActionSyntheseSchema, + getFichesActionSyntheseSchema ) {} export class GetFichesActionFilterRequestClass extends createZodDto( - getFichesActionFilterRequestSchema, + getFichesActionFilterRequestSchema ) {} @ApiTags('Fiches action') @Controller('collectivites/:collectivite_id/fiches-action') export class FichesActionController { constructor( - private readonly fichesActionSyntheseService: FichesActionSyntheseService, + private readonly fichesActionSyntheseService: FichesActionSyntheseService ) {} @Get('synthese') @@ -33,12 +33,12 @@ export class FichesActionController { async getFichesActionSynthese( @Param('collectivite_id') collectiviteId: number, @Query() request: GetFichesActionFilterRequestClass, - @TokenInfo() tokenInfo: SupabaseJwtPayload, + @TokenInfo() tokenInfo: SupabaseJwtPayload ) { return this.fichesActionSyntheseService.getFichesActionSynthese( collectiviteId, request, - tokenInfo, + tokenInfo ); } @@ -50,12 +50,12 @@ export class FichesActionController { async getFichesAction( @Param('collectivite_id') collectiviteId: number, @Query() request: GetFichesActionFilterRequestClass, - @TokenInfo() tokenInfo: SupabaseJwtPayload, + @TokenInfo() tokenInfo: SupabaseJwtPayload ) { return this.fichesActionSyntheseService.getFichesAction( collectiviteId, request, - tokenInfo, + tokenInfo ); } } diff --git a/backend/src/indicateurs/indicateurs.module.ts b/backend/src/indicateurs/indicateurs.module.ts index 607af82596..3a3c11747e 100644 --- a/backend/src/indicateurs/indicateurs.module.ts +++ b/backend/src/indicateurs/indicateurs.module.ts @@ -12,11 +12,13 @@ import IndicateurSourcesService from './services/indicateurSources.service'; import TrajectoiresDataService from './services/trajectoires-data.service'; import TrajectoiresSpreadsheetService from './services/trajectoires-spreadsheet.service'; import TrajectoiresXlsxService from './services/trajectoires-xlsx.service'; +import { ConfigurationModule } from '../config/configuration.module'; @Module({ imports: [ - TrpcModule, + ConfigurationModule, CommonModule, + TrpcModule, AuthModule, CollectivitesModule, SheetModule, diff --git a/backend/src/indicateurs/services/trajectoires-spreadsheet.service.ts b/backend/src/indicateurs/services/trajectoires-spreadsheet.service.ts index de5a76074f..1258e92e92 100644 --- a/backend/src/indicateurs/services/trajectoires-spreadsheet.service.ts +++ b/backend/src/indicateurs/services/trajectoires-spreadsheet.service.ts @@ -10,8 +10,8 @@ import slugify from 'slugify'; import { SupabaseJwtPayload } from '../../auth/models/auth.models'; import { EpciType } from '../../collectivites/models/collectivite.models'; import GroupementsService from '../../collectivites/services/groupements.service'; -import { BackendConfigurationType } from '../../common/models/backend-configuration.models'; -import BackendConfigurationService from '../../common/services/backend-configuration.service'; +import { BackendConfigurationType } from '../../config/configuration.model'; +import ConfigurationService from '../../config/configuration.service'; import SheetService from '../../spreadsheets/services/sheet.service'; import { CalculTrajectoireRequestType, @@ -33,25 +33,21 @@ import TrajectoiresDataService from './trajectoires-data.service'; export default class TrajectoiresSpreadsheetService { private readonly logger = new Logger(TrajectoiresSpreadsheetService.name); private readonly TRAJECTOIRE_GROUPEMENT = 'trajectoire'; - private readonly backendConfiguration: BackendConfigurationType; constructor( - backendConfigurationService: BackendConfigurationService, + private readonly configService: ConfigurationService, private readonly indicateurSourcesService: IndicateurSourcesService, private readonly indicateursService: IndicateursService, private readonly trajectoiresDataService: TrajectoiresDataService, private readonly sheetService: SheetService, private readonly groupementsService: GroupementsService - ) { - this.backendConfiguration = - backendConfigurationService.getBackendConfiguration(); - } + ) {} getIdentifiantSpreadsheetCalcul() { - return this.backendConfiguration.TRAJECTOIRE_SNBC_SHEET_ID; + return this.configService.get('TRAJECTOIRE_SNBC_SHEET_ID'); } getIdentifiantDossierResultat() { - return this.backendConfiguration.TRAJECTOIRE_SNBC_RESULT_FOLDER_ID; + return this.configService.get('TRAJECTOIRE_SNBC_RESULT_FOLDER_ID'); } getNomFichierTrajectoire(epci: EpciType) { diff --git a/backend/src/indicateurs/services/trajectoires-xlsx.service.ts b/backend/src/indicateurs/services/trajectoires-xlsx.service.ts index 879b3d4f6e..78f7d06425 100644 --- a/backend/src/indicateurs/services/trajectoires-xlsx.service.ts +++ b/backend/src/indicateurs/services/trajectoires-xlsx.service.ts @@ -9,8 +9,7 @@ import { default as XlsxTemplate } from 'xlsx-template'; import { SupabaseJwtPayload } from '../../auth/models/auth.models'; import { EpciType } from '../../collectivites/models/collectivite.models'; import { CollectiviteRequestType } from '../../collectivites/models/collectivite.request'; -import { BackendConfigurationType } from '../../common/models/backend-configuration.models'; -import BackendConfigurationService from '../../common/services/backend-configuration.service'; +import BackendConfigurationService from '../../config/configuration.service'; import SheetService from '../../spreadsheets/services/sheet.service'; import { DonneesCalculTrajectoireARemplirType, @@ -25,20 +24,17 @@ export default class TrajectoiresXlsxService { private xlsxModeleBuffer: Buffer | null = null; private xlsxVideBuffer: Buffer | null = null; - private readonly backendConfiguration: BackendConfigurationType; constructor( - backendConfigurationService: BackendConfigurationService, + private readonly configService: BackendConfigurationService, private readonly sheetService: SheetService, private readonly trajectoiresDataService: TrajectoiresDataService ) { - this.backendConfiguration = - backendConfigurationService.getBackendConfiguration(); this.initXlsxBuffers(); } getIdentifiantXlsxCalcul() { - return this.backendConfiguration.TRAJECTOIRE_SNBC_XLSX_ID; + return this.configService.get('TRAJECTOIRE_SNBC_XLSX_ID'); } getNomFichierTrajectoire(epci: EpciType) { From a316783c46e2fbda47c72555001e6fd46e442e7c Mon Sep 17 00:00:00 2001 From: Fred <98240+farnoux@users.noreply.github.com> Date: Tue, 22 Oct 2024 12:00:27 +0200 Subject: [PATCH 2/2] test(backend): Fix vitest configuration --- backend/.env.default | 17 ++++++- backend/README.md | 44 +++++++++++++---- backend/test/.env.default | 8 ---- .../test/indicateurs/indicateurs.e2e-spec.ts | 8 ++-- .../indicateurs/trajectoire-snbc.e2e-spec.ts | 18 +++---- backend/tsconfig.spec.json | 1 - backend/vitest.config.mts | 24 +++++----- package.json | 3 +- pnpm-lock.yaml | 48 ++++++++++++++++++- 9 files changed, 125 insertions(+), 46 deletions(-) delete mode 100644 backend/test/.env.default diff --git a/backend/.env.default b/backend/.env.default index bf64b11d4c..b030e8a0a3 100644 --- a/backend/.env.default +++ b/backend/.env.default @@ -1,8 +1,21 @@ +#Identifiant du Google spreadsheet utilisĂ© pour le calcul de la trajectoire. TRAJECTOIRE_SNBC_SHEET_ID= + +# Identifiant du Xlsx original utilisĂ© pour le calcul de la trajectoire (stockĂ© sur le drive) TRAJECTOIRE_SNBC_XLSX_ID= + +# Identifiant du dossier Google Drive dans lequel les spreadsheets des trajectoires calculĂ©es doivent ĂȘtre sauvĂ©s (un fichier par EPCI). +# Il existe un dossier par environnement (dev, preprod, prod). TRAJECTOIRE_SNBC_RESULT_FOLDER_ID= + +# Contenu au format json du fichier de clĂ© de compte de service permettant l'utilisation des api Google Drive et Google Spreadsheet GCLOUD_SERVICE_ACCOUNT_KEY= -SUPABASE_DATABASE_URL=postgresql://postgres:postgres@localhost:54322/postgres + +# ClĂ© de signature des tokens jwt. UtilisĂ© pour vĂ©rifier la signature des tokens. SUPABASE_JWT_SECRET=super-secret-jwt-token-with-at-least-32-characters-long + +# Supabase database connection credentials +SUPABASE_DATABASE_URL=postgresql://postgres:postgres@localhost:54322/postgres SUPABASE_URL=http://127.0.0.1:54321 -SUPABASE_SERVICE_ROLE_KEY= \ No newline at end of file +SUPABASE_SERVICE_ROLE_KEY= +SUPABASE_ANON_KEY= diff --git a/backend/README.md b/backend/README.md index 079cc7cece..202cb76da2 100644 --- a/backend/README.md +++ b/backend/README.md @@ -6,18 +6,24 @@ Backend de territoires en transitions basĂ© sur [Nest](https://github.com/nestjs ## Configuration -Les variables d'environnement suivantes doivent ĂȘtre dĂ©finies dans un fichier .env (voir le fichier [.env.default](.env.default)): +Les variables d'environnement du fichier [.env.default](.env.default) doivent ĂȘtre dĂ©finies dans un fichier `.env` Ă  la racine. -- **TRAJECTOIRE_SNBC_SHEET_ID**: Identifiant du Google spreadsheet utilisĂ© pour le calcul de la trajectoire. -- **TRAJECTOIRE_SNBC_XLSX_ID**: Identifiant du Xlsx original utilisĂ© pour le calcul de la trajectoire (stockĂ© sur le drive) -- **TRAJECTOIRE_SNBC_RESULT_FOLDER_ID**: Identifiant du dossier Google Drive dans lequel les spreadsheets des trajectoires calculĂ©es doivent ĂȘtre sauvĂ©s (un fichier par EPCI). A noter qu'il existe **un dossier par environnement** (dev, preprod, prod). -- **GCLOUD_SERVICE_ACCOUNT_KEY**: contenu au format json du fichier de clĂ© de compte de service permettant l'utilisation des api Google Drive et Google Spreadsheet. -- **SUPABASE_JWT_SECRET**: clĂ© de signature des tokens jwt. UtilisĂ© pour vĂ©rifier la signature des tokens. +Les variables d'environnement suivantes sont dĂ©finies: -Ces variables d'environnement sont dĂ©finies: +- Dans les [variables d'environnement de Github](https://github.com/incubateur-ademe/territoires-en-transitions/settings/environments/1431973268/edit) utilisĂ©es pour configurer le [dĂ©ploiement Koyeb](https://app.koyeb.com/services/c7001069-ca11-4fd7-86c6-7feb45b9b68d/settings) pour : -- pour **TRAJECTOIRE_SNBC_SHEET_ID**, **TRAJECTOIRE_SNBC_XLSX_ID** et **TRAJECTOIRE_SNBC_RESULT_FOLDER_ID** dans les [variables d'environnement de Github](https://github.com/incubateur-ademe/territoires-en-transitions/settings/environments/1431973268/edit) utilisĂ©es pour configurer le [dĂ©ploiement Koyeb](https://app.koyeb.com/services/c7001069-ca11-4fd7-86c6-7feb45b9b68d/settings). Les identifiants peuvent Ă©galement ĂȘtre rĂ©cupĂ©rĂ©s Ă  partir du drive de `territoiresentransitions`. -- pour **GCLOUD_SERVICE_ACCOUNT_KEY**, **SUPABASE_JWT_SECRET** et **SUPABASE_SERVICE_ROLE_KEY** dans le [gestionnaire de secret de Koyeb](https://app.koyeb.com/secrets) + - `TRAJECTOIRE_SNBC_SHEET_ID` + - `TRAJECTOIRE_SNBC_XLSX_ID` + - `TRAJECTOIRE_SNBC_RESULT_FOLDER_ID` + + Les identifiants peuvent Ă©galement ĂȘtre rĂ©cupĂ©rĂ©s Ă  partir du drive de `territoiresentransitions`. + +- Dans le [gestionnaire de secret de Koyeb](https://app.koyeb.com/secrets) pour : + + - `GCLOUD_SERVICE_ACCOUNT_KEY` + - `SUPABASE_JWT_SECRET` + - `SUPABASE_SERVICE_ROLE_KEY` + - `SUPABASE_ANON_KEY` ## Scripts disponibles @@ -37,3 +43,23 @@ $ pnpm test:backend # Ou directement avec Nx $ nx test @tet/backend ``` + +### Tests + +Pour lancer tous les tests : + +``` +nx test @tet/backend +``` + +Pour lancer uniquement les tests unitaires (dossier `src`) : + +``` +nx test @tet/backend src +``` + +Pour lancer uniquement les tests end-to-end (dossier `test`) : + +``` +nx test @tet/backend test +``` diff --git a/backend/test/.env.default b/backend/test/.env.default deleted file mode 100644 index b9239260a1..0000000000 --- a/backend/test/.env.default +++ /dev/null @@ -1,8 +0,0 @@ -TRAJECTOIRE_SNBC_SHEET_ID= -TRAJECTOIRE_SNBC_XLSX_ID= -TRAJECTOIRE_SNBC_RESULT_FOLDER_ID= -GCLOUD_SERVICE_ACCOUNT_KEY= -JWT_SECRET= -SUPABASE_URL= -SUPABASE_ANON_KEY= -SUPABASE_SERVICE_ROLE_KEY= \ No newline at end of file diff --git a/backend/test/indicateurs/indicateurs.e2e-spec.ts b/backend/test/indicateurs/indicateurs.e2e-spec.ts index 3dfea4e36d..49147cd721 100644 --- a/backend/test/indicateurs/indicateurs.e2e-spec.ts +++ b/backend/test/indicateurs/indicateurs.e2e-spec.ts @@ -29,6 +29,10 @@ describe('Route de lecture / ecriture des indicateurs', () => { yoloDodoToken = signinResponse.data.session?.access_token || ''; }); + afterAll(async () => { + await app.close(); + }); + it(`Lecture sans acces`, () => { return request(app.getHttpServer()) .get('/indicateurs?collectivite_id=3') @@ -71,8 +75,4 @@ describe('Route de lecture / ecriture des indicateurs', () => { statusCode: 401, }); }); - - afterAll(async () => { - await app.close(); - }); }); diff --git a/backend/test/indicateurs/trajectoire-snbc.e2e-spec.ts b/backend/test/indicateurs/trajectoire-snbc.e2e-spec.ts index dbf606f98a..c881365d3c 100644 --- a/backend/test/indicateurs/trajectoire-snbc.e2e-spec.ts +++ b/backend/test/indicateurs/trajectoire-snbc.e2e-spec.ts @@ -1,8 +1,8 @@ import { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { createClient, SupabaseClient } from '@supabase/supabase-js'; -import * as _ from 'lodash'; -import * as request from 'supertest'; +import { default as _ } from 'lodash'; +import { default as request } from 'supertest'; import { AppModule } from '../../src/app.module'; import { CalculTrajectoireResultatMode, @@ -27,11 +27,13 @@ describe('Calcul de trajectoire SNBC', () => { supabase = createClient( process.env.SUPABASE_URL!, - process.env.SUPABASE_ANON_KEY!, + process.env.SUPABASE_ANON_KEY! ); + const signinResponse = await supabase.auth.signInWithPassword( - YOLO_DODO_CREDENTIALS, + YOLO_DODO_CREDENTIALS ); + yoloDodoToken = signinResponse.data.session?.access_token || ''; }); @@ -262,7 +264,7 @@ describe('Calcul de trajectoire SNBC', () => { }; return request(app.getHttpServer()) .get( - '/trajectoires/snbc/verification?collectivite_id=3829&epci_info=true', + '/trajectoires/snbc/verification?collectivite_id=3829&epci_info=true' ) .set('Authorization', `Bearer ${process.env.SUPABASE_SERVICE_ROLE_KEY}`) .expect(200) @@ -478,7 +480,7 @@ describe('Calcul de trajectoire SNBC', () => { }; request(app.getHttpServer()) .get( - '/trajectoires/snbc/verification?collectivite_id=4936&epci_info=true', + '/trajectoires/snbc/verification?collectivite_id=4936&epci_info=true' ) .set('Authorization', `Bearer ${yoloDodoToken}`) .expect(200) @@ -517,7 +519,7 @@ describe('Calcul de trajectoire SNBC', () => { // Si on requĂȘte de nouveau le calcul, il doit provenir de la base de donnĂ©es const trajectoireSnbcCalculRetourExistant = _.cloneDeep( - trajectoireSnbcCalculRetour, + trajectoireSnbcCalculRetour ); trajectoireSnbcCalculRetourExistant.mode = CalculTrajectoireResultatMode.DONNEES_EN_BDD; @@ -545,7 +547,7 @@ describe('Calcul de trajectoire SNBC', () => { .split('filename=')[1] .split(';')[0]; expect(fileName).toBe( - '"Trajectoire SNBC - 246700488 - Eurome?tropole de Strasbourg.xlsx"', + '"Trajectoire SNBC - 246700488 - Eurome?tropole de Strasbourg.xlsx"' ); }, 30000); diff --git a/backend/tsconfig.spec.json b/backend/tsconfig.spec.json index 5aae4f1f75..7123030d57 100644 --- a/backend/tsconfig.spec.json +++ b/backend/tsconfig.spec.json @@ -11,7 +11,6 @@ ] }, "include": [ - "vitest.config.mts", "vitest.config.mts", "src/**/*.test.ts", "src/**/*.spec.ts", diff --git a/backend/vitest.config.mts b/backend/vitest.config.mts index d7b97eea39..da422d8274 100644 --- a/backend/vitest.config.mts +++ b/backend/vitest.config.mts @@ -1,22 +1,22 @@ /// -import { defineConfig } from 'vitest/config'; + import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; +import swc from 'unplugin-swc'; +import { loadEnv } from 'vite'; +import { defineConfig } from 'vitest/config'; -export default defineConfig({ +export default defineConfig(({ mode }) => ({ root: __dirname, - cacheDir: '../node_modules/.vite/backend', + cacheDir: '../node_modules/.vite/apps/backend', - plugins: [nxViteTsPaths()], - - // Uncomment this if you are using workers. - // worker: { - // plugins: [ nxViteTsPaths() ], - // }, + plugins: [nxViteTsPaths(), swc.vite()], test: { + fileParallelism: false, watch: false, globals: true, - environment: 'jsdom', + env: loadEnv(mode, process.cwd(), ''), + include: [ 'src/**/*.{test,spec,e2e-spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}', './test/**/*.e2e-spec.ts', @@ -24,8 +24,8 @@ export default defineConfig({ reporters: ['default'], coverage: { - reportsDirectory: '../coverage/backend', + reportsDirectory: '../coverage/apps/backend', provider: 'v8', }, }, -}); +})); diff --git a/package.json b/package.json index adfed9404e..ed08d01cf5 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,7 @@ "@storybook/test-runner": "^0.19.1", "@swc-node/register": "~1.9.1", "@swc/cli": "~0.3.12", - "@swc/core": "~1.5.7", + "@swc/core": "~1.5.29", "@swc/helpers": "~0.5.11", "@types/async-retry": "^1.4.8", "@types/dompurify": "^2.3.4", @@ -194,6 +194,7 @@ "ts-node": "10.9.1", "tsconfig-paths-webpack-plugin": "^4.1.0", "typescript": "^5.6.2", + "unplugin-swc": "^1.5.1", "vite": "~5.1.8", "vitest": "^1.6.0", "webpack-cli": "^5.1.4" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c624abcbd9..73367cb879 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -421,7 +421,7 @@ importers: specifier: ~0.3.12 version: 0.3.14(@swc/core@1.5.29(@swc/helpers@0.5.13))(chokidar@3.6.0) '@swc/core': - specifier: ~1.5.7 + specifier: ~1.5.29 version: 1.5.29(@swc/helpers@0.5.13) '@swc/helpers': specifier: ~0.5.11 @@ -570,6 +570,9 @@ importers: typescript: specifier: ^5.6.2 version: 5.6.2 + unplugin-swc: + specifier: ^1.5.1 + version: 1.5.1(@swc/core@1.5.29(@swc/helpers@0.5.13))(rollup@2.79.2)(webpack-sources@3.2.3) vite: specifier: ~5.1.8 version: 5.1.8(@types/node@18.16.9)(less@4.1.3)(sass@1.79.3)(stylus@0.59.0)(terser@5.33.0) @@ -3307,6 +3310,15 @@ packages: peerDependencies: rollup: ^1.20.0||^2.0.0 + '@rollup/pluginutils@5.1.2': + resolution: {integrity: sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-android-arm-eabi@4.22.4': resolution: {integrity: sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==} cpu: [arm] @@ -6891,6 +6903,9 @@ packages: estree-walker@1.0.1: resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -8726,6 +8741,10 @@ packages: resolution: {integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + loader-runner@4.3.0: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} @@ -12257,6 +12276,11 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + unplugin-swc@1.5.1: + resolution: {integrity: sha512-/ZLrPNjChhGx3Z95pxJ4tQgfI6rWqukgYHKflrNB4zAV1izOQuDhkTn55JWeivpBxDCoK7M/TStb2aS/14PS/g==} + peerDependencies: + '@swc/core': ^1.2.108 + unplugin@1.14.1: resolution: {integrity: sha512-lBlHbfSFPToDYp9pjXlUEFVxYLaue9f9T1HC+4OHlmj+HnMDdz9oZY+erXfoCe/5V/7gKUSY2jpXPb9S7f0f/w==} engines: {node: '>=14.0.0'} @@ -16652,6 +16676,14 @@ snapshots: picomatch: 2.3.1 rollup: 2.79.2 + '@rollup/pluginutils@5.1.2(rollup@2.79.2)': + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 2.3.1 + optionalDependencies: + rollup: 2.79.2 + '@rollup/rollup-android-arm-eabi@4.22.4': optional: true @@ -21110,6 +21142,8 @@ snapshots: estree-walker@1.0.1: {} + estree-walker@2.0.2: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.6 @@ -23791,6 +23825,8 @@ snapshots: lines-and-columns@2.0.3: {} + load-tsconfig@0.2.5: {} + loader-runner@4.3.0: {} loader-utils@2.0.4: @@ -28132,6 +28168,16 @@ snapshots: unpipe@1.0.0: {} + unplugin-swc@1.5.1(@swc/core@1.5.29(@swc/helpers@0.5.13))(rollup@2.79.2)(webpack-sources@3.2.3): + dependencies: + '@rollup/pluginutils': 5.1.2(rollup@2.79.2) + '@swc/core': 1.5.29(@swc/helpers@0.5.13) + load-tsconfig: 0.2.5 + unplugin: 1.14.1(webpack-sources@3.2.3) + transitivePeerDependencies: + - rollup + - webpack-sources + unplugin@1.14.1(webpack-sources@3.2.3): dependencies: acorn: 8.12.1