Skip to content

Commit 0a97c63

Browse files
fix: TT-106 Syntax correction in the ProjectListHover, EntryFields, TimeClock components and test files
1 parent d467356 commit 0a97c63

File tree

6 files changed

+152
-34
lines changed

6 files changed

+152
-34
lines changed

src/app/modules/time-clock/components/entry-fields/entry-fields.component.spec.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Observable, of } from 'rxjs';
12
import { LoadActiveEntry, EntryActionTypes, UpdateEntry } from './../../store/entry.actions';
23
import { ActivityManagementActionTypes } from './../../../activities-management/store/activity-management.actions';
34
import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
@@ -15,6 +16,7 @@ import { formatDate } from '@angular/common';
1516
import { NgxMaterialTimepickerModule } from 'ngx-material-timepicker';
1617
import * as moment from 'moment';
1718
import { DATE_FORMAT_YEAR } from 'src/environments/environment';
19+
import { FeatureManagerService } from 'src/app/modules/shared/feature-toggles/feature-toggle-manager.service';
1820

1921
describe('EntryFieldsComponent', () => {
2022
type Merged = TechnologyState & ProjectState;
@@ -24,6 +26,7 @@ describe('EntryFieldsComponent', () => {
2426
let mockTechnologySelector;
2527
let mockProjectsSelector;
2628
let entryForm;
29+
let featureManagerService: FeatureManagerService;
2730
const actionSub: ActionsSubject = new ActionsSubject();
2831
const toastrServiceStub = {
2932
error: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { },
@@ -114,6 +117,7 @@ describe('EntryFieldsComponent', () => {
114117
entryForm = TestBed.inject(FormBuilder);
115118
mockTechnologySelector = store.overrideSelector(allTechnologies, state.technologies);
116119
mockProjectsSelector = store.overrideSelector(getCustomerProjects, state.projects);
120+
featureManagerService = TestBed.inject(FeatureManagerService);
117121
}));
118122

119123
beforeEach(() => {
@@ -136,8 +140,6 @@ describe('EntryFieldsComponent', () => {
136140

137141
spyOn(component.entryForm, 'patchValue');
138142

139-
component.setDataToUpdate(entry);
140-
141143
expect(component.entryForm.patchValue).toHaveBeenCalledTimes(1);
142144
expect(component.entryForm.patchValue).toHaveBeenCalledWith(
143145
{
@@ -151,11 +153,22 @@ describe('EntryFieldsComponent', () => {
151153
expect(component.selectedTechnologies).toEqual([]);
152154
});
153155

156+
const exponentialGrowth = [true, false];
157+
exponentialGrowth.map((toggleValue) => {
158+
it(`when FeatureToggle is ${toggleValue} should return true`, () => {
159+
spyOn(featureManagerService, 'isToggleEnabled').and.returnValue(of(toggleValue));
160+
const isFeatureToggleActivated: Promise<boolean> = component.isFeatureToggleActivated();
161+
expect(featureManagerService.isToggleEnabled).toHaveBeenCalled();
162+
isFeatureToggleActivated.then((value) => expect(value).toEqual(toggleValue));
163+
});
164+
});
165+
154166
it('displays error message when the date selected is in the future', () => {
155167
const mockEntry = { ...entry,
156168
start_date : moment().format(DATE_FORMAT_YEAR),
157169
start_hour : moment().format('HH:mm')
158170
};
171+
159172
component.newData = mockEntry;
160173
component.activeEntry = mockEntry ;
161174
component.setDataToUpdate(mockEntry);
@@ -411,5 +424,4 @@ describe('EntryFieldsComponent', () => {
411424

412425
expect(component.selectedTechnologies).toBe(initialTechnologies);
413426
});
414-
415427
});

src/app/modules/time-clock/components/entry-fields/entry-fields.component.ts

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { ActivityManagementActionTypes } from './../../../activities-management/store/activity-management.actions';
22
import { EntryActionTypes, LoadActiveEntry } from './../../store/entry.actions';
3-
import { filter } from 'rxjs/operators';
4-
import { Component, OnInit } from '@angular/core';
3+
import { filter, map } from 'rxjs/operators';
4+
import { Component, OnDestroy, OnInit } from '@angular/core';
55
import { FormBuilder, FormGroup } from '@angular/forms';
66
import { Store, ActionsSubject, select } from '@ngrx/store';
77
import { Activity, NewEntry } from '../../../shared/models';
88
import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer';
99
import { TechnologyState } from '../../../shared/store/technology.reducers';
1010
import { ActivityState, LoadActivities } from '../../../activities-management/store';
11+
import { FeatureManagerService } from 'src/app/modules/shared/feature-toggles/feature-toggle-manager.service';
1112

1213
import * as entryActions from '../../store/entry.actions';
1314
import { get } from 'lodash';
@@ -16,6 +17,7 @@ import { ToastrService } from 'ngx-toastr';
1617
import { formatDate } from '@angular/common';
1718
import { getTimeEntriesDataSource } from '../../store/entry.selectors';
1819
import { DATE_FORMAT } from 'src/environments/environment';
20+
import { Subscription } from 'rxjs';
1921

2022
type Merged = TechnologyState & ProjectState & ActivityState;
2123

@@ -24,16 +26,25 @@ type Merged = TechnologyState & ProjectState & ActivityState;
2426
templateUrl: './entry-fields.component.html',
2527
styleUrls: ['./entry-fields.component.scss'],
2628
})
27-
export class EntryFieldsComponent implements OnInit {
29+
export class EntryFieldsComponent implements OnInit, OnDestroy {
2830
entryForm: FormGroup;
2931
selectedTechnologies: string[] = [];
3032
activities: Activity[] = [];
3133
activeEntry;
3234
newData;
3335
lastEntry;
3436
showTimeInbuttons = false;
37+
loadActivitiesSubscribe: Subscription;
38+
loadActiveEntrySubscribe: Subscription;
39+
actionSetDateSubscribe: Subscription;
40+
loadActivitiesSubject;
41+
loadActiveEntrySubject;
42+
actionSetDateSubject;
43+
44+
exponentialGrowth;
3545

3646
constructor(
47+
private featureManagerService: FeatureManagerService,
3748
private formBuilder: FormBuilder,
3849
private store: Store<Merged>,
3950
private actionsSubject$: ActionsSubject,
@@ -48,17 +59,20 @@ export class EntryFieldsComponent implements OnInit {
4859
});
4960
}
5061

51-
ngOnInit(): void {
62+
63+
async ngOnInit(): Promise<void> {
64+
this.exponentialGrowth = await this.isFeatureToggleActivated();
5265
this.store.dispatch(new LoadActivities());
5366
this.store.dispatch(new entryActions.LoadEntries(new Date().getMonth() + 1, new Date().getFullYear()));
54-
this.actionsSubject$
67+
this.loadActivitiesSubject = this.actionsSubject$
5568
.pipe(filter((action: any) => action.type === ActivityManagementActionTypes.LOAD_ACTIVITIES_SUCCESS))
5669
.subscribe((action) => {
5770
this.activities = action.payload;
5871
this.store.dispatch(new LoadActiveEntry());
5972
});
60-
61-
this.actionsSubject$
73+
// tslint:disable-next-line
74+
this.exponentialGrowth ? this.loadActivitiesSubscribe = this.loadActivitiesSubject : this.loadActivitiesSubject;
75+
this.loadActiveEntrySubject = this.actionsSubject$
6276
.pipe(
6377
filter(
6478
(action: any) =>
@@ -76,8 +90,9 @@ export class EntryFieldsComponent implements OnInit {
7690
this.store.dispatch(new entryActions.LoadEntriesSummary());
7791
}
7892
});
79-
80-
this.actionsSubject$
93+
// tslint:disable-next-line
94+
this.exponentialGrowth ? this.loadActiveEntrySubscribe = this.loadActiveEntrySubject : this.loadActiveEntrySubject;
95+
this.actionSetDateSubject = this.actionsSubject$
8196
.pipe(filter((action: any) => action.type === EntryActionTypes.LOAD_ACTIVE_ENTRY_SUCCESS))
8297
.subscribe((action) => {
8398
this.activeEntry = action.payload;
@@ -90,17 +105,16 @@ export class EntryFieldsComponent implements OnInit {
90105
start_date: this.activeEntry.start_date,
91106
start_hour: formatDate(this.activeEntry.start_date, 'HH:mm', 'en'),
92107
};
93-
});
108+
});
109+
// tslint:disable-next-line
110+
this.exponentialGrowth ? this.actionSetDateSubscribe = this.actionSetDateSubject : this.actionSetDateSubject;
94111
}
95-
96112
get activity_id() {
97113
return this.entryForm.get('activity_id');
98114
}
99-
100115
get start_hour() {
101116
return this.entryForm.get('start_hour');
102117
}
103-
104118
setDataToUpdate(entryData: NewEntry) {
105119
if (entryData) {
106120
this.entryForm.patchValue({
@@ -174,4 +188,22 @@ export class EntryFieldsComponent implements OnInit {
174188
onTechnologyRemoved($event: string[]) {
175189
this.store.dispatch(new entryActions.UpdateEntryRunning({ ...this.newData, technologies: $event }));
176190
}
191+
192+
193+
ngOnDestroy(): void {
194+
195+
if (this.exponentialGrowth) {
196+
this.loadActivitiesSubscribe.unsubscribe();
197+
this.loadActiveEntrySubscribe.unsubscribe();
198+
this.actionSetDateSubscribe.unsubscribe();
199+
}
200+
}
201+
202+
isFeatureToggleActivated() {
203+
return this.featureManagerService.isToggleEnabledForUser('exponential-growth').pipe(
204+
map((enabled) => {
205+
return enabled === true ? true : false;
206+
})
207+
).toPromise();
208+
}
177209
}

src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.spec.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,20 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
55
import { provideMockStore, MockStore } from '@ngrx/store/testing';
66
import { HttpClientTestingModule } from '@angular/common/http/testing';
77
import { AutocompleteLibModule } from 'angular-ng-autocomplete';
8-
import { Subscription } from 'rxjs';
8+
import { Subscription, of } from 'rxjs';
99
import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer';
1010
import { getCustomerProjects } from '../../../customer-management/components/projects/components/store/project.selectors';
1111
import { FilterProjectPipe } from '../../../shared/pipes';
1212
import { UpdateEntryRunning } from '../../store/entry.actions';
1313
import { ProjectListHoverComponent } from './project-list-hover.component';
14+
import { FeatureManagerService } from 'src/app/modules/shared/feature-toggles/feature-toggle-manager.service';
1415

1516
describe('ProjectListHoverComponent', () => {
1617
let component: ProjectListHoverComponent;
1718
let fixture: ComponentFixture<ProjectListHoverComponent>;
1819
let store: MockStore<ProjectState>;
1920
let mockProjectsSelector;
21+
let featureManagerService: FeatureManagerService;
2022
const toastrServiceStub = {
2123
error: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { }
2224
};
@@ -56,6 +58,7 @@ describe('ProjectListHoverComponent', () => {
5658
fixture = TestBed.createComponent(ProjectListHoverComponent);
5759
component = fixture.componentInstance;
5860
fixture.detectChanges();
61+
featureManagerService = TestBed.inject(FeatureManagerService);
5962
});
6063

6164
it('should create', () => {
@@ -118,7 +121,15 @@ describe('ProjectListHoverComponent', () => {
118121
.toHaveBeenCalledWith({ project_id: 'customer - xyz'});
119122
});
120123

121-
124+
const exponentialGrowth = [true, false];
125+
exponentialGrowth.map((toggleValue) => {
126+
it(`when FeatureToggle is ${toggleValue} should return true`, () => {
127+
spyOn(featureManagerService, 'isToggleEnabled').and.returnValue(of(toggleValue));
128+
const isFeatureToggleActivated: Promise<boolean> = component.isFeatureToggleActivated();
129+
expect(featureManagerService.isToggleEnabled).toHaveBeenCalled();
130+
isFeatureToggleActivated.then((value) => expect(value).toEqual(toggleValue));
131+
});
132+
});
122133
// TODO Fix this test since it is throwing this error
123134
// Expected spy dispatch to have been called with:
124135
// [CreateEntry({ payload: Object({ project_id: '1', start_date: '2020-07-27T22:30:26.743Z', timezone_offset: 300 }),
@@ -140,5 +151,4 @@ describe('ProjectListHoverComponent', () => {
140151
// })
141152
// );
142153
// });
143-
144154
});

src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,48 @@ import { FormBuilder, FormGroup } from '@angular/forms';
33
import { ActionsSubject, select, Store } from '@ngrx/store';
44
import { ToastrService } from 'ngx-toastr';
55
import { Observable, Subscription } from 'rxjs';
6-
import { delay, filter } from 'rxjs/operators';
6+
import { delay, filter, map } from 'rxjs/operators';
77
import { Project } from 'src/app/modules/shared/models';
88
import * as actions from '../../../customer-management/components/projects/components/store/project.actions';
99
import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer';
1010
import * as entryActions from '../../store/entry.actions';
1111
import { getIsLoading, getProjects } from './../../../customer-management/components/projects/components/store/project.selectors';
1212
import { EntryActionTypes } from './../../store/entry.actions';
1313
import { getActiveTimeEntry } from './../../store/entry.selectors';
14+
import { FeatureManagerService } from 'src/app/modules/shared/feature-toggles/feature-toggle-manager.service';
1415
@Component({
1516
selector: 'app-project-list-hover',
1617
templateUrl: './project-list-hover.component.html',
1718
styleUrls: ['./project-list-hover.component.scss'],
1819
})
1920
export class ProjectListHoverComponent implements OnInit, OnDestroy {
20-
2121
keyword = 'search_field';
2222
listProjects: Project[] = [];
2323
activeEntry;
2424
projectsForm: FormGroup;
2525
showClockIn: boolean;
2626
updateEntrySubscription: Subscription;
2727
isLoading$: Observable<boolean>;
28+
projectsSubscribe: Subscription;
29+
activeEntrySubscribe: Subscription;
30+
projectsSubject;
31+
activeEntrySubject;
32+
exponentialGrowth;
2833

29-
constructor(private formBuilder: FormBuilder, private store: Store<ProjectState>,
34+
constructor(private featureManagerService: FeatureManagerService,
35+
private formBuilder: FormBuilder, private store: Store<ProjectState>,
3036
private actionsSubject$: ActionsSubject, private toastrService: ToastrService) {
3137
this.projectsForm = this.formBuilder.group({ project_id: null, });
3238
this.isLoading$ = this.store.pipe(delay(0), select(getIsLoading));
3339
}
3440

35-
ngOnInit(): void {
41+
async ngOnInit(): Promise<void> {
42+
43+
this.exponentialGrowth = await this.isFeatureToggleActivated();
44+
3645
this.store.dispatch(new actions.LoadProjects());
3746
const projects$ = this.store.pipe(select(getProjects));
38-
projects$.subscribe((projects) => {
47+
this.projectsSubject = projects$.subscribe((projects) => {
3948
this.listProjects = [];
4049
projects.forEach((project) => {
4150
const projectWithSearchField = {...project};
@@ -45,7 +54,8 @@ export class ProjectListHoverComponent implements OnInit, OnDestroy {
4554
);
4655
this.loadActiveTimeEntry();
4756
});
48-
57+
// tslint:disable-next-line
58+
this.exponentialGrowth ? this.projectsSubscribe = this.projectsSubject : this.projectsSubject;
4959
this.updateEntrySubscription = this.actionsSubject$.pipe(
5060
filter((action: any) => (
5161
action.type === EntryActionTypes.UPDATE_ENTRY_SUCCESS
@@ -61,7 +71,7 @@ export class ProjectListHoverComponent implements OnInit, OnDestroy {
6171
loadActiveTimeEntry() {
6272
this.store.dispatch(new entryActions.LoadActiveEntry());
6373
const activeEntry$ = this.store.pipe(select(getActiveTimeEntry));
64-
activeEntry$.subscribe((activeEntry) => {
74+
this.activeEntrySubject = activeEntry$.subscribe((activeEntry) => {
6575
this.activeEntry = activeEntry;
6676
if (activeEntry) {
6777
this.showClockIn = false;
@@ -71,8 +81,9 @@ export class ProjectListHoverComponent implements OnInit, OnDestroy {
7181
this.projectsForm.setValue({ project_id: null });
7282
}
7383
});
84+
// tslint:disable-next-line
85+
this.exponentialGrowth ? this.activeEntrySubscribe = this.activeEntrySubject : this.activeEntrySubject;
7486
}
75-
7687
setSelectedProject() {
7788
this.listProjects.forEach( (project) => {
7889
if (project.id === this.activeEntry.project_id) {
@@ -110,6 +121,18 @@ export class ProjectListHoverComponent implements OnInit, OnDestroy {
110121
}
111122

112123
ngOnDestroy(): void {
124+
if (this.exponentialGrowth) {
125+
this.projectsSubscribe.unsubscribe();
126+
this.activeEntrySubscribe.unsubscribe();
127+
}
113128
this.updateEntrySubscription.unsubscribe();
114129
}
130+
131+
isFeatureToggleActivated() {
132+
return this.featureManagerService.isToggleEnabledForUser('exponential-growth').pipe(
133+
map((enabled) => {
134+
return enabled === true ? true : false;
135+
})
136+
).toPromise();
137+
}
115138
}

src/app/modules/time-clock/pages/time-clock.component.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { of } from 'rxjs';
12
import { FormBuilder } from '@angular/forms';
23
import { StopTimeEntryRunning, EntryActionTypes, LoadEntriesSummary } from './../store/entry.actions';
34
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
@@ -11,12 +12,14 @@ import { AzureAdB2CService } from '../../login/services/azure.ad.b2c.service';
1112
import { ActionsSubject } from '@ngrx/store';
1213
import { EntryFieldsComponent } from '../components/entry-fields/entry-fields.component';
1314
import { ToastrService } from 'ngx-toastr';
15+
import { FeatureManagerService } from 'src/app/modules/shared/feature-toggles/feature-toggle-manager.service';
1416

1517
describe('TimeClockComponent', () => {
1618
let component: TimeClockComponent;
1719
let fixture: ComponentFixture<TimeClockComponent>;
1820
let store: MockStore<ProjectState>;
1921
let azureAdB2CService: AzureAdB2CService;
22+
let featureManagerService: FeatureManagerService;
2023
const actionSub: ActionsSubject = new ActionsSubject();
2124

2225
let injectedToastrService;
@@ -69,6 +72,7 @@ describe('TimeClockComponent', () => {
6972
fixture.detectChanges();
7073
azureAdB2CService = TestBed.inject(AzureAdB2CService);
7174
injectedToastrService = TestBed.inject(ToastrService);
75+
featureManagerService = TestBed.inject(FeatureManagerService);
7276
});
7377

7478
it('should be created', () => {
@@ -142,4 +146,14 @@ describe('TimeClockComponent', () => {
142146

143147
expect(injectedToastrService.error).toHaveBeenCalled();
144148
});
149+
150+
const exponentialGrowth = [true, false];
151+
exponentialGrowth.map((toggleValue) => {
152+
it(`when FeatureToggle is ${toggleValue} should return true`, () => {
153+
spyOn(featureManagerService, 'isToggleEnabled').and.returnValue(of(toggleValue));
154+
const isFeatureToggleActivated: Promise<boolean> = component.isFeatureToggleActivated();
155+
expect(featureManagerService.isToggleEnabled).toHaveBeenCalled();
156+
isFeatureToggleActivated.then((value) => expect(value).toEqual(toggleValue));
157+
});
158+
});
145159
});

0 commit comments

Comments
 (0)