diff --git a/.github/workflows/CD-time-tracker-ui.yml b/.github/workflows/CD-time-tracker-ui.yml index 50424f661..bcac64246 100644 --- a/.github/workflows/CD-time-tracker-ui.yml +++ b/.github/workflows/CD-time-tracker-ui.yml @@ -24,6 +24,26 @@ jobs: with: node-version: '12.x' + - name: Inject Secrets + shell: python + env: + SCOPES: ${{ secrets.scopes }} + CLIENT_ID: ${{ secrets.client_id }} + AUTHORITY: ${{ secrets.authority }} + BASE_PATH: "src/environments/" + run: | + import os + import json + data = {} + base_path = os.environ.get('BASE_PATH', 'src/environments/') + with open(base_path + "keys.example.json", "r+") as jsonFileRead: + data = json.load(jsonFileRead) + data["scopes"] = str(os.environ['SCOPES']).split(",") + data["client_id"] = os.environ['CLIENT_ID'] + data["authority"] = os.environ['AUTHORITY'] + with open(base_path + ".keys.json", "w+") as jsonFileWrite: + json.dump(data, jsonFileWrite) + - name: 'run: npm install and build' run: | npm install diff --git a/.github/workflows/CI-time-tracker-ui.yml b/.github/workflows/CI-time-tracker-ui.yml index 1c4a7fbd6..4d6aad5de 100644 --- a/.github/workflows/CI-time-tracker-ui.yml +++ b/.github/workflows/CI-time-tracker-ui.yml @@ -39,5 +39,25 @@ jobs: - name: Install dependencies run: npm install + - name: Inject Secrets + shell: python + env: + SCOPES: ${{ secrets.scopes }} + CLIENT_ID: ${{ secrets.client_id }} + AUTHORITY: ${{ secrets.authority }} + BASE_PATH: "src/environments/" + run: | + import os + import json + data = {} + base_path = os.environ.get('BASE_PATH', 'src/environments/') + with open(base_path + "keys.example.json", "r+") as jsonFileRead: + data = json.load(jsonFileRead) + data["scopes"] = str(os.environ['SCOPES']).split(",") + data["client_id"] = os.environ['CLIENT_ID'] + data["authority"] = os.environ['AUTHORITY'] + with open(base_path + ".keys.json", "w+") as jsonFileWrite: + json.dump(data, jsonFileWrite) + - name: Run the test run: npm run ci-test --if-present diff --git a/.gitignore b/.gitignore index 86d943a9b..4606716c0 100644 --- a/.gitignore +++ b/.gitignore @@ -40,7 +40,7 @@ npm-debug.log yarn-error.log testem.log /typings - +.keys.json # System Files .DS_Store Thumbs.db diff --git a/README.md b/README.md index 0bc8a1a49..c5f40ba8a 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,12 @@ Run `npm install` to install the required node_modules for this project. Run `ng serve` to run the app in dev mode. After executing this command, you can navigate to `http://localhost:4200/` to see the app working. The app will automatically reload if you change anything in the source files. -## Prepare your environment for vscode +## Prepare your environment +### Set environment variables +Create file .keys.json from keys.example.ts into environments folder + +### Prepare your environment for vscode Install the following extensions: - `EditorConfig for Visual Studio Code`. diff --git a/package-lock.json b/package-lock.json index 2ed368ccd..eaec87f61 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7257,6 +7257,14 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "msal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/msal/-/msal-1.2.1.tgz", + "integrity": "sha512-Zo28eyRtT/Un+zcpMfPtTPD+eo/OqzsRER0k5dyk8Mje/K1oLlaEOAgZHlJs59Y2xyuVg8OrcKqSn/1MeNjZYw==", + "requires": { + "tslib": "^1.9.3" + } + }, "multicast-dns": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", diff --git a/package.json b/package.json index a8c270fb5..deb40e2ce 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "bootstrap": "^4.4.1", "jquery": "^3.4.1", "minimist": "^1.2.5", + "msal": "^1.2.1", "rxjs": "~6.5.4", "tslib": "^1.10.0", "zone.js": "~0.10.2" diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 5be963b0a..e60f6b66f 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,19 +1,28 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; + +import { AzureGuardService } from './guards/azure-guard.service' import { ReportsComponent } from './modules/reports/pages/reports.component'; import { TimeClockComponent } from './modules/time-clock/pages/time-clock.component'; import { TimeEntriesComponent } from './modules/time-entries/pages/time-entries.component'; import { ProjectManagementComponent } from './modules/project-management/pages/project-management.component'; import { ActivitiesManagementComponent } from './modules/activities-management/pages/activities-management.component'; +import { HomeComponent } from './modules/home/home.component'; +import { LoginComponent } from './modules/login/login.component'; const routes: Routes = [ - {path: 'reports', component: ReportsComponent}, - {path: 'time-clock', component: TimeClockComponent}, - {path: 'time-entries', component: TimeEntriesComponent}, - {path: 'project-management', component: ProjectManagementComponent}, - {path: 'activities-management', component: ActivitiesManagementComponent}, - {path: '', pathMatch: 'full', redirectTo: 'time-clock'}, - {path: '**', pathMatch: 'full', redirectTo: 'time-clock'}, + + { path: '', component: HomeComponent, canActivate:[AzureGuardService], + children: [ + { path: 'reports', component: ReportsComponent }, + { path: 'time-clock', component: TimeClockComponent }, + { path: 'time-entries', component: TimeEntriesComponent }, + { path: 'project-management', component: ProjectManagementComponent }, + { path: 'activities-management', component: ActivitiesManagementComponent }, + {path: '', pathMatch: 'full', redirectTo: 'time-clock'}, + ] + }, + { path: 'login', component: LoginComponent }, ]; @NgModule({ diff --git a/src/app/app.component.html b/src/app/app.component.html index 98c2c932e..90c6b6463 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,5 +1 @@ - - - - - + \ No newline at end of file diff --git a/src/app/app.module.ts b/src/app/app.module.ts index d2d216329..f310c20ff 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -25,6 +25,8 @@ import { ActivitiesManagementComponent } from './modules/activities-management/p import { ActivityListComponent } from './modules/activities-management/components/activity-list/activity-list.component'; import { CreateActivityComponent } from './modules/activities-management/components/create-activity/create-activity.component'; +import { HomeComponent } from './modules/home/home.component'; +import { LoginComponent } from './modules/login/login.component'; @NgModule({ declarations: [ @@ -47,7 +49,9 @@ import { CreateActivityComponent } from './modules/activities-management/compone GroupByDatePipe, ActivitiesManagementComponent, CreateActivityComponent, - ActivityListComponent + ActivityListComponent, + HomeComponent, + LoginComponent ], imports: [ CommonModule, diff --git a/src/app/guards/azure-guard.service.spec.ts b/src/app/guards/azure-guard.service.spec.ts new file mode 100644 index 000000000..a18c1793d --- /dev/null +++ b/src/app/guards/azure-guard.service.spec.ts @@ -0,0 +1,48 @@ +import { TestBed, inject } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { Router } from '@angular/router' + +import { AzureAdB2CService } from '../modules/login/services/azure.ad.b2c.service'; +import { AzureGuardService } from './azure-guard.service'; + + +describe('AzureGuardService', () => { + let service: AzureGuardService; + let azureAdB2CService: AzureAdB2CService; + const azureAdB2CServiceStub = { + isLogin() { + return true; + } + }; + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ RouterTestingModule ], + providers: [ + { providers: AzureAdB2CService, useValue: azureAdB2CServiceStub}, + ] + }); + service = TestBed.inject(AzureGuardService); + azureAdB2CService = TestBed.inject(AzureAdB2CService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('should check if is login', () => { + spyOn(azureAdB2CService, 'isLogin').and.returnValue(true) + const isAcitve = service.canActivate(); + expect(azureAdB2CService.isLogin).toHaveBeenCalled; + expect(isAcitve).toEqual(true); + }); + + it('should check if not is login', inject([Router], (router: Router) => { + spyOn(azureAdB2CService, 'isLogin').and.returnValue(false) + spyOn(router, 'navigate').and.stub(); + const isAcitve = service.canActivate(); + expect(azureAdB2CService.isLogin).toHaveBeenCalled; + expect(isAcitve).toEqual(false); + expect(router.navigate).toHaveBeenCalledWith(['login']); + })); + +}); diff --git a/src/app/guards/azure-guard.service.ts b/src/app/guards/azure-guard.service.ts new file mode 100644 index 000000000..08f965f52 --- /dev/null +++ b/src/app/guards/azure-guard.service.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@angular/core'; +import { Router, CanActivate } from '@angular/router'; +import { AzureAdB2CService } from '../modules/login/services/azure.ad.b2c.service'; + +@Injectable({ + providedIn: 'root' +}) +export class AzureGuardService implements CanActivate { + + constructor(private azureAdB2CService: AzureAdB2CService, private router: Router) { } + canActivate() { + if(this.azureAdB2CService.isLogin()) { + return true; + } else { + this.router.navigate(['login']); + return false; + } +} +} diff --git a/src/app/modules/activities-management/components/create-activity/create-activity.component.spec.ts b/src/app/modules/activities-management/components/create-activity/create-activity.component.spec.ts index 15cace0a6..602fef7c1 100644 --- a/src/app/modules/activities-management/components/create-activity/create-activity.component.spec.ts +++ b/src/app/modules/activities-management/components/create-activity/create-activity.component.spec.ts @@ -7,6 +7,11 @@ describe('CreateActivityComponent', () => { let component: CreateActivityComponent; + const data = { + name: '', + description: '' + } + beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ CreateActivityComponent], @@ -19,4 +24,19 @@ describe('CreateActivityComponent', () => { expect(component).toBeTruthy(); }); + it('should reset form', () => { + component.onSubmit(data) + expect(component.activityForm.reset()).toHaveBeenCalled + }); + + it('should get name', () => { + component.name + expect(component.activityForm.get('name')).toHaveBeenCalled + }); + + it('should get description', () => { + component.description + expect(component.activityForm.get('description')).toHaveBeenCalled + }); + }); diff --git a/src/app/modules/home/home.component.html b/src/app/modules/home/home.component.html new file mode 100644 index 000000000..924cf8b51 --- /dev/null +++ b/src/app/modules/home/home.component.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/app/modules/home/home.component.scss b/src/app/modules/home/home.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/modules/home/home.component.spec.ts b/src/app/modules/home/home.component.spec.ts new file mode 100644 index 000000000..490e81bdf --- /dev/null +++ b/src/app/modules/home/home.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HomeComponent } from './home.component'; + +describe('HomeComponent', () => { + let component: HomeComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HomeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HomeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/modules/home/home.component.ts b/src/app/modules/home/home.component.ts new file mode 100644 index 000000000..73acf06f0 --- /dev/null +++ b/src/app/modules/home/home.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-home', + templateUrl: './home.component.html', + styleUrls: ['./home.component.scss'] +}) +export class HomeComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/modules/login/login.component.html b/src/app/modules/login/login.component.html new file mode 100644 index 000000000..19e52d0f4 --- /dev/null +++ b/src/app/modules/login/login.component.html @@ -0,0 +1 @@ + diff --git a/src/app/modules/login/login.component.scss b/src/app/modules/login/login.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/modules/login/login.component.spec.ts b/src/app/modules/login/login.component.spec.ts new file mode 100644 index 000000000..122490aa1 --- /dev/null +++ b/src/app/modules/login/login.component.spec.ts @@ -0,0 +1,66 @@ +import { async, ComponentFixture, TestBed, inject } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { AzureAdB2CService } from '../../modules/login/services/azure.ad.b2c.service'; +import { of } from 'rxjs' + +import { LoginComponent } from './login.component'; +import { Router } from '@angular/router'; + +describe('LoginComponent', () => { + let component: LoginComponent; + let fixture: ComponentFixture; + let azureAdB2CService: AzureAdB2CService; + + const azureAdB2CServiceStub = { + isLogin() { + return true; + }, + signIn() { + return of(); + } + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ RouterTestingModule ], + declarations: [ LoginComponent ], + providers: [ + { providers: AzureAdB2CService, useValue: azureAdB2CServiceStub} + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LoginComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + azureAdB2CService = TestBed.inject(AzureAdB2CService); + + }); + + it('Service injected via inject(...) and TestBed.get(...) should be the same instance', + inject([AzureAdB2CService], (injectService: AzureAdB2CService) => { + expect(injectService).toEqual(azureAdB2CService); + }) + ); + + it('should create login component', () => { + expect(component).toBeTruthy(); + }); + + it('should sign up or login with google', inject([Router], (router: Router) => { + spyOn(azureAdB2CService, 'isLogin').and.returnValue(false); + spyOn(azureAdB2CService, 'signIn').and.returnValue(of()) + component.login(); + expect(azureAdB2CService.signIn).toHaveBeenCalled; + })); + + it('should not sign up or login with google', inject([Router], (router: Router) => { + spyOn(azureAdB2CService, 'isLogin').and.returnValue(true) + spyOn(router, 'navigate').and.stub(); + component.login(); + expect(azureAdB2CService.isLogin).toHaveBeenCalled; + expect(router.navigate).toHaveBeenCalledWith(['']); + })); +}); diff --git a/src/app/modules/login/login.component.ts b/src/app/modules/login/login.component.ts new file mode 100644 index 000000000..51178c075 --- /dev/null +++ b/src/app/modules/login/login.component.ts @@ -0,0 +1,25 @@ +import { Component } from '@angular/core'; +import { AzureAdB2CService } from './services/azure.ad.b2c.service' +import { Router } from '@angular/router'; + +@Component({ + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.scss'] +}) + +export class LoginComponent { + + constructor(private azureAdB2CService: AzureAdB2CService, private router:Router) {} + + login(): void { + if(this.azureAdB2CService.isLogin()) { + this.router.navigate(['']); + } else { + this.azureAdB2CService.signIn().subscribe(() => { + this.router.navigate(['']); + }); + } + } + +} diff --git a/src/app/modules/login/services/azure.ad.b2c.service.spec.ts b/src/app/modules/login/services/azure.ad.b2c.service.spec.ts new file mode 100644 index 000000000..328a4f977 --- /dev/null +++ b/src/app/modules/login/services/azure.ad.b2c.service.spec.ts @@ -0,0 +1,82 @@ +import { TestBed, inject } from '@angular/core/testing'; +import { AzureAdB2CService } from './azure.ad.b2c.service'; +import { UserAgentApplication, Account } from 'msal'; + +describe('AzureAdB2CService', () => { + let service: AzureAdB2CService; + const msalStub = { + loginPopup() { + return {} + } + } + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [] + }); + service = TestBed.inject(AzureAdB2CService); + }); + + it('should create', inject([AzureAdB2CService], + ( apiService: AzureAdB2CService) => { + expect(apiService).toBeTruthy(); + })); + + it('should call msal loginPopup', () => { + spyOn(UserAgentApplication.prototype, 'loginPopup').and.returnValue(( + new Promise((resolve) => { + resolve(); + }) + )) + service.signIn() + expect(UserAgentApplication.prototype.loginPopup).toHaveBeenCalled; + }); + + it('should call msal logout', () => { + spyOn(UserAgentApplication.prototype, 'logout').and.returnValue() + service.logout() + expect(UserAgentApplication.prototype.logout).toHaveBeenCalled; + }); + + it('should get name Account', () => { + const account: Account = { + accountIdentifier: 'abc', + homeAccountIdentifier: 'abc', + userName: 'abc', + name: 'abc', + idToken: {}, + idTokenClaims: {}, + sid: 'abc', + environment: "abc" + } + spyOn(UserAgentApplication.prototype, 'getAccount').and.returnValues(account) + const name = service.getName() + expect(UserAgentApplication.prototype.getAccount).toHaveBeenCalled; + expect(name).toEqual(account.name) + }); + + it('should return true when user is login', () => { + const account: Account = { + accountIdentifier: 'abc', + homeAccountIdentifier: 'abc', + userName: 'abc', + name: 'abc', + idToken: {}, + idTokenClaims: {}, + sid: 'abc', + environment: "abc" + } + spyOn(UserAgentApplication.prototype, 'getAccount').and.returnValue(account) + const isLogin = service.isLogin() + expect(UserAgentApplication.prototype.getAccount).toHaveBeenCalled; + expect(isLogin).toEqual(true) + }); + + it('should return false when user is not login', () => { + spyOn(UserAgentApplication.prototype, 'getAccount').and.returnValue(null) + const isLogin = service.isLogin() + expect(UserAgentApplication.prototype.getAccount).toHaveBeenCalled; + expect(isLogin).toEqual(false) + }); + +}); diff --git a/src/app/modules/login/services/azure.ad.b2c.service.ts b/src/app/modules/login/services/azure.ad.b2c.service.ts new file mode 100644 index 000000000..8c2d687ea --- /dev/null +++ b/src/app/modules/login/services/azure.ad.b2c.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@angular/core'; +import { Observable, from } from 'rxjs'; +import { CLIENT_ID, AUTHORITY, SCOPES } from '../../../../environments/environment' +import { UserAgentApplication } from 'msal'; + +@Injectable({ + providedIn: 'root' +}) + +export class AzureAdB2CService { + + msalConfig = { + auth: { + clientId: CLIENT_ID, + authority: AUTHORITY, + validateAuthority: false + } + }; + + tokenRequest = { + scopes: SCOPES + }; + + msal = new UserAgentApplication(this.msalConfig); + + signIn(): Observable { + return from(this.msal.loginPopup(this.tokenRequest)); + } + + logout() { + this.msal.logout(); + } + + getName(): string { + return this.msal.getAccount().name + } + + isLogin() { + return this.msal.getAccount() ? true : false + } +} diff --git a/src/app/modules/shared/components/clock/clock.component.spec.ts b/src/app/modules/shared/components/clock/clock.component.spec.ts index 73172557f..94b2d4d70 100644 --- a/src/app/modules/shared/components/clock/clock.component.spec.ts +++ b/src/app/modules/shared/components/clock/clock.component.spec.ts @@ -37,11 +37,10 @@ describe('ClockComponent', () => { const currentSeconds = component.currentDate.getSeconds(); expect(component.currentDate.getSeconds()).toEqual(currentSeconds); }); - + it('should startTimer called', () => { spyOn(component, 'showClock'); component.showClock(); expect(component.showClock).toHaveBeenCalled(); }); - }); diff --git a/src/app/modules/shared/components/clock/clock.component.ts b/src/app/modules/shared/components/clock/clock.component.ts index e8598ca05..85142de81 100644 --- a/src/app/modules/shared/components/clock/clock.component.ts +++ b/src/app/modules/shared/components/clock/clock.component.ts @@ -6,7 +6,7 @@ import { interval } from 'rxjs'; templateUrl: './clock.component.html', styleUrls: ['./clock.component.scss'] }) -export class ClockComponent implements OnInit { +export class ClockComponent { currentDate: Date = new Date(); hour: number; @@ -31,8 +31,4 @@ export class ClockComponent implements OnInit { this.seconds = this.currentDate.getSeconds(); }); } - - ngOnInit(): void { - } - } diff --git a/src/app/modules/shared/components/sidebar/sidebar.component.ts b/src/app/modules/shared/components/sidebar/sidebar.component.ts index 2d2883c56..58de5a33c 100644 --- a/src/app/modules/shared/components/sidebar/sidebar.component.ts +++ b/src/app/modules/shared/components/sidebar/sidebar.component.ts @@ -17,11 +17,11 @@ export class SidebarComponent implements OnInit { getItemsSidebar() { this.itemsSidebar = [ - {route: './time-clock', icon: 'far fa-clock', text: 'Time Clock' }, - {route: './time-entries', icon: 'far fa-list-alt', text: 'Time Entries' }, - {route: './reports', icon: 'fas fa-chart-pie', text: 'Reports' }, - {route: './project-management', icon: 'far fa-folder-open', text: 'Projects' }, - {route: './activities-management', icon: 'far fa-file-alt', text: 'Activities' } + {route: '/time-clock', icon: 'far fa-clock', text: 'Time Clock' }, + {route: '/time-entries', icon: 'far fa-list-alt', text: 'Time Entries' }, + {route: '/reports', icon: 'fas fa-chart-pie', text: 'Reports' }, + {route: '/project-management', icon: 'far fa-folder-open', text: 'Projects' }, + {route: '/activities-management', icon: 'far fa-file-alt', text: 'Activities' } ]; } } diff --git a/src/app/modules/shared/components/user/user.component.html b/src/app/modules/shared/components/user/user.component.html index 76fed457e..a28505efd 100644 --- a/src/app/modules/shared/components/user/user.component.html +++ b/src/app/modules/shared/components/user/user.component.html @@ -1,19 +1,10 @@
- - diff --git a/src/app/modules/shared/components/user/user.component.spec.ts b/src/app/modules/shared/components/user/user.component.spec.ts index bf5e41717..9b44146e0 100644 --- a/src/app/modules/shared/components/user/user.component.spec.ts +++ b/src/app/modules/shared/components/user/user.component.spec.ts @@ -1,14 +1,28 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - +import { of } from 'rxjs'; import { UserComponent } from './user.component'; +import { AzureAdB2CService } from '../../../login/services/azure.ad.b2c.service'; describe('UserComponent', () => { let component: UserComponent; let fixture: ComponentFixture; + let azureAdB2CService: AzureAdB2CService; + + const azureAdB2CServiceStub = { + isLogin() { + return true; + }, + signIn() { + return of(); + } + }; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ UserComponent ] + declarations: [ UserComponent ], + providers: [ + { providers: AzureAdB2CService, useValue: azureAdB2CServiceStub} + ] }) .compileComponents(); })); @@ -17,9 +31,19 @@ describe('UserComponent', () => { fixture = TestBed.createComponent(UserComponent); component = fixture.componentInstance; fixture.detectChanges(); + azureAdB2CService = TestBed.inject(AzureAdB2CService); }); - it('should be created', () => { + it('should be created user component ', () => { expect(component).toBeTruthy(); }); + + it('should check onInit', () => { + spyOn(azureAdB2CService, 'isLogin').and.returnValue(true); + spyOn(azureAdB2CService, 'getName').and.returnValue('Name'); + component.ngOnInit(); + expect(azureAdB2CService.isLogin).toHaveBeenCalled; + expect(azureAdB2CService.getName).toHaveBeenCalled; + }); + }); diff --git a/src/app/modules/shared/components/user/user.component.ts b/src/app/modules/shared/components/user/user.component.ts index 5df0c83d0..dfab1c71d 100644 --- a/src/app/modules/shared/components/user/user.component.ts +++ b/src/app/modules/shared/components/user/user.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit } from '@angular/core'; +import { AzureAdB2CService } from '../../../login/services/azure.ad.b2c.service'; @Component({ selector: 'app-user', @@ -7,9 +8,17 @@ import { Component, OnInit } from '@angular/core'; }) export class UserComponent implements OnInit { - constructor() { } + name: string = '' + constructor(private azureAdB2CService: AzureAdB2CService) { } ngOnInit(): void { + if(this.azureAdB2CService.isLogin()) { + this.name = this.azureAdB2CService.getName() + } + } + + logout() { + this.azureAdB2CService.logout() } } diff --git a/src/app/modules/shared/pipes/group-by-date/group-by-date.pipe.spec.ts b/src/app/modules/shared/pipes/group-by-date/group-by-date.pipe.spec.ts index b8b4906ff..ddf869c20 100644 --- a/src/app/modules/shared/pipes/group-by-date/group-by-date.pipe.spec.ts +++ b/src/app/modules/shared/pipes/group-by-date/group-by-date.pipe.spec.ts @@ -1,8 +1,75 @@ import { GroupByDatePipe } from './group-by-date.pipe'; +import { Pipe } from '@angular/core'; describe('GroupByDatePipe', () => { it('create an instance', () => { const pipe = new GroupByDatePipe(); expect(pipe).toBeTruthy(); }); + + it('create an instance', () => { + const pipe = new GroupByDatePipe(); + const date = '2020-02-05T15:36:15.887Z'; + const result = pipe.getDate(date); + expect(pipe.getDate).toHaveBeenCalled + expect(result).toEqual(new Date('2/5/2020').toLocaleDateString()) + }); + + it('should add new date', () => { + const entryList = [ + { + id: 'entry_1', + project: 'Mido - 05 de Febrero', + startDate: '2020-02-05T15:36:15.887Z', + endDate: '2020-02-05T18:36:15.887Z', + activity: 'development', + technology: 'Angular, TypeScript', + comments: 'No comments', + ticket: 'EY-25' + }, + { + id: 'entry_2', + project: 'Mido 15 de Marzo', + startDate: '2020-03-15T20:36:15.887Z', + endDate: '2020-03-15T23:36:15.887Z', + activity: 'development', + technology: 'Angular, TypeScript', + comments: 'No comments', + ticket: 'EY-38' + }, + { + id: 'entry_3', + project: 'GoSpace 15 y 16 de Marzo', + startDate: '2020-03-15T23:36:15.887Z', + endDate: '2020-03-16T05:36:15.887Z', + activity: 'development', + technology: 'Angular, TypeScript', + comments: 'No comments', + ticket: 'EY-225' + }, + { + id: 'entry_4', + project: 'Mido 16 de Marzo', + startDate: '2020-03-16T15:36:15.887Z', + endDate: '2020-03-16T18:36:15.887Z', + activity: 'development', + technology: 'Angular, TypeScript', + comments: 'No comments', + ticket: 'EY-89' + }, + { + id: 'entry_5', + project: 'Ernst&Young 01 de Abril', + startDate: '2020-04-01T09:36:15.887Z', + endDate: '2020-04-01T15:36:15.887Z', + activity: 'development', + technology: 'Angular, TypeScript', + comments: 'No comments', + ticket: 'EY-59' + } + ]; + const pipe = new GroupByDatePipe(); + pipe.transform(entryList) + expect(pipe.transform).toHaveBeenCalled + }); }); diff --git a/src/app/modules/time-entries/pages/time-entries.component.spec.ts b/src/app/modules/time-entries/pages/time-entries.component.spec.ts index b80ba7d36..4d5516a4d 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.spec.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.spec.ts @@ -61,7 +61,7 @@ describe('TimeEntriesComponent', () => { it('should call dataByMonth in ngOnInit()', async(() => { component.ngOnInit(); - expect(component.dataByMonth.length).toEqual(3); + expect(component.dataByMonth.length).toEqual(1); })); it('should open Delete Modal', () => { @@ -91,9 +91,9 @@ describe('TimeEntriesComponent', () => { }); it('should delete a Entry', () => { - const entryId = 'entry_2'; + const entryId = 'entry_5'; component.removeEntry(entryId); - expect(component.dataByMonth.length).toBe(2); + expect(component.dataByMonth.length).toBe(0); }); it('should get the entry List by Month', () => { diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 3612073bc..84b2f5826 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -1,3 +1,9 @@ +import * as keys from './.keys.json'; + export const environment = { production: true }; + +export const AUTHORITY = keys.authority; +export const CLIENT_ID = keys.client_id; +export const SCOPES = keys.scopes; \ No newline at end of file diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 7b4f817ad..21d08f023 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -1,11 +1,16 @@ // This file can be replaced during build by using the `fileReplacements` array. // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. // The list of file replacements can be found in `angular.json`. +import * as keys from './.keys.json'; export const environment = { production: false }; +export const AUTHORITY = keys.authority; +export const CLIENT_ID = keys.client_id; +export const SCOPES = keys.scopes; + /* * For easier debugging in development mode, you can import the following file * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. diff --git a/src/environments/keys.example.json b/src/environments/keys.example.json new file mode 100644 index 000000000..c65a76e7f --- /dev/null +++ b/src/environments/keys.example.json @@ -0,0 +1,6 @@ +{ + "authority": "XXXXX", + "client_id": "XXXXX", + "scopes": ["XXXXX"] + } + \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 30956ae7e..582f5574d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,6 +21,7 @@ }, "angularCompilerOptions": { "fullTemplateTypeCheck": true, - "strictInjectionParameters": true + "strictInjectionParameters": true, + "resolveJsonModule": true } }