@centreon/js-config 23.10.34 → 23.10.36

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,7 +4,7 @@ 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
 
@@ -24,7 +24,7 @@ export enum Method {
24
24
  PUT = 'PUT'
25
25
  }
26
26
 
27
- Cypress.Commands.add('mount', ({ Component, options = {} }) => {
27
+ Cypress.Commands.add('mount', ({ Component, options }) => {
28
28
  const wrapped = (
29
29
  <ThemeProvider>
30
30
  <Box
@@ -36,10 +36,11 @@ Cypress.Commands.add('mount', ({ Component, options = {} }) => {
36
36
  >
37
37
  {Component}
38
38
  </Box>
39
- <CssBaseline />
40
39
  </ThemeProvider>
41
40
  );
42
41
 
42
+ document.getElementsByTagName('body')[0].setAttribute('style', 'margin:0px');
43
+
43
44
  return mount(wrapped, options);
44
45
  });
45
46
 
@@ -127,11 +128,6 @@ Cypress.Commands.add(
127
128
  }
128
129
  );
129
130
 
130
- Cypress.Commands.add('makeSnapshot', (title?: string) => {
131
- cy.viewport(1280, 590);
132
- cy.matchImageSnapshot(title);
133
- });
134
-
135
131
  declare global {
136
132
  namespace Cypress {
137
133
  interface Chainable {
@@ -139,9 +135,8 @@ declare global {
139
135
  props: InterceptAPIRequestProps<T>
140
136
  ) => Cypress.Chainable;
141
137
  interceptRequest: (method, path, mock, alias) => Cypress.Chainable;
142
- makeSnapshot: (title?: string) => void;
143
- mount: ({ Component, options }: MountProps) => Cypress.Chainable;
144
- moveSortableElement: ({ element, direction }) => void;
138
+ mount: ({ Component, options = {} }: MountProps) => Cypress.Chainable;
139
+ moveSortableElement: ({ ariaLabel, direction }) => void;
145
140
  moveSortableElementUsingAriaLabel: ({ ariaLabel, direction }) => void;
146
141
  waitForRequest: (alias) => Cypress.Chainable;
147
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();
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,15 +135,12 @@ 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' })
@@ -229,7 +197,9 @@ interface StartContainerProps {
229
197
  Cypress.Commands.add(
230
198
  'startContainer',
231
199
  ({ name, image, portBindings }: StartContainerProps): Cypress.Chainable => {
232
- return cy.task('startContainer', { image, name, portBindings });
200
+ return cy
201
+ .exec(`docker image inspect ${image} || docker pull ${image}`)
202
+ .task('startContainer', { image, name, portBindings });
233
203
  }
234
204
  );
235
205
 
@@ -244,7 +214,7 @@ Cypress.Commands.add(
244
214
  'startWebContainer',
245
215
  ({
246
216
  name = Cypress.env('dockerName'),
247
- os = Cypress.env('WEB_IMAGE_OS'),
217
+ os = 'alma9',
248
218
  useSlim = true,
249
219
  version = Cypress.env('WEB_IMAGE_VERSION')
250
220
  }: StartWebContainerProps = {}): Cypress.Chainable => {
@@ -259,13 +229,12 @@ Cypress.Commands.add(
259
229
  portBindings: [{ destination: 4000, source: 80 }]
260
230
  })
261
231
  .then(() => {
262
- const baseUrl = 'http://127.0.0.1:4000';
232
+ const baseUrl = 'http://0.0.0.0:4000';
263
233
 
264
234
  Cypress.config('baseUrl', baseUrl);
265
235
 
266
- return cy.task(
267
- 'waitOn',
268
- `${baseUrl}/centreon/api/latest/platform/installation/status`
236
+ return cy.exec(
237
+ `npx wait-on ${baseUrl}/centreon/api/latest/platform/installation/status`
269
238
  );
270
239
  })
271
240
  .visit('/') // this is necessary to refresh browser cause baseUrl has changed (flash appears in video)
@@ -295,38 +264,22 @@ Cypress.Commands.add(
295
264
  .exec(`mkdir -p "${logDirectory}"`)
296
265
  .copyFromContainer({
297
266
  destination: `${logDirectory}/broker`,
298
- name,
299
267
  source: '/var/log/centreon-broker'
300
268
  })
301
269
  .copyFromContainer({
302
270
  destination: `${logDirectory}/engine`,
303
- name,
304
271
  source: '/var/log/centreon-engine'
305
272
  })
273
+ .execInContainer({
274
+ command: `bash -e <<EOF
275
+ chmod 777 /var/log/centreon/centreon-web.log > /dev/null 2>&1 || :
276
+ EOF`,
277
+ name
278
+ })
306
279
  .copyFromContainer({
307
280
  destination: `${logDirectory}/centreon`,
308
- name,
309
281
  source: '/var/log/centreon'
310
282
  })
311
- .then(() => {
312
- if (Cypress.env('WEB_IMAGE_OS').includes('alma')) {
313
- return cy.copyFromContainer({
314
- destination: `${logDirectory}/php`,
315
- name,
316
- source: '/var/log/php-fpm'
317
- });
318
- }
319
-
320
- return cy.copyFromContainer(
321
- {
322
- destination: `${logDirectory}/php8.1-fpm-centreon-error.log`,
323
- name,
324
- source: '/var/log/php8.1-fpm-centreon-error.log'
325
- },
326
- { failOnNonZeroExit: false }
327
- );
328
- })
329
- .exec(`chmod -R 755 "${logDirectory}"`)
330
283
  .stopContainer({ name });
331
284
  }
332
285
  );
@@ -355,127 +308,21 @@ Cypress.Commands.add(
355
308
  }
356
309
  );
357
310
 
358
- interface Dashboard {
359
- description?: string;
360
- name: string;
361
- }
362
-
363
- Cypress.Commands.add(
364
- 'insertDashboardList',
365
- (fixtureFile: string): Cypress.Chainable => {
366
- return cy.fixture(fixtureFile).then((dashboardList) => {
367
- cy.wrap(
368
- Promise.all(
369
- dashboardList.map((dashboardBody: Dashboard) =>
370
- cy.insertDashboard({ ...dashboardBody })
371
- )
372
- )
373
- );
374
- });
375
- }
376
- );
377
-
378
- Cypress.Commands.add(
379
- 'insertDashboard',
380
- (dashboardBody: Dashboard): Cypress.Chainable => {
381
- return cy.request({
382
- body: {
383
- ...dashboardBody
384
- },
385
- method: 'POST',
386
- url: '/centreon/api/latest/configuration/dashboards'
387
- });
388
- }
389
- );
390
-
391
- interface ShareDashboardToUserProps {
392
- dashboardName: string;
393
- role: string;
394
- userName: string;
395
- }
396
-
397
- interface ListingRequestResult {
398
- body: {
399
- result: Array<{
400
- id: number;
401
- }>;
402
- };
403
- }
404
-
405
- Cypress.Commands.add(
406
- 'shareDashboardToUser',
407
- ({ dashboardName, userName, role }: ShareDashboardToUserProps): void => {
408
- Promise.all([
409
- cy.request({
410
- method: 'GET',
411
- url: `/centreon/api/latest/configuration/users?search={"name":"${userName}"}`
412
- }),
413
- cy.request({
414
- method: 'GET',
415
- url: `/centreon/api/latest/configuration/dashboards?search={"name":"${dashboardName}"}`
416
- })
417
- ]).then(
418
- ([retrievedUser, retrievedDashboard]: [
419
- ListingRequestResult,
420
- ListingRequestResult
421
- ]) => {
422
- const userId = retrievedUser.body.result[0].id;
423
- const dashboardId = retrievedDashboard.body.result[0].id;
424
-
425
- cy.request({
426
- body: {
427
- id: userId,
428
- role: `${role}`
429
- },
430
- method: 'POST',
431
- url: `/centreon/api/latest/configuration/dashboards/${dashboardId}/access_rights/contacts`
432
- });
433
- }
434
- );
435
- }
436
- );
437
-
438
- Cypress.Commands.add('getTimeFromHeader', (): Cypress.Chainable => {
439
- return cy
440
- .get('header div[data-cy="clock"]', { timeout: 10000 })
441
- .should('be.visible')
442
- .then(($time) => {
443
- const headerTime = $time.children()[1].textContent;
444
- if (headerTime?.match(/\d+:\d+/)) {
445
- cy.log(`header time is : ${headerTime}`);
446
-
447
- return cy.wrap(headerTime);
448
- }
449
-
450
- throw new Error(`header time is not displayed`);
451
- });
452
- });
453
-
454
311
  declare global {
455
312
  namespace Cypress {
456
313
  interface Chainable {
457
- clickSubRootMenuItem: (page: string) => Cypress.Chainable;
458
- copyFromContainer: (
459
- props: CopyFromContainerProps,
460
- options?: Partial<Cypress.ExecOptions>
461
- ) => Cypress.Chainable;
462
- copyToContainer: (
463
- props: CopyToContainerProps,
464
- options?: Partial<Cypress.ExecOptions>
465
- ) => Cypress.Chainable;
314
+ copyFromContainer: (props: CopyFromContainerProps) => Cypress.Chainable;
315
+ copyToContainer: (props: CopyToContainerProps) => Cypress.Chainable;
466
316
  execInContainer: ({
467
317
  command,
468
318
  name
469
319
  }: ExecInContainerProps) => Cypress.Chainable;
470
320
  getIframeBody: () => Cypress.Chainable;
471
- getTimeFromHeader: () => Cypress.Chainable;
472
321
  getWebVersion: () => Cypress.Chainable;
473
322
  hoverRootMenuItem: (rootItemNumber: number) => Cypress.Chainable;
474
- insertDashboard: (dashboard: Dashboard) => Cypress.Chainable;
475
- insertDashboardList: (fixtureFile: string) => Cypress.Chainable;
476
323
  loginByTypeOfUser: ({
477
- jsonName,
478
- loginViaApi
324
+ jsonName = 'admin',
325
+ loginViaApi = false
479
326
  }: LoginByTypeOfUserProps) => Cypress.Chainable;
480
327
  moveSortableElement: (direction: string) => Cypress.Chainable;
481
328
  navigateTo: ({
@@ -483,11 +330,6 @@ declare global {
483
330
  rootItemNumber,
484
331
  subMenu
485
332
  }: NavigateToProps) => Cypress.Chainable;
486
- shareDashboardToUser: ({
487
- dashboardName,
488
- userName,
489
- role
490
- }: ShareDashboardToUserProps) => Cypress.Chainable;
491
333
  startContainer: ({
492
334
  name,
493
335
  image
@@ -4,11 +4,8 @@
4
4
  import { execSync } from 'child_process';
5
5
 
6
6
  import { defineConfig } from 'cypress';
7
- import installLogsPrinter from 'cypress-terminal-report/src/installLogsPrinter';
8
7
 
9
- import esbuildPreprocessor from './esbuild-preprocessor';
10
- import plugins from './plugins';
11
- import tasks from './tasks';
8
+ import setupNodeEvents from './plugins';
12
9
 
13
10
  interface ConfigurationOptions {
14
11
  cypressFolder?: string;
@@ -25,7 +22,9 @@ export default ({
25
22
  dockerName,
26
23
  env
27
24
  }: ConfigurationOptions): Cypress.ConfigOptions => {
28
- const resultsFolder = `${cypressFolder || 'cypress'}/results`;
25
+ const resultsFolder = `${cypressFolder || 'cypress'}/results${
26
+ isDevelopment ? '/dev' : ''
27
+ }`;
29
28
 
30
29
  const webImageVersion = execSync('git rev-parse --abbrev-ref HEAD')
31
30
  .toString('utf8')
@@ -36,17 +35,7 @@ export default ({
36
35
  defaultCommandTimeout: 6000,
37
36
  e2e: {
38
37
  excludeSpecPattern: ['*.js', '*.ts', '*.md'],
39
- reporter: require.resolve('cypress-multi-reporters'),
40
- reporterOptions: {
41
- configFile: `${__dirname}/reporter-config.js`
42
- },
43
- setupNodeEvents: async (on, config) => {
44
- installLogsPrinter(on);
45
- await esbuildPreprocessor(on, config);
46
- tasks(on);
47
-
48
- return plugins(on, config);
49
- },
38
+ setupNodeEvents,
50
39
  specPattern
51
40
  },
52
41
  env: {
@@ -56,12 +45,34 @@ export default ({
56
45
  WEB_IMAGE_VERSION: webImageVersion,
57
46
  dockerName: dockerName || 'centreon-dev'
58
47
  },
59
- execTimeout: 60000,
48
+ execTimeout: 120000,
49
+ reporter: 'mochawesome',
50
+ reporterOptions: {
51
+ html: false,
52
+ json: true,
53
+ overwrite: true,
54
+ reportDir: `${resultsFolder}/reports`,
55
+ reportFilename: '[name]-report.json'
56
+ },
60
57
  requestTimeout: 10000,
61
58
  retries: 0,
62
59
  screenshotsFolder: `${resultsFolder}/screenshots`,
60
+ setupNodeEvents: (on, config) => {
61
+ on('before:browser:launch', (browser, launchOptions) => {
62
+ if (browser.name === 'chrome' && browser.isHeadless) {
63
+ launchOptions.args = launchOptions.args.map((arg) => {
64
+ if (arg === '--headless') {
65
+ return '--headless=new';
66
+ }
67
+
68
+ return arg;
69
+ });
70
+ }
71
+
72
+ return launchOptions;
73
+ });
74
+ },
63
75
  video: true,
64
- videoCompression: 0,
65
76
  videosFolder: `${resultsFolder}/videos`
66
77
  });
67
78
  };
@@ -3,34 +3,132 @@
3
3
  /* eslint-disable @typescript-eslint/no-var-requires */
4
4
  /* eslint-disable no-param-reassign */
5
5
 
6
- export default (
7
- on: Cypress.PluginEvents,
8
- config: Cypress.PluginConfigOptions
9
- ): Cypress.PluginConfigOptions => {
10
- on('before:browser:launch', (browser, launchOptions) => {
11
- const width = 1920;
12
- const height = 1080;
13
-
14
- if (browser.name === 'chrome') {
15
- if (browser.isHeadless) {
16
- launchOptions.args.push('--headless=new');
17
- }
6
+ import Docker from 'dockerode';
7
+ import { addCucumberPreprocessorPlugin } from '@badeball/cypress-cucumber-preprocessor';
8
+ import webpackPreprocessor from '@cypress/webpack-preprocessor';
18
9
 
19
- // flags description : https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md
20
- launchOptions.args.push('--disable-gpu');
21
- launchOptions.args.push('--auto-open-devtools-for-tabs');
22
- launchOptions.args.push('--disable-extensions');
23
- launchOptions.args.push('--hide-scrollbars');
24
- launchOptions.args.push('--mute-audio');
10
+ const docker = new Docker();
11
+
12
+ const getWebpackOptions = (config): object => {
13
+ return {
14
+ module: {
15
+ rules: [
16
+ {
17
+ exclude: [/node_modules/],
18
+ test: /\.ts?$/,
19
+ use: [
20
+ {
21
+ loader: 'swc-loader'
22
+ }
23
+ ]
24
+ },
25
+ {
26
+ test: /\.feature$/,
27
+ use: [
28
+ {
29
+ loader: '@badeball/cypress-cucumber-preprocessor/webpack',
30
+ options: config
31
+ }
32
+ ]
33
+ }
34
+ ]
35
+ },
36
+ resolve: {
37
+ extensions: ['.ts', '.js']
38
+ }
39
+ };
40
+ };
41
+
42
+ export default async (on, config): Promise<void> => {
43
+ await addCucumberPreprocessorPlugin(on, config);
25
44
 
26
- launchOptions.args.push(`--window-size=${width},${height}`);
45
+ const webpackOptions = await getWebpackOptions(config);
46
+ const options = {
47
+ webpackOptions
48
+ };
27
49
 
28
- // force screen to be non-retina and just use our given resolution
29
- launchOptions.args.push('--force-device-scale-factor=1');
50
+ on('file:preprocessor', webpackPreprocessor(options));
51
+
52
+ on('before:browser:launch', (browser = {}, launchOptions) => {
53
+ if ((browser as { name }).name === 'chrome') {
54
+ launchOptions.args.push('--disable-gpu');
55
+ launchOptions.args = launchOptions.args.filter(
56
+ (element) => element !== '--disable-dev-shm-usage'
57
+ );
30
58
  }
31
59
 
32
60
  return launchOptions;
33
61
  });
34
62
 
63
+ interface PortBinding {
64
+ destination: number;
65
+ source: number;
66
+ }
67
+
68
+ interface StartContainerProps {
69
+ image: string;
70
+ name: string;
71
+ portBindings: Array<PortBinding>;
72
+ }
73
+
74
+ interface StopContainerProps {
75
+ name: string;
76
+ }
77
+
78
+ on('task', {
79
+ startContainer: async ({
80
+ image,
81
+ name,
82
+ portBindings = []
83
+ }: StartContainerProps) => {
84
+ const webContainers = await docker.listContainers({
85
+ all: true,
86
+ filters: { name: [name] }
87
+ });
88
+ if (webContainers.length) {
89
+ return webContainers[0];
90
+ }
91
+
92
+ const container = await docker.createContainer({
93
+ AttachStderr: true,
94
+ AttachStdin: false,
95
+ AttachStdout: true,
96
+ ExposedPorts: portBindings.reduce((accumulator, currentValue) => {
97
+ accumulator[`${currentValue.source}/tcp`] = {};
98
+
99
+ return accumulator;
100
+ }, {}),
101
+ HostConfig: {
102
+ PortBindings: portBindings.reduce((accumulator, currentValue) => {
103
+ accumulator[`${currentValue.source}/tcp`] = [
104
+ {
105
+ HostIP: '0.0.0.0',
106
+ HostPort: `${currentValue.destination}`
107
+ }
108
+ ];
109
+
110
+ return accumulator;
111
+ }, {})
112
+ },
113
+ Image: image,
114
+ OpenStdin: false,
115
+ StdinOnce: false,
116
+ Tty: true,
117
+ name
118
+ });
119
+
120
+ await container.start();
121
+
122
+ return container;
123
+ },
124
+ stopContainer: async ({ name }: StopContainerProps) => {
125
+ const container = await docker.getContainer(name);
126
+ await container.kill();
127
+ await container.remove();
128
+
129
+ return null;
130
+ }
131
+ });
132
+
35
133
  return config;
36
134
  };
@@ -21,15 +21,11 @@ module.exports = {
21
21
  }
22
22
  ],
23
23
  '@typescript-eslint/camelcase': 'off',
24
- '@typescript-eslint/consistent-type-definitions': ['off', 'interface'],
25
- '@typescript-eslint/explicit-function-return-type': [
24
+ '@typescript-eslint/consistent-type-definitions': [
26
25
  'error',
27
- {
28
- allowExpressions: true,
29
- allowHigherOrderFunctions: true,
30
- allowTypedFunctionExpressions: true
31
- }
26
+ 'interface'
32
27
  ],
28
+ '@typescript-eslint/explicit-function-return-type': ['error'],
33
29
  '@typescript-eslint/explicit-member-accessibility': [
34
30
  'error',
35
31
  {
@@ -80,21 +76,13 @@ module.exports = {
80
76
  }
81
77
  ],
82
78
  camelcase: 'off',
83
- 'import/no-cycle': 'off',
84
- 'import/no-named-as-default': 'warn',
85
79
  'no-shadow': 'off',
86
80
  'no-unused-expressions': 'off'
87
81
  },
88
82
  settings: {
89
- 'import/parsers': {
90
- '@typescript-eslint/parser': ['.ts', '.tsx']
91
- },
92
83
  'import/resolver': {
93
84
  alias: {
94
85
  extensions: ['.ts', '.tsx', '.js', '.jsx']
95
- },
96
- typescript: {
97
- alwaysTryTypes: true
98
86
  }
99
87
  }
100
88
  }
package/jest/index.js CHANGED
@@ -1,16 +1,12 @@
1
1
  module.exports = {
2
2
  moduleNameMapper: {
3
3
  '\\.(s?css|png|svg|jpg)$': 'identity-obj-proxy',
4
- '^.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$':
5
- 'jest-transform-stub',
6
4
  '^react($|/.+)': '<rootDir>/node_modules/react$1'
7
5
  },
8
6
  setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],
9
7
  testEnvironment: 'jsdom',
10
- testPathIgnorePatterns: ['/node_modules/', '!*.cypress.spec.tsx'],
8
+ testPathIgnorePatterns: ['/node_modules/'],
11
9
  transform: {
12
- '.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$':
13
- 'jest-transform-stub',
14
10
  '^.+\\.[jt]sx?$': [
15
11
  '@swc/jest',
16
12
  {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@centreon/js-config",
3
3
  "description": "Centreon Frontend shared build configuration",
4
- "version": "23.10.34",
4
+ "version": "23.10.36",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/centreon/centreon-frontend.git"
@@ -16,12 +16,13 @@
16
16
  "url": "https://github.com/centreon/centreon-frontend/issues"
17
17
  },
18
18
  "devDependencies": {
19
- "@tsconfig/node16": "^16.1.1",
19
+ "@badeball/cypress-cucumber-preprocessor": "^14.0.0",
20
+ "@types/dockerode": "^3.3.16",
21
+ "dockerode": "^3.3.5",
20
22
  "eslint": "^8.17.0",
21
23
  "eslint-config-airbnb": "19.0.4",
22
24
  "eslint-config-prettier": "^8.5.0",
23
25
  "eslint-import-resolver-alias": "^1.1.2",
24
- "eslint-import-resolver-typescript": "^3.5.5",
25
26
  "eslint-plugin-babel": "^5.3.1",
26
27
  "eslint-plugin-hooks": "^0.4.3",
27
28
  "eslint-plugin-import": "^2.26.0",
@@ -42,18 +43,5 @@
42
43
  "tsconfig",
43
44
  "webpack",
44
45
  "cypress"
45
- ],
46
- "dependencies": {
47
- "@badeball/cypress-cucumber-preprocessor": "^18.0.6",
48
- "@bahmutov/cypress-esbuild-preprocessor": "^2.2.0",
49
- "@esbuild-plugins/node-globals-polyfill": "^0.2.3",
50
- "@esbuild-plugins/node-modules-polyfill": "^0.2.2",
51
- "@types/cypress-cucumber-preprocessor": "^4.0.2",
52
- "@types/dockerode": "^3.3.19",
53
- "cypress-multi-reporters": "^1.6.3",
54
- "cypress-terminal-report": "^5.3.6",
55
- "dockerode": "^3.3.5",
56
- "esbuild": "^0.19.3",
57
- "mochawesome": "^7.1.3"
58
- }
46
+ ]
59
47
  }
@@ -1,14 +1,13 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "downlevelIteration": true,
4
- "module": "ESNext",
5
3
  "moduleResolution": "node",
6
- "target": "es2018",
4
+ "downlevelIteration": true,
5
+ "module": "es6",
6
+ "target": "es6",
7
7
  "jsx": "react-jsx",
8
8
  "strict": true,
9
9
  "noImplicitAny": false,
10
10
  "skipLibCheck": true,
11
- "esModuleInterop": true,
12
- "resolveJsonModule": true
11
+ "esModuleInterop": true
13
12
  }
14
13
  }
@@ -3,22 +3,68 @@ const path = require('path');
3
3
  const { CleanWebpackPlugin } = require('clean-webpack-plugin');
4
4
  const { ModuleFederationPlugin } = require('webpack').container;
5
5
 
6
- const {
7
- getModuleConfiguration,
8
- optimization,
9
- output,
10
- cache
11
- } = require('./globalConfig');
6
+ const excludeNodeModulesExceptCentreonUi =
7
+ /node_modules(\\|\/)\.pnpm(\\|\/)(?!(@centreon))/;
12
8
 
13
9
  const getBaseConfiguration = ({
14
10
  moduleName,
15
11
  moduleFederationConfig,
16
12
  jscTransformConfiguration
17
13
  }) => ({
18
- cache,
19
- module: getModuleConfiguration(jscTransformConfiguration),
20
- optimization,
21
- output,
14
+ cache: false,
15
+ module: {
16
+ rules: [
17
+ {
18
+ parser: { system: false },
19
+ test: /\.[cm]?(j|t)sx?$/
20
+ },
21
+ {
22
+ exclude: excludeNodeModulesExceptCentreonUi,
23
+ test: /\.[jt]sx?$/,
24
+ use: {
25
+ loader: 'swc-loader',
26
+ options: {
27
+ jsc: {
28
+ parser: {
29
+ syntax: 'typescript',
30
+ tsx: true
31
+ },
32
+ transform: jscTransformConfiguration
33
+ }
34
+ }
35
+ }
36
+ },
37
+ {
38
+ test: /\.icon.svg$/,
39
+ use: ['@svgr/webpack']
40
+ },
41
+ {
42
+ exclude: excludeNodeModulesExceptCentreonUi,
43
+ test: /\.(bmp|png|jpg|jpeg|gif|svg)$/,
44
+ use: [
45
+ {
46
+ loader: 'url-loader',
47
+ options: {
48
+ limit: 10000,
49
+ name: '[name].[hash:8].[ext]'
50
+ }
51
+ }
52
+ ]
53
+ }
54
+ ]
55
+ },
56
+ optimization: {
57
+ splitChunks: {
58
+ chunks: 'all',
59
+ maxSize: 400 * 1024
60
+ }
61
+ },
62
+ output: {
63
+ chunkFilename: '[name].[chunkhash:8].chunk.js',
64
+ filename: '[name].[chunkhash:8].js',
65
+ libraryTarget: 'umd',
66
+ umdNamedDefine: true
67
+ },
22
68
  plugins: [
23
69
  new CleanWebpackPlugin(),
24
70
  moduleName &&
@@ -75,10 +121,7 @@ const getBaseConfiguration = ({
75
121
  ].filter(Boolean),
76
122
  resolve: {
77
123
  alias: {
78
- react: path.resolve('./node_modules/react'),
79
- '@centreon/ui/fonts': path.resolve(
80
- './node_modules/@centreon/ui/public/fonts'
81
- )
124
+ react: path.resolve('./node_modules/react')
82
125
  },
83
126
  extensions: ['.js', '.jsx', '.ts', '.tsx']
84
127
  }
@@ -1,75 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-namespace */
2
-
3
- const apiBase = '/centreon/api';
4
- const apiActionV1 = `${apiBase}/index.php`;
5
-
6
- const getStatusNumberFromString = (status: string): number => {
7
- const statuses = {
8
- critical: '2',
9
- down: '1',
10
- ok: '0',
11
- unknown: '3',
12
- unreachable: '2',
13
- up: '0',
14
- warning: '1'
15
- };
16
-
17
- if (status in statuses) {
18
- return statuses[status];
19
- }
20
-
21
- throw new Error(`Status ${status} does not exist`);
22
- };
23
-
24
- interface SubmitResult {
25
- host: string;
26
- output: string;
27
- perfdata?: string | null;
28
- service?: string | null;
29
- status: string;
30
- }
31
-
32
- Cypress.Commands.add(
33
- 'submitResults',
34
- (results: Array<SubmitResult>): Cypress.Chainable => {
35
- results.forEach(
36
- ({ host, output, perfdata = '', service = null, status }) => {
37
- const timestampNow = Math.floor(Date.now() / 1000) - 15;
38
- const updatetime = timestampNow.toString();
39
-
40
- const result = {
41
- host,
42
- output,
43
- perfdata,
44
- service,
45
- status: getStatusNumberFromString(status),
46
- updatetime
47
- };
48
-
49
- cy.request({
50
- body: {
51
- results: [result]
52
- },
53
- headers: {
54
- 'Content-Type': 'application/json',
55
- 'centreon-auth-token': window.localStorage.getItem('userTokenApiV1')
56
- },
57
- method: 'POST',
58
- url: `${apiActionV1}?action=submit&object=centreon_submit_results`
59
- });
60
- }
61
- );
62
-
63
- return cy.wrap(null);
64
- }
65
- );
66
-
67
- declare global {
68
- namespace Cypress {
69
- interface Chainable {
70
- submitResults: (props: Array<SubmitResult>) => Cypress.Chainable;
71
- }
72
- }
73
- }
74
-
75
- export {};
@@ -1,26 +0,0 @@
1
- import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill';
2
- import { NodeModulesPolyfillPlugin } from '@esbuild-plugins/node-modules-polyfill';
3
- import { addCucumberPreprocessorPlugin } from '@badeball/cypress-cucumber-preprocessor';
4
- import createBundler from '@bahmutov/cypress-esbuild-preprocessor';
5
- import createEsbuildPlugin from '@badeball/cypress-cucumber-preprocessor/esbuild';
6
-
7
- export default async (
8
- on: Cypress.PluginEvents,
9
- config: Cypress.PluginConfigOptions
10
- ): Promise<void> => {
11
- await addCucumberPreprocessorPlugin(on, config);
12
-
13
- on(
14
- 'file:preprocessor',
15
- createBundler({
16
- plugins: [
17
- createEsbuildPlugin(config),
18
- NodeModulesPolyfillPlugin(),
19
- NodeGlobalsPolyfillPlugin({
20
- buffer: true,
21
- process: true
22
- })
23
- ]
24
- })
25
- );
26
- };
@@ -1,13 +0,0 @@
1
- module.exports = {
2
- mochawesomeReporterOptions: {
3
- consoleReporter: 'none',
4
- html: false,
5
- json: true,
6
- overwrite: true,
7
- reportDir: 'cypress/results/reports',
8
- reportFilename: '[name]-report.json'
9
- },
10
- reporterEnabled: `mochawesome,${require.resolve(
11
- '@badeball/cypress-cucumber-preprocessor/pretty-reporter'
12
- )}`
13
- };
@@ -1,97 +0,0 @@
1
- import { execSync } from 'child_process';
2
-
3
- import Docker from 'dockerode';
4
-
5
- export default (on: Cypress.PluginEvents): void => {
6
- const docker = new Docker();
7
-
8
- interface PortBinding {
9
- destination: number;
10
- source: number;
11
- }
12
-
13
- interface StartContainerProps {
14
- image: string;
15
- name: string;
16
- portBindings: Array<PortBinding>;
17
- }
18
-
19
- interface StopContainerProps {
20
- name: string;
21
- }
22
-
23
- on('task', {
24
- startContainer: async ({
25
- image,
26
- name,
27
- portBindings = []
28
- }: StartContainerProps) => {
29
- const imageList = execSync(
30
- 'docker image list --format "{{.Repository}}:{{.Tag}}"'
31
- ).toString('utf8');
32
-
33
- if (
34
- !imageList.match(
35
- new RegExp(
36
- `^${image.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}`,
37
- 'm'
38
- )
39
- )
40
- ) {
41
- execSync(`docker pull ${image}`);
42
- }
43
-
44
- const webContainers = await docker.listContainers({
45
- all: true,
46
- filters: { name: [name] }
47
- });
48
- if (webContainers.length) {
49
- return webContainers[0];
50
- }
51
-
52
- const container = await docker.createContainer({
53
- AttachStderr: true,
54
- AttachStdin: false,
55
- AttachStdout: true,
56
- ExposedPorts: portBindings.reduce((accumulator, currentValue) => {
57
- accumulator[`${currentValue.source}/tcp`] = {};
58
-
59
- return accumulator;
60
- }, {}),
61
- HostConfig: {
62
- PortBindings: portBindings.reduce((accumulator, currentValue) => {
63
- accumulator[`${currentValue.source}/tcp`] = [
64
- {
65
- HostIP: '127.0.0.1',
66
- HostPort: `${currentValue.destination}`
67
- }
68
- ];
69
-
70
- return accumulator;
71
- }, {})
72
- },
73
- Image: image,
74
- OpenStdin: false,
75
- StdinOnce: false,
76
- Tty: true,
77
- name
78
- });
79
-
80
- await container.start();
81
-
82
- return container;
83
- },
84
- stopContainer: async ({ name }: StopContainerProps) => {
85
- const container = await docker.getContainer(name);
86
- await container.kill();
87
- await container.remove();
88
-
89
- return null;
90
- },
91
- waitOn: async (url: string) => {
92
- execSync(`npx wait-on ${url}`);
93
-
94
- return null;
95
- }
96
- });
97
- };
@@ -1,48 +0,0 @@
1
- module.exports = {
2
- extends: [ '../node/typescript.eslintrc.js'],
3
- overrides: [
4
- {
5
- files: ["*.spec.js", "*.test.ts", "*.tests.ts"],
6
- rules: {
7
- "import/first": 0,
8
- "import/order": 0,
9
- "@typescript-eslint/ban-ts-comment": 0,
10
- "@typescript-eslint/no-explicit-any": 0
11
- }
12
- }
13
- ],
14
- rules: {
15
- "import/extensions": ["off"],
16
- "no-console": "off",
17
- "no-underscore-dangle": "off",
18
- "class-methods-use-this": "off",
19
- "@typescript-eslint/naming-convention": [
20
- "error",
21
- {
22
- format: ["camelCase", "PascalCase", "UPPER_CASE"],
23
- selector: "variable"
24
- },
25
- {
26
- filter: {
27
- match: false,
28
- regex: "(__esModule|.+-.+)"
29
- },
30
- format: ["snake_case", "camelCase", "PascalCase", "UPPER_CASE"],
31
- selector: "property",
32
- leadingUnderscore: "allow"
33
- },
34
- {
35
- filter: {
36
- match: false,
37
- regex: "^_$"
38
- },
39
- format: ["snake_case", "camelCase", "PascalCase"],
40
- selector: "parameter"
41
- }
42
- ],
43
- "@typescript-eslint/require-array-sort-compare": "error"
44
- },
45
- parserOptions: {
46
- project: ["./tsconfig.json"]
47
- }
48
- }
@@ -1,49 +0,0 @@
1
- /*
2
- * Copyright 2023 Centreon Team
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
-
17
- // For a detailed explanation regarding each configuration property, visit:
18
- // https://jestjs.io/docs/en/configuration.html
19
- const path = require('path');
20
-
21
- const rootPath = path.join(__dirname);
22
-
23
-
24
-
25
- module.exports = {
26
- rootDir: rootPath,
27
- // Automatically clear mock calls and instances between every test
28
- clearMocks: true,
29
- // The directory where Jest should output its coverage files
30
- coverageDirectory: '<rootDir>/coverage',
31
- // An array of regexp pattern strings used to skip coverage collection
32
- coveragePathIgnorePatterns: ['\\\\node_modules\\\\', 'tests'],
33
-
34
- // An array of file extensions your modules use
35
- moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
36
-
37
- // Automatically reset mock state between every test
38
- // resetMocks: true,
39
-
40
- testMatch: ['**/*.(test|tests|spec|specs).+(ts|tsx|js)'],
41
-
42
- // This option allows the use of a custom results processor
43
- // testResultsProcessor: 'jest-sonar-reporter',
44
-
45
- // A map from regular expressions to paths to transformers
46
- transform: {
47
- '^.+\\.(ts|tsx)$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.json' }],
48
- },
49
- };
@@ -1,14 +0,0 @@
1
- {
2
- "extends": "@tsconfig/node16/tsconfig.json",
3
- "compilerOptions": {
4
- "sourceMap": true,
5
- "allowJs": true,
6
- "strictNullChecks": false,
7
- "declaration": false,
8
- "esModuleInterop": true,
9
- "types": [
10
- "@types/jest",
11
- "node"
12
- ]
13
- }
14
- }
@@ -1,71 +0,0 @@
1
- const excludeNodeModulesExceptCentreonUi =
2
- /node_modules(\\|\/)\.pnpm(\\|\/)(?!(@centreon))/;
3
-
4
- module.exports = {
5
- cache: false,
6
- excludeNodeModulesExceptCentreonUi,
7
- getModuleConfiguration: (jscTransformConfiguration) => ({
8
- rules: [
9
- {
10
- parser: { system: false },
11
- test: /\.[cm]?(j|t)sx?$/
12
- },
13
- {
14
- exclude: [excludeNodeModulesExceptCentreonUi],
15
- test: /\.[jt]sx?$/,
16
- use: {
17
- loader: 'swc-loader',
18
- options: {
19
- jsc: {
20
- parser: {
21
- syntax: 'typescript',
22
- tsx: true
23
- },
24
- transform: jscTransformConfiguration
25
- }
26
- }
27
- }
28
- },
29
- {
30
- test: /\.icon.svg$/,
31
- use: ['@svgr/webpack']
32
- },
33
- {
34
- exclude: excludeNodeModulesExceptCentreonUi,
35
- test: /\.(bmp|png|jpg|jpeg|gif|svg)$/,
36
- use: [
37
- {
38
- loader: 'url-loader',
39
- options: {
40
- limit: 10000,
41
- name: '[name].[hash:8].[ext]'
42
- }
43
- }
44
- ]
45
- },
46
- {
47
- generator: {
48
- filename: '[name][ext]'
49
- },
50
- test: /\.(woff|woff2|eot|ttf|otf)$/i,
51
- type: 'asset/resource'
52
- },
53
- {
54
- test: /\.css$/i,
55
- use: ['style-loader', 'css-loader']
56
- }
57
- ]
58
- }),
59
- optimization: {
60
- splitChunks: {
61
- chunks: 'all',
62
- maxSize: 400 * 1024
63
- }
64
- },
65
- output: {
66
- chunkFilename: '[name].[chunkhash:8].chunk.js',
67
- filename: '[name].[chunkhash:8].js',
68
- libraryTarget: 'umd',
69
- umdNamedDefine: true
70
- }
71
- };