@centreon/js-config 24.7.4 → 24.8.0

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.
@@ -1,11 +1,64 @@
1
1
  /* eslint-disable @typescript-eslint/no-namespace */
2
+ import path from 'path';
3
+ import 'cypress-wait-until';
2
4
 
3
5
  import './commands/configuration';
6
+ import './commands/monitoring';
4
7
 
8
+ import installLogsCollector from 'cypress-terminal-report/src/installLogsCollector';
9
+
10
+ installLogsCollector({
11
+ commandTimings: 'seconds',
12
+ enableExtendedCollector: true
13
+ });
14
+
15
+ const apiBase = '/centreon/api';
16
+ const apiActionV1 = `${apiBase}/index.php`;
5
17
  const apiLoginV2 = '/centreon/authentication/providers/configurations/local';
6
18
 
7
19
  const artifactIllegalCharactersMatcher = /[,\s/|<>*?:"]/g;
8
20
 
21
+ export enum PatternType {
22
+ contains = '*',
23
+ endsWith = '$',
24
+ equals = '',
25
+ startsWith = '^'
26
+ }
27
+
28
+ interface GetByLabelProps {
29
+ label: string;
30
+ patternType?: PatternType;
31
+ tag?: string;
32
+ }
33
+
34
+ Cypress.Commands.add(
35
+ 'getByLabel',
36
+ ({
37
+ tag = '',
38
+ patternType = PatternType.equals,
39
+ label
40
+ }: GetByLabelProps): Cypress.Chainable => {
41
+ return cy.get(`${tag}[aria-label${patternType}="${label}"]`);
42
+ }
43
+ );
44
+
45
+ interface GetByTestIdProps {
46
+ patternType?: PatternType;
47
+ tag?: string;
48
+ testId: string;
49
+ }
50
+
51
+ Cypress.Commands.add(
52
+ 'getByTestId',
53
+ ({
54
+ tag = '',
55
+ patternType = PatternType.equals,
56
+ testId
57
+ }: GetByTestIdProps): Cypress.Chainable => {
58
+ return cy.get(`${tag}[data-testid${patternType}="${testId}"]`);
59
+ }
60
+ );
61
+
9
62
  Cypress.Commands.add('getWebVersion', (): Cypress.Chainable => {
10
63
  return cy
11
64
  .exec(
@@ -23,7 +76,7 @@ Cypress.Commands.add('getWebVersion', (): Cypress.Chainable => {
23
76
 
24
77
  Cypress.Commands.add('getIframeBody', (): Cypress.Chainable => {
25
78
  return cy
26
- .get('iframe#main-content')
79
+ .get('iframe#main-content', { timeout: 10000 })
27
80
  .its('0.contentDocument.body')
28
81
  .should('not.be.empty')
29
82
  .then(cy.wrap);
@@ -39,6 +92,13 @@ Cypress.Commands.add(
39
92
  }
40
93
  );
41
94
 
95
+ Cypress.Commands.add(
96
+ 'clickSubRootMenuItem',
97
+ (page: string): Cypress.Chainable => {
98
+ return cy.get('div[data-cy="collapse"]').eq(1).contains(page).click();
99
+ }
100
+ );
101
+
42
102
  interface NavigateToProps {
43
103
  page: string;
44
104
  rootItemNumber: number;
@@ -47,12 +107,17 @@ interface NavigateToProps {
47
107
 
48
108
  Cypress.Commands.add(
49
109
  'navigateTo',
50
- ({ rootItemNumber, subMenu, page }): void => {
110
+ ({ rootItemNumber, subMenu, page }: NavigateToProps): void => {
51
111
  if (subMenu) {
52
112
  cy.hoverRootMenuItem(rootItemNumber)
53
113
  .contains(subMenu)
54
- .trigger('mouseover', { force: true });
55
- cy.contains(page).click({ force: true });
114
+ .trigger('mouseover')
115
+ .get('.MuiCollapse-wrapper')
116
+ .find('div[data-cy="collapse"]')
117
+ .should('be.visible')
118
+ .and('contain', page);
119
+
120
+ cy.clickSubRootMenuItem(page);
56
121
 
57
122
  return;
58
123
  }
@@ -83,34 +148,80 @@ Cypress.Commands.add(
83
148
  }
84
149
  );
85
150
 
151
+ Cypress.Commands.add('getContainerId', (containerName: string) => {
152
+ cy.log(`Getting container id of ${containerName}`);
153
+
154
+ return cy.task('getContainerId', containerName);
155
+ });
156
+
157
+ Cypress.Commands.add('getContainerIpAddress', (containerName: string) => {
158
+ cy.log(`Getting container ip address of ${containerName}`);
159
+
160
+ return cy.task('getContainerIpAddress', containerName);
161
+ });
162
+
163
+ Cypress.Commands.add('getContainersLogs', () => {
164
+ cy.log('Getting containers logs');
165
+
166
+ return cy.task('getContainersLogs');
167
+ });
168
+
86
169
  interface CopyFromContainerProps {
87
170
  destination: string;
171
+ name?: string;
88
172
  source: string;
89
173
  }
90
174
 
91
175
  Cypress.Commands.add(
92
176
  'copyFromContainer',
93
- ({ source, destination }: CopyFromContainerProps) => {
94
- return cy.exec(
95
- `docker cp ${Cypress.env('dockerName')}:${source} "${destination}"`
96
- );
177
+ ({ name = 'web', source, destination }: CopyFromContainerProps) => {
178
+ cy.log(`Copy content from ${name}:${source} to ${destination}`);
179
+
180
+ return cy.task('copyFromContainer', {
181
+ destination,
182
+ serviceName: name,
183
+ source
184
+ });
97
185
  }
98
186
  );
99
187
 
188
+ export enum CopyToContainerContentType {
189
+ Directory = 'directory',
190
+ File = 'file'
191
+ }
192
+
100
193
  interface CopyToContainerProps {
101
194
  destination: string;
195
+ name?: string;
102
196
  source: string;
197
+ type: CopyToContainerContentType;
103
198
  }
104
199
 
105
200
  Cypress.Commands.add(
106
201
  'copyToContainer',
107
- ({ source, destination }: CopyToContainerProps) => {
108
- return cy.exec(
109
- `docker cp ${source} ${Cypress.env('dockerName')}:${destination}`
110
- );
202
+ ({ name = 'web', source, destination, type }: CopyToContainerProps) => {
203
+ cy.log(`Copy content from ${source} to ${name}:${destination}`);
204
+
205
+ return cy.task('copyToContainer', {
206
+ destination,
207
+ serviceName: name,
208
+ source,
209
+ type
210
+ });
111
211
  }
112
212
  );
113
213
 
214
+ Cypress.Commands.add('loginAsAdminViaApiV2', (): Cypress.Chainable => {
215
+ return cy.request({
216
+ body: {
217
+ login: 'admin',
218
+ password: 'Centreon!2021'
219
+ },
220
+ method: 'POST',
221
+ url: apiLoginV2
222
+ });
223
+ });
224
+
114
225
  interface LoginByTypeOfUserProps {
115
226
  jsonName?: string;
116
227
  loginViaApi?: boolean;
@@ -118,7 +229,7 @@ interface LoginByTypeOfUserProps {
118
229
 
119
230
  Cypress.Commands.add(
120
231
  'loginByTypeOfUser',
121
- ({ jsonName, loginViaApi }): Cypress.Chainable => {
232
+ ({ jsonName = 'admin', loginViaApi = false }): Cypress.Chainable => {
122
233
  if (loginViaApi) {
123
234
  return cy
124
235
  .fixture(`users/${jsonName}.json`)
@@ -135,27 +246,56 @@ Cypress.Commands.add(
135
246
  .visit(`${Cypress.config().baseUrl}`)
136
247
  .wait('@getNavigationList');
137
248
  }
249
+
138
250
  cy.visit(`${Cypress.config().baseUrl}`)
139
251
  .fixture(`users/${jsonName}.json`)
140
252
  .then((credential) => {
141
- cy.getByLabel({ label: 'Alias', tag: 'input' }).type(credential.login);
253
+ cy.getByLabel({ label: 'Alias', tag: 'input' }).type(
254
+ `{selectAll}{backspace}${credential.login}`
255
+ );
142
256
  cy.getByLabel({ label: 'Password', tag: 'input' }).type(
143
- credential.password
257
+ `{selectAll}{backspace}${credential.password}`
144
258
  );
145
259
  })
146
260
  .getByLabel({ label: 'Connect', tag: 'button' })
147
261
  .click();
148
262
 
149
- return cy
150
- .get('.SnackbarContent-root > .MuiPaper-root')
151
- .then(($snackbar) => {
152
- if ($snackbar.text().includes('Login succeeded')) {
153
- cy.wait('@getNavigationList');
154
- }
155
- });
263
+ return cy.get('.MuiAlert-message').then(($snackbar) => {
264
+ if ($snackbar.text().includes('Login succeeded')) {
265
+ cy.wait('@getNavigationList');
266
+ cy.get('.MuiAlert-message').should('not.be.visible');
267
+ }
268
+ });
156
269
  }
157
270
  );
158
271
 
272
+ Cypress.Commands.add('logout', (): void => {
273
+ cy.getByLabel({ label: 'Profile' }).should('exist').click();
274
+
275
+ cy.intercept({
276
+ method: 'GET',
277
+ times: 1,
278
+ url: '/centreon/api/latest/authentication/logout'
279
+ }).as('logout');
280
+
281
+ cy.contains(/^Logout$/).click();
282
+
283
+ cy.wait('@logout').its('response.statusCode').should('eq', 302);
284
+
285
+ // https://github.com/cypress-io/cypress/issues/25841
286
+ cy.clearAllCookies();
287
+ });
288
+
289
+ Cypress.Commands.add('logoutViaAPI', (): Cypress.Chainable => {
290
+ return cy
291
+ .request({
292
+ method: 'GET',
293
+ url: '/centreon/authentication/logout'
294
+ })
295
+ .visit('/')
296
+ .getByLabel({ label: 'Alias', tag: 'input' });
297
+ });
298
+
159
299
  Cypress.Commands.add(
160
300
  'visitEmptyPage',
161
301
  (): Cypress.Chainable =>
@@ -167,32 +307,91 @@ Cypress.Commands.add(
167
307
  .visit('/waiting-page')
168
308
  );
169
309
 
170
- Cypress.Commands.add('waitForContainerAndSetToken', (): Cypress.Chainable => {
171
- return cy.setUserTokenApiV1();
172
- });
173
-
174
310
  interface ExecInContainerProps {
175
- command: string;
311
+ command: string | Array<string>;
176
312
  name: string;
177
313
  }
178
314
 
315
+ interface ExecInContainerResult {
316
+ exitCode: number;
317
+ output: string;
318
+ }
319
+
179
320
  Cypress.Commands.add(
180
321
  'execInContainer',
181
322
  ({ command, name }: ExecInContainerProps): Cypress.Chainable => {
182
- return cy
183
- .exec(`docker exec -i ${name} ${command}`, { failOnNonZeroExit: false })
184
- .then((result) => {
185
- if (result.code) {
186
- // output will not be truncated
187
- throw new Error(`
188
- Execution of "${command}" failed
189
- Exit code: ${result.code}
190
- Stdout:\n${result.stdout}
191
- Stderr:\n${result.stderr}`);
192
- }
323
+ const commands =
324
+ typeof command === 'string' || command instanceof String
325
+ ? [command]
326
+ : command;
327
+
328
+ const results = commands.reduce(
329
+ (acc, runCommand) => {
330
+ cy.task<ExecInContainerResult>(
331
+ 'execInContainer',
332
+ { command: runCommand, name },
333
+ { timeout: 600000 }
334
+ ).then((result) => {
335
+ if (result.exitCode) {
336
+ cy.log(result.output);
337
+
338
+ // output will not be truncated
339
+ throw new Error(`
340
+ Execution of "${runCommand}" failed
341
+ Exit code: ${result.exitCode}
342
+ Output:\n${result.output}`);
343
+ }
344
+
345
+ acc.output = `${acc.output}${result.output}`;
346
+ });
347
+
348
+ return acc;
349
+ },
350
+ { exitCode: 0, output: '' }
351
+ );
193
352
 
194
- return cy.wrap(result);
195
- });
353
+ return cy.wrap(results);
354
+ }
355
+ );
356
+
357
+ interface RequestOnDatabaseProps {
358
+ database: string;
359
+ query: string;
360
+ }
361
+
362
+ Cypress.Commands.add(
363
+ 'requestOnDatabase',
364
+ ({ database, query }: RequestOnDatabaseProps): Cypress.Chainable => {
365
+ return cy.task('requestOnDatabase', { database, query });
366
+ }
367
+ );
368
+
369
+ interface SetUserTokenApiV1Props {
370
+ login?: string;
371
+ password?: string;
372
+ }
373
+
374
+ Cypress.Commands.add(
375
+ 'setUserTokenApiV1',
376
+ ({
377
+ login = 'admin',
378
+ password = 'Centreon!2021'
379
+ }: SetUserTokenApiV1Props = {}): Cypress.Chainable => {
380
+ return cy
381
+ .request({
382
+ body: {
383
+ password,
384
+ username: login
385
+ },
386
+ headers: {
387
+ 'Content-Type': 'application/x-www-form-urlencoded'
388
+ },
389
+ method: 'POST',
390
+ url: `${apiActionV1}?action=authenticate`
391
+ })
392
+ .then(({ body }) =>
393
+ window.localStorage.setItem('userTokenApiV1', body.authToken)
394
+ );
196
395
  }
197
396
  );
198
397
 
@@ -202,6 +401,7 @@ interface PortBinding {
202
401
  }
203
402
 
204
403
  interface StartContainerProps {
404
+ command?: string;
205
405
  image: string;
206
406
  name: string;
207
407
  portBindings: Array<PortBinding>;
@@ -209,174 +409,447 @@ interface StartContainerProps {
209
409
 
210
410
  Cypress.Commands.add(
211
411
  'startContainer',
212
- ({ name, image, portBindings }: StartContainerProps): Cypress.Chainable => {
213
- return cy
214
- .exec('docker image list --format "{{.Repository}}:{{.Tag}}"')
215
- .then(({ stdout }) => {
216
- if (
217
- stdout.match(
218
- new RegExp(
219
- `^${image.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}`,
220
- 'm'
221
- )
222
- )
223
- ) {
224
- cy.log(`Local docker image found : ${image}`);
225
-
226
- return cy.wrap(image);
227
- }
228
-
229
- cy.log(`Pulling remote docker image : ${image}`);
230
-
231
- return cy.exec(`docker pull ${image}`).then(() => cy.wrap(image));
232
- })
233
- .then((imageName) =>
234
- cy.task('startContainer', { image: imageName, name, portBindings })
235
- );
412
+ ({
413
+ command,
414
+ name,
415
+ image,
416
+ portBindings
417
+ }: StartContainerProps): Cypress.Chainable => {
418
+ cy.log(`Starting container ${name} from image ${image}`);
419
+
420
+ return cy.task(
421
+ 'startContainer',
422
+ { command, image, name, portBindings },
423
+ { timeout: 600000 } // 10 minutes because docker pull can be very slow
424
+ );
236
425
  }
237
426
  );
238
427
 
239
- interface StartWebContainerProps {
240
- name?: string;
241
- os?: string;
428
+ interface StartContainersProps {
429
+ composeFile?: string;
430
+ databaseImage?: string;
431
+ moduleName?: string;
432
+ openidImage?: string;
433
+ profiles?: Array<string>;
434
+ samlImage?: string;
242
435
  useSlim?: boolean;
243
- version?: string;
436
+ webOs?: string;
437
+ webVersion?: string;
244
438
  }
245
439
 
246
440
  Cypress.Commands.add(
247
- 'startWebContainer',
441
+ 'startContainers',
248
442
  ({
249
- name = Cypress.env('dockerName'),
250
- os = 'alma9',
443
+ composeFile,
444
+ databaseImage = Cypress.env('DATABASE_IMAGE'),
445
+ moduleName = 'centreon-web',
446
+ openidImage = `docker.centreon.com/centreon/keycloak:${Cypress.env(
447
+ 'OPENID_IMAGE_VERSION'
448
+ )}`,
449
+ profiles = [],
450
+ samlImage = `docker.centreon.com/centreon/keycloak:${Cypress.env(
451
+ 'SAML_IMAGE_VERSION'
452
+ )}`,
251
453
  useSlim = true,
252
- version = Cypress.env('WEB_IMAGE_VERSION')
253
- }: StartWebContainerProps = {}): Cypress.Chainable => {
454
+ webOs = Cypress.env('WEB_IMAGE_OS'),
455
+ webVersion = Cypress.env('WEB_IMAGE_VERSION')
456
+ }: StartContainersProps = {}): Cypress.Chainable => {
457
+ cy.log('Starting containers ...');
458
+
459
+ let composeFilePath = composeFile;
460
+ if (!composeFile) {
461
+ const cypressDir = path.dirname(Cypress.config('configFile'));
462
+ composeFilePath = `${cypressDir}/../../../.github/docker/docker-compose.yml`;
463
+ }
464
+
254
465
  const slimSuffix = useSlim ? '-slim' : '';
255
466
 
256
- const image = `docker.centreon.com/centreon/centreon-web${slimSuffix}-${os}:${version}`;
467
+ const webImage = `docker.centreon.com/centreon/${moduleName}${slimSuffix}-${webOs}:${webVersion}`;
257
468
 
258
469
  return cy
259
- .startContainer({
260
- image,
261
- name,
262
- portBindings: [{ destination: 4000, source: 80 }]
263
- })
470
+ .task(
471
+ 'startContainers',
472
+ {
473
+ composeFile: composeFilePath,
474
+ databaseImage,
475
+ openidImage,
476
+ profiles,
477
+ samlImage,
478
+ webImage
479
+ },
480
+ { timeout: 600000 } // 10 minutes because docker pull can be very slow
481
+ )
264
482
  .then(() => {
265
- const baseUrl = 'http://0.0.0.0:4000';
483
+ const baseUrl = 'http://127.0.0.1:4000';
266
484
 
267
485
  Cypress.config('baseUrl', baseUrl);
268
486
 
269
- return cy.exec(
270
- `npx wait-on ${baseUrl}/centreon/api/latest/platform/installation/status`
271
- );
487
+ return cy.wrap(null);
272
488
  })
273
489
  .visit('/') // this is necessary to refresh browser cause baseUrl has changed (flash appears in video)
274
490
  .setUserTokenApiV1();
275
491
  }
276
492
  );
277
493
 
278
- interface StopWebContainerProps {
279
- name?: string;
494
+ interface StopContainerProps {
495
+ name: string;
280
496
  }
281
497
 
282
498
  Cypress.Commands.add(
283
- 'stopWebContainer',
284
- ({
285
- name = Cypress.env('dockerName')
286
- }: StopWebContainerProps = {}): Cypress.Chainable => {
287
- const logDirectory = `cypress/results/logs/${Cypress.spec.name.replace(
288
- artifactIllegalCharactersMatcher,
289
- '_'
290
- )}/${Cypress.currentTest.title.replace(
291
- artifactIllegalCharactersMatcher,
292
- '_'
293
- )}`;
499
+ 'stopContainer',
500
+ ({ name }: StopContainerProps): Cypress.Chainable => {
501
+ cy.log(`Stopping container ${name}`);
294
502
 
295
- return cy
296
- .visitEmptyPage()
297
- .exec(`mkdir -p "${logDirectory}"`)
298
- .copyFromContainer({
299
- destination: `${logDirectory}/broker`,
300
- source: '/var/log/centreon-broker'
301
- })
302
- .copyFromContainer({
303
- destination: `${logDirectory}/engine`,
304
- source: '/var/log/centreon-engine'
305
- })
306
- .execInContainer({
307
- command: `bash -e <<EOF
308
- chmod 777 /var/log/centreon/centreon-web.log > /dev/null 2>&1 || :
309
- EOF`,
310
- name
311
- })
312
- .copyFromContainer({
313
- destination: `${logDirectory}/centreon`,
314
- source: '/var/log/centreon'
315
- })
316
- .stopContainer({ name });
503
+ return cy.task('stopContainer', { name });
317
504
  }
318
505
  );
319
506
 
320
- interface StopContainerProps {
507
+ Cypress.Commands.add('stopContainers', (): Cypress.Chainable => {
508
+ cy.log('Stopping containers ...');
509
+
510
+ const logDirectory = `results/logs/${Cypress.spec.name.replace(
511
+ artifactIllegalCharactersMatcher,
512
+ '_'
513
+ )}/${Cypress.currentTest.title.replace(
514
+ artifactIllegalCharactersMatcher,
515
+ '_'
516
+ )}`;
517
+
518
+ const name = 'web';
519
+
520
+ return cy
521
+ .visitEmptyPage()
522
+ .createDirectory(logDirectory)
523
+ .getContainersLogs()
524
+ .then((containersLogs: Array<Array<string>>) => {
525
+ if (!containersLogs) {
526
+ return;
527
+ }
528
+
529
+ Object.entries(containersLogs).forEach(([containerName, logs]) => {
530
+ cy.writeFile(
531
+ `results/logs/${Cypress.spec.name.replace(
532
+ artifactIllegalCharactersMatcher,
533
+ '_'
534
+ )}/${Cypress.currentTest.title.replace(
535
+ artifactIllegalCharactersMatcher,
536
+ '_'
537
+ )}/container-${containerName}.log`,
538
+ logs
539
+ );
540
+ });
541
+ })
542
+ .copyFromContainer({
543
+ destination: `${logDirectory}/broker`,
544
+ name,
545
+ source: '/var/log/centreon-broker'
546
+ })
547
+ .copyFromContainer({
548
+ destination: `${logDirectory}/engine`,
549
+ name,
550
+ source: '/var/log/centreon-engine'
551
+ })
552
+ .copyFromContainer({
553
+ destination: `${logDirectory}/centreon`,
554
+ name,
555
+ source: '/var/log/centreon'
556
+ })
557
+ .copyFromContainer({
558
+ destination: `${logDirectory}/centreon-gorgone`,
559
+ name,
560
+ source: '/var/log/centreon-gorgone'
561
+ })
562
+ .then(() => {
563
+ if (Cypress.env('WEB_IMAGE_OS').includes('alma')) {
564
+ return cy.copyFromContainer({
565
+ destination: `${logDirectory}/php`,
566
+ name,
567
+ source: '/var/log/php-fpm'
568
+ });
569
+ }
570
+
571
+ return cy.copyFromContainer(
572
+ {
573
+ destination: `${logDirectory}/php8.1-fpm-centreon-error.log`,
574
+ name,
575
+ source: '/var/log/php8.1-fpm-centreon-error.log'
576
+ },
577
+ { failOnNonZeroExit: false }
578
+ );
579
+ })
580
+ .then(() => {
581
+ if (Cypress.env('WEB_IMAGE_OS').includes('alma')) {
582
+ return cy.copyFromContainer({
583
+ destination: `${logDirectory}/httpd`,
584
+ name,
585
+ source: '/var/log/httpd'
586
+ });
587
+ }
588
+
589
+ return cy.copyFromContainer(
590
+ {
591
+ destination: `${logDirectory}/apache2`,
592
+ name,
593
+ source: '/var/log/apache2'
594
+ },
595
+ { failOnNonZeroExit: false }
596
+ );
597
+ })
598
+ .exec(`chmod -R 755 "${logDirectory}"`)
599
+ .task(
600
+ 'stopContainers',
601
+ {},
602
+ { timeout: 600000 } // 10 minutes because docker pull can be very slow
603
+ );
604
+ });
605
+
606
+ Cypress.Commands.add(
607
+ 'createDirectory',
608
+ (directoryPath: string): Cypress.Chainable => {
609
+ return cy.task('createDirectory', directoryPath);
610
+ }
611
+ );
612
+
613
+ interface Dashboard {
614
+ description?: string;
321
615
  name: string;
322
616
  }
323
617
 
324
618
  Cypress.Commands.add(
325
- 'stopContainer',
326
- ({ name }: StopContainerProps): Cypress.Chainable => {
327
- cy.exec(`docker logs ${name}`).then(({ stdout }) => {
328
- cy.writeFile(
329
- `cypress/results/logs/${Cypress.spec.name.replace(
330
- artifactIllegalCharactersMatcher,
331
- '_'
332
- )}/${Cypress.currentTest.title.replace(
333
- artifactIllegalCharactersMatcher,
334
- '_'
335
- )}/container-${name}.log`,
336
- stdout
619
+ 'insertDashboardList',
620
+ (fixtureFile: string): Cypress.Chainable => {
621
+ return cy.fixture(fixtureFile).then((dashboardList) => {
622
+ cy.wrap(
623
+ Promise.all(
624
+ dashboardList.map((dashboardBody: Dashboard) =>
625
+ cy.insertDashboard({ ...dashboardBody })
626
+ )
627
+ )
337
628
  );
338
629
  });
630
+ }
631
+ );
339
632
 
340
- return cy.task('stopContainer', { name });
633
+ Cypress.Commands.add(
634
+ 'insertDashboard',
635
+ (dashboardBody: Dashboard): Cypress.Chainable => {
636
+ return cy.request({
637
+ body: {
638
+ ...dashboardBody
639
+ },
640
+ method: 'POST',
641
+ url: '/centreon/api/latest/configuration/dashboards'
642
+ });
341
643
  }
342
644
  );
343
645
 
646
+ Cypress.Commands.add(
647
+ 'insertDashboardWithWidget',
648
+ (dashboardBody, patchBody) => {
649
+ cy.request({
650
+ body: {
651
+ ...dashboardBody
652
+ },
653
+ method: 'POST',
654
+ url: '/centreon/api/latest/configuration/dashboards'
655
+ }).then((response) => {
656
+ const dashboardId = response.body.id;
657
+ cy.waitUntil(
658
+ () => {
659
+ return cy
660
+ .request({
661
+ method: 'GET',
662
+ url: `/centreon/api/latest/configuration/dashboards/${dashboardId}`
663
+ })
664
+ .then((getResponse) => {
665
+ return getResponse.body && getResponse.body.id === dashboardId;
666
+ });
667
+ },
668
+ {
669
+ timeout: 10000
670
+ }
671
+ );
672
+ cy.request({
673
+ body: patchBody,
674
+ method: 'PATCH',
675
+ url: `/centreon/api/latest/configuration/dashboards/${dashboardId}`
676
+ });
677
+ });
678
+ }
679
+ );
680
+
681
+ interface ShareDashboardToUserProps {
682
+ dashboardName: string;
683
+ role: string;
684
+ userName: string;
685
+ }
686
+
687
+ interface ListingRequestResult {
688
+ body: {
689
+ result: Array<{
690
+ id: number;
691
+ }>;
692
+ };
693
+ }
694
+
695
+ interface PatchDashboardBody {
696
+ panels: Array<{
697
+ layout: {
698
+ height: number;
699
+ min_height: number;
700
+ min_width: number;
701
+ width: number;
702
+ x: number;
703
+ y: number;
704
+ };
705
+ name: string;
706
+ widget_settings: {
707
+ options: {
708
+ description: {
709
+ content: string;
710
+ enabled: boolean;
711
+ };
712
+ name: string;
713
+ };
714
+ };
715
+ widget_type: string;
716
+ }>;
717
+ }
718
+
719
+ Cypress.Commands.add(
720
+ 'shareDashboardToUser',
721
+ ({ dashboardName, userName, role }: ShareDashboardToUserProps): void => {
722
+ Promise.all([
723
+ cy.request({
724
+ method: 'GET',
725
+ url: `/centreon/api/latest/configuration/users?search={"name":"${userName}"}`
726
+ }),
727
+ cy.request({
728
+ method: 'GET',
729
+ url: `/centreon/api/latest/configuration/dashboards?search={"name":"${dashboardName}"}`
730
+ })
731
+ ]).then(
732
+ ([retrievedUser, retrievedDashboard]: [
733
+ ListingRequestResult,
734
+ ListingRequestResult
735
+ ]) => {
736
+ const userId = retrievedUser.body.result[0].id;
737
+ const dashboardId = retrievedDashboard.body.result[0].id;
738
+
739
+ cy.request({
740
+ body: {
741
+ id: userId,
742
+ role: `${role}`
743
+ },
744
+ method: 'POST',
745
+ url: `/centreon/api/latest/configuration/dashboards/${dashboardId}/access_rights/contacts`
746
+ });
747
+ }
748
+ );
749
+ }
750
+ );
751
+
752
+ Cypress.Commands.add('getTimeFromHeader', (): Cypress.Chainable => {
753
+ return cy
754
+ .get('header div[data-cy="clock"]', { timeout: 20000 })
755
+ .should('be.visible')
756
+ .then(($time) => {
757
+ const headerTime = $time.children()[1].textContent;
758
+ if (headerTime?.match(/\d+:\d+/)) {
759
+ cy.log(`header time is : ${headerTime}`);
760
+
761
+ return cy.wrap(headerTime);
762
+ }
763
+
764
+ throw new Error(`header time is not displayed`);
765
+ });
766
+ });
767
+
344
768
  declare global {
345
769
  namespace Cypress {
346
770
  interface Chainable {
347
- copyFromContainer: (props: CopyFromContainerProps) => Cypress.Chainable;
348
- copyToContainer: (props: CopyToContainerProps) => Cypress.Chainable;
771
+ clickSubRootMenuItem: (page: string) => Cypress.Chainable;
772
+ copyFromContainer: (
773
+ props: CopyFromContainerProps,
774
+ options?: Partial<Cypress.ExecOptions>
775
+ ) => Cypress.Chainable;
776
+ copyToContainer: (
777
+ props: CopyToContainerProps,
778
+ options?: Partial<Cypress.ExecOptions>
779
+ ) => Cypress.Chainable;
780
+ createDirectory: (directoryPath: string) => Cypress.Chainable;
349
781
  execInContainer: ({
350
782
  command,
351
783
  name
352
784
  }: ExecInContainerProps) => Cypress.Chainable;
785
+ getByLabel: ({
786
+ patternType,
787
+ tag,
788
+ label
789
+ }: GetByLabelProps) => Cypress.Chainable;
790
+ getByTestId: ({
791
+ patternType,
792
+ tag,
793
+ testId
794
+ }: GetByTestIdProps) => Cypress.Chainable;
795
+ getContainerId: (containerName: string) => Cypress.Chainable;
796
+ getContainerIpAddress: (containerName: string) => Cypress.Chainable;
797
+ getContainersLogs: () => Cypress.Chainable;
353
798
  getIframeBody: () => Cypress.Chainable;
799
+ getTimeFromHeader: () => Cypress.Chainable;
354
800
  getWebVersion: () => Cypress.Chainable;
355
801
  hoverRootMenuItem: (rootItemNumber: number) => Cypress.Chainable;
802
+ insertDashboard: (dashboard: Dashboard) => Cypress.Chainable;
803
+ insertDashboardList: (fixtureFile: string) => Cypress.Chainable;
804
+ insertDashboardWithWidget: (
805
+ dashboard: Dashboard,
806
+ patch: PatchDashboardBody
807
+ ) => Cypress.Chainable;
808
+ loginAsAdminViaApiV2: () => Cypress.Chainable;
356
809
  loginByTypeOfUser: ({
357
- jsonName = 'admin',
358
- loginViaApi = false
810
+ jsonName,
811
+ loginViaApi
359
812
  }: LoginByTypeOfUserProps) => Cypress.Chainable;
813
+ logout: () => void;
814
+ logoutViaAPI: () => Cypress.Chainable;
360
815
  moveSortableElement: (direction: string) => Cypress.Chainable;
361
816
  navigateTo: ({
362
817
  page,
363
818
  rootItemNumber,
364
819
  subMenu
365
820
  }: NavigateToProps) => Cypress.Chainable;
821
+ requestOnDatabase: ({
822
+ database,
823
+ query
824
+ }: RequestOnDatabaseProps) => Cypress.Chainable;
825
+ setUserTokenApiV1: ({
826
+ login,
827
+ password
828
+ }?: SetUserTokenApiV1Props) => Cypress.Chainable;
829
+ shareDashboardToUser: ({
830
+ dashboardName,
831
+ userName,
832
+ role
833
+ }: ShareDashboardToUserProps) => Cypress.Chainable;
366
834
  startContainer: ({
835
+ command,
367
836
  name,
368
- image
837
+ image,
838
+ portBindings
369
839
  }: StartContainerProps) => Cypress.Chainable;
370
- startWebContainer: ({
371
- name,
372
- os,
840
+ startContainers: ({
841
+ composeFile,
842
+ databaseImage,
843
+ moduleName,
844
+ openidImage,
845
+ profiles,
373
846
  useSlim,
374
- version
375
- }?: StartWebContainerProps) => Cypress.Chainable;
847
+ webOs,
848
+ webVersion
849
+ }?: StartContainersProps) => Cypress.Chainable;
376
850
  stopContainer: ({ name }: StopContainerProps) => Cypress.Chainable;
377
- stopWebContainer: ({ name }?: StopWebContainerProps) => Cypress.Chainable;
851
+ stopContainers: () => Cypress.Chainable;
378
852
  visitEmptyPage: () => Cypress.Chainable;
379
- waitForContainerAndSetToken: () => Cypress.Chainable;
380
853
  }
381
854
  }
382
855
  }