]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.spec.ts
241910f2b4152294400b4504358e9e08ef538f81
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / core / navigation / navigation / navigation.component.spec.ts
1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ComponentFixture, TestBed } from '@angular/core/testing';
3 import { By } from '@angular/platform-browser';
4
5 import { MockModule } from 'ng-mocks';
6 import { of } from 'rxjs';
7
8 import { Permission, Permissions } from '~/app/shared/models/permissions';
9 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
10 import {
11 Features,
12 FeatureTogglesMap,
13 FeatureTogglesService
14 } from '~/app/shared/services/feature-toggles.service';
15 import { PrometheusAlertService } from '~/app/shared/services/prometheus-alert.service';
16 import { SummaryService } from '~/app/shared/services/summary.service';
17 import { configureTestBed } from '~/testing/unit-test-helper';
18 import { NavigationModule } from '../navigation.module';
19 import { NavigationComponent } from './navigation.component';
20
21 function everythingPermittedExcept(disabledPermissions: string[] = []): any {
22 const permissions: Permissions = new Permissions({});
23 Object.keys(permissions).forEach(
24 (key) => (permissions[key] = new Permission(disabledPermissions.includes(key) ? [] : ['read']))
25 );
26 return permissions;
27 }
28
29 function onlyPermitted(enabledPermissions: string[] = []): any {
30 const permissions: Permissions = new Permissions({});
31 enabledPermissions.forEach((key) => (permissions[key] = new Permission(['read'])));
32 return permissions;
33 }
34
35 function everythingEnabledExcept(features: Features[] = []): FeatureTogglesMap {
36 const featureTogglesMap: FeatureTogglesMap = new FeatureTogglesMap();
37 features.forEach((key) => (featureTogglesMap[key] = false));
38 return featureTogglesMap;
39 }
40
41 function onlyEnabled(features: Features[] = []): FeatureTogglesMap {
42 const featureTogglesMap: FeatureTogglesMap = new FeatureTogglesMap();
43 Object.keys(featureTogglesMap).forEach(
44 (key) => (featureTogglesMap[key] = features.includes(<Features>key))
45 );
46 return featureTogglesMap;
47 }
48
49 describe('NavigationComponent', () => {
50 let component: NavigationComponent;
51 let fixture: ComponentFixture<NavigationComponent>;
52
53 configureTestBed({
54 declarations: [NavigationComponent],
55 imports: [HttpClientTestingModule, MockModule(NavigationModule)],
56 providers: [
57 {
58 provide: AuthStorageService,
59 useValue: {
60 getPermissions: jest.fn(),
61 isPwdDisplayed$: { subscribe: jest.fn() },
62 telemetryNotification$: { subscribe: jest.fn() }
63 }
64 },
65 { provide: SummaryService, useValue: { subscribe: jest.fn() } },
66 { provide: FeatureTogglesService, useValue: { get: jest.fn() } },
67 { provide: PrometheusAlertService, useValue: { alerts: [] } }
68 ]
69 });
70
71 beforeEach(() => {
72 fixture = TestBed.createComponent(NavigationComponent);
73 component = fixture.componentInstance;
74 });
75
76 describe('Test Permissions', () => {
77 const testCases: [string[], string[]][] = [
78 [
79 ['hosts'],
80 [
81 '.tc_submenuitem_hosts',
82 '.tc_submenuitem_cluster_inventory',
83 '.tc_submenuitem_cluster_services'
84 ]
85 ],
86 [['monitor'], ['.tc_submenuitem_cluster_monitor']],
87 [['osd'], ['.tc_submenuitem_osds', '.tc_submenuitem_crush']],
88 [['configOpt'], ['.tc_submenuitem_configuration', '.tc_submenuitem_modules']],
89 [['log'], ['.tc_submenuitem_log']],
90 [['prometheus'], ['.tc_submenuitem_monitoring']],
91 [['pool'], ['.tc_menuitem_pool']],
92 [['rbdImage'], ['.tc_submenuitem_block_images']],
93 [['rbdMirroring'], ['.tc_submenuitem_block_mirroring']],
94 [['iscsi'], ['.tc_submenuitem_block_iscsi']],
95 [['rbdImage', 'rbdMirroring', 'iscsi'], ['.tc_menuitem_block']],
96 [['nfs'], ['.tc_menuitem_nfs']],
97 [['cephfs'], ['.tc_menuitem_cephfs']],
98 [
99 ['rgw'],
100 [
101 '.tc_menuitem_rgw',
102 '.tc_submenuitem_rgw_daemons',
103 '.tc_submenuitem_rgw_buckets',
104 '.tc_submenuitem_rgw_users'
105 ]
106 ]
107 ];
108
109 for (const [disabledPermissions, selectors] of testCases) {
110 it(`When disabled permissions: ${JSON.stringify(
111 disabledPermissions
112 )} => hidden: "${selectors}"`, () => {
113 component.permissions = everythingPermittedExcept(disabledPermissions);
114 component.enabledFeature$ = of(everythingEnabledExcept());
115
116 fixture.detectChanges();
117 for (const selector of selectors) {
118 expect(fixture.debugElement.query(By.css(selector))).toBeFalsy();
119 }
120 });
121 }
122
123 for (const [enabledPermissions, selectors] of testCases) {
124 it(`When enabled permissions: ${JSON.stringify(
125 enabledPermissions
126 )} => visible: "${selectors}"`, () => {
127 component.permissions = onlyPermitted(enabledPermissions);
128 component.enabledFeature$ = of(everythingEnabledExcept());
129
130 fixture.detectChanges();
131 for (const selector of selectors) {
132 expect(fixture.debugElement.query(By.css(selector))).toBeTruthy();
133 }
134 });
135 }
136 });
137
138 describe('Test FeatureToggles', () => {
139 const testCases: [Features[], string[]][] = [
140 [['rbd'], ['.tc_submenuitem_block_images']],
141 [['mirroring'], ['.tc_submenuitem_block_mirroring']],
142 [['iscsi'], ['.tc_submenuitem_block_iscsi']],
143 [['rbd', 'mirroring', 'iscsi'], ['.tc_menuitem_block']],
144 [['nfs'], ['.tc_menuitem_nfs']],
145 [['cephfs'], ['.tc_menuitem_cephfs']],
146 [
147 ['rgw'],
148 [
149 '.tc_menuitem_rgw',
150 '.tc_submenuitem_rgw_daemons',
151 '.tc_submenuitem_rgw_buckets',
152 '.tc_submenuitem_rgw_users'
153 ]
154 ]
155 ];
156
157 for (const [disabledFeatures, selectors] of testCases) {
158 it(`When disabled features: ${JSON.stringify(
159 disabledFeatures
160 )} => hidden: "${selectors}"`, () => {
161 component.enabledFeature$ = of(everythingEnabledExcept(disabledFeatures));
162 component.permissions = everythingPermittedExcept();
163
164 fixture.detectChanges();
165 for (const selector of selectors) {
166 expect(fixture.debugElement.query(By.css(selector))).toBeFalsy();
167 }
168 });
169 }
170
171 for (const [enabledFeatures, selectors] of testCases) {
172 it(`When enabled features: ${JSON.stringify(
173 enabledFeatures
174 )} => visible: "${selectors}"`, () => {
175 component.enabledFeature$ = of(onlyEnabled(enabledFeatures));
176 component.permissions = everythingPermittedExcept();
177
178 fixture.detectChanges();
179 for (const selector of selectors) {
180 expect(fixture.debugElement.query(By.css(selector))).toBeTruthy();
181 }
182 });
183 }
184 });
185
186 describe('showTopNotification', () => {
187 const notification1 = 'notificationName1';
188 const notification2 = 'notificationName2';
189
190 beforeEach(() => {
191 component.notifications = [];
192 });
193
194 it('should show notification', () => {
195 component.showTopNotification(notification1, true);
196 expect(component.notifications.includes(notification1)).toBeTruthy();
197 expect(component.notifications.length).toBe(1);
198 });
199
200 it('should not add a second notification if it is already shown', () => {
201 component.showTopNotification(notification1, true);
202 component.showTopNotification(notification1, true);
203 expect(component.notifications.includes(notification1)).toBeTruthy();
204 expect(component.notifications.length).toBe(1);
205 });
206
207 it('should add a second notification if the first one is different', () => {
208 component.showTopNotification(notification1, true);
209 component.showTopNotification(notification2, true);
210 expect(component.notifications.includes(notification1)).toBeTruthy();
211 expect(component.notifications.includes(notification2)).toBeTruthy();
212 expect(component.notifications.length).toBe(2);
213 });
214
215 it('should hide an active notification', () => {
216 component.showTopNotification(notification1, true);
217 expect(component.notifications.includes(notification1)).toBeTruthy();
218 expect(component.notifications.length).toBe(1);
219 component.showTopNotification(notification1, false);
220 expect(component.notifications.length).toBe(0);
221 });
222
223 it('should not fail if it tries to hide an inactive notification', () => {
224 expect(() => component.showTopNotification(notification1, false)).not.toThrow();
225 expect(component.notifications.length).toBe(0);
226 });
227
228 it('should keep other notifications if it hides one', () => {
229 component.showTopNotification(notification1, true);
230 component.showTopNotification(notification2, true);
231 expect(component.notifications.length).toBe(2);
232 component.showTopNotification(notification2, false);
233 expect(component.notifications.length).toBe(1);
234 expect(component.notifications.includes(notification1)).toBeTruthy();
235 });
236 });
237 });