diff --git a/.act.secrets.example b/.act.secrets.example new file mode 100644 index 0000000..14cf500 --- /dev/null +++ b/.act.secrets.example @@ -0,0 +1,2 @@ +ROBOT_TOKEN=fake_gitea_token +ENV_URL=fake_env_url diff --git a/.actrc b/.actrc index b0f4a64..c9c13ba 100644 --- a/.actrc +++ b/.actrc @@ -1,3 +1,5 @@ ---container-architecture linux/amd64 --W .gitea/workflows --P ubuntu-latest==ghcr.io/catthehacker/ubuntu:act-latest +--container-architecture linux/arm64 +--workflows .gitea/workflows/ +--platform ubuntu-latest +--secret-file .act.secrets +--env-file .env diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ef8ce16 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +GITEA_SERVER_URL=https://fake-gitea-url.example.com \ No newline at end of file diff --git a/.gitea/workflows/trigger-deploy.yaml b/.gitea/workflows/trigger-deploy.yaml new file mode 100644 index 0000000..3e72ee6 --- /dev/null +++ b/.gitea/workflows/trigger-deploy.yaml @@ -0,0 +1,31 @@ +name: Trigger Deploy Repo +run-name: Trigger deploy + +on: + push: + tags: + - '*' # Se déclenche sur n'importe quel tag + +jobs: + dispatch: + runs-on: ubuntu-latest + + env: + # ------- À ADAPTER ------- + CODE_REF: ${{ gitea.ref }} # branche/tag/sha à récupérer + GITEA_SERVER_URL: https://git.prod.k3s.technostrea.fr # URL du serveur Gitea + # -------------------------- + steps: + - name: Dispatch Signal to ttp-deploy + run: | + # Récupération de la version sans le "refs/tags/" + VERSION=${{ env.CODE_REF }} + + echo "Déclenchement du déploiement pour la version $VERSION sur l'instance ${{ env.GITEA_SERVER_URL }}" + + # Appel API Gitea. + # Notez la structure de l'URL : /api/v1/repos/{owner}/{repo}/dispatches + curl -X POST "${{ env.GITEA_SERVER_URL }}/api/v1/repos/technostrea/trouvetonprofile-deployment/dispatches" \ + -H "Authorization: token ${{ secrets.ROBOT_TOKEN }}" \ + -H "Content-Type: application/json" \ + -d "{\"event_type\": \"build-release\", \"client_payload\": {\"version\": \"$VERSION\"}}" diff --git a/.gitignore b/.gitignore index 62714e8..3f3a096 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,11 @@ logs/*.log pb/data/* src/environments/environment.development.ts + +*.iml +.idea +logs/ +*.log +*.secrets +.act.secrets +.env diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 1052520..ac13549 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -30,7 +30,7 @@ describe('AppComponent', () => { create: jest.fn(), list: jest.fn(), update: jest.fn(), - getByUserId: jest.fn(), + getById: jest.fn(), }; await TestBed.configureTestingModule({ diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 450dd6a..af96bb9 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -2,6 +2,7 @@ import { ApplicationConfig } from '@angular/core'; import { PreloadAllModules, provideRouter, + withComponentInputBinding, withInMemoryScrolling, withPreloading, withViewTransitions, @@ -21,6 +22,8 @@ import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository import { PbUserRepository } from '@app/infrastructure/users/pb-user.repository'; import { AUTH_REPOSITORY_TOKEN } from '@app/infrastructure/authentification/auth-repository.token'; import { PbAuthRepository } from '@app/infrastructure/authentification/pb-auth.repository'; +import { WEB_SHARE_SERVICE_TOKEN } from '@app/infrastructure/shareData/web-share.service.token'; +import { WebShareService } from '@app/infrastructure/shareData/web-share.service'; export const appConfig: ApplicationConfig = { providers: [ @@ -31,7 +34,8 @@ export const appConfig: ApplicationConfig = { withInMemoryScrolling({ scrollPositionRestoration: 'enabled', anchorScrolling: 'enabled', - }) + }), + withComponentInputBinding() ), provideAnimations(), provideHttpClient(withFetch()), @@ -40,6 +44,7 @@ export const appConfig: ApplicationConfig = { { provide: SECTOR_REPOSITORY_TOKEN, useExisting: PbSectorRepository }, { provide: USER_REPOSITORY_TOKEN, useExisting: PbUserRepository }, { provide: AUTH_REPOSITORY_TOKEN, useExisting: PbAuthRepository }, + { provide: WEB_SHARE_SERVICE_TOKEN, useExisting: WebShareService }, provideToastr({ timeOut: 10000, positionClass: 'toast-top-right', diff --git a/src/app/domain/profiles/profile.repository.ts b/src/app/domain/profiles/profile.repository.ts index 440bad0..86ddeeb 100644 --- a/src/app/domain/profiles/profile.repository.ts +++ b/src/app/domain/profiles/profile.repository.ts @@ -4,7 +4,7 @@ import { SearchFilters } from '@app/domain/search/search-filters'; export interface ProfileRepository { list(params?: SearchFilters): Observable; - getByUserId(userId: string): Observable; + getById(profileId: string): Observable; create(profile: Profile): Observable; update(profileId: string, profile: Partial): Observable; } diff --git a/src/app/domain/shareData/share-data.repository.ts b/src/app/domain/shareData/share-data.repository.ts new file mode 100644 index 0000000..0a8d058 --- /dev/null +++ b/src/app/domain/shareData/share-data.repository.ts @@ -0,0 +1,3 @@ +export abstract class ShareDataRepository { + abstract share(shareData: ShareData): void; +} diff --git a/src/app/domain/shareData/share-data.ts b/src/app/domain/shareData/share-data.ts new file mode 100644 index 0000000..27e7625 --- /dev/null +++ b/src/app/domain/shareData/share-data.ts @@ -0,0 +1,5 @@ +export interface ShareData { + title: string; + text: string; + url: string; +} diff --git a/src/app/infrastructure/profiles/pb-profile.repository.ts b/src/app/infrastructure/profiles/pb-profile.repository.ts index 925f89c..2e42615 100644 --- a/src/app/infrastructure/profiles/pb-profile.repository.ts +++ b/src/app/infrastructure/profiles/pb-profile.repository.ts @@ -29,9 +29,9 @@ export class PbProfileRepository implements ProfileRepository { ); } - getByUserId(userId: string): Observable { + getById(userId: string): Observable { return from( - this.pb.collection('profiles').getFirstListItem(`utilisateur="${userId}"`) + this.pb.collection('profiles').getOne(`${userId}`, { expand: 'utilisateur' }) ); } diff --git a/src/app/infrastructure/shareData/web-share.service.token.ts b/src/app/infrastructure/shareData/web-share.service.token.ts new file mode 100644 index 0000000..d6d5faf --- /dev/null +++ b/src/app/infrastructure/shareData/web-share.service.token.ts @@ -0,0 +1,6 @@ +import { InjectionToken } from '@angular/core'; +import { ShareDataRepository } from '@app/domain/shareData/share-data.repository'; + +export const WEB_SHARE_SERVICE_TOKEN = new InjectionToken( + 'ShareDataRepository' +); diff --git a/src/app/infrastructure/shareData/web-share.service.ts b/src/app/infrastructure/shareData/web-share.service.ts new file mode 100644 index 0000000..1cb9abf --- /dev/null +++ b/src/app/infrastructure/shareData/web-share.service.ts @@ -0,0 +1,36 @@ +import { inject, Injectable } from '@angular/core'; +import { DOCUMENT } from '@angular/common'; +import { ShareDataRepository } from '@app/domain/shareData/share-data.repository'; +import { ToastrService } from 'ngx-toastr'; + +@Injectable({ + providedIn: 'root', +}) +export class WebShareService implements ShareDataRepository { + private document = inject(DOCUMENT); + private toastr = inject(ToastrService); + + async share(shareData: ShareData) { + const navigator = this.document.defaultView?.navigator; + + if (navigator && navigator.canShare && navigator.canShare(shareData)) { + try { + await navigator.share(shareData); + return; + } catch (error) { + return; + } + } + this.copyToClipboard(shareData.url!); + } + + private copyToClipboard(text: string) { + navigator.clipboard.writeText(text).then(() => { + this.toastr.info(`Le lien du profil est copié dans le presse papier !`, `Partage de profil`, { + closeButton: true, + progressAnimation: 'decreasing', + progressBar: true, + }); + }); + } +} diff --git a/src/app/routes/home/home.component.spec.ts b/src/app/routes/home/home.component.spec.ts index 016aa95..461fa67 100644 --- a/src/app/routes/home/home.component.spec.ts +++ b/src/app/routes/home/home.component.spec.ts @@ -4,38 +4,25 @@ import { HomeComponent } from './home.component'; import { provideRouter } from '@angular/router'; import { ProfileRepository } from '@app/domain/profiles/profile.repository'; import { SectorRepository } from '@app/domain/sectors/sector.repository'; -import { of } from 'rxjs'; -import { Profile } from '@app/domain/profiles/profile.model'; import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token'; import { SECTOR_REPOSITORY_TOKEN } from '@app/infrastructure/sectors/sector-repository.token'; -import { Sector } from '@app/domain/sectors/sector.model'; +import { mockSectorRepo } from '@app/testing/sector.mock'; +import { mockProfileRepo } from '@app/testing/profile.mock'; describe('HomeComponent', () => { let component: HomeComponent; let fixture: ComponentFixture; - let mockProfileRepo: jest.Mocked>; - let mockSectorRepo: jest.Mocked>; + let mockProfileRepository: jest.Mocked> = mockProfileRepo; + let mockSectorRepository: jest.Mocked> = mockSectorRepo; beforeEach(async () => { - mockProfileRepo = { - create: jest.fn().mockReturnValue(of({} as Profile)), - list: jest.fn().mockReturnValue(of([])), - getByUserId: jest.fn().mockReturnValue(of({} as Profile)), - update: jest.fn().mockReturnValue(of({} as Profile)), - }; - - mockSectorRepo = { - list: jest.fn().mockReturnValue(of([])), - getOne: jest.fn().mockReturnValue(of({} as Sector)), - }; - await TestBed.configureTestingModule({ imports: [HomeComponent], providers: [ provideRouter([]), - { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo }, - { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepo }, + { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepository }, + { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepository }, ], }).compileComponents(); diff --git a/src/app/routes/my-profile/my-profile.component.spec.ts b/src/app/routes/my-profile/my-profile.component.spec.ts index 7851222..36d83c0 100644 --- a/src/app/routes/my-profile/my-profile.component.spec.ts +++ b/src/app/routes/my-profile/my-profile.component.spec.ts @@ -4,62 +4,33 @@ import { MyProfileComponent } from './my-profile.component'; import { provideRouter } from '@angular/router'; import { ProfileRepository } from '@app/domain/profiles/profile.repository'; import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token'; -import { of } from 'rxjs'; -import { Profile } from '@app/domain/profiles/profile.model'; import { ToastrService } from 'ngx-toastr'; import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository.token'; import { UserRepository } from '@app/domain/users/user.repository'; import { AuthRepository } from '@app/domain/authentification/auth.repository'; import { AUTH_REPOSITORY_TOKEN } from '@app/infrastructure/authentification/auth-repository.token'; +import { mockProfileRepo } from '@app/testing/profile.mock'; +import { mockToastR } from '@app/testing/toastr.mock'; +import { mockUserRepo } from '@app/testing/user.mock'; +import { mockAuthRepo } from '@app/testing/auth.mock'; describe('MyProfileComponent', () => { let component: MyProfileComponent; let fixture: ComponentFixture; - let mockProfileRepo: ProfileRepository; - let mockToastrService: Partial; - let mockUserRepo: Partial; - let mockAuthRepository: jest.Mocked>; + let mockProfileRepository: jest.Mocked> = mockProfileRepo; + let mockToastrService: jest.Mocked> = mockToastR; + let mockUserRepository: jest.Mocked> = mockUserRepo; + let mockAuthRepository: jest.Mocked> = mockAuthRepo; beforeEach(async () => { - mockProfileRepo = { - create: jest.fn(), - list: jest.fn(), - update: jest.fn(), - getByUserId: jest.fn().mockReturnValue(of({} as Profile)), - }; - - mockUserRepo = { - update: jest.fn(), - getUserById: jest.fn(), - }; - - mockToastrService = { - warning: jest.fn(), - success: jest.fn(), - info: jest.fn(), - error: jest.fn(), - }; - - mockAuthRepository = { - get: jest.fn(), - login: jest.fn(), - sendVerificationEmail: jest.fn(), - logout: jest.fn(), - isAuthenticated: jest.fn(), - isEmailVerified: jest.fn(), - register: jest.fn(), - sendRequestPasswordReset: jest.fn(), - confirmPasswordReset: jest.fn(), - }; - await TestBed.configureTestingModule({ imports: [MyProfileComponent], providers: [ provideRouter([]), - { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo }, + { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepository }, { provide: AUTH_REPOSITORY_TOKEN, useValue: mockAuthRepository }, - { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepo }, + { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepository }, { provide: ToastrService, useValue: mockToastrService }, ], }).compileComponents(); diff --git a/src/app/routes/profile/profile-detail/profile-detail.component.html b/src/app/routes/profile/profile-detail/profile-detail.component.html index 6336a68..51b64fa 100644 --- a/src/app/routes/profile/profile-detail/profile-detail.component.html +++ b/src/app/routes/profile/profile-detail/profile-detail.component.html @@ -9,11 +9,13 @@
- +
+ - - @if (profile().estVerifier) { -
+
+ + @if (profile()!.estVerifier) { +
+ + Profil vérifié + + + +
+ } + + +
- } + +
@@ -103,7 +131,7 @@ }

- {{ profile().profession | uppercase }} + {{ profile()!.profession | uppercase }}

@@ -135,9 +163,9 @@ Biographie - @if (profile().bio) { + @if (profile()!.bio) {

- {{ profile().bio }} + {{ profile()!.bio }}

} @else {

@@ -149,7 +177,7 @@ - @if (profile().secteur) { + @if (profile()!.secteur) {

@@ -168,12 +196,12 @@ Secteur - +
} - @if (profile().reseaux) { + @if (profile()!.reseaux) {
@@ -195,7 +223,7 @@ Réseaux - +
} @@ -203,7 +231,7 @@
- @if (profile().apropos) { + @if (profile()!.apropos) {
@@ -225,7 +253,7 @@ À propos

- {{ profile().apropos }} + {{ profile()!.apropos }}

} diff --git a/src/app/routes/profile/profile-detail/profile-detail.component.spec.ts b/src/app/routes/profile/profile-detail/profile-detail.component.spec.ts index 90469d3..da4aa8c 100644 --- a/src/app/routes/profile/profile-detail/profile-detail.component.spec.ts +++ b/src/app/routes/profile/profile-detail/profile-detail.component.spec.ts @@ -4,37 +4,39 @@ import { ProfileDetailComponent } from './profile-detail.component'; import { provideRouter } from '@angular/router'; import { PROJECT_REPOSITORY_TOKEN } from '@app/infrastructure/projects/project-repository.token'; import { ProjectRepository } from '@app/domain/projects/project.repository'; -import { of } from 'rxjs'; -import { Project } from '@app/domain/projects/project.model'; -import { Sector } from '@app/domain/sectors/sector.model'; import { SectorRepository } from '@app/domain/sectors/sector.repository'; import { SECTOR_REPOSITORY_TOKEN } from '@app/infrastructure/sectors/sector-repository.token'; +import { ToastrService } from 'ngx-toastr'; +import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token'; +import { ProfileRepository } from '@app/domain/profiles/profile.repository'; +import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository.token'; +import { UserRepository } from '@app/domain/users/user.repository'; +import { mockProfileRepo } from '@app/testing/profile.mock'; +import { mockSectorRepo } from '@app/testing/sector.mock'; +import { mockToastR } from '@app/testing/toastr.mock'; +import { mockUserRepo } from '@app/testing/user.mock'; +import { mockProjectRepo } from '@app/testing/project.mock'; describe('ProfileDetailComponent', () => { let component: ProfileDetailComponent; let fixture: ComponentFixture; - let mockProjectRepository: jest.Mocked; - let mockSectorRepo: SectorRepository; + + let mockProjectRepository: jest.Mocked> = mockProjectRepo; + let mockProfileRepository: jest.Mocked> = mockProfileRepo; + let mockSectorRepository: jest.Mocked> = mockSectorRepo; + let mockToastr: jest.Mocked> = mockToastR; + let mockUserRepository: jest.Mocked> = mockUserRepo; beforeEach(async () => { - mockProjectRepository = { - create: jest.fn().mockReturnValue(of({} as Project)), - list: jest.fn().mockReturnValue(of([])), - get: jest.fn().mockReturnValue(of({} as Project)), - update: jest.fn().mockReturnValue(of({} as Project)), - }; - - mockSectorRepo = { - list: jest.fn(), - getOne: jest.fn().mockReturnValue(of({} as Sector)), - }; - await TestBed.configureTestingModule({ imports: [ProfileDetailComponent], providers: [ provideRouter([]), { provide: PROJECT_REPOSITORY_TOKEN, useValue: mockProjectRepository }, - { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepo }, + { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepository }, + { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepository }, + { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepository }, + { provide: ToastrService, useValue: mockToastr }, ], }).compileComponents(); diff --git a/src/app/routes/profile/profile-detail/profile-detail.component.ts b/src/app/routes/profile/profile-detail/profile-detail.component.ts index b9ecebd..2401080 100644 --- a/src/app/routes/profile/profile-detail/profile-detail.component.ts +++ b/src/app/routes/profile/profile-detail/profile-detail.component.ts @@ -1,4 +1,4 @@ -import { Component, computed, inject } from '@angular/core'; +import { Component, computed, effect, inject, OnInit } from '@angular/core'; import { ActivatedRoute, RouterLink } from '@angular/router'; import { UpperCasePipe } from '@angular/common'; import { User } from '@app/domain/users/user.model'; @@ -7,29 +7,86 @@ import { ReseauxComponent } from '@app/shared/components/reseaux/reseaux.compone import { UntilDestroy } from '@ngneat/until-destroy'; import { ProjectListComponent } from '@app/shared/components/project-list/project-list.component'; import { environment } from '@env/environment'; -import { Profile } from '@app/domain/profiles/profile.model'; +import { WebShareService } from '@app/infrastructure/shareData/web-share.service'; +import { ProfileFacade } from '@app/ui/profiles/profile.facade'; +import { ProfileViewModel } from '@app/ui/profiles/profile.presenter.model'; +import { ActionType } from '@app/domain/action-type.util'; +import { UserFacade } from '@app/ui/users/user.facade'; @Component({ selector: 'app-profile-detail', standalone: true, imports: [ChipsComponent, ReseauxComponent, RouterLink, UpperCasePipe, ProjectListComponent], + providers: [UserFacade], templateUrl: './profile-detail.component.html', styleUrl: './profile-detail.component.scss', }) @UntilDestroy() -export class ProfileDetailComponent { +export class ProfileDetailComponent implements OnInit { + private readonly webShare = inject(WebShareService); + private readonly profileFacade = inject(ProfileFacade); + private readonly userFacade = inject(UserFacade); protected readonly environment = environment; + protected readonly ActionType = ActionType; private readonly route = inject(ActivatedRoute); - protected extraData: { user: User; profile: Profile } = this.route.snapshot.data['profile']; + protected extraData: { user: User; profile: ProfileViewModel } | undefined = + this.route.snapshot.data['profile']; - protected user = computed(() => { - if (this.extraData != undefined) return this.extraData.user; - return {} as User; - }); + slug = computed(() => this.route.snapshot.params['name'] ?? ''); - protected profile = computed(() => { - if (this.extraData != undefined) return this.extraData.profile; - return {} as Profile; - }); + protected user = this.userFacade.user; + protected readonly userLoading = this.userFacade.loading; + protected readonly userError = this.userFacade.error; + + protected profile = this.profileFacade.profile; + protected readonly profileLoading = this.profileFacade.loading; + protected readonly profileError = this.profileFacade.error; + + constructor() { + effect(() => { + if (!this.profileLoading().isLoading) { + switch (this.profileLoading().action) { + case ActionType.READ: + if (!this.profileError().hasError) { + this.profile = this.profileFacade.profile; + } + break; + } + } + if (!this.userLoading().isLoading) { + switch (this.userLoading().action) { + case ActionType.READ: + if (!this.userError().hasError) { + this.user = this.userFacade.user; + } + break; + } + } + }); + } + + ngOnInit() { + if (this.extraData === undefined) { + const extractSlug = this.slug().split('-'); + const profileId = extractSlug[extractSlug.length - 1]; + const userId = extractSlug[extractSlug.length - 2]; + this.profileFacade.loadOne(profileId); + this.userFacade.loadOne(userId); + } else { + this.profile.set(this.extraData.profile); + this.user.set(this.extraData.user); + } + } + + async onShare() { + if (!this.profile) return; + const fullUrl = `${window.location.origin}/profiles/${this.slug()}`; + + await this.webShare.share({ + title: `Découvrez le profil de ${this.profile.name}`, + text: `Jette un œil à ce profil intéressant sur notre application !`, + url: fullUrl, + }); + } } diff --git a/src/app/routes/profile/profile-list/profile-list.component.spec.ts b/src/app/routes/profile/profile-list/profile-list.component.spec.ts index cc2653d..06baafe 100644 --- a/src/app/routes/profile/profile-list/profile-list.component.spec.ts +++ b/src/app/routes/profile/profile-list/profile-list.component.spec.ts @@ -2,33 +2,20 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ProfileListComponent } from './profile-list.component'; import { provideRouter } from '@angular/router'; -import { of } from 'rxjs'; import { ProfileRepository } from '@app/domain/profiles/profile.repository'; import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token'; -import { Profile } from '@app/domain/profiles/profile.model'; import { SECTOR_REPOSITORY_TOKEN } from '@app/infrastructure/sectors/sector-repository.token'; import { SectorRepository } from '@app/domain/sectors/sector.repository'; -import { Sector } from '@app/domain/sectors/sector.model'; +import { mockProfileRepo } from '@app/testing/profile.mock'; +import { mockSectorRepo } from '@app/testing/sector.mock'; describe('ProfileListComponent', () => { let component: ProfileListComponent; let fixture: ComponentFixture; - let mockProfileRepository: jest.Mocked>; - let mockSectorRepository: jest.Mocked>; + let mockProfileRepository: jest.Mocked> = mockProfileRepo; + let mockSectorRepository: jest.Mocked> = mockSectorRepo; beforeEach(async () => { - mockProfileRepository = { - create: jest.fn().mockReturnValue(of({} as Profile)), - list: jest.fn().mockReturnValue(of([])), - getByUserId: jest.fn().mockReturnValue(of({} as Profile)), - update: jest.fn().mockReturnValue(of({} as Profile)), - }; - - mockSectorRepository = { - list: jest.fn().mockReturnValue(of([])), - getOne: jest.fn().mockReturnValue(of({} as Sector)), - }; - await TestBed.configureTestingModule({ imports: [ProfileListComponent], providers: [ diff --git a/src/app/shared/components/chips/chips.component.spec.ts b/src/app/shared/components/chips/chips.component.spec.ts index 6e70bcd..1cecd4d 100644 --- a/src/app/shared/components/chips/chips.component.spec.ts +++ b/src/app/shared/components/chips/chips.component.spec.ts @@ -3,27 +3,21 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ChipsComponent } from './chips.component'; import { provideRouter } from '@angular/router'; import { SECTOR_REPOSITORY_TOKEN } from '@app/infrastructure/sectors/sector-repository.token'; -import { of } from 'rxjs'; -import { Sector } from '@app/domain/sectors/sector.model'; import { SectorRepository } from '@app/domain/sectors/sector.repository'; +import { mockSectorRepo } from '@app/testing/sector.mock'; describe('ChipsComponent', () => { let component: ChipsComponent; let fixture: ComponentFixture; - let mockSectorRepo: SectorRepository; + let mockSectorRepository: jest.Mocked> = mockSectorRepo; beforeEach(async () => { - mockSectorRepo = { - list: jest.fn(), - getOne: jest.fn().mockReturnValue(of({} as Sector)), - }; - await TestBed.configureTestingModule({ imports: [ChipsComponent], providers: [ provideRouter([]), - { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepo }, + { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepository }, ], }).compileComponents(); diff --git a/src/app/shared/components/my-profile-project-item/my-profile-project-item.component.spec.ts b/src/app/shared/components/my-profile-project-item/my-profile-project-item.component.spec.ts index 6c80b5f..4131509 100644 --- a/src/app/shared/components/my-profile-project-item/my-profile-project-item.component.spec.ts +++ b/src/app/shared/components/my-profile-project-item/my-profile-project-item.component.spec.ts @@ -6,21 +6,15 @@ import { Project } from '@app/domain/projects/project.model'; import { ProjectRepository } from '@app/domain/projects/project.repository'; import { provideRouter } from '@angular/router'; import { PROJECT_REPOSITORY_TOKEN } from '@app/infrastructure/projects/project-repository.token'; +import { mockProjectRepo } from '@app/testing/project.mock'; describe('MyProfileProjectItemComponent', () => { let component: MyProfileProjectItemComponent; let fixture: ComponentFixture; - let mockProjectRepository: jest.Mocked; + let mockProjectRepository: jest.Mocked> = mockProjectRepo; beforeEach(async () => { - mockProjectRepository = { - create: jest.fn().mockReturnValue(of({} as Project)), - list: jest.fn().mockReturnValue(of([])), - get: jest.fn().mockReturnValue(of({} as Project)), - update: jest.fn().mockReturnValue(of({} as Project)), - }; - await TestBed.configureTestingModule({ imports: [MyProfileProjectItemComponent], providers: [ diff --git a/src/app/shared/components/my-profile-project-list/my-profile-project-list.component.spec.ts b/src/app/shared/components/my-profile-project-list/my-profile-project-list.component.spec.ts index d332d39..8e80b31 100644 --- a/src/app/shared/components/my-profile-project-list/my-profile-project-list.component.spec.ts +++ b/src/app/shared/components/my-profile-project-list/my-profile-project-list.component.spec.ts @@ -2,24 +2,16 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MyProfileProjectListComponent } from './my-profile-project-list.component'; import { ProjectRepository } from '@app/domain/projects/project.repository'; -import { of } from 'rxjs'; import { provideRouter } from '@angular/router'; import { PROJECT_REPOSITORY_TOKEN } from '@app/infrastructure/projects/project-repository.token'; -import { Project } from '@app/domain/projects/project.model'; +import { mockProfileRepo } from '@app/testing/profile.mock'; describe('MyProfileProjectListComponent', () => { let component: MyProfileProjectListComponent; let fixture: ComponentFixture; - let mockProjectRepository: jest.Mocked; + let mockProjectRepository: jest.Mocked> = mockProfileRepo; beforeEach(async () => { - mockProjectRepository = { - create: jest.fn().mockReturnValue(of({} as Project)), - list: jest.fn().mockReturnValue(of([])), - get: jest.fn().mockReturnValue(of({} as Project)), - update: jest.fn().mockReturnValue(of({} as Project)), - }; - await TestBed.configureTestingModule({ imports: [MyProfileProjectListComponent], providers: [ diff --git a/src/app/shared/components/my-profile-update-cv-form/my-profile-update-cv-form.component.spec.ts b/src/app/shared/components/my-profile-update-cv-form/my-profile-update-cv-form.component.spec.ts index 0da159f..382eded 100644 --- a/src/app/shared/components/my-profile-update-cv-form/my-profile-update-cv-form.component.spec.ts +++ b/src/app/shared/components/my-profile-update-cv-form/my-profile-update-cv-form.component.spec.ts @@ -3,37 +3,24 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MyProfileUpdateCvFormComponent } from './my-profile-update-cv-form.component'; import { ToastrService } from 'ngx-toastr'; import { provideRouter } from '@angular/router'; -import { ProfileRepository } from '@app/domain/profiles/profile.repository'; -import { of } from 'rxjs'; -import { Profile } from '@app/domain/profiles/profile.model'; import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token'; +import { ProjectRepository } from '@app/domain/projects/project.repository'; +import { mockProfileRepo } from '@app/testing/profile.mock'; +import { mockToastR } from '@app/testing/toastr.mock'; describe('MyProfileUpdateCvFormComponent', () => { let component: MyProfileUpdateCvFormComponent; let fixture: ComponentFixture; - let mockToastrService: Partial; - let mockProfileRepo: ProfileRepository; + let mockToastrService: jest.Mocked> = mockToastR; + let mockProjectRepository: jest.Mocked> = mockProfileRepo; beforeEach(async () => { - mockToastrService = { - success: jest.fn(), - error: jest.fn(), - warning: jest.fn(), - }; - - mockProfileRepo = { - create: jest.fn(), - list: jest.fn(), - update: jest.fn().mockReturnValue(of({} as Profile)), - getByUserId: jest.fn().mockReturnValue(of({} as Profile)), - }; - await TestBed.configureTestingModule({ imports: [MyProfileUpdateCvFormComponent], providers: [ provideRouter([]), - { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo }, + { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProjectRepository }, { provide: ToastrService, useValue: mockToastrService }, ], }).compileComponents(); diff --git a/src/app/shared/components/my-profile-update-form/my-profile-update-form.component.spec.ts b/src/app/shared/components/my-profile-update-form/my-profile-update-form.component.spec.ts index d499b4b..f4d9ea8 100644 --- a/src/app/shared/components/my-profile-update-form/my-profile-update-form.component.spec.ts +++ b/src/app/shared/components/my-profile-update-form/my-profile-update-form.component.spec.ts @@ -11,14 +11,18 @@ import { Profile } from '@app/domain/profiles/profile.model'; import { SectorRepository } from '@app/domain/sectors/sector.repository'; import { Sector } from '@app/domain/sectors/sector.model'; import { SECTOR_REPOSITORY_TOKEN } from '@app/infrastructure/sectors/sector-repository.token'; +import { mockToastR } from '@app/testing/toastr.mock'; +import { ProjectRepository } from '@app/domain/projects/project.repository'; +import { mockProfileRepo } from '@app/testing/profile.mock'; +import { mockSectorRepo } from '@app/testing/sector.mock'; describe('MyProfileUpdateFormComponent', () => { let component: MyProfileUpdateFormComponent; let fixture: ComponentFixture; - let mockToastrService: Partial; - let mockProfileRepo: ProfileRepository; - let mockSectorRepo: SectorRepository; + let mockToastrService: jest.Mocked> = mockToastR; + let mockProfileRepository: jest.Mocked> = mockProfileRepo; + let mockSectorRepository: jest.Mocked> = mockSectorRepo; const mockProfileData = { profession: '', @@ -29,32 +33,14 @@ describe('MyProfileUpdateFormComponent', () => { }; beforeEach(async () => { - mockToastrService = { - warning: jest.fn(), - success: jest.fn(), - error: jest.fn(), - }; - - mockProfileRepo = { - create: jest.fn(), - list: jest.fn(), - update: jest.fn().mockReturnValue(of({} as Profile)), - getByUserId: jest.fn().mockReturnValue(of({} as Profile)), - }; - - mockSectorRepo = { - list: jest.fn().mockReturnValue(of([])), - getOne: jest.fn().mockReturnValue(of({} as Sector)), - }; - await TestBed.configureTestingModule({ imports: [MyProfileUpdateFormComponent], providers: [ FormBuilder, provideRouter([]), { provide: ToastrService, useValue: mockToastrService }, - { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo }, - { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepo }, + { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepository }, + { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepository }, ], }).compileComponents(); diff --git a/src/app/shared/components/my-profile-update-project-form/my-profile-update-project-form.component.spec.ts b/src/app/shared/components/my-profile-update-project-form/my-profile-update-project-form.component.spec.ts index 8a802ce..e3205b1 100644 --- a/src/app/shared/components/my-profile-update-project-form/my-profile-update-project-form.component.spec.ts +++ b/src/app/shared/components/my-profile-update-project-form/my-profile-update-project-form.component.spec.ts @@ -11,49 +11,22 @@ import { AUTH_REPOSITORY_TOKEN } from '@app/infrastructure/authentification/auth import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token'; import { AuthRepository } from '@app/domain/authentification/auth.repository'; import { ProfileRepository } from '@app/domain/profiles/profile.repository'; +import { mockAuthRepo } from '@app/testing/auth.mock'; +import { mockProfileRepo } from '@app/testing/profile.mock'; +import { mockProjectRepo } from '@app/testing/project.mock'; +import { mockToastR } from '@app/testing/toastr.mock'; describe('MyProfileUpdateProjectFormComponent', () => { let component: MyProfileUpdateProjectFormComponent; let fixture: ComponentFixture; - let mockToastrService: jest.Mocked>; - let mockProjectRepository: jest.Mocked>; + let mockToastrService: jest.Mocked> = mockToastR; + let mockProjectRepository: jest.Mocked> = mockProjectRepo; - let mockAuthRepository: jest.Mocked>; - let mockProfileRepo: jest.Mocked>; + let mockAuthRepository: jest.Mocked> = mockAuthRepo; + let mockProfileRepository: jest.Mocked> = mockProfileRepo; beforeEach(async () => { - mockToastrService = { - success: jest.fn(), - error: jest.fn(), - warning: jest.fn(), - }; - - mockProjectRepository = { - create: jest.fn().mockReturnValue(of({} as Project)), - list: jest.fn().mockReturnValue(of([])), - get: jest.fn().mockReturnValue(of({} as Project)), - update: jest.fn().mockReturnValue(of({} as Project)), - }; - mockAuthRepository = { - get: jest.fn(), - login: jest.fn(), - sendVerificationEmail: jest.fn(), - logout: jest.fn(), - isAuthenticated: jest.fn(), - isEmailVerified: jest.fn(), - register: jest.fn(), - sendRequestPasswordReset: jest.fn(), - confirmPasswordReset: jest.fn(), - }; - - mockProfileRepo = { - create: jest.fn(), - list: jest.fn(), - update: jest.fn(), - getByUserId: jest.fn(), - }; - await TestBed.configureTestingModule({ imports: [MyProfileUpdateProjectFormComponent], providers: [ @@ -61,7 +34,7 @@ describe('MyProfileUpdateProjectFormComponent', () => { { provide: ToastrService, useValue: mockToastrService }, { provide: PROJECT_REPOSITORY_TOKEN, useValue: mockProjectRepository }, { provide: AUTH_REPOSITORY_TOKEN, useValue: mockAuthRepository }, - { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo }, + { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepository }, ], }).compileComponents(); diff --git a/src/app/shared/components/nav-bar/nav-bar.component.html b/src/app/shared/components/nav-bar/nav-bar.component.html index 9671885..aca3b08 100644 --- a/src/app/shared/components/nav-bar/nav-bar.component.html +++ b/src/app/shared/components/nav-bar/nav-bar.component.html @@ -7,12 +7,12 @@ - TrouveTonProfile + TrouveTonProfil diff --git a/src/app/shared/components/nav-bar/nav-bar.component.spec.ts b/src/app/shared/components/nav-bar/nav-bar.component.spec.ts index 408ab20..2d01f23 100644 --- a/src/app/shared/components/nav-bar/nav-bar.component.spec.ts +++ b/src/app/shared/components/nav-bar/nav-bar.component.spec.ts @@ -3,21 +3,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NavBarComponent } from './nav-bar.component'; import { ThemeService } from '@app/core/services/theme/theme.service'; import { provideRouter } from '@angular/router'; -import { signal } from '@angular/core'; -import { AuthModel } from '@app/domain/authentification/auth.model'; import { User } from '@app/domain/users/user.model'; import { AUTH_REPOSITORY_TOKEN } from '@app/infrastructure/authentification/auth-repository.token'; import { AuthRepository } from '@app/domain/authentification/auth.repository'; import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token'; import { ProfileRepository } from '@app/domain/profiles/profile.repository'; +import { mockProfileRepo } from '@app/testing/profile.mock'; +import { mockAuthRepo } from '@app/testing/auth.mock'; +import { mockThemeService } from '@app/testing/theme.mock'; describe('NavBarComponent', () => { let component: NavBarComponent; let fixture: ComponentFixture; - let mockThemeService: jest.Mocked>; + let mockTheme: jest.Mocked> = mockThemeService; - let mockAuthRepository: jest.Mocked>; - let mockProfileRepo: jest.Mocked>; + let mockAuthRepository: jest.Mocked> = mockAuthRepo; + let mockProfileRepository: jest.Mocked> = mockProfileRepo; const user: User = { id: 'adbc123', @@ -32,37 +33,13 @@ describe('NavBarComponent', () => { }; beforeEach(async () => { - mockThemeService = { - darkModeSignal: signal('null'), - updateDarkMode: jest.fn(), - }; - - mockAuthRepository = { - get: jest.fn(), - login: jest.fn(), - sendVerificationEmail: jest.fn(), - logout: jest.fn(), - isAuthenticated: jest.fn(), - isEmailVerified: jest.fn(), - register: jest.fn(), - sendRequestPasswordReset: jest.fn(), - confirmPasswordReset: jest.fn(), - }; - - mockProfileRepo = { - create: jest.fn(), - list: jest.fn(), - update: jest.fn(), - getByUserId: jest.fn(), - }; - await TestBed.configureTestingModule({ imports: [NavBarComponent], providers: [ provideRouter([]), - { provide: ThemeService, useValue: mockThemeService }, + { provide: ThemeService, useValue: mockTheme }, { provide: AUTH_REPOSITORY_TOKEN, useValue: mockAuthRepository }, - { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo }, + { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepository }, ], }).compileComponents(); diff --git a/src/app/shared/components/project-list/project-list.component.spec.ts b/src/app/shared/components/project-list/project-list.component.spec.ts index 4cad4fa..660b843 100644 --- a/src/app/shared/components/project-list/project-list.component.spec.ts +++ b/src/app/shared/components/project-list/project-list.component.spec.ts @@ -2,25 +2,17 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ProjectListComponent } from './project-list.component'; import { ProjectRepository } from '@app/domain/projects/project.repository'; -import { of } from 'rxjs'; -import { Project } from '@app/domain/projects/project.model'; import { provideRouter } from '@angular/router'; import { PROJECT_REPOSITORY_TOKEN } from '@app/infrastructure/projects/project-repository.token'; +import { mockProjectRepo } from '@app/testing/project.mock'; describe('ProjectListComponent', () => { let component: ProjectListComponent; let fixture: ComponentFixture; - let mockProjectRepository: jest.Mocked; + let mockProjectRepository: jest.Mocked = mockProjectRepo; beforeEach(async () => { - mockProjectRepository = { - create: jest.fn().mockReturnValue(of({} as Project)), - list: jest.fn().mockReturnValue(of([])), - get: jest.fn().mockReturnValue(of({} as Project)), - update: jest.fn().mockReturnValue(of({} as Project)), - }; - await TestBed.configureTestingModule({ imports: [ProjectListComponent], providers: [ diff --git a/src/app/shared/components/project-list/project-list.component.ts b/src/app/shared/components/project-list/project-list.component.ts index 456d9c2..b0579c8 100644 --- a/src/app/shared/components/project-list/project-list.component.ts +++ b/src/app/shared/components/project-list/project-list.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; import { UntilDestroy } from '@ngneat/until-destroy'; import { ProjectItemComponent } from '@app/shared/components/project-item/project-item.component'; import { ProjectFacade } from '@app/ui/projects/project.facade'; @@ -11,14 +11,14 @@ import { ProjectFacade } from '@app/ui/projects/project.facade'; styleUrl: './project-list.component.scss', }) @UntilDestroy() -export class ProjectListComponent implements OnInit { +export class ProjectListComponent implements OnChanges { @Input({ required: true }) userProjectId = ''; private readonly projectFacade = new ProjectFacade(); protected projects = this.projectFacade.projects; - ngOnInit(): void { + ngOnChanges(changes: SimpleChanges) { this.projectFacade.load(this.userProjectId); } } diff --git a/src/app/shared/components/project-picture-form/project-picture-form.component.spec.ts b/src/app/shared/components/project-picture-form/project-picture-form.component.spec.ts index e1851fe..940dd32 100644 --- a/src/app/shared/components/project-picture-form/project-picture-form.component.spec.ts +++ b/src/app/shared/components/project-picture-form/project-picture-form.component.spec.ts @@ -4,31 +4,18 @@ import { ProjectPictureFormComponent } from './project-picture-form.component'; import { provideRouter } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; import { PROJECT_REPOSITORY_TOKEN } from '@app/infrastructure/projects/project-repository.token'; -import { of } from 'rxjs'; -import { Project } from '@app/domain/projects/project.model'; import { ProjectRepository } from '@app/domain/projects/project.repository'; +import { mockToastR } from '@app/testing/toastr.mock'; +import { mockProjectRepo } from '@app/testing/project.mock'; describe('ProjectPictureFormComponent', () => { let component: ProjectPictureFormComponent; let fixture: ComponentFixture; - let mockToastrService: Partial; - let mockProjectRepository: jest.Mocked; + let mockToastrService: jest.Mocked> = mockToastR; + let mockProjectRepository: jest.Mocked> = mockProjectRepo; beforeEach(async () => { - mockToastrService = { - success: jest.fn(), - error: jest.fn(), - warning: jest.fn(), - }; - - mockProjectRepository = { - create: jest.fn().mockReturnValue(of({} as Project)), - list: jest.fn().mockReturnValue(of([])), - get: jest.fn().mockReturnValue(of({} as Project)), - update: jest.fn().mockReturnValue(of({} as Project)), - }; - await TestBed.configureTestingModule({ imports: [ProjectPictureFormComponent], providers: [ diff --git a/src/app/shared/components/user-avatar-form/user-avatar-form.component.spec.ts b/src/app/shared/components/user-avatar-form/user-avatar-form.component.spec.ts index 486eb2b..081e1be 100644 --- a/src/app/shared/components/user-avatar-form/user-avatar-form.component.spec.ts +++ b/src/app/shared/components/user-avatar-form/user-avatar-form.component.spec.ts @@ -5,31 +5,22 @@ import { provideRouter } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; import { UserRepository } from '@app/domain/users/user.repository'; import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository.token'; +import { mockToastR } from '@app/testing/toastr.mock'; +import { mockUserRepo } from '@app/testing/user.mock'; describe('UserAvatarFormComponent', () => { let component: UserAvatarFormComponent; let fixture: ComponentFixture; - let mockToastrService: Partial; - let mockUserRepo: UserRepository; + let mockToastrService: jest.Mocked> = mockToastR; + let mockUserRepository: jest.Mocked> = mockUserRepo; beforeEach(async () => { - mockToastrService = { - warning: jest.fn(), - success: jest.fn(), - error: jest.fn(), - }; - - mockUserRepo = { - update: jest.fn(), - getUserById: jest.fn(), - }; - await TestBed.configureTestingModule({ imports: [UserAvatarFormComponent], providers: [ provideRouter([]), - { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepo }, + { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepository }, { provide: ToastrService, useValue: mockToastrService }, ], }).compileComponents(); diff --git a/src/app/shared/components/user-form/user-form.component.spec.ts b/src/app/shared/components/user-form/user-form.component.spec.ts index 5f2f3be..2184ae0 100644 --- a/src/app/shared/components/user-form/user-form.component.spec.ts +++ b/src/app/shared/components/user-form/user-form.component.spec.ts @@ -6,32 +6,23 @@ import { provideRouter } from '@angular/router'; import { FormBuilder } from '@angular/forms'; import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository.token'; import { UserRepository } from '@app/domain/users/user.repository'; +import { mockToastR } from '@app/testing/toastr.mock'; +import { mockUserRepo } from '@app/testing/user.mock'; describe('UserFormComponent', () => { let component: UserFormComponent; let fixture: ComponentFixture; - let mockToastrService: Partial; - let mockUserRepo: UserRepository; + let mockToastrService: jest.Mocked> = mockToastR; + let mockUserRepository: jest.Mocked> = mockUserRepo; beforeEach(async () => { - mockToastrService = { - warning: jest.fn(), - success: jest.fn(), - error: jest.fn(), - }; - - mockUserRepo = { - update: jest.fn(), - getUserById: jest.fn(), - }; - await TestBed.configureTestingModule({ imports: [UserFormComponent], providers: [ provideRouter([]), FormBuilder, - { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepo }, + { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepository }, { provide: ToastrService, useValue: mockToastrService }, ], }).compileComponents(); diff --git a/src/app/shared/components/user-password-form/user-password-form.component.spec.ts b/src/app/shared/components/user-password-form/user-password-form.component.spec.ts index c597cc1..7c74db4 100644 --- a/src/app/shared/components/user-password-form/user-password-form.component.spec.ts +++ b/src/app/shared/components/user-password-form/user-password-form.component.spec.ts @@ -6,34 +6,23 @@ import { AuthFacade } from '@app/ui/authentification/auth.facade'; import { By } from '@angular/platform-browser'; import { ActionType } from '@app/domain/action-type.util'; import { signal, WritableSignal } from '@angular/core'; +import { mockToastR } from '@app/testing/toastr.mock'; +import { mockAuthenticationFacade } from '@app/testing/ui/authentification/auth.facade.mock'; describe('UserPasswordFormComponent', () => { let component: UserPasswordFormComponent; let fixture: ComponentFixture; - let mockToastrService: Partial; + let mockToastrService: jest.Mocked> = mockToastR; // On mocke la Facade car c'est ce que le composant utilise directement let mockAuthFacade: { sendRequestPasswordReset: jest.Mock; loading: WritableSignal<{ isLoading: boolean; action: ActionType }>; error: WritableSignal<{ hasError: boolean }>; - }; + } = mockAuthenticationFacade; beforeEach(async () => { - mockToastrService = { - warning: jest.fn(), - success: jest.fn(), - info: jest.fn(), - error: jest.fn(), - }; - - mockAuthFacade = { - sendRequestPasswordReset: jest.fn(), - loading: signal({ isLoading: false, action: ActionType.NONE }), - error: signal({ hasError: false }), - }; - await TestBed.configureTestingModule({ imports: [UserPasswordFormComponent], providers: [ diff --git a/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.html b/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.html index d1cfdcb..5f513b5 100644 --- a/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.html +++ b/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.html @@ -1,5 +1,5 @@ @if (user() !== undefined) { - +
{ let component: VerticalProfileItemComponent; let fixture: ComponentFixture; - let mockUserRepo: UserRepository; - let mockSectorRepo: SectorRepository; + let mockUserRepository: jest.Mocked> = mockUserRepo; + let mockSectorRepository: jest.Mocked> = mockSectorRepo; beforeEach(async () => { - mockUserRepo = { - update: jest.fn().mockReturnValue(of({} as User)), - getUserById: jest.fn().mockReturnValue(of({} as User)), - }; - - mockSectorRepo = { - list: jest.fn().mockReturnValue(of({} as Sector)), - getOne: jest.fn().mockReturnValue(of({} as Sector)), - }; - await TestBed.configureTestingModule({ imports: [VerticalProfileItemComponent], providers: [ provideRouter([]), - { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepo }, - { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepo }, + { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepository }, + { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepository }, ], }).compileComponents(); diff --git a/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.ts b/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.ts index a20da25..5d688f2 100644 --- a/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.ts +++ b/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.ts @@ -1,4 +1,4 @@ -import { Component, inject, Input, OnInit } from '@angular/core'; +import { Component, computed, inject, Input, OnInit } from '@angular/core'; import { Router, RouterLink } from '@angular/router'; import { UntilDestroy } from '@ngneat/until-destroy'; import { environment } from '@env/environment'; @@ -23,6 +23,12 @@ export class VerticalProfileItemComponent implements OnInit { protected readonly loading = this.facade.loading; protected readonly error = this.facade.error; + protected slug = computed(() => { + const slug = this.user().slug ?? ''; + const profileId = this.profile.id ? this.profile.id : ''; + return slug === '' ? profileId : slug.concat('-', profileId); + }); + ngOnInit(): void { this.facade.loadOne(this.profile.utilisateur); } diff --git a/src/app/shared/features/filter/filter.component.spec.ts b/src/app/shared/features/filter/filter.component.spec.ts index abdddc4..8a6b913 100644 --- a/src/app/shared/features/filter/filter.component.spec.ts +++ b/src/app/shared/features/filter/filter.component.spec.ts @@ -9,26 +9,16 @@ import { of } from 'rxjs'; import { Profile } from '@app/domain/profiles/profile.model'; import { ProfileRepository } from '@app/domain/profiles/profile.repository'; import { Sector } from '@app/domain/sectors/sector.model'; +import { mockProfileRepo } from '@app/testing/profile.mock'; +import { mockSectorRepo } from '@app/testing/sector.mock'; describe('FilterComponent', () => { let component: FilterComponent; let fixture: ComponentFixture; - let mockProfileRepository: jest.Mocked>; - let mockSectorRepository: jest.Mocked>; + let mockProfileRepository: jest.Mocked> = mockProfileRepo; + let mockSectorRepository: jest.Mocked> = mockSectorRepo; beforeEach(async () => { - mockProfileRepository = { - create: jest.fn().mockReturnValue(of({} as Profile)), - list: jest.fn().mockReturnValue(of([])), - getByUserId: jest.fn().mockReturnValue(of({} as Profile)), - update: jest.fn().mockReturnValue(of({} as Profile)), - }; - - mockSectorRepository = { - list: jest.fn().mockReturnValue(of([])), - getOne: jest.fn().mockReturnValue(of({} as Sector)), - }; - await TestBed.configureTestingModule({ imports: [FilterComponent], providers: [ diff --git a/src/app/shared/features/login/login.component.spec.ts b/src/app/shared/features/login/login.component.spec.ts index 20f370d..cd2392c 100644 --- a/src/app/shared/features/login/login.component.spec.ts +++ b/src/app/shared/features/login/login.component.spec.ts @@ -8,43 +8,20 @@ import { AuthRepository } from '@app/domain/authentification/auth.repository'; import { AUTH_REPOSITORY_TOKEN } from '@app/infrastructure/authentification/auth-repository.token'; import { ProfileRepository } from '@app/domain/profiles/profile.repository'; import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token'; +import { mockAuthRepo } from '@app/testing/auth.mock'; +import { mockProfileRepo } from '@app/testing/profile.mock'; +import { mockToastR } from '@app/testing/toastr.mock'; describe('LoginComponent', () => { let component: LoginComponent; let fixture: ComponentFixture; // Mocks des services - let mockToastrService: Partial; - let mockAuthRepository: jest.Mocked>; - let mockProfileRepo: jest.Mocked>; + let mockToastrService: Partial = mockToastR; + let mockAuthRepository: jest.Mocked> = mockAuthRepo; + let mockProfileRepository: jest.Mocked> = mockProfileRepo; beforeEach(async () => { - mockToastrService = { - warning: jest.fn(), - success: jest.fn(), - info: jest.fn(), - error: jest.fn(), - }; - - mockAuthRepository = { - get: jest.fn(), - login: jest.fn(), - sendVerificationEmail: jest.fn(), - logout: jest.fn(), - isAuthenticated: jest.fn(), - isEmailVerified: jest.fn(), - register: jest.fn(), - sendRequestPasswordReset: jest.fn(), - confirmPasswordReset: jest.fn(), - }; - - mockProfileRepo = { - create: jest.fn(), - list: jest.fn(), - update: jest.fn(), - getByUserId: jest.fn(), - }; - await TestBed.configureTestingModule({ imports: [LoginComponent], providers: [ @@ -52,7 +29,7 @@ describe('LoginComponent', () => { provideRouter([]), { provide: ToastrService, useValue: mockToastrService }, { provide: AUTH_REPOSITORY_TOKEN, useValue: mockAuthRepository }, - { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo }, + { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepository }, ], }).compileComponents(); diff --git a/src/app/shared/features/register/register.component.spec.ts b/src/app/shared/features/register/register.component.spec.ts index 9e207e6..cb8e9e0 100644 --- a/src/app/shared/features/register/register.component.spec.ts +++ b/src/app/shared/features/register/register.component.spec.ts @@ -7,47 +7,25 @@ import { ProfileRepository } from '@app/domain/profiles/profile.repository'; import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token'; import { AUTH_REPOSITORY_TOKEN } from '@app/infrastructure/authentification/auth-repository.token'; import { AuthRepository } from '@app/domain/authentification/auth.repository'; +import { mockToastR } from '@app/testing/toastr.mock'; +import { mockProfileRepo } from '@app/testing/profile.mock'; +import { mockAuthRepo } from '@app/testing/auth.mock'; describe('RegisterComponent', () => { let component: RegisterComponent; let fixture: ComponentFixture; - let mockToastrService: jest.Mocked>; - let mockProfileRepo: jest.Mocked>; - let mockAuthRepository: jest.Mocked>; + let mockToastrService: jest.Mocked> = mockToastR; + let mockProfileRepository: jest.Mocked> = mockProfileRepo; + let mockAuthRepository: jest.Mocked> = mockAuthRepo; beforeEach(async () => { - mockProfileRepo = { - create: jest.fn(), - list: jest.fn(), - update: jest.fn(), - getByUserId: jest.fn(), - }; - - mockToastrService = { - success: jest.fn(), - error: jest.fn(), - warning: jest.fn(), - }; - - mockAuthRepository = { - get: jest.fn(), - login: jest.fn(), - sendVerificationEmail: jest.fn(), - logout: jest.fn(), - isAuthenticated: jest.fn(), - isEmailVerified: jest.fn(), - register: jest.fn(), - sendRequestPasswordReset: jest.fn(), - confirmPasswordReset: jest.fn(), - }; - await TestBed.configureTestingModule({ imports: [RegisterComponent], providers: [ provideRouter([]), { provide: ToastrService, useValue: mockToastrService }, - { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo }, + { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepository }, { provide: AUTH_REPOSITORY_TOKEN, useValue: mockAuthRepository }, ], }).compileComponents(); diff --git a/src/app/shared/features/search/search.component.spec.ts b/src/app/shared/features/search/search.component.spec.ts index bc1f1b8..2601a38 100644 --- a/src/app/shared/features/search/search.component.spec.ts +++ b/src/app/shared/features/search/search.component.spec.ts @@ -4,37 +4,25 @@ import { SearchComponent } from './search.component'; import { provideRouter } from '@angular/router'; import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token'; import { SECTOR_REPOSITORY_TOKEN } from '@app/infrastructure/sectors/sector-repository.token'; -import { of } from 'rxjs'; -import { Profile } from '@app/domain/profiles/profile.model'; import { ProfileRepository } from '@app/domain/profiles/profile.repository'; import { SectorRepository } from '@app/domain/sectors/sector.repository'; -import { Sector } from '@app/domain/sectors/sector.model'; +import { mockProfileRepo } from '@app/testing/profile.mock'; +import { mockSectorRepo } from '@app/testing/sector.mock'; describe('SearchComponent', () => { let component: SearchComponent; let fixture: ComponentFixture; - let mockProfileRepo: jest.Mocked>; - let mockSectorRepo: jest.Mocked>; + let mockProfileRepository: jest.Mocked> = mockProfileRepo; + let mockSectorRepository: jest.Mocked> = mockSectorRepo; beforeEach(async () => { - mockProfileRepo = { - create: jest.fn().mockReturnValue(of({} as Profile)), - list: jest.fn().mockReturnValue(of([])), - getByUserId: jest.fn().mockReturnValue(of({} as Profile)), - update: jest.fn().mockReturnValue(of({} as Profile)), - }; - - mockSectorRepo = { - list: jest.fn().mockReturnValue(of([])), - getOne: jest.fn().mockReturnValue(of({} as Sector)), - }; await TestBed.configureTestingModule({ imports: [SearchComponent], providers: [ provideRouter([]), - { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo }, - { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepo }, + { provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepository }, + { provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepository }, ], }).compileComponents(); diff --git a/src/app/shared/features/update-user/update-user.component.spec.ts b/src/app/shared/features/update-user/update-user.component.spec.ts index 5418c0e..57b9f1e 100644 --- a/src/app/shared/features/update-user/update-user.component.spec.ts +++ b/src/app/shared/features/update-user/update-user.component.spec.ts @@ -5,28 +5,22 @@ import { provideRouter } from '@angular/router'; import { UserRepository } from '@app/domain/users/user.repository'; import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository.token'; import { ToastrService } from 'ngx-toastr'; +import { mockUserRepo } from '@app/testing/user.mock'; +import { mockToastR } from '@app/testing/toastr.mock'; describe('UpdateUserComponent', () => { let component: UpdateUserComponent; let fixture: ComponentFixture; - let mockUserRepo: jest.Mocked>; - let mockToastrService: jest.Mocked>; + let mockUserRepository: jest.Mocked> = mockUserRepo; + let mockToastrService: jest.Mocked> = mockToastR; beforeEach(async () => { - mockUserRepo = { - getUserById: jest.fn(), - }; - mockToastrService = { - warning: jest.fn(), - success: jest.fn(), - error: jest.fn(), - }; await TestBed.configureTestingModule({ imports: [UpdateUserComponent], providers: [ provideRouter([]), - { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepo }, + { provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepository }, { provide: ToastrService, useValue: mockToastrService }, ], }).compileComponents(); diff --git a/src/app/testing/auth.mock.ts b/src/app/testing/auth.mock.ts new file mode 100644 index 0000000..3147831 --- /dev/null +++ b/src/app/testing/auth.mock.ts @@ -0,0 +1,11 @@ +export const mockAuthRepo = { + get: jest.fn(), + login: jest.fn(), + sendVerificationEmail: jest.fn(), + logout: jest.fn(), + isAuthenticated: jest.fn(), + isEmailVerified: jest.fn(), + register: jest.fn(), + sendRequestPasswordReset: jest.fn(), + confirmPasswordReset: jest.fn(), +}; diff --git a/src/app/testing/domain/profiles/fake-profile.repository.ts b/src/app/testing/domain/profiles/fake-profile.repository.ts index c54291c..6652659 100644 --- a/src/app/testing/domain/profiles/fake-profile.repository.ts +++ b/src/app/testing/domain/profiles/fake-profile.repository.ts @@ -8,8 +8,8 @@ export class FakeProfileRepository implements ProfileRepository { return of(mockProfilePaginated); } - getByUserId(userId: string): Observable { - const profile = mockProfiles.find((p) => p.utilisateur === userId) ?? ({} as Profile); + getById(profileId: string): Observable { + const profile = mockProfiles.find((p) => p.utilisateur === profileId) ?? ({} as Profile); return of(profile); } diff --git a/src/app/testing/infrastructure/profiles/pb-profile.repository.spec.ts b/src/app/testing/infrastructure/profiles/pb-profile.repository.spec.ts index 87d4e8d..0c3de47 100644 --- a/src/app/testing/infrastructure/profiles/pb-profile.repository.spec.ts +++ b/src/app/testing/infrastructure/profiles/pb-profile.repository.spec.ts @@ -15,7 +15,7 @@ describe('PbProfileRepository', () => { // Création d’un faux client PocketBase avec les méthodes dont on a besoin mockCollection = { getList: jest.fn(), - getFirstListItem: jest.fn(), + getOne: jest.fn(), create: jest.fn(), update: jest.fn(), }; @@ -54,13 +54,13 @@ describe('PbProfileRepository', () => { // ------------------------------------------ // 🔹 TEST : getByUserId() // ------------------------------------------ - it('devrait appeler pb.collection("profiles").getFirstListItem() avec le bon filtre utilisateur', () => { - const userId = '1'; + it('devrait appeler pb.collection("profiles").getOne() avec le bon filtre utilisateur', () => { + const profileId = '1'; - mockCollection.getFirstListItem.mockResolvedValue(mockProfiles); + mockCollection.getOne.mockResolvedValue(mockProfiles); - repo.getByUserId(userId).subscribe((result) => { - expect(mockCollection.getFirstListItem).toHaveBeenCalledWith(`utilisateur="${userId}"`); + repo.getById(profileId).subscribe((result) => { + expect(mockCollection.getOne).toHaveBeenCalledWith(`${profileId}`, { expand: 'utilisateur' }); expect(result).toEqual(mockProfiles[0]); }); }); diff --git a/src/app/testing/profile.mock.ts b/src/app/testing/profile.mock.ts index 7d316da..864fb4b 100644 --- a/src/app/testing/profile.mock.ts +++ b/src/app/testing/profile.mock.ts @@ -1,4 +1,5 @@ import { Profile, ProfilePaginated } from '@app/domain/profiles/profile.model'; +import { of } from 'rxjs'; export const mockProfiles: Profile[] = [ { @@ -38,3 +39,10 @@ export const mockProfilePaginated: ProfilePaginated = { totalItems: 1, items: mockProfiles, }; + +export const mockProfileRepo = { + create: jest.fn().mockReturnValue(of({} as Profile)), + list: jest.fn().mockReturnValue(of([])), + getById: jest.fn().mockReturnValue(of({} as Profile)), + update: jest.fn().mockReturnValue(of({} as Profile)), +}; diff --git a/src/app/testing/project.mock.ts b/src/app/testing/project.mock.ts index 1226577..db6a8be 100644 --- a/src/app/testing/project.mock.ts +++ b/src/app/testing/project.mock.ts @@ -1,4 +1,5 @@ import { Project } from '@app/domain/projects/project.model'; +import { of } from 'rxjs'; export const fakeProjects: Project[] = [ { @@ -57,3 +58,10 @@ export const fakeProjects: Project[] = [ utilisateur: 'user_001', }, ]; + +export const mockProjectRepo = { + create: jest.fn().mockReturnValue(of({} as Project)), + list: jest.fn().mockReturnValue(of([])), + get: jest.fn().mockReturnValue(of({} as Project)), + update: jest.fn().mockReturnValue(of({} as Project)), +}; diff --git a/src/app/testing/sector.mock.ts b/src/app/testing/sector.mock.ts index fe1b2db..560584a 100644 --- a/src/app/testing/sector.mock.ts +++ b/src/app/testing/sector.mock.ts @@ -1,4 +1,5 @@ import { Sector } from '@app/domain/sectors/sector.model'; +import { of } from 'rxjs'; export const fakeSectors: Sector[] = [ { @@ -32,3 +33,8 @@ export const fakeSectors: Sector[] = [ nom: 'Ressources humaines', }, ]; + +export const mockSectorRepo = { + list: jest.fn().mockReturnValue(of([])), + getOne: jest.fn().mockReturnValue(of({} as Sector)), +}; diff --git a/src/app/testing/theme.mock.ts b/src/app/testing/theme.mock.ts new file mode 100644 index 0000000..06deef6 --- /dev/null +++ b/src/app/testing/theme.mock.ts @@ -0,0 +1,6 @@ +import { signal } from '@angular/core'; + +export const mockThemeService = { + darkModeSignal: signal('null'), + updateDarkMode: jest.fn(), +}; diff --git a/src/app/testing/toastr.mock.ts b/src/app/testing/toastr.mock.ts new file mode 100644 index 0000000..e51bc40 --- /dev/null +++ b/src/app/testing/toastr.mock.ts @@ -0,0 +1,6 @@ +export const mockToastR = { + warning: jest.fn(), + success: jest.fn(), + info: jest.fn(), + error: jest.fn(), +}; diff --git a/src/app/testing/ui/authentification/auth.facade.mock.ts b/src/app/testing/ui/authentification/auth.facade.mock.ts new file mode 100644 index 0000000..0bef9bc --- /dev/null +++ b/src/app/testing/ui/authentification/auth.facade.mock.ts @@ -0,0 +1,8 @@ +import { signal } from '@angular/core'; +import { ActionType } from '@app/domain/action-type.util'; + +export const mockAuthenticationFacade = { + sendRequestPasswordReset: jest.fn(), + loading: signal({ isLoading: false, action: ActionType.NONE }), + error: signal({ hasError: false }), +}; diff --git a/src/app/testing/user.mock.ts b/src/app/testing/user.mock.ts index 288de1f..b23238c 100644 --- a/src/app/testing/user.mock.ts +++ b/src/app/testing/user.mock.ts @@ -1,4 +1,5 @@ import { User } from '@app/domain/users/user.model'; +import { of } from 'rxjs'; export const fakeUsers: User[] = [ { @@ -13,3 +14,8 @@ export const fakeUsers: User[] = [ verified: false, }, ]; + +export const mockUserRepo = { + getUserById: jest.fn().mockReturnValue(of({} as User)), + update: jest.fn(), +}; diff --git a/src/app/ui/profiles/profile.facade.ts b/src/app/ui/profiles/profile.facade.ts index 9521a75..6e73070 100644 --- a/src/app/ui/profiles/profile.facade.ts +++ b/src/app/ui/profiles/profile.facade.ts @@ -67,9 +67,9 @@ export class ProfileFacade { }); } - loadOne(userId: string) { + loadOne(profileId: string) { this.handleError(ActionType.READ, false, null, true); - this.getUseCase.execute(userId).subscribe({ + this.getUseCase.execute(profileId).subscribe({ next: (profile: Profile) => { this.profile.set(ProfilePresenter.toViewModel(profile)); this.handleError(ActionType.READ, false, null, false); diff --git a/src/app/ui/users/user.presenter.ts b/src/app/ui/users/user.presenter.ts index 1cb559c..88b3827 100644 --- a/src/app/ui/users/user.presenter.ts +++ b/src/app/ui/users/user.presenter.ts @@ -4,8 +4,8 @@ import { User } from '@app/domain/users/user.model'; export class UserPresenter { toViewModel(user: User): UserViewModel { const slug = user.name - ? user.name.toLowerCase().replace(/\s/g, '-') - : user.email.split('@')[0].toLowerCase().trim(); + ? this.generateProfileSlug(user.name, user.id) + : this.generateProfileSlug('Non renséigné'); let userViewModel: UserViewModel = { id: user.id, @@ -30,4 +30,16 @@ export class UserPresenter { toViewModels(users: User[]): UserViewModel[] { return users.map(this.toViewModel); } + + private generateProfileSlug(name: string, id?: string): string { + return name + .concat(id ? ` ${id}` : '') + .toLowerCase() + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') // Enlève les accents + .trim() + .replace(/[^a-z0-9 -]/g, '') // Enlève les caractères spéciaux + .replace(/\s+/g, '-') // Remplace les espaces par des tirets + .replace(/-+/g, '-'); // Évite les tirets multiples + } } diff --git a/src/app/usecase/profiles/get-profile.usecase.ts b/src/app/usecase/profiles/get-profile.usecase.ts index 7841dd2..fd01fc0 100644 --- a/src/app/usecase/profiles/get-profile.usecase.ts +++ b/src/app/usecase/profiles/get-profile.usecase.ts @@ -5,7 +5,7 @@ import { Profile } from '@app/domain/profiles/profile.model'; export class GetProfileUseCase { constructor(private readonly repo: ProfileRepository) {} - execute(userId: string): Observable { - return this.repo.getByUserId(userId); + execute(profileId: string): Observable { + return this.repo.getById(profileId); } } diff --git a/src/app/usecase/users/get-user.usecase.ts b/src/app/usecase/users/get-user.usecase.ts index 1839c26..b885023 100644 --- a/src/app/usecase/users/get-user.usecase.ts +++ b/src/app/usecase/users/get-user.usecase.ts @@ -1,8 +1,10 @@ import { UserRepository } from '@app/domain/users/user.repository'; +import { Observable } from 'rxjs'; +import { User } from '@app/domain/users/user.model'; export class GetUserUseCase { constructor(private readonly repo: UserRepository) {} - execute(userId: string) { + execute(userId: string): Observable { return this.repo.getUserById(userId); } } diff --git a/tsconfig.json b/tsconfig.json index 1f50ff3..e8d3149 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,7 @@ { "compileOnSave": false, "compilerOptions": { + "skipLibCheck": true, "baseUrl": ".", "resolveJsonModule": true, "paths": {