]>
Commit | Line | Data |
---|---|---|
9f95a23c | 1 | import { LOCALE_ID, TRANSLATIONS, TRANSLATIONS_FORMAT, Type } from '@angular/core'; |
11fdf7f2 TL |
2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; |
3 | import { AbstractControl } from '@angular/forms'; | |
4 | import { By } from '@angular/platform-browser'; | |
5 | ||
6 | import { I18n } from '@ngx-translate/i18n-polyfill'; | |
9f95a23c | 7 | import { BsModalRef } from 'ngx-bootstrap/modal'; |
11fdf7f2 TL |
8 | |
9 | import { TableActionsComponent } from '../app/shared/datatable/table-actions/table-actions.component'; | |
9f95a23c | 10 | import { Icons } from '../app/shared/enum/icons.enum'; |
11fdf7f2 | 11 | import { CdFormGroup } from '../app/shared/forms/cd-form-group'; |
9f95a23c TL |
12 | import { CdTableAction } from '../app/shared/models/cd-table-action'; |
13 | import { CdTableSelection } from '../app/shared/models/cd-table-selection'; | |
11fdf7f2 TL |
14 | import { Permission } from '../app/shared/models/permissions'; |
15 | import { | |
494da23a TL |
16 | AlertmanagerAlert, |
17 | AlertmanagerNotification, | |
18 | AlertmanagerNotificationAlert, | |
19 | PrometheusRule | |
11fdf7f2 TL |
20 | } from '../app/shared/models/prometheus-alerts'; |
21 | import { _DEV_ } from '../unit-test-configuration'; | |
22 | ||
9f95a23c | 23 | export function configureTestBed(configuration: any, useOldMethod?: boolean) { |
11fdf7f2 TL |
24 | if (_DEV_ && !useOldMethod) { |
25 | const resetTestingModule = TestBed.resetTestingModule; | |
26 | beforeAll((done) => | |
27 | (async () => { | |
28 | TestBed.resetTestingModule(); | |
29 | TestBed.configureTestingModule(configuration); | |
30 | // prevent Angular from resetting testing module | |
31 | TestBed.resetTestingModule = () => TestBed; | |
32 | })() | |
33 | .then(done) | |
34 | .catch(done.fail) | |
35 | ); | |
36 | afterAll(() => { | |
37 | TestBed.resetTestingModule = resetTestingModule; | |
38 | }); | |
39 | } else { | |
40 | beforeEach(async(() => { | |
41 | TestBed.configureTestingModule(configuration); | |
42 | })); | |
43 | } | |
44 | } | |
45 | ||
46 | export class PermissionHelper { | |
9f95a23c | 47 | tac: TableActionsComponent; |
11fdf7f2 | 48 | permission: Permission; |
11fdf7f2 | 49 | |
9f95a23c | 50 | constructor(permission: Permission) { |
11fdf7f2 | 51 | this.permission = permission; |
11fdf7f2 TL |
52 | } |
53 | ||
9f95a23c TL |
54 | setPermissionsAndGetActions(tableActions: CdTableAction[]): any { |
55 | const result = {}; | |
56 | [true, false].forEach((create) => { | |
57 | [true, false].forEach((update) => { | |
58 | [true, false].forEach((deleteP) => { | |
59 | this.permission.create = create; | |
60 | this.permission.update = update; | |
61 | this.permission.delete = deleteP; | |
62 | ||
63 | this.tac = new TableActionsComponent(); | |
64 | this.tac.selection = new CdTableSelection(); | |
65 | this.tac.tableActions = [...tableActions]; | |
66 | this.tac.permission = this.permission; | |
67 | this.tac.ngOnInit(); | |
68 | ||
69 | const perms = []; | |
70 | if (create) { | |
71 | perms.push('create'); | |
72 | } | |
73 | if (update) { | |
74 | perms.push('update'); | |
75 | } | |
76 | if (deleteP) { | |
77 | perms.push('delete'); | |
78 | } | |
79 | const permissionText = perms.join(','); | |
80 | ||
81 | result[permissionText !== '' ? permissionText : 'no-permissions'] = { | |
82 | actions: this.tac.tableActions.map((action) => action.name), | |
83 | primary: this.testScenarios() | |
84 | }; | |
85 | }); | |
86 | }); | |
87 | }); | |
88 | ||
89 | return result; | |
90 | } | |
91 | ||
92 | testScenarios() { | |
93 | const result: any = {}; | |
94 | // 'multiple selections' | |
95 | result.multiple = this.testScenario([{}, {}]); | |
96 | // 'select executing item' | |
97 | result.executing = this.testScenario([{ cdExecuting: 'someAction' }]); | |
98 | // 'select non-executing item' | |
99 | result.single = this.testScenario([{}]); | |
100 | // 'no selection' | |
101 | result.no = this.testScenario([]); | |
102 | ||
103 | return result; | |
104 | } | |
105 | ||
106 | private testScenario(selection: object[]) { | |
11fdf7f2 | 107 | this.setSelection(selection); |
9f95a23c TL |
108 | const btn = this.tac.getCurrentButton(); |
109 | return btn ? btn.name : ''; | |
11fdf7f2 TL |
110 | } |
111 | ||
112 | setSelection(selection: object[]) { | |
9f95a23c | 113 | this.tac.selection.selected = selection; |
11fdf7f2 TL |
114 | } |
115 | } | |
116 | ||
117 | export class FormHelper { | |
118 | form: CdFormGroup; | |
119 | ||
120 | constructor(form: CdFormGroup) { | |
121 | this.form = form; | |
122 | } | |
123 | ||
124 | /** | |
125 | * Changes multiple values in multiple controls | |
126 | */ | |
127 | setMultipleValues(values: { [controlName: string]: any }, markAsDirty?: boolean) { | |
128 | Object.keys(values).forEach((key) => { | |
129 | this.setValue(key, values[key], markAsDirty); | |
130 | }); | |
131 | } | |
132 | ||
133 | /** | |
134 | * Changes the value of a control | |
135 | */ | |
136 | setValue(control: AbstractControl | string, value: any, markAsDirty?: boolean): AbstractControl { | |
137 | control = this.getControl(control); | |
138 | if (markAsDirty) { | |
139 | control.markAsDirty(); | |
140 | } | |
141 | control.setValue(value); | |
142 | return control; | |
143 | } | |
144 | ||
145 | private getControl(control: AbstractControl | string): AbstractControl { | |
146 | if (typeof control === 'string') { | |
147 | return this.form.get(control); | |
148 | } | |
149 | return control; | |
150 | } | |
151 | ||
152 | /** | |
153 | * Change the value of the control and expect the control to be valid afterwards. | |
154 | */ | |
155 | expectValidChange(control: AbstractControl | string, value: any, markAsDirty?: boolean) { | |
156 | this.expectValid(this.setValue(control, value, markAsDirty)); | |
157 | } | |
158 | ||
159 | /** | |
160 | * Expect that the given control is valid. | |
161 | */ | |
162 | expectValid(control: AbstractControl | string) { | |
163 | // 'isValid' would be false for disabled controls | |
164 | expect(this.getControl(control).errors).toBe(null); | |
165 | } | |
166 | ||
167 | /** | |
168 | * Change the value of the control and expect a specific error. | |
169 | */ | |
170 | expectErrorChange( | |
171 | control: AbstractControl | string, | |
172 | value: any, | |
173 | error: string, | |
174 | markAsDirty?: boolean | |
175 | ) { | |
176 | this.expectError(this.setValue(control, value, markAsDirty), error); | |
177 | } | |
178 | ||
179 | /** | |
180 | * Expect a specific error for the given control. | |
181 | */ | |
182 | expectError(control: AbstractControl | string, error: string) { | |
183 | expect(this.getControl(control).hasError(error)).toBeTruthy(); | |
184 | } | |
185 | } | |
186 | ||
9f95a23c TL |
187 | /** |
188 | * Use this to mock 'ModalService.show' to make the embedded component with it's fixture usable | |
189 | * in tests. The function gives back all needed parts including the modal reference. | |
190 | * | |
191 | * Please make sure to call this function *inside* your mock and return the reference at the end. | |
192 | */ | |
193 | export function modalServiceShow(componentClass: Type<any>, modalConfig: any) { | |
194 | const ref = new BsModalRef(); | |
195 | const fixture = TestBed.createComponent(componentClass); | |
196 | let component = fixture.componentInstance; | |
197 | if (modalConfig.initialState) { | |
198 | component = Object.assign(component, modalConfig.initialState); | |
199 | } | |
200 | fixture.detectChanges(); | |
201 | ref.content = component; | |
202 | return { ref, fixture, component }; | |
203 | } | |
204 | ||
11fdf7f2 TL |
205 | export class FixtureHelper { |
206 | fixture: ComponentFixture<any>; | |
207 | ||
9f95a23c TL |
208 | constructor(fixture?: ComponentFixture<any>) { |
209 | if (fixture) { | |
210 | this.updateFixture(fixture); | |
211 | } | |
212 | } | |
213 | ||
214 | updateFixture(fixture: ComponentFixture<any>) { | |
11fdf7f2 TL |
215 | this.fixture = fixture; |
216 | } | |
217 | ||
218 | /** | |
219 | * Expect a list of id elements to be visible or not. | |
220 | */ | |
221 | expectIdElementsVisible(ids: string[], visibility: boolean) { | |
222 | ids.forEach((css) => { | |
223 | this.expectElementVisible(`#${css}`, visibility); | |
224 | }); | |
225 | } | |
226 | ||
227 | /** | |
228 | * Expect a specific element to be visible or not. | |
229 | */ | |
230 | expectElementVisible(css: string, visibility: boolean) { | |
9f95a23c | 231 | expect(visibility).toBe(Boolean(this.getElementByCss(css))); |
11fdf7f2 TL |
232 | } |
233 | ||
234 | expectFormFieldToBe(css: string, value: string) { | |
235 | const props = this.getElementByCss(css).properties; | |
236 | expect(props['value'] || props['checked'].toString()).toBe(value); | |
237 | } | |
238 | ||
9f95a23c TL |
239 | expectTextToBe(css: string, value: string) { |
240 | expect(this.getText(css)).toBe(value); | |
241 | } | |
242 | ||
11fdf7f2 TL |
243 | clickElement(css: string) { |
244 | this.getElementByCss(css).triggerEventHandler('click', null); | |
245 | this.fixture.detectChanges(); | |
246 | } | |
247 | ||
9f95a23c TL |
248 | selectElement(css: string, value: string) { |
249 | const nativeElement = this.getElementByCss(css).nativeElement; | |
250 | nativeElement.value = value; | |
251 | nativeElement.dispatchEvent(new Event('change')); | |
252 | this.fixture.detectChanges(); | |
253 | } | |
254 | ||
11fdf7f2 TL |
255 | getText(css: string) { |
256 | const e = this.getElementByCss(css); | |
257 | return e ? e.nativeElement.textContent.trim() : null; | |
258 | } | |
259 | ||
9f95a23c TL |
260 | getTextAll(css: string) { |
261 | const elements = this.getElementByCssAll(css); | |
262 | return elements.map((element) => { | |
263 | return element ? element.nativeElement.textContent.trim() : null; | |
264 | }); | |
265 | } | |
266 | ||
11fdf7f2 TL |
267 | getElementByCss(css: string) { |
268 | this.fixture.detectChanges(); | |
269 | return this.fixture.debugElement.query(By.css(css)); | |
270 | } | |
9f95a23c TL |
271 | |
272 | getElementByCssAll(css: string) { | |
273 | this.fixture.detectChanges(); | |
274 | return this.fixture.debugElement.queryAll(By.css(css)); | |
275 | } | |
11fdf7f2 TL |
276 | } |
277 | ||
278 | export class PrometheusHelper { | |
9f95a23c | 279 | createSilence(id: string) { |
494da23a TL |
280 | return { |
281 | id: id, | |
282 | createdBy: `Creator of ${id}`, | |
283 | comment: `A comment for ${id}`, | |
284 | startsAt: new Date('2022-02-22T22:22:00').toISOString(), | |
285 | endsAt: new Date('2022-02-23T22:22:00').toISOString(), | |
286 | matchers: [ | |
287 | { | |
288 | name: 'job', | |
289 | value: 'someJob', | |
290 | isRegex: true | |
291 | } | |
292 | ] | |
293 | }; | |
294 | } | |
295 | ||
9f95a23c | 296 | createRule(name: string, severity: string, alerts: any[]): PrometheusRule { |
494da23a TL |
297 | return { |
298 | name: name, | |
299 | labels: { | |
300 | severity: severity | |
301 | }, | |
302 | alerts: alerts | |
303 | } as PrometheusRule; | |
304 | } | |
305 | ||
9f95a23c | 306 | createAlert(name: string, state = 'active', timeMultiplier = 1): AlertmanagerAlert { |
11fdf7f2 TL |
307 | return { |
308 | fingerprint: name, | |
309 | status: { state }, | |
310 | labels: { | |
494da23a TL |
311 | alertname: name, |
312 | instance: 'someInstance', | |
313 | job: 'someJob', | |
314 | severity: 'someSeverity' | |
11fdf7f2 TL |
315 | }, |
316 | annotations: { | |
317 | summary: `${name} is ${state}` | |
318 | }, | |
319 | generatorURL: `http://${name}`, | |
320 | startsAt: new Date(new Date('2022-02-22').getTime() * timeMultiplier).toString() | |
494da23a | 321 | } as AlertmanagerAlert; |
11fdf7f2 TL |
322 | } |
323 | ||
9f95a23c | 324 | createNotificationAlert(name: string, status = 'firing'): AlertmanagerNotificationAlert { |
11fdf7f2 TL |
325 | return { |
326 | status: status, | |
327 | labels: { | |
328 | alertname: name | |
329 | }, | |
330 | annotations: { | |
331 | summary: `${name} is ${status}` | |
332 | }, | |
333 | generatorURL: `http://${name}` | |
494da23a | 334 | } as AlertmanagerNotificationAlert; |
11fdf7f2 TL |
335 | } |
336 | ||
494da23a | 337 | createNotification(alertNumber = 1, status = 'firing'): AlertmanagerNotification { |
11fdf7f2 TL |
338 | const alerts = []; |
339 | for (let i = 0; i < alertNumber; i++) { | |
340 | alerts.push(this.createNotificationAlert('alert' + i, status)); | |
341 | } | |
494da23a | 342 | return { alerts, status } as AlertmanagerNotification; |
11fdf7f2 TL |
343 | } |
344 | ||
9f95a23c TL |
345 | createLink(url: string) { |
346 | return `<a href="${url}" target="_blank"><i class="${Icons.lineChart}"></i></a>`; | |
11fdf7f2 TL |
347 | } |
348 | } | |
349 | ||
350 | const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> | |
351 | <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> | |
352 | <file source-language="en" datatype="plaintext" original="ng2.template"> | |
353 | <body> | |
354 | </body> | |
355 | </file> | |
356 | </xliff> | |
357 | `; | |
358 | ||
359 | const i18nProviders = [ | |
360 | { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }, | |
361 | { provide: TRANSLATIONS, useValue: XLIFF }, | |
362 | { provide: LOCALE_ID, useValue: 'en' }, | |
363 | I18n | |
364 | ]; | |
365 | ||
366 | export { i18nProviders }; | |
eafe8130 TL |
367 | |
368 | export function expectItemTasks(item: any, executing: string, percentage?: number) { | |
369 | if (executing) { | |
370 | executing = executing + '...'; | |
371 | if (percentage) { | |
372 | executing = `${executing} ${percentage}%`; | |
373 | } | |
374 | } | |
375 | expect(item.cdExecuting).toBe(executing); | |
376 | } |