@ieeesa-npm/tenants 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/.eslintrc.json +31 -0
  2. package/ng-package.json +8 -0
  3. package/package.json +12 -25
  4. package/src/lib/assets/constants.json +454 -0
  5. package/src/lib/assets/tenant-validations.ts +18 -0
  6. package/src/lib/assets/tenants-mock.ts +1240 -0
  7. package/src/lib/components/create-modify-group-type/create-modify-group-type.component.html +15 -0
  8. package/src/lib/components/create-modify-group-type/create-modify-group-type.component.scss +44 -0
  9. package/src/lib/components/create-modify-group-type/create-modify-group-type.component.spec.ts +574 -0
  10. package/src/lib/components/create-modify-group-type/create-modify-group-type.component.ts +602 -0
  11. package/src/lib/components/create-modify-role/create-modify-role.component.html +15 -0
  12. package/src/lib/components/create-modify-role/create-modify-role.component.scss +83 -0
  13. package/src/lib/components/create-modify-role/create-modify-role.component.spec.ts +346 -0
  14. package/src/lib/components/create-modify-role/create-modify-role.component.ts +321 -0
  15. package/src/lib/components/create-tenant-application/create-tenant-application.component.html +18 -0
  16. package/src/lib/components/create-tenant-application/create-tenant-application.component.scss +73 -0
  17. package/src/lib/components/create-tenant-application/create-tenant-application.component.spec.ts +775 -0
  18. package/src/lib/components/create-tenant-application/create-tenant-application.component.ts +638 -0
  19. package/src/lib/components/roles-and-permissions-mapping/roles-and-permissions-mapping.component.html +22 -0
  20. package/src/lib/components/roles-and-permissions-mapping/roles-and-permissions-mapping.component.scss +79 -0
  21. package/src/lib/components/roles-and-permissions-mapping/roles-and-permissions-mapping.component.spec.ts +716 -0
  22. package/src/lib/components/roles-and-permissions-mapping/roles-and-permissions-mapping.component.ts +504 -0
  23. package/src/lib/components/tenant-basic-details/tenant-basic-details.component.html +44 -0
  24. package/src/lib/components/tenant-basic-details/tenant-basic-details.component.scss +16 -0
  25. package/src/lib/components/tenant-basic-details/tenant-basic-details.component.spec.ts +115 -0
  26. package/src/lib/components/tenant-basic-details/tenant-basic-details.component.ts +109 -0
  27. package/src/lib/components/view-tenant-details/view-tenant-details.component.html +195 -0
  28. package/src/lib/components/view-tenant-details/view-tenant-details.component.scss +163 -0
  29. package/src/lib/components/view-tenant-details/view-tenant-details.component.spec.ts +1221 -0
  30. package/src/lib/components/view-tenant-details/view-tenant-details.component.ts +876 -0
  31. package/src/lib/components/view-tenant-group-types/view-tenant-group-types.component.html +10 -0
  32. package/src/lib/components/view-tenant-group-types/view-tenant-group-types.component.scss +44 -0
  33. package/src/lib/components/view-tenant-group-types/view-tenant-group-types.component.spec.ts +410 -0
  34. package/src/lib/components/view-tenant-group-types/view-tenant-group-types.component.ts +219 -0
  35. package/src/lib/components/view-tenants-list/view-tenants-list.component.html +32 -0
  36. package/src/lib/components/view-tenants-list/view-tenants-list.component.scss +35 -0
  37. package/src/lib/components/view-tenants-list/view-tenants-list.component.spec.ts +464 -0
  38. package/src/lib/components/view-tenants-list/view-tenants-list.component.ts +388 -0
  39. package/src/lib/models/app-type-config.model.ts +14 -0
  40. package/src/lib/models/app-type.model.ts +5 -0
  41. package/src/lib/models/create-group-type-config.model.ts +18 -0
  42. package/src/lib/models/create-group-type.model.ts +46 -0
  43. package/src/lib/models/feature-permission-id.model.ts +6 -0
  44. package/src/lib/models/features.model.ts +15 -0
  45. package/src/lib/models/form-status.model.ts +5 -0
  46. package/src/lib/models/permission-type.model.ts +9 -0
  47. package/src/lib/models/role-menu-action.model.ts +5 -0
  48. package/src/lib/models/role-type.model.ts +34 -0
  49. package/src/lib/models/roles-and-permissions-table-type.model.ts +5 -0
  50. package/src/lib/models/roles-and-permissions.model.ts +113 -0
  51. package/src/lib/models/route-config.model.ts +4 -0
  52. package/src/lib/models/table-column-schema-view-tenant-list.model.ts +21 -0
  53. package/src/lib/models/tenant-function-type.model.ts +10 -0
  54. package/src/lib/models/tenant.model.ts +47 -0
  55. package/src/lib/models/tenants-permission.model.ts +9 -0
  56. package/src/lib/models/update-tenant-status.model.ts +12 -0
  57. package/src/lib/models/view-tenant-group-types.model.ts +34 -0
  58. package/src/lib/services/tenant-applications.service.spec.ts +1245 -0
  59. package/src/lib/services/tenant-applications.service.ts +798 -0
  60. package/src/lib/services/tenant-permissions-map.service.spec.ts +25 -0
  61. package/src/lib/services/tenant-permissions-map.service.ts +28 -0
  62. package/src/lib/services/tenant-permissions.service.spec.ts +62 -0
  63. package/src/lib/services/tenant-permissions.service.ts +49 -0
  64. package/src/lib/tenant-applications.component.html +0 -0
  65. package/src/lib/tenant-applications.component.scss +0 -0
  66. package/src/lib/tenant-applications.component.spec.ts +28 -0
  67. package/src/lib/tenant-applications.component.ts +12 -0
  68. package/src/lib/tenant-applications.module.ts +8 -0
  69. package/{public-api.d.ts → src/public-api.ts} +40 -30
  70. package/tsconfig.lib.json +14 -0
  71. package/tsconfig.lib.prod.json +10 -0
  72. package/tsconfig.spec.json +14 -0
  73. package/esm2022/ieeesa-npm-tenants.mjs +0 -5
  74. package/esm2022/lib/assets/constants.json +0 -390
  75. package/esm2022/lib/assets/tenant-validations.mjs +0 -13
  76. package/esm2022/lib/components/create-modify-role/create-modify-role.component.mjs +0 -280
  77. package/esm2022/lib/components/create-tenant-application/create-tenant-application.component.mjs +0 -512
  78. package/esm2022/lib/components/roles-and-permissions-mapping/roles-and-permissions-mapping.component.mjs +0 -391
  79. package/esm2022/lib/components/tenant-basic-details/tenant-basic-details.component.mjs +0 -95
  80. package/esm2022/lib/components/view-tenant-details/view-tenant-details.component.mjs +0 -708
  81. package/esm2022/lib/components/view-tenant-group-types/view-tenant-group-types.component.mjs +0 -174
  82. package/esm2022/lib/components/view-tenants-list/view-tenants-list.component.mjs +0 -334
  83. package/esm2022/lib/models/app-type-config.model.mjs +0 -2
  84. package/esm2022/lib/models/app-type.model.mjs +0 -7
  85. package/esm2022/lib/models/feature-permission-id.model.mjs +0 -8
  86. package/esm2022/lib/models/features.model.mjs +0 -2
  87. package/esm2022/lib/models/form-status.model.mjs +0 -7
  88. package/esm2022/lib/models/permission-type.model.mjs +0 -12
  89. package/esm2022/lib/models/role-menu-action.model.mjs +0 -7
  90. package/esm2022/lib/models/role-type.model.mjs +0 -2
  91. package/esm2022/lib/models/roles-and-permissions-table-type.model.mjs +0 -7
  92. package/esm2022/lib/models/roles-and-permissions.model.mjs +0 -2
  93. package/esm2022/lib/models/route-config.model.mjs +0 -2
  94. package/esm2022/lib/models/table-column-schema-view-tenant-list.model.mjs +0 -16
  95. package/esm2022/lib/models/tenant-function-type.model.mjs +0 -10
  96. package/esm2022/lib/models/tenant.model.mjs +0 -2
  97. package/esm2022/lib/models/tenants-permission.model.mjs +0 -2
  98. package/esm2022/lib/models/update-tenant-status.model.mjs +0 -2
  99. package/esm2022/lib/models/view-tenant-group-types.model.mjs +0 -9
  100. package/esm2022/lib/services/tenant-applications.service.mjs +0 -542
  101. package/esm2022/lib/services/tenant-permissions-map.service.mjs +0 -36
  102. package/esm2022/lib/services/tenant-permissions.service.mjs +0 -38
  103. package/esm2022/lib/tenant-applications.component.mjs +0 -14
  104. package/esm2022/lib/tenant-applications.module.mjs +0 -16
  105. package/esm2022/public-api.mjs +0 -34
  106. package/fesm2022/ieeesa-npm-tenants.mjs +0 -3565
  107. package/fesm2022/ieeesa-npm-tenants.mjs.map +0 -1
  108. package/index.d.ts +0 -5
  109. package/lib/assets/tenant-validations.d.ts +0 -11
  110. package/lib/components/create-modify-role/create-modify-role.component.d.ts +0 -103
  111. package/lib/components/create-tenant-application/create-tenant-application.component.d.ts +0 -128
  112. package/lib/components/roles-and-permissions-mapping/roles-and-permissions-mapping.component.d.ts +0 -106
  113. package/lib/components/tenant-basic-details/tenant-basic-details.component.d.ts +0 -408
  114. package/lib/components/view-tenant-details/view-tenant-details.component.d.ts +0 -216
  115. package/lib/components/view-tenant-group-types/view-tenant-group-types.component.d.ts +0 -58
  116. package/lib/components/view-tenants-list/view-tenants-list.component.d.ts +0 -134
  117. package/lib/models/app-type-config.model.d.ts +0 -14
  118. package/lib/models/app-type.model.d.ts +0 -4
  119. package/lib/models/feature-permission-id.model.d.ts +0 -4
  120. package/lib/models/features.model.d.ts +0 -15
  121. package/lib/models/form-status.model.d.ts +0 -4
  122. package/lib/models/permission-type.model.d.ts +0 -8
  123. package/lib/models/role-menu-action.model.d.ts +0 -4
  124. package/lib/models/role-type.model.d.ts +0 -27
  125. package/lib/models/roles-and-permissions-table-type.model.d.ts +0 -4
  126. package/lib/models/roles-and-permissions.model.d.ts +0 -119
  127. package/lib/models/route-config.model.d.ts +0 -4
  128. package/lib/models/table-column-schema-view-tenant-list.model.d.ts +0 -20
  129. package/lib/models/tenant-function-type.model.d.ts +0 -7
  130. package/lib/models/tenant.model.d.ts +0 -51
  131. package/lib/models/tenants-permission.model.d.ts +0 -9
  132. package/lib/models/update-tenant-status.model.d.ts +0 -14
  133. package/lib/models/view-tenant-group-types.model.d.ts +0 -27
  134. package/lib/services/tenant-applications.service.d.ts +0 -357
  135. package/lib/services/tenant-permissions-map.service.d.ts +0 -13
  136. package/lib/services/tenant-permissions.service.d.ts +0 -22
  137. package/lib/tenant-applications.component.d.ts +0 -5
  138. package/lib/tenant-applications.module.d.ts +0 -6
@@ -0,0 +1,775 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
3
+ import { validColorValidator } from 'ngx-colors';
4
+ import {
5
+ CheckboxOption,
6
+ FormModel,
7
+ RadioOption,
8
+ FormControlType,
9
+ FileUploadService,
10
+ } from '@ieeesa-npm/presentation';
11
+ import { Observable } from 'rxjs';
12
+ import { HttpErrorResponse } from '@angular/common/http';
13
+ import { AlertsService, GlobalErrorHandlerService } from '@ieeesa-npm/utility';
14
+ import {
15
+ MAT_DIALOG_DATA,
16
+ MatDialog,
17
+ MatDialogModule,
18
+ } from '@angular/material/dialog';
19
+ import { HttpClientTestingModule } from '@angular/common/http/testing';
20
+ import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
21
+ import { CreateTenantApplicationComponent } from './create-tenant-application.component';
22
+ import { TenantApplicationsService } from '../../services/tenant-applications.service';
23
+ import { TenantsValidationPatterns } from '../../assets/tenant-validations';
24
+ import { TenantsMocks } from '../../assets/tenants-mock';
25
+ import { TenantFunctionType } from '../../models/tenant-function-type.model';
26
+
27
+ describe('CreateTenantApplicationComponent', () => {
28
+ let component: CreateTenantApplicationComponent;
29
+ let fixture: ComponentFixture<CreateTenantApplicationComponent>;
30
+ let tenantAppService: TenantApplicationsService;
31
+ let globalErrorHandlerService: GlobalErrorHandlerService;
32
+ let fileUploadService: FileUploadService;
33
+ const formBuilder: FormBuilder = new FormBuilder();
34
+ const mockFormGroup = formBuilder.group({
35
+ appTitle: [
36
+ 'SAAPS1',
37
+ [
38
+ Validators.required,
39
+ Validators.maxLength(TenantsValidationPatterns.appTitleMaxLength),
40
+ ],
41
+ ],
42
+ appId: [
43
+ 'T001',
44
+ [
45
+ Validators.required,
46
+ Validators.maxLength(TenantsValidationPatterns.appIdMaxLength),
47
+ Validators.pattern(TenantsValidationPatterns.alphaNumeric),
48
+ ],
49
+ ],
50
+ appLogo: ['logo.svg', [Validators.required]],
51
+ appHeading: [
52
+ 'SAAPS1 Heading',
53
+ [
54
+ Validators.required,
55
+ Validators.maxLength(TenantsValidationPatterns.appHeadingMaxLength),
56
+ ],
57
+ ],
58
+ appDescription: [
59
+ 'SAAPS1 Description',
60
+ [
61
+ Validators.required,
62
+ Validators.maxLength(TenantsValidationPatterns.appDescriptionMaxLength),
63
+ ],
64
+ ],
65
+ backgroundColor: ['#ffffff', [Validators.required, validColorValidator()]],
66
+ appHelpLink: [
67
+ 'https://localhost:4200',
68
+ [Validators.required, Validators.pattern(TenantsValidationPatterns.url)],
69
+ ],
70
+ features: [[{ id: '1', name: 'test' }], [Validators.required]],
71
+ appDomainUrl: [
72
+ 'https://localhost:4200',
73
+ [Validators.required, Validators.pattern(TenantsValidationPatterns.url)],
74
+ ],
75
+ appType: [
76
+ 'AT_SAAPPS_25634ef4-07d7-4d98-ba8b-ad33ed330789',
77
+ [Validators.required],
78
+ ],
79
+ });
80
+ const dialogOptions = {
81
+ heading: 'New Application',
82
+ isCloseNeeded: true,
83
+ componentReference: CreateTenantApplicationComponent,
84
+ modalType: 1,
85
+ };
86
+ const mockFormModel: FormModel = {
87
+ formGroup: [
88
+ {
89
+ legend: '',
90
+ controls: [
91
+ {
92
+ type: FormControlType.INPUT,
93
+ controlName: 'appTitle',
94
+ },
95
+ {
96
+ type: FormControlType.INPUT,
97
+ controlName: 'appId',
98
+ },
99
+ {
100
+ type: FormControlType.INPUT,
101
+ controlName: 'appHeading',
102
+ },
103
+ {
104
+ type: FormControlType.TEXT_AREA,
105
+ controlName: 'appDescription',
106
+ },
107
+ {
108
+ type: FormControlType.COLOR_PICKER,
109
+ controlName: 'backgroundColor',
110
+ },
111
+ {
112
+ type: FormControlType.INPUT,
113
+ controlName: 'appHelpLink',
114
+ },
115
+ {
116
+ type: FormControlType.CHECKBOX,
117
+ controlName: 'features',
118
+ },
119
+ {
120
+ type: FormControlType.INPUT,
121
+ controlName: 'appDomainUrl',
122
+ },
123
+ {
124
+ type: FormControlType.RADIO,
125
+ controlName: 'appType',
126
+ },
127
+ ],
128
+ },
129
+ ],
130
+ };
131
+ const fileData = new Uint8Array(200);
132
+ const mockFile = new File([fileData], 'testFile.jpg', {
133
+ type: 'image/jpg',
134
+ });
135
+ const mockServerErrorResponse = new HttpErrorResponse({
136
+ error: 'test',
137
+ });
138
+ beforeEach(() => {
139
+ TestBed.configureTestingModule({
140
+ imports: [
141
+ CreateTenantApplicationComponent,
142
+ BrowserAnimationsModule,
143
+ ReactiveFormsModule,
144
+ HttpClientTestingModule,
145
+ MatDialogModule,
146
+ ],
147
+ providers: [
148
+ TenantApplicationsService,
149
+ AlertsService,
150
+ { provide: MAT_DIALOG_DATA, useValue: dialogOptions },
151
+ MatDialog,
152
+ FileUploadService,
153
+ ],
154
+ });
155
+ fixture = TestBed.createComponent(CreateTenantApplicationComponent);
156
+ tenantAppService = TestBed.inject(TenantApplicationsService);
157
+ globalErrorHandlerService = TestBed.inject(GlobalErrorHandlerService);
158
+ fileUploadService = TestBed.inject(FileUploadService);
159
+ component = fixture.componentInstance;
160
+ component.createTenantFormGroup = mockFormModel;
161
+ fixture.detectChanges();
162
+ });
163
+
164
+ it('should create', () => {
165
+ const componentInstance = fixture.componentInstance;
166
+ expect(componentInstance).toBeTruthy();
167
+ });
168
+
169
+ describe('#ngOnInit', () => {
170
+ it('should initialize the create tenant form group', () => {
171
+ component.createTenantFormGroup = mockFormModel;
172
+ component.ngOnInit();
173
+ expect(
174
+ component.createTenantFormGroup?.formGroup?.[0]?.controls?.length
175
+ ).toBe(9);
176
+ });
177
+ it('should return groupFunctionType as EDIT', () => {
178
+ tenantAppService.setTenantFunctionType(TenantFunctionType.EDIT);
179
+ component.ngOnInit();
180
+ expect(component.tenantFunctionType).toEqual(TenantFunctionType.EDIT);
181
+ });
182
+ it('should setSelectedTenantInformation when groupFunctionType is EDIT', () => {
183
+ component.tenantFunctionType = TenantFunctionType.EDIT;
184
+ tenantAppService.setSelectedTenantInformation(
185
+ TenantsMocks?.tenantInfoMock
186
+ );
187
+ component.ngOnInit();
188
+ expect(component.selectedTenantInfo).toEqual(
189
+ TenantsMocks?.tenantInfoMock
190
+ );
191
+ });
192
+ });
193
+
194
+ describe('#getFeatures', () => {
195
+ it('should call getFeatures and set features', () => {
196
+ const mockFeatures: CheckboxOption[] =
197
+ TenantsMocks.mockFeaturesFormattedDefaultResponse;
198
+ spyOn(tenantAppService, 'getFeatures').and.returnValue(
199
+ new Observable((subscriber) => {
200
+ subscriber.next(TenantsMocks.mockFeatureResponse);
201
+ })
202
+ );
203
+ component.getFeatures();
204
+ expect(component.featuresOptions).toEqual(mockFeatures);
205
+ });
206
+ it('should call getFeatures and set selected features as checked for EDIT functionType', () => {
207
+ const mockFeatures: CheckboxOption[] = [
208
+ {
209
+ id: 'FEATURE_c000425e-b716-4593-9b3f-74280741a4ee',
210
+ name: 'Groups & Rosters',
211
+ checked: true,
212
+ disabled: true,
213
+ },
214
+ {
215
+ id: 'FEATURE_049753e8-ea5c-4fad-adb0-e1456e69c7a5',
216
+ name: 'Meetings & Events',
217
+ checked: true,
218
+ disabled: false,
219
+ },
220
+ {
221
+ id: 'FEATURE_a0ad3616-20dc-43da-813f-9b76d33f227a',
222
+ name: 'Ballots',
223
+ checked: false,
224
+ disabled: false,
225
+ },
226
+ ];
227
+ component.tenantFunctionType = TenantFunctionType.EDIT;
228
+ component.selectedTenantInfo =
229
+ TenantsMocks?.viewTenantDetailsMockResponse?.body;
230
+ spyOn(tenantAppService, 'getFeatures').and.returnValue(
231
+ new Observable((subscriber) => {
232
+ subscriber.next(TenantsMocks.mockFeatureResponse);
233
+ })
234
+ );
235
+ component.getFeatures();
236
+ expect(component.featuresOptions).toEqual(mockFeatures);
237
+ });
238
+ it('should throw error in retrieving getFeatures', () => {
239
+ spyOn(tenantAppService, 'getFeatures').and.returnValue(
240
+ new Observable((subscriber) => {
241
+ subscriber.error(mockServerErrorResponse);
242
+ })
243
+ );
244
+ spyOn(globalErrorHandlerService, 'handleError');
245
+ component.getFeatures();
246
+ expect(globalErrorHandlerService.handleError).toHaveBeenCalledWith(
247
+ mockServerErrorResponse
248
+ );
249
+ });
250
+ });
251
+
252
+ describe('#getApplicationTypes', () => {
253
+ it('should call getApplicationTypes and set radio options', () => {
254
+ const mockAppTypes: RadioOption[] =
255
+ TenantsMocks.mockAppTypesFormattedResponse;
256
+ spyOn(tenantAppService, 'getApplicationTypes').and.returnValue(
257
+ new Observable((subscriber) => {
258
+ subscriber.next(TenantsMocks.mockAppTypesResponse);
259
+ })
260
+ );
261
+ component.getApplicationTypes();
262
+ expect(component.appTypeOptions).toEqual(mockAppTypes);
263
+ });
264
+ it('should call getApplicationTypes and set selected radio option as checked for EDIT functionType', () => {
265
+ const mockAppTypes: RadioOption[] = [
266
+ {
267
+ id: 'AT_SAAPPS_25634ef4-07d7-4d98-ba8b-ad33ed330789',
268
+ label: 'Generic',
269
+ checked: true,
270
+ },
271
+ {
272
+ id: 'AT_SAAPPS_ab655442-fe69-4aee-96cb-a661e6ea1e24',
273
+ label: 'Standalone',
274
+ checked: false,
275
+ },
276
+ ];
277
+ component.tenantFunctionType = TenantFunctionType.EDIT;
278
+ component.selectedTenantInfo =
279
+ TenantsMocks?.viewTenantDetailsMockResponse?.body;
280
+ spyOn(tenantAppService, 'getApplicationTypes').and.returnValue(
281
+ new Observable((subscriber) => {
282
+ subscriber.next(TenantsMocks.mockAppTypesResponse);
283
+ })
284
+ );
285
+ component.getApplicationTypes();
286
+ expect(component.appTypeOptions).toEqual(mockAppTypes);
287
+ });
288
+ it('should throw error in retrieving getApplicationTypes', () => {
289
+ spyOn(tenantAppService, 'getApplicationTypes').and.returnValue(
290
+ new Observable((subscriber) => {
291
+ subscriber.error(mockServerErrorResponse);
292
+ })
293
+ );
294
+ spyOn(globalErrorHandlerService, 'handleError');
295
+ component.getApplicationTypes();
296
+ expect(globalErrorHandlerService.handleError).toHaveBeenCalledWith(
297
+ mockServerErrorResponse
298
+ );
299
+ });
300
+ });
301
+ describe('#getCreateTenantPayload', () => {
302
+ it('should prepare the create tenant payload on form submit', () => {
303
+ const featureOptions = TenantsMocks.mockFeaturesFormattedResponse;
304
+ const mockFormGroup = formBuilder.group({
305
+ appTitle: [
306
+ 'SA Collaboration portal',
307
+ [
308
+ Validators.required,
309
+ Validators.maxLength(TenantsValidationPatterns.appTitleMaxLength),
310
+ ],
311
+ ],
312
+ appId: [
313
+ 'SAAPPS1',
314
+ [
315
+ Validators.required,
316
+ Validators.maxLength(TenantsValidationPatterns.appIdMaxLength),
317
+ Validators.pattern(TenantsValidationPatterns.alphaNumeric),
318
+ ],
319
+ ],
320
+ appLogo: ['logo.svg', [Validators.required]],
321
+ appHeading: [
322
+ 'SAAPPS Heading',
323
+ [
324
+ Validators.required,
325
+ Validators.maxLength(TenantsValidationPatterns.appHeadingMaxLength),
326
+ ],
327
+ ],
328
+ appDescription: [
329
+ 'SAAPPS Desc',
330
+ [
331
+ Validators.required,
332
+ Validators.maxLength(
333
+ TenantsValidationPatterns.appDescriptionMaxLength
334
+ ),
335
+ ],
336
+ ],
337
+ backgroundColor: [
338
+ '#000000',
339
+ [Validators.required, validColorValidator()],
340
+ ],
341
+ appHelpLink: [
342
+ 'https://localhost:4200',
343
+ [
344
+ Validators.required,
345
+ Validators.pattern(TenantsValidationPatterns.url),
346
+ ],
347
+ ],
348
+ features: formBuilder.array([
349
+ [
350
+ {
351
+ id: 'FEATURE_c000425e-b716-4593-9b3f-74280741a4ee',
352
+ name: 'Groups & Rosters',
353
+ checked: true,
354
+ disabled: true,
355
+ },
356
+ {
357
+ id: 'FEATURE_049753e8-ea5c-4fad-adb0-e1456e69c7a5',
358
+ name: 'Meetings & Events',
359
+ checked: true,
360
+ disable: false,
361
+ },
362
+ {
363
+ id: 'FEATURE_a0ad3616-20dc-43da-813f-9b76d33f227a',
364
+ name: 'Ballots',
365
+ checked: true,
366
+ disable: false,
367
+ },
368
+ ],
369
+ [Validators.required],
370
+ ]),
371
+ appDomainUrl: [
372
+ 'https://localhost:4200',
373
+ [
374
+ Validators.required,
375
+ Validators.pattern(TenantsValidationPatterns.url),
376
+ ],
377
+ ],
378
+ appType: [
379
+ 'AT_SAAPPS_25634ef4-07d7-4d98-ba8b-ad33ed330789',
380
+ [Validators.required],
381
+ ],
382
+ });
383
+ component.createTenantFormGroup = mockFormModel;
384
+ component.featuresOptions = featureOptions;
385
+ component.appTypeOptions = TenantsMocks.mockAppTypesFormattedResponse;
386
+ component.selectedAppTypeOption =
387
+ TenantsMocks.mockAppTypesFormattedResponse[0];
388
+ const payload = component.getCreateTenantPayload(
389
+ mockFormGroup?.getRawValue()
390
+ );
391
+ expect(payload).toEqual(TenantsMocks.createTenantMockPayload);
392
+ });
393
+ });
394
+ describe('#getCreateTenantFormGroupRef', () => {
395
+ it('should initialize getCreateTenantFormGroupRef', () => {
396
+ component.featuresOptions = TenantsMocks.mockFeaturesFormattedResponse;
397
+ const mockFormGroup = formBuilder.group({
398
+ appTitle: [
399
+ 'SAAPS1',
400
+ [
401
+ Validators.required,
402
+ Validators.maxLength(TenantsValidationPatterns.appTitleMaxLength),
403
+ ],
404
+ ],
405
+ appId: [
406
+ 'T001',
407
+ [
408
+ Validators.required,
409
+ Validators.maxLength(TenantsValidationPatterns.appIdMaxLength),
410
+ Validators.pattern(TenantsValidationPatterns.alphaNumeric),
411
+ ],
412
+ ],
413
+ appLogo: ['logo.svg', [Validators.required]],
414
+ appHeading: [
415
+ 'SAAPS1 Heading',
416
+ [
417
+ Validators.required,
418
+ Validators.maxLength(TenantsValidationPatterns.appHeadingMaxLength),
419
+ ],
420
+ ],
421
+ appDescription: [
422
+ 'SAAPS1 Description',
423
+ [
424
+ Validators.required,
425
+ Validators.maxLength(
426
+ TenantsValidationPatterns.appDescriptionMaxLength
427
+ ),
428
+ ],
429
+ ],
430
+ backgroundColor: [
431
+ '#ffffff',
432
+ [Validators.required, validColorValidator()],
433
+ ],
434
+ appHelpLink: [
435
+ 'https://localhost:4200',
436
+ [
437
+ Validators.required,
438
+ Validators.pattern(TenantsValidationPatterns.url),
439
+ ],
440
+ ],
441
+ features: formBuilder.array([
442
+ [{ id: '1', name: 'test' }],
443
+ [Validators.required],
444
+ ]),
445
+ appDomainUrl: [
446
+ 'https://localhost:4200',
447
+ [
448
+ Validators.required,
449
+ Validators.pattern(TenantsValidationPatterns.url),
450
+ ],
451
+ ],
452
+ appType: [
453
+ 'AT_SAAPPS_25634ef4-07d7-4d98-ba8b-ad33ed330789',
454
+ [Validators.required],
455
+ ],
456
+ });
457
+ component.createTenantFormGroup = mockFormModel;
458
+ fixture.detectChanges();
459
+ component.getCreateTenantFormGroupRef([mockFormGroup]);
460
+ expect(component.createTenantFormGroupRef).toEqual(mockFormGroup);
461
+ });
462
+ });
463
+ describe('#onCreateTenantFormChange', () => {
464
+ it('should call onCreateTenantFormChange whenever the form control value changes ', () => {
465
+ component.onCreateTenantFormChange([mockFormGroup]);
466
+ expect(component.createTenantFormGroupRef).toBe(mockFormGroup);
467
+ });
468
+ it('should set isAppLogoModified to true whenever the appLogo form control value changes and tenantFunctionType is EDIT', () => {
469
+ component.tenantFunctionType = TenantFunctionType.EDIT;
470
+ component.createTenantFormGroupRef = mockFormGroup;
471
+ component.createTenantFormGroupRef?.controls['appLogo']?.markAsDirty();
472
+ component.onCreateTenantFormChange([mockFormGroup]);
473
+ expect(component.isAppLogoModified).toBeTrue();
474
+ });
475
+ });
476
+ describe('#onFormCancel', () => {
477
+ it('should emit formCancel event', () => {
478
+ const formCancelEmitSpy = spyOn(
479
+ component.formCancel,
480
+ 'emit'
481
+ ).and.callThrough();
482
+ component.onFormCancel();
483
+ expect(formCancelEmitSpy).toHaveBeenCalled();
484
+ });
485
+ });
486
+ describe('#onFormFileUpload', () => {
487
+ it('should call onFormFileUpload method while browsing the file', () => {
488
+ component.onFormFileUpload(mockFile);
489
+ expect(component.file).toBe(mockFile);
490
+ });
491
+ });
492
+ describe('#onFormColorPickerChange', () => {
493
+ it('should call onColorPickerChange method while changing the color', () => {
494
+ component.onColorPickerChange('#000000');
495
+ expect(component.selectedColor).toBe('#000000');
496
+ });
497
+ });
498
+ describe('#onRadioOptionSelected', () => {
499
+ it('should call onRadioOptionSelected method while selecting the application type', () => {
500
+ const selectedAppType: RadioOption = { id: 1, label: 'Generic' };
501
+ component.onRadioOptionSelected(selectedAppType);
502
+ expect(component.selectedAppTypeOption).toBe(selectedAppType);
503
+ });
504
+ });
505
+ describe('#onCreateTenantFormSubmit and #getFileUploadPresignedUrl', () => {
506
+ it('should get the presigned url to upload the file', () => {
507
+ const mockPresignedUrlResponse = TenantsMocks.mockPreSignedUrlResponse;
508
+ component.file = mockFile;
509
+ const getPreseignedUrlSpy = spyOn(
510
+ fileUploadService,
511
+ 'getFileUploadPresignedUrl'
512
+ ).and.returnValue(
513
+ new Observable((subscriber) => {
514
+ subscriber.next(mockPresignedUrlResponse);
515
+ })
516
+ );
517
+ component.onCreateTenantFormSubmit([mockFormGroup]);
518
+ expect(component.fileUploadPresignedUrl).toBe(
519
+ mockPresignedUrlResponse?.body
520
+ );
521
+ expect(getPreseignedUrlSpy).toHaveBeenCalled();
522
+ });
523
+ it('should throw error while getting the presigned url', () => {
524
+ component.file = mockFile;
525
+ spyOn(fileUploadService, 'getFileUploadPresignedUrl').and.returnValue(
526
+ new Observable((subscriber) => {
527
+ subscriber.error(mockServerErrorResponse);
528
+ })
529
+ );
530
+ spyOn(globalErrorHandlerService, 'handleError');
531
+ component.onCreateTenantFormSubmit([mockFormGroup]);
532
+ expect(globalErrorHandlerService.handleError).toHaveBeenCalledWith(
533
+ mockServerErrorResponse
534
+ );
535
+ });
536
+ it('should not call the presigned url if there is no file', () => {
537
+ const getPresignedUrlSpy = spyOn(
538
+ fileUploadService,
539
+ 'getFileUploadPresignedUrl'
540
+ ).and.returnValue(
541
+ new Observable((subscriber) => {
542
+ subscriber.next(TenantsMocks.mockPreSignedUrlResponse);
543
+ })
544
+ );
545
+ component.onCreateTenantFormSubmit([mockFormGroup]);
546
+ expect(getPresignedUrlSpy).not.toHaveBeenCalled();
547
+ });
548
+ it('should call editTenant method directly when tenantFunctionType is EDIT and isAppLogoModified is false', () => {
549
+ component.createTenantPayload = TenantsMocks.editTenantMockPayload;
550
+ component.tenantFunctionType = TenantFunctionType.EDIT;
551
+ component.isAppLogoModified = false;
552
+ const editTenantSpy = spyOn(component, 'editTenant').and.callThrough();
553
+ const getPresignedUrlSpy = spyOn(
554
+ fileUploadService,
555
+ 'getFileUploadPresignedUrl'
556
+ ).and.returnValue(
557
+ new Observable((subscriber) => {
558
+ subscriber.next(TenantsMocks.mockPreSignedUrlResponse);
559
+ })
560
+ );
561
+ component.onCreateTenantFormSubmit([mockFormGroup]);
562
+ expect(editTenantSpy).toHaveBeenCalled();
563
+ expect(getPresignedUrlSpy).not.toHaveBeenCalled();
564
+ });
565
+ });
566
+ describe('#createTenant', () => {
567
+ it('should submit the create tenant form', () => {
568
+ component.createTenantPayload = TenantsMocks.createTenantMockPayload;
569
+ const submitResponseSpy = spyOn(
570
+ component.submitFormResponse,
571
+ 'emit'
572
+ ).and.callThrough();
573
+ const createTenantSpy = spyOn(
574
+ tenantAppService,
575
+ 'createTenant'
576
+ ).and.returnValue(
577
+ new Observable((subscriber) => {
578
+ subscriber.next(TenantsMocks.createTenantMockResponse);
579
+ })
580
+ );
581
+ component.createTenant();
582
+ expect(createTenantSpy).toHaveBeenCalled();
583
+ expect(submitResponseSpy).toHaveBeenCalled();
584
+ });
585
+ it('should throw error while creating the tenant', () => {
586
+ const submitResponseSpy = spyOn(
587
+ component.submitFormResponse,
588
+ 'emit'
589
+ ).and.callThrough();
590
+ spyOn(tenantAppService, 'createTenant').and.returnValue(
591
+ new Observable((subscriber) => {
592
+ subscriber.error(mockServerErrorResponse);
593
+ })
594
+ );
595
+ spyOn(globalErrorHandlerService, 'handleError');
596
+ component.createTenant();
597
+ expect(globalErrorHandlerService.handleError).toHaveBeenCalledWith(
598
+ mockServerErrorResponse
599
+ );
600
+ expect(submitResponseSpy).not.toHaveBeenCalled();
601
+ });
602
+ });
603
+ describe('#editTenant', () => {
604
+ it('should submit the edit tenant form', () => {
605
+ component.createTenantPayload = TenantsMocks.editTenantMockPayload;
606
+ component.tenantFunctionType = TenantFunctionType.EDIT;
607
+ const submitResponseSpy = spyOn(
608
+ component.submitFormResponse,
609
+ 'emit'
610
+ ).and.callThrough();
611
+ const editTenantSpy = spyOn(
612
+ tenantAppService,
613
+ 'editTenant'
614
+ ).and.returnValue(
615
+ new Observable((subscriber) => {
616
+ subscriber.next(TenantsMocks.editTenantMockResponse);
617
+ })
618
+ );
619
+ component.editTenant();
620
+ expect(editTenantSpy).toHaveBeenCalled();
621
+ expect(submitResponseSpy).toHaveBeenCalled();
622
+ });
623
+ it('should throw error while editing the tenant', () => {
624
+ const submitResponseSpy = spyOn(
625
+ component.submitFormResponse,
626
+ 'emit'
627
+ ).and.callThrough();
628
+ spyOn(tenantAppService, 'editTenant').and.returnValue(
629
+ new Observable((subscriber) => {
630
+ subscriber.error(mockServerErrorResponse);
631
+ })
632
+ );
633
+ spyOn(globalErrorHandlerService, 'handleError');
634
+ component.editTenant();
635
+ expect(globalErrorHandlerService.handleError).toHaveBeenCalledWith(
636
+ mockServerErrorResponse
637
+ );
638
+ expect(submitResponseSpy).not.toHaveBeenCalled();
639
+ });
640
+ });
641
+ describe('#uploadFileToS3', () => {
642
+ it('should upload the file with presigned url and creates tenant ', () => {
643
+ const mockFileUploadedResponse = TenantsMocks.mockFileUploadedResponse;
644
+ const uploadFileToS3Spy = spyOn(
645
+ fileUploadService,
646
+ 'uploadFileToS3'
647
+ ).and.returnValue(
648
+ new Observable((subscriber) => {
649
+ subscriber.next(mockFileUploadedResponse);
650
+ })
651
+ );
652
+ const submitResponseSpy = spyOn(
653
+ component.submitFormResponse,
654
+ 'emit'
655
+ ).and.callThrough();
656
+ const createTenantSpy = spyOn(
657
+ tenantAppService,
658
+ 'createTenant'
659
+ ).and.returnValue(
660
+ new Observable((subscriber) => {
661
+ subscriber.next(TenantsMocks.createTenantMockResponse);
662
+ })
663
+ );
664
+ component.uploadFileToS3(mockFile);
665
+ expect(uploadFileToS3Spy).toHaveBeenCalled();
666
+ expect(createTenantSpy).toHaveBeenCalled();
667
+ expect(submitResponseSpy).toHaveBeenCalled();
668
+ });
669
+ it('should upload the file with presigned url and fail to create tenant', () => {
670
+ const mockFileUploadedResponse = TenantsMocks.mockFileUploadedResponse;
671
+ const uploadFileToS3Spy = spyOn(
672
+ fileUploadService,
673
+ 'uploadFileToS3'
674
+ ).and.returnValue(
675
+ new Observable((subscriber) => {
676
+ subscriber.next(mockFileUploadedResponse);
677
+ })
678
+ );
679
+ const submitResponseSpy = spyOn(
680
+ component.submitFormResponse,
681
+ 'emit'
682
+ ).and.callThrough();
683
+ spyOn(tenantAppService, 'createTenant').and.returnValue(
684
+ new Observable((subscriber) => {
685
+ subscriber.error(mockServerErrorResponse);
686
+ })
687
+ );
688
+ spyOn(globalErrorHandlerService, 'handleError');
689
+ component.uploadFileToS3(mockFile);
690
+ expect(uploadFileToS3Spy).toHaveBeenCalled();
691
+ expect(globalErrorHandlerService.handleError).toHaveBeenCalledWith(
692
+ mockServerErrorResponse
693
+ );
694
+ expect(submitResponseSpy).not.toHaveBeenCalled();
695
+ });
696
+ it('should upload the file with presigned url and edits tenant ', () => {
697
+ const mockFileUploadedResponse = TenantsMocks.mockFileUploadedResponse;
698
+ component.tenantFunctionType = TenantFunctionType.EDIT;
699
+ component.createTenantPayload = TenantsMocks.editTenantMockPayload;
700
+ const uploadFileToS3Spy = spyOn(
701
+ fileUploadService,
702
+ 'uploadFileToS3'
703
+ ).and.returnValue(
704
+ new Observable((subscriber) => {
705
+ subscriber.next(mockFileUploadedResponse);
706
+ })
707
+ );
708
+ const submitResponseSpy = spyOn(
709
+ component.submitFormResponse,
710
+ 'emit'
711
+ ).and.callThrough();
712
+ const editTenantSpy = spyOn(
713
+ tenantAppService,
714
+ 'editTenant'
715
+ ).and.returnValue(
716
+ new Observable((subscriber) => {
717
+ subscriber.next(TenantsMocks.editTenantMockResponse);
718
+ })
719
+ );
720
+ component.uploadFileToS3(mockFile);
721
+ expect(uploadFileToS3Spy).toHaveBeenCalled();
722
+ expect(editTenantSpy).toHaveBeenCalled();
723
+ expect(submitResponseSpy).toHaveBeenCalled();
724
+ });
725
+ it('should upload the file with presigned url and fail to edit tenant', () => {
726
+ const mockFileUploadedResponse = TenantsMocks.mockFileUploadedResponse;
727
+ component.tenantFunctionType = TenantFunctionType.EDIT;
728
+ const uploadFileToS3Spy = spyOn(
729
+ fileUploadService,
730
+ 'uploadFileToS3'
731
+ ).and.returnValue(
732
+ new Observable((subscriber) => {
733
+ subscriber.next(mockFileUploadedResponse);
734
+ })
735
+ );
736
+ const submitResponseSpy = spyOn(
737
+ component.submitFormResponse,
738
+ 'emit'
739
+ ).and.callThrough();
740
+ spyOn(tenantAppService, 'editTenant').and.returnValue(
741
+ new Observable((subscriber) => {
742
+ subscriber.error(mockServerErrorResponse);
743
+ })
744
+ );
745
+ spyOn(globalErrorHandlerService, 'handleError');
746
+ component.uploadFileToS3(mockFile);
747
+ expect(uploadFileToS3Spy).toHaveBeenCalled();
748
+ expect(globalErrorHandlerService.handleError).toHaveBeenCalledWith(
749
+ mockServerErrorResponse
750
+ );
751
+ expect(submitResponseSpy).not.toHaveBeenCalled();
752
+ });
753
+ it('should throw error while uploading the file into s3 bucket', () => {
754
+ spyOn(fileUploadService, 'uploadFileToS3').and.returnValue(
755
+ new Observable((subscriber) => {
756
+ subscriber.error(mockServerErrorResponse);
757
+ })
758
+ );
759
+ spyOn(globalErrorHandlerService, 'handleError');
760
+ component.uploadFileToS3(mockFile);
761
+ expect(globalErrorHandlerService.handleError).toHaveBeenCalledWith(
762
+ mockServerErrorResponse
763
+ );
764
+ });
765
+ });
766
+ describe('#ngOnDestroy', () => {
767
+ it('should unsubscribe on ngOnDestroy', () => {
768
+ spyOn(component.destroy$, 'next');
769
+ spyOn(component.destroy$, 'unsubscribe');
770
+ component.ngOnDestroy();
771
+ expect(component.destroy$.next).toHaveBeenCalledWith(true);
772
+ expect(component.destroy$.unsubscribe).toHaveBeenCalled();
773
+ });
774
+ });
775
+ });