@centreon/js-config 23.10.62 → 23.10.64

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.
@@ -4,15 +4,13 @@ import React from 'react';
4
4
  import { mount } from 'cypress/react18';
5
5
  import { equals, isNil } from 'ramda';
6
6
 
7
- import { Box, CssBaseline } from '@mui/material';
7
+ import { Box } from '@mui/material';
8
8
 
9
9
  import { ThemeProvider } from '@centreon/ui';
10
10
 
11
11
  import '@testing-library/cypress/add-commands';
12
12
  import 'cypress-msw-interceptor';
13
13
 
14
- import disableMotion from './disableCssTransitions';
15
-
16
14
  interface MountProps {
17
15
  Component: React.ReactNode;
18
16
  options?: object;
@@ -26,7 +24,7 @@ export enum Method {
26
24
  PUT = 'PUT'
27
25
  }
28
26
 
29
- Cypress.Commands.add('mount', ({ Component, options = {} }) => {
27
+ Cypress.Commands.add('mount', ({ Component, options }) => {
30
28
  const wrapped = (
31
29
  <ThemeProvider>
32
30
  <Box
@@ -38,10 +36,11 @@ Cypress.Commands.add('mount', ({ Component, options = {} }) => {
38
36
  >
39
37
  {Component}
40
38
  </Box>
41
- <CssBaseline />
42
39
  </ThemeProvider>
43
40
  );
44
41
 
42
+ document.getElementsByTagName('body')[0].setAttribute('style', 'margin:0px');
43
+
45
44
  return mount(wrapped, options);
46
45
  });
47
46
 
@@ -96,32 +95,20 @@ Cypress.Commands.add(
96
95
  }
97
96
  );
98
97
 
99
- interface MoveSortableElementProps {
100
- direction: 'up' | 'down' | 'left' | 'right';
101
- element: Cypress.Chainable<JQuery<HTMLElement>>;
102
- times?: number;
103
- }
104
-
105
- Cypress.Commands.add(
106
- 'moveSortableElement',
107
- ({ element, direction, times = 1 }: MoveSortableElementProps): void => {
108
- const key = `{${direction}arrow}`;
109
-
110
- element.type(' ', {
111
- force: true,
112
- scrollBehavior: false
113
- });
98
+ Cypress.Commands.add('moveSortableElement', ({ element, direction }): void => {
99
+ const key = `{${direction}arrow}`;
114
100
 
115
- Array.from({ length: times }).forEach(() => {
116
- element.eq(-1).type(key, {
117
- scrollBehavior: false
118
- });
119
- });
120
- element.eq(-1).type(' ', {
121
- scrollBehavior: false
122
- });
123
- }
124
- );
101
+ element.type(' ', {
102
+ force: true,
103
+ scrollBehavior: false
104
+ });
105
+ element.eq(-1).type(key, {
106
+ scrollBehavior: false
107
+ });
108
+ element.eq(-1).type(' ', {
109
+ scrollBehavior: false
110
+ });
111
+ });
125
112
 
126
113
  Cypress.Commands.add(
127
114
  'moveSortableElementUsingAriaLabel',
@@ -141,32 +128,15 @@ Cypress.Commands.add(
141
128
  }
142
129
  );
143
130
 
144
- Cypress.Commands.add('makeSnapshot', (title?: string) => {
145
- cy.viewport(1280, 590);
146
- cy.matchImageSnapshot(title);
147
- });
148
-
149
- Cypress.Commands.add('cssDisableMotion', (): void => {
150
- Cypress.on('window:before:load', (cyWindow) => {
151
- disableMotion(cyWindow);
152
- });
153
- });
154
-
155
131
  declare global {
156
132
  namespace Cypress {
157
133
  interface Chainable {
158
- cssDisableMotion: () => Cypress.Chainable;
159
134
  interceptAPIRequest: <T extends object>(
160
135
  props: InterceptAPIRequestProps<T>
161
136
  ) => Cypress.Chainable;
162
137
  interceptRequest: (method, path, mock, alias) => Cypress.Chainable;
163
- makeSnapshot: (title?: string) => void;
164
- mount: ({ Component, options }: MountProps) => Cypress.Chainable;
165
- moveSortableElement: ({
166
- element,
167
- direction,
168
- times
169
- }: MoveSortableElementProps) => void;
138
+ mount: ({ Component, options = {} }: MountProps) => Cypress.Chainable;
139
+ moveSortableElement: ({ ariaLabel, direction }) => void;
170
140
  moveSortableElementUsingAriaLabel: ({ ariaLabel, direction }) => void;
171
141
  waitForRequest: (alias) => Cypress.Chainable;
172
142
  }
@@ -4,30 +4,28 @@ const {
4
4
  addMatchImageSnapshotPlugin
5
5
  } = require('@simonsmith/cypress-image-snapshot/plugin');
6
6
 
7
- module.exports = ({
8
- webpackConfig,
9
- cypressFolder,
10
- specPattern,
11
- env,
12
- useVite = false,
13
- excludeSpecPattern
14
- }) => {
7
+ module.exports = ({ webpackConfig, cypressFolder, specPattern, env }) => {
15
8
  const mainCypressFolder = cypressFolder || 'cypress';
16
9
 
17
10
  return defineConfig({
18
11
  component: {
19
12
  devServer: {
20
- bundler: useVite ? 'vite' : 'webpack',
13
+ bundler: 'webpack',
21
14
  framework: 'react',
22
15
  webpackConfig
23
16
  },
24
- excludeSpecPattern,
25
17
  setupNodeEvents: (on, config) => {
26
18
  addMatchImageSnapshotPlugin(on, config);
27
19
 
28
20
  on('before:browser:launch', (browser, launchOptions) => {
29
21
  if (browser.name === 'chrome' && browser.isHeadless) {
30
- launchOptions.args.push('--headless=new');
22
+ launchOptions.args = launchOptions.args.map((arg) => {
23
+ if (arg === '--headless') {
24
+ return '--headless=new';
25
+ }
26
+
27
+ return arg;
28
+ });
31
29
  }
32
30
 
33
31
  return launchOptions;
@@ -13,7 +13,7 @@ const enableVisualTesting = (cypressFolder = 'cypress'): void => {
13
13
  capture: 'viewport',
14
14
  customDiffConfig: { threshold: 0.01 },
15
15
  customSnapshotsDir: `${cypressFolder}/visual-testing-snapshots`,
16
- failureThreshold: 0.07,
16
+ failureThreshold: 0.06,
17
17
  failureThresholdType: 'percent'
18
18
  });
19
19
  };
@@ -1,11 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-namespace */
2
2
 
3
3
  import './commands/configuration';
4
- import './commands/monitoring';
5
-
6
- import installLogsCollector from 'cypress-terminal-report/src/installLogsCollector';
7
-
8
- installLogsCollector({ enableExtendedCollector: true });
9
4
 
10
5
  const apiLoginV2 = '/centreon/authentication/providers/configurations/local';
11
6
 
@@ -28,7 +23,7 @@ Cypress.Commands.add('getWebVersion', (): Cypress.Chainable => {
28
23
 
29
24
  Cypress.Commands.add('getIframeBody', (): Cypress.Chainable => {
30
25
  return cy
31
- .get('iframe#main-content', { timeout: 10000 })
26
+ .get('iframe#main-content')
32
27
  .its('0.contentDocument.body')
33
28
  .should('not.be.empty')
34
29
  .then(cy.wrap);
@@ -44,13 +39,6 @@ Cypress.Commands.add(
44
39
  }
45
40
  );
46
41
 
47
- Cypress.Commands.add(
48
- 'clickSubRootMenuItem',
49
- (page: string): Cypress.Chainable => {
50
- return cy.get('div[data-cy="collapse"]').eq(1).contains(page).click();
51
- }
52
- );
53
-
54
42
  interface NavigateToProps {
55
43
  page: string;
56
44
  rootItemNumber: number;
@@ -63,13 +51,8 @@ Cypress.Commands.add(
63
51
  if (subMenu) {
64
52
  cy.hoverRootMenuItem(rootItemNumber)
65
53
  .contains(subMenu)
66
- .trigger('mouseover')
67
- .get('.MuiCollapse-wrapper')
68
- .find('div[data-cy="collapse"]')
69
- .should('be.visible')
70
- .and('contain', page);
71
-
72
- cy.clickSubRootMenuItem(page);
54
+ .trigger('mouseover', { force: true });
55
+ cy.contains(page).click({ force: true });
73
56
 
74
57
  return;
75
58
  }
@@ -102,41 +85,29 @@ Cypress.Commands.add(
102
85
 
103
86
  interface CopyFromContainerProps {
104
87
  destination: string;
105
- name?: string;
106
88
  source: string;
107
89
  }
108
90
 
109
91
  Cypress.Commands.add(
110
92
  'copyFromContainer',
111
- (
112
- {
113
- name = Cypress.env('dockerName'),
114
- source,
115
- destination
116
- }: CopyFromContainerProps,
117
- options?: Partial<Cypress.ExecOptions>
118
- ) => {
119
- return cy.exec(`docker cp ${name}:${source} "${destination}"`, options);
93
+ ({ source, destination }: CopyFromContainerProps) => {
94
+ return cy.exec(
95
+ `docker cp ${Cypress.env('dockerName')}:${source} "${destination}"`
96
+ );
120
97
  }
121
98
  );
122
99
 
123
100
  interface CopyToContainerProps {
124
101
  destination: string;
125
- name?: string;
126
102
  source: string;
127
103
  }
128
104
 
129
105
  Cypress.Commands.add(
130
106
  'copyToContainer',
131
- (
132
- {
133
- name = Cypress.env('dockerName'),
134
- source,
135
- destination
136
- }: CopyToContainerProps,
137
- options?: Partial<Cypress.ExecOptions>
138
- ) => {
139
- return cy.exec(`docker cp ${source} ${name}:${destination}`, options);
107
+ ({ source, destination }: CopyToContainerProps) => {
108
+ return cy.exec(
109
+ `docker cp ${source} ${Cypress.env('dockerName')}:${destination}`
110
+ );
140
111
  }
141
112
  );
142
113
 
@@ -147,7 +118,7 @@ interface LoginByTypeOfUserProps {
147
118
 
148
119
  Cypress.Commands.add(
149
120
  'loginByTypeOfUser',
150
- ({ jsonName = 'admin', loginViaApi = false }): Cypress.Chainable => {
121
+ ({ jsonName, loginViaApi }): Cypress.Chainable => {
151
122
  if (loginViaApi) {
152
123
  return cy
153
124
  .fixture(`users/${jsonName}.json`)
@@ -164,25 +135,24 @@ Cypress.Commands.add(
164
135
  .visit(`${Cypress.config().baseUrl}`)
165
136
  .wait('@getNavigationList');
166
137
  }
167
-
168
138
  cy.visit(`${Cypress.config().baseUrl}`)
169
139
  .fixture(`users/${jsonName}.json`)
170
140
  .then((credential) => {
171
- cy.getByLabel({ label: 'Alias', tag: 'input' }).type(
172
- `{selectAll}{backspace}${credential.login}`
173
- );
141
+ cy.getByLabel({ label: 'Alias', tag: 'input' }).type(credential.login);
174
142
  cy.getByLabel({ label: 'Password', tag: 'input' }).type(
175
- `{selectAll}{backspace}${credential.password}`
143
+ credential.password
176
144
  );
177
145
  })
178
146
  .getByLabel({ label: 'Connect', tag: 'button' })
179
147
  .click();
180
148
 
181
- return cy.get('.MuiAlert-message').then(($snackbar) => {
182
- if ($snackbar.text().includes('Login succeeded')) {
183
- cy.wait('@getNavigationList');
184
- }
185
- });
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
+ });
186
156
  }
187
157
  );
188
158
 
@@ -240,20 +210,9 @@ interface StartContainerProps {
240
210
  Cypress.Commands.add(
241
211
  'startContainer',
242
212
  ({ name, image, portBindings }: StartContainerProps): Cypress.Chainable => {
243
- cy.log(`Starting container ${name} from image ${image}`);
244
-
245
- return cy.task(
246
- 'startContainer',
247
- { image, name, portBindings },
248
- { timeout: 600000 } // 10 minutes because docker pull can be very slow
249
- );
250
- }
251
- );
252
-
253
- Cypress.Commands.add(
254
- 'createDirectory',
255
- (directoryPath: string): Cypress.Chainable => {
256
- return cy.task('createDirectory', directoryPath);
213
+ return cy
214
+ .exec(`docker image inspect ${image} || docker pull ${image}`)
215
+ .task('startContainer', { image, name, portBindings });
257
216
  }
258
217
  );
259
218
 
@@ -268,7 +227,7 @@ Cypress.Commands.add(
268
227
  'startWebContainer',
269
228
  ({
270
229
  name = Cypress.env('dockerName'),
271
- os = Cypress.env('WEB_IMAGE_OS'),
230
+ os = 'alma9',
272
231
  useSlim = true,
273
232
  version = Cypress.env('WEB_IMAGE_VERSION')
274
233
  }: StartWebContainerProps = {}): Cypress.Chainable => {
@@ -283,13 +242,12 @@ Cypress.Commands.add(
283
242
  portBindings: [{ destination: 4000, source: 80 }]
284
243
  })
285
244
  .then(() => {
286
- const baseUrl = 'http://127.0.0.1:4000';
245
+ const baseUrl = 'http://0.0.0.0:4000';
287
246
 
288
247
  Cypress.config('baseUrl', baseUrl);
289
248
 
290
- return cy.task(
291
- 'waitOn',
292
- `${baseUrl}/centreon/api/latest/platform/installation/status`
249
+ return cy.exec(
250
+ `npx wait-on ${baseUrl}/centreon/api/latest/platform/installation/status`
293
251
  );
294
252
  })
295
253
  .visit('/') // this is necessary to refresh browser cause baseUrl has changed (flash appears in video)
@@ -306,7 +264,7 @@ Cypress.Commands.add(
306
264
  ({
307
265
  name = Cypress.env('dockerName')
308
266
  }: StopWebContainerProps = {}): Cypress.Chainable => {
309
- const logDirectory = `results/logs/${Cypress.spec.name.replace(
267
+ const logDirectory = `cypress/results/logs/${Cypress.spec.name.replace(
310
268
  artifactIllegalCharactersMatcher,
311
269
  '_'
312
270
  )}/${Cypress.currentTest.title.replace(
@@ -316,64 +274,25 @@ Cypress.Commands.add(
316
274
 
317
275
  return cy
318
276
  .visitEmptyPage()
319
- .createDirectory(logDirectory)
277
+ .exec(`mkdir -p "${logDirectory}"`)
320
278
  .copyFromContainer({
321
279
  destination: `${logDirectory}/broker`,
322
- name,
323
280
  source: '/var/log/centreon-broker'
324
281
  })
325
282
  .copyFromContainer({
326
283
  destination: `${logDirectory}/engine`,
327
- name,
328
284
  source: '/var/log/centreon-engine'
329
285
  })
286
+ .execInContainer({
287
+ command: `bash -e <<EOF
288
+ chmod 777 /var/log/centreon/centreon-web.log > /dev/null 2>&1 || :
289
+ EOF`,
290
+ name
291
+ })
330
292
  .copyFromContainer({
331
293
  destination: `${logDirectory}/centreon`,
332
- name,
333
294
  source: '/var/log/centreon'
334
295
  })
335
- .copyFromContainer({
336
- destination: `${logDirectory}/centreon-gorgone`,
337
- name,
338
- source: '/var/log/centreon-gorgone'
339
- })
340
- .then(() => {
341
- if (Cypress.env('WEB_IMAGE_OS').includes('alma')) {
342
- return cy.copyFromContainer({
343
- destination: `${logDirectory}/php`,
344
- name,
345
- source: '/var/log/php-fpm'
346
- });
347
- }
348
-
349
- return cy.copyFromContainer(
350
- {
351
- destination: `${logDirectory}/php8.1-fpm-centreon-error.log`,
352
- name,
353
- source: '/var/log/php8.1-fpm-centreon-error.log'
354
- },
355
- { failOnNonZeroExit: false }
356
- );
357
- })
358
- .then(() => {
359
- if (Cypress.env('WEB_IMAGE_OS').includes('alma')) {
360
- return cy.copyFromContainer({
361
- destination: `${logDirectory}/httpd`,
362
- name,
363
- source: '/var/log/httpd'
364
- });
365
- }
366
-
367
- return cy.copyFromContainer(
368
- {
369
- destination: `${logDirectory}/apache2`,
370
- name,
371
- source: '/var/log/apache2'
372
- },
373
- { failOnNonZeroExit: false }
374
- );
375
- })
376
- .exec(`chmod -R 755 "${logDirectory}"`)
377
296
  .stopContainer({ name });
378
297
  }
379
298
  );
@@ -385,11 +304,9 @@ interface StopContainerProps {
385
304
  Cypress.Commands.add(
386
305
  'stopContainer',
387
306
  ({ name }: StopContainerProps): Cypress.Chainable => {
388
- cy.log(`Stopping container ${name}`);
389
-
390
307
  cy.exec(`docker logs ${name}`).then(({ stdout }) => {
391
308
  cy.writeFile(
392
- `results/logs/${Cypress.spec.name.replace(
309
+ `cypress/results/logs/${Cypress.spec.name.replace(
393
310
  artifactIllegalCharactersMatcher,
394
311
  '_'
395
312
  )}/${Cypress.currentTest.title.replace(
@@ -404,192 +321,21 @@ Cypress.Commands.add(
404
321
  }
405
322
  );
406
323
 
407
- interface Dashboard {
408
- description?: string;
409
- name: string;
410
- }
411
-
412
- Cypress.Commands.add(
413
- 'insertDashboardList',
414
- (fixtureFile: string): Cypress.Chainable => {
415
- return cy.fixture(fixtureFile).then((dashboardList) => {
416
- cy.wrap(
417
- Promise.all(
418
- dashboardList.map((dashboardBody: Dashboard) =>
419
- cy.insertDashboard({ ...dashboardBody })
420
- )
421
- )
422
- );
423
- });
424
- }
425
- );
426
-
427
- Cypress.Commands.add(
428
- 'insertDashboard',
429
- (dashboardBody: Dashboard): Cypress.Chainable => {
430
- return cy.request({
431
- body: {
432
- ...dashboardBody
433
- },
434
- method: 'POST',
435
- url: '/centreon/api/latest/configuration/dashboards'
436
- });
437
- }
438
- );
439
-
440
- Cypress.Commands.add(
441
- 'insertDashboardWithWidget',
442
- (dashboardBody, patchBody) => {
443
- cy.request({
444
- body: {
445
- ...dashboardBody
446
- },
447
- method: 'POST',
448
- url: '/centreon/api/latest/configuration/dashboards'
449
- }).then((response) => {
450
- const dashboardId = response.body.id;
451
- cy.waitUntil(
452
- () => {
453
- return cy
454
- .request({
455
- method: 'GET',
456
- url: `/centreon/api/latest/configuration/dashboards/${dashboardId}`
457
- })
458
- .then((getResponse) => {
459
- return getResponse.body && getResponse.body.id === dashboardId;
460
- });
461
- },
462
- {
463
- timeout: 10000
464
- }
465
- );
466
- cy.request({
467
- body: patchBody,
468
- method: 'PATCH',
469
- url: `/centreon/api/latest/configuration/dashboards/${dashboardId}`
470
- });
471
- });
472
- }
473
- );
474
-
475
- interface ShareDashboardToUserProps {
476
- dashboardName: string;
477
- role: string;
478
- userName: string;
479
- }
480
-
481
- interface ListingRequestResult {
482
- body: {
483
- result: Array<{
484
- id: number;
485
- }>;
486
- };
487
- }
488
-
489
- interface PatchDashboardBody {
490
- panels: Array<{
491
- layout: {
492
- height: number;
493
- min_height: number;
494
- min_width: number;
495
- width: number;
496
- x: number;
497
- y: number;
498
- };
499
- name: string;
500
- widget_settings: {
501
- options: {
502
- description: {
503
- content: string;
504
- enabled: boolean;
505
- };
506
- name: string;
507
- };
508
- };
509
- widget_type: string;
510
- }>;
511
- }
512
-
513
- Cypress.Commands.add(
514
- 'shareDashboardToUser',
515
- ({ dashboardName, userName, role }: ShareDashboardToUserProps): void => {
516
- Promise.all([
517
- cy.request({
518
- method: 'GET',
519
- url: `/centreon/api/latest/configuration/users?search={"name":"${userName}"}`
520
- }),
521
- cy.request({
522
- method: 'GET',
523
- url: `/centreon/api/latest/configuration/dashboards?search={"name":"${dashboardName}"}`
524
- })
525
- ]).then(
526
- ([retrievedUser, retrievedDashboard]: [
527
- ListingRequestResult,
528
- ListingRequestResult
529
- ]) => {
530
- const userId = retrievedUser.body.result[0].id;
531
- const dashboardId = retrievedDashboard.body.result[0].id;
532
-
533
- cy.request({
534
- body: {
535
- id: userId,
536
- role: `${role}`
537
- },
538
- method: 'POST',
539
- url: `/centreon/api/latest/configuration/dashboards/${dashboardId}/access_rights/contacts`
540
- });
541
- }
542
- );
543
- }
544
- );
545
-
546
- Cypress.Commands.add('getTimeFromHeader', (): Cypress.Chainable => {
547
- return cy
548
- .get('header div[data-cy="clock"]', { timeout: 10000 })
549
- .should('be.visible')
550
- .then(($time) => {
551
- const headerTime = $time.children()[1].textContent;
552
- if (headerTime?.match(/\d+:\d+/)) {
553
- cy.log(`header time is : ${headerTime}`);
554
-
555
- return cy.wrap(headerTime);
556
- }
557
-
558
- throw new Error(`header time is not displayed`);
559
- });
560
- });
561
-
562
324
  declare global {
563
325
  namespace Cypress {
564
326
  interface Chainable {
565
- clickSubRootMenuItem: (page: string) => Cypress.Chainable;
566
- copyFromContainer: (
567
- props: CopyFromContainerProps,
568
- options?: Partial<Cypress.ExecOptions>
569
- ) => Cypress.Chainable;
570
- copyToContainer: (
571
- props: CopyToContainerProps,
572
- options?: Partial<Cypress.ExecOptions>
573
- ) => Cypress.Chainable;
574
- createDirectory: (directoryPath: string) => Cypress.Chainable;
327
+ copyFromContainer: (props: CopyFromContainerProps) => Cypress.Chainable;
328
+ copyToContainer: (props: CopyToContainerProps) => Cypress.Chainable;
575
329
  execInContainer: ({
576
330
  command,
577
331
  name
578
332
  }: ExecInContainerProps) => Cypress.Chainable;
579
333
  getIframeBody: () => Cypress.Chainable;
580
- getTimeFromHeader: () => Cypress.Chainable;
581
334
  getWebVersion: () => Cypress.Chainable;
582
335
  hoverRootMenuItem: (rootItemNumber: number) => Cypress.Chainable;
583
- insertDashboard: (dashboard: Dashboard) => Cypress.Chainable;
584
- insertDashboardList: (fixtureFile: string) => Cypress.Chainable;
585
- insertDashboardWithWidget: (
586
- dashboard: Dashboard,
587
- patch: PatchDashboardBody
588
- ) => Cypress.Chainable;
589
-
590
336
  loginByTypeOfUser: ({
591
- jsonName,
592
- loginViaApi
337
+ jsonName = 'admin',
338
+ loginViaApi = false
593
339
  }: LoginByTypeOfUserProps) => Cypress.Chainable;
594
340
  moveSortableElement: (direction: string) => Cypress.Chainable;
595
341
  navigateTo: ({
@@ -597,11 +343,6 @@ declare global {
597
343
  rootItemNumber,
598
344
  subMenu
599
345
  }: NavigateToProps) => Cypress.Chainable;
600
- shareDashboardToUser: ({
601
- dashboardName,
602
- userName,
603
- role
604
- }: ShareDashboardToUserProps) => Cypress.Chainable;
605
346
  startContainer: ({
606
347
  name,
607
348
  image