@centreon/js-config 23.10.30 → 23.10.31

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,24 +4,16 @@ 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
  },
@@ -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,7 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-namespace */
2
2
 
3
3
  import './commands/configuration';
4
- import './commands/monitoring';
5
4
 
6
5
  const apiLoginV2 = '/centreon/authentication/providers/configurations/local';
7
6
 
@@ -24,7 +23,7 @@ Cypress.Commands.add('getWebVersion', (): Cypress.Chainable => {
24
23
 
25
24
  Cypress.Commands.add('getIframeBody', (): Cypress.Chainable => {
26
25
  return cy
27
- .get('iframe#main-content', { timeout: 10000 })
26
+ .get('iframe#main-content')
28
27
  .its('0.contentDocument.body')
29
28
  .should('not.be.empty')
30
29
  .then(cy.wrap);
@@ -40,13 +39,6 @@ Cypress.Commands.add(
40
39
  }
41
40
  );
42
41
 
43
- Cypress.Commands.add(
44
- 'clickSubRootMenuItem',
45
- (page: string): Cypress.Chainable => {
46
- return cy.get('div[data-cy="collapse"]').eq(1).contains(page).click();
47
- }
48
- );
49
-
50
42
  interface NavigateToProps {
51
43
  page: string;
52
44
  rootItemNumber: number;
@@ -59,13 +51,8 @@ Cypress.Commands.add(
59
51
  if (subMenu) {
60
52
  cy.hoverRootMenuItem(rootItemNumber)
61
53
  .contains(subMenu)
62
- .trigger('mouseover')
63
- .get('.MuiCollapse-wrapper')
64
- .find('div[data-cy="collapse"]')
65
- .should('be.visible')
66
- .and('contain', page);
67
-
68
- cy.clickSubRootMenuItem(page);
54
+ .trigger('mouseover', { force: true });
55
+ cy.contains(page).click({ force: true });
69
56
 
70
57
  return;
71
58
  }
@@ -98,41 +85,29 @@ Cypress.Commands.add(
98
85
 
99
86
  interface CopyFromContainerProps {
100
87
  destination: string;
101
- name?: string;
102
88
  source: string;
103
89
  }
104
90
 
105
91
  Cypress.Commands.add(
106
92
  'copyFromContainer',
107
- (
108
- {
109
- name = Cypress.env('dockerName'),
110
- source,
111
- destination
112
- }: CopyFromContainerProps,
113
- options?: Partial<Cypress.ExecOptions>
114
- ) => {
115
- 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
+ );
116
97
  }
117
98
  );
118
99
 
119
100
  interface CopyToContainerProps {
120
101
  destination: string;
121
- name?: string;
122
102
  source: string;
123
103
  }
124
104
 
125
105
  Cypress.Commands.add(
126
106
  'copyToContainer',
127
- (
128
- {
129
- name = Cypress.env('dockerName'),
130
- source,
131
- destination
132
- }: CopyToContainerProps,
133
- options?: Partial<Cypress.ExecOptions>
134
- ) => {
135
- 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
+ );
136
111
  }
137
112
  );
138
113
 
@@ -143,7 +118,7 @@ interface LoginByTypeOfUserProps {
143
118
 
144
119
  Cypress.Commands.add(
145
120
  'loginByTypeOfUser',
146
- ({ jsonName = 'admin', loginViaApi = false }): Cypress.Chainable => {
121
+ ({ jsonName, loginViaApi }): Cypress.Chainable => {
147
122
  if (loginViaApi) {
148
123
  return cy
149
124
  .fixture(`users/${jsonName}.json`)
@@ -160,15 +135,12 @@ Cypress.Commands.add(
160
135
  .visit(`${Cypress.config().baseUrl}`)
161
136
  .wait('@getNavigationList');
162
137
  }
163
-
164
138
  cy.visit(`${Cypress.config().baseUrl}`)
165
139
  .fixture(`users/${jsonName}.json`)
166
140
  .then((credential) => {
167
- cy.getByLabel({ label: 'Alias', tag: 'input' }).type(
168
- `{selectAll}{backspace}${credential.login}`
169
- );
141
+ cy.getByLabel({ label: 'Alias', tag: 'input' }).type(credential.login);
170
142
  cy.getByLabel({ label: 'Password', tag: 'input' }).type(
171
- `{selectAll}{backspace}${credential.password}`
143
+ credential.password
172
144
  );
173
145
  })
174
146
  .getByLabel({ label: 'Connect', tag: 'button' })
@@ -225,7 +197,9 @@ interface StartContainerProps {
225
197
  Cypress.Commands.add(
226
198
  'startContainer',
227
199
  ({ name, image, portBindings }: StartContainerProps): Cypress.Chainable => {
228
- 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 });
229
203
  }
230
204
  );
231
205
 
@@ -240,7 +214,7 @@ Cypress.Commands.add(
240
214
  'startWebContainer',
241
215
  ({
242
216
  name = Cypress.env('dockerName'),
243
- os = Cypress.env('WEB_IMAGE_OS'),
217
+ os = 'alma9',
244
218
  useSlim = true,
245
219
  version = Cypress.env('WEB_IMAGE_VERSION')
246
220
  }: StartWebContainerProps = {}): Cypress.Chainable => {
@@ -255,13 +229,12 @@ Cypress.Commands.add(
255
229
  portBindings: [{ destination: 4000, source: 80 }]
256
230
  })
257
231
  .then(() => {
258
- const baseUrl = 'http://127.0.0.1:4000';
232
+ const baseUrl = 'http://0.0.0.0:4000';
259
233
 
260
234
  Cypress.config('baseUrl', baseUrl);
261
235
 
262
- return cy.task(
263
- 'waitOn',
264
- `${baseUrl}/centreon/api/latest/platform/installation/status`
236
+ return cy.exec(
237
+ `npx wait-on ${baseUrl}/centreon/api/latest/platform/installation/status`
265
238
  );
266
239
  })
267
240
  .visit('/') // this is necessary to refresh browser cause baseUrl has changed (flash appears in video)
@@ -291,38 +264,22 @@ Cypress.Commands.add(
291
264
  .exec(`mkdir -p "${logDirectory}"`)
292
265
  .copyFromContainer({
293
266
  destination: `${logDirectory}/broker`,
294
- name,
295
267
  source: '/var/log/centreon-broker'
296
268
  })
297
269
  .copyFromContainer({
298
270
  destination: `${logDirectory}/engine`,
299
- name,
300
271
  source: '/var/log/centreon-engine'
301
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
+ })
302
279
  .copyFromContainer({
303
280
  destination: `${logDirectory}/centreon`,
304
- name,
305
281
  source: '/var/log/centreon'
306
282
  })
307
- .then(() => {
308
- if (Cypress.env('WEB_IMAGE_OS').includes('alma')) {
309
- return cy.copyFromContainer({
310
- destination: `${logDirectory}/php`,
311
- name,
312
- source: '/var/log/php-fpm'
313
- });
314
- }
315
-
316
- return cy.copyFromContainer(
317
- {
318
- destination: `${logDirectory}/php8.1-fpm-centreon-error.log`,
319
- name,
320
- source: '/var/log/php8.1-fpm-centreon-error.log'
321
- },
322
- { failOnNonZeroExit: false }
323
- );
324
- })
325
- .exec(`chmod -R 755 "${logDirectory}"`)
326
283
  .stopContainer({ name });
327
284
  }
328
285
  );
@@ -351,127 +308,21 @@ Cypress.Commands.add(
351
308
  }
352
309
  );
353
310
 
354
- interface Dashboard {
355
- description?: string;
356
- name: string;
357
- }
358
-
359
- Cypress.Commands.add(
360
- 'insertDashboardList',
361
- (fixtureFile: string): Cypress.Chainable => {
362
- return cy.fixture(fixtureFile).then((dashboardList) => {
363
- cy.wrap(
364
- Promise.all(
365
- dashboardList.map((dashboardBody: Dashboard) =>
366
- cy.insertDashboard({ ...dashboardBody })
367
- )
368
- )
369
- );
370
- });
371
- }
372
- );
373
-
374
- Cypress.Commands.add(
375
- 'insertDashboard',
376
- (dashboardBody: Dashboard): Cypress.Chainable => {
377
- return cy.request({
378
- body: {
379
- ...dashboardBody
380
- },
381
- method: 'POST',
382
- url: '/centreon/api/latest/configuration/dashboards'
383
- });
384
- }
385
- );
386
-
387
- interface ShareDashboardToUserProps {
388
- dashboardName: string;
389
- role: string;
390
- userName: string;
391
- }
392
-
393
- interface ListingRequestResult {
394
- body: {
395
- result: Array<{
396
- id: number;
397
- }>;
398
- };
399
- }
400
-
401
- Cypress.Commands.add(
402
- 'shareDashboardToUser',
403
- ({ dashboardName, userName, role }: ShareDashboardToUserProps): void => {
404
- Promise.all([
405
- cy.request({
406
- method: 'GET',
407
- url: `/centreon/api/latest/configuration/users?search={"name":"${userName}"}`
408
- }),
409
- cy.request({
410
- method: 'GET',
411
- url: `/centreon/api/latest/configuration/dashboards?search={"name":"${dashboardName}"}`
412
- })
413
- ]).then(
414
- ([retrievedUser, retrievedDashboard]: [
415
- ListingRequestResult,
416
- ListingRequestResult
417
- ]) => {
418
- const userId = retrievedUser.body.result[0].id;
419
- const dashboardId = retrievedDashboard.body.result[0].id;
420
-
421
- cy.request({
422
- body: {
423
- id: userId,
424
- role: `${role}`
425
- },
426
- method: 'POST',
427
- url: `/centreon/api/latest/configuration/dashboards/${dashboardId}/access_rights/contacts`
428
- });
429
- }
430
- );
431
- }
432
- );
433
-
434
- Cypress.Commands.add('getTimeFromHeader', (): Cypress.Chainable => {
435
- return cy
436
- .get('header div[data-cy="clock"]', { timeout: 10000 })
437
- .should('be.visible')
438
- .then(($time) => {
439
- const headerTime = $time.children()[1].textContent;
440
- if (headerTime?.match(/\d+:\d+/)) {
441
- cy.log(`header time is : ${headerTime}`);
442
-
443
- return cy.wrap(headerTime);
444
- }
445
-
446
- throw new Error(`header time is not displayed`);
447
- });
448
- });
449
-
450
311
  declare global {
451
312
  namespace Cypress {
452
313
  interface Chainable {
453
- clickSubRootMenuItem: (page: string) => Cypress.Chainable;
454
- copyFromContainer: (
455
- props: CopyFromContainerProps,
456
- options?: Partial<Cypress.ExecOptions>
457
- ) => Cypress.Chainable;
458
- copyToContainer: (
459
- props: CopyToContainerProps,
460
- options?: Partial<Cypress.ExecOptions>
461
- ) => Cypress.Chainable;
314
+ copyFromContainer: (props: CopyFromContainerProps) => Cypress.Chainable;
315
+ copyToContainer: (props: CopyToContainerProps) => Cypress.Chainable;
462
316
  execInContainer: ({
463
317
  command,
464
318
  name
465
319
  }: ExecInContainerProps) => Cypress.Chainable;
466
320
  getIframeBody: () => Cypress.Chainable;
467
- getTimeFromHeader: () => Cypress.Chainable;
468
321
  getWebVersion: () => Cypress.Chainable;
469
322
  hoverRootMenuItem: (rootItemNumber: number) => Cypress.Chainable;
470
- insertDashboard: (dashboard: Dashboard) => Cypress.Chainable;
471
- insertDashboardList: (fixtureFile: string) => Cypress.Chainable;
472
323
  loginByTypeOfUser: ({
473
- jsonName,
474
- loginViaApi
324
+ jsonName = 'admin',
325
+ loginViaApi = false
475
326
  }: LoginByTypeOfUserProps) => Cypress.Chainable;
476
327
  moveSortableElement: (direction: string) => Cypress.Chainable;
477
328
  navigateTo: ({
@@ -479,11 +330,6 @@ declare global {
479
330
  rootItemNumber,
480
331
  subMenu
481
332
  }: NavigateToProps) => Cypress.Chainable;
482
- shareDashboardToUser: ({
483
- dashboardName,
484
- userName,
485
- role
486
- }: ShareDashboardToUserProps) => Cypress.Chainable;
487
333
  startContainer: ({
488
334
  name,
489
335
  image
@@ -5,9 +5,7 @@ import { execSync } from 'child_process';
5
5
 
6
6
  import { defineConfig } from 'cypress';
7
7
 
8
- import esbuildPreprocessor from './esbuild-preprocessor';
9
- import plugins from './plugins';
10
- import tasks from './tasks';
8
+ import setupNodeEvents from './plugins';
11
9
 
12
10
  interface ConfigurationOptions {
13
11
  cypressFolder?: string;
@@ -24,7 +22,9 @@ export default ({
24
22
  dockerName,
25
23
  env
26
24
  }: ConfigurationOptions): Cypress.ConfigOptions => {
27
- const resultsFolder = `${cypressFolder || 'cypress'}/results`;
25
+ const resultsFolder = `${cypressFolder || 'cypress'}/results${
26
+ isDevelopment ? '/dev' : ''
27
+ }`;
28
28
 
29
29
  const webImageVersion = execSync('git rev-parse --abbrev-ref HEAD')
30
30
  .toString('utf8')
@@ -35,12 +35,7 @@ export default ({
35
35
  defaultCommandTimeout: 6000,
36
36
  e2e: {
37
37
  excludeSpecPattern: ['*.js', '*.ts', '*.md'],
38
- setupNodeEvents: async (on, config) => {
39
- await esbuildPreprocessor(on, config);
40
- tasks(on);
41
-
42
- return plugins(on, config);
43
- },
38
+ setupNodeEvents,
44
39
  specPattern
45
40
  },
46
41
  env: {
@@ -50,7 +45,7 @@ export default ({
50
45
  WEB_IMAGE_VERSION: webImageVersion,
51
46
  dockerName: dockerName || 'centreon-dev'
52
47
  },
53
- execTimeout: 60000,
48
+ execTimeout: 120000,
54
49
  reporter: 'mochawesome',
55
50
  reporterOptions: {
56
51
  html: false,
@@ -63,7 +58,6 @@ export default ({
63
58
  retries: 0,
64
59
  screenshotsFolder: `${resultsFolder}/screenshots`,
65
60
  video: true,
66
- videoCompression: isDevelopment ? 0 : 16,
67
61
  videosFolder: `${resultsFolder}/videos`
68
62
  });
69
63
  };
@@ -3,30 +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;
6
+ import Docker from 'dockerode';
7
+ import { addCucumberPreprocessorPlugin } from '@badeball/cypress-cucumber-preprocessor';
8
+ import webpackPreprocessor from '@cypress/webpack-preprocessor';
13
9
 
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);
44
+
45
+ const webpackOptions = await getWebpackOptions(config);
46
+ const options = {
47
+ webpackOptions
48
+ };
49
+
50
+ on('file:preprocessor', webpackPreprocessor(options));
51
+
52
+ on('before:browser:launch', (browser = {}, launchOptions) => {
14
53
  if ((browser as { name }).name === 'chrome') {
15
- // flags description : https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md
16
54
  launchOptions.args.push('--disable-gpu');
17
- launchOptions.args.push('--auto-open-devtools-for-tabs');
18
- launchOptions.args.push('--disable-extensions');
19
- launchOptions.args.push('--hide-scrollbars');
20
- launchOptions.args.push('--mute-audio');
21
- launchOptions.args.push('--hide-scrollbars');
22
-
23
- launchOptions.args.push(`--window-size=${width},${height}`);
24
- // force screen to be non-retina and just use our given resolution
25
- launchOptions.args.push('--force-device-scale-factor=1');
55
+ launchOptions.args = launchOptions.args.filter(
56
+ (element) => element !== '--disable-dev-shm-usage'
57
+ );
26
58
  }
27
59
 
28
60
  return launchOptions;
29
61
  });
30
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
+
31
133
  return config;
32
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.30",
4
+ "version": "23.10.31",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/centreon/centreon-frontend.git"
@@ -16,20 +16,13 @@
16
16
  "url": "https://github.com/centreon/centreon-frontend/issues"
17
17
  },
18
18
  "devDependencies": {
19
- "@badeball/cypress-cucumber-preprocessor": "^18.0.5",
20
- "@bahmutov/cypress-esbuild-preprocessor": "^2.2.0",
21
- "@esbuild-plugins/node-globals-polyfill": "^0.2.3",
22
- "@esbuild-plugins/node-modules-polyfill": "^0.2.2",
23
- "@tsconfig/node16": "^1.0.4",
24
- "@types/cypress-cucumber-preprocessor": "^4.0.2",
25
- "@types/dockerode": "^3.3.19",
19
+ "@badeball/cypress-cucumber-preprocessor": "^14.0.0",
20
+ "@types/dockerode": "^3.3.16",
26
21
  "dockerode": "^3.3.5",
27
- "esbuild": "^0.19.2",
28
22
  "eslint": "^8.17.0",
29
23
  "eslint-config-airbnb": "19.0.4",
30
24
  "eslint-config-prettier": "^8.5.0",
31
25
  "eslint-import-resolver-alias": "^1.1.2",
32
- "eslint-import-resolver-typescript": "^3.5.5",
33
26
  "eslint-plugin-babel": "^5.3.1",
34
27
  "eslint-plugin-hooks": "^0.4.3",
35
28
  "eslint-plugin-import": "^2.26.0",
@@ -1,15 +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
- "moduleResolution": "node",
10
9
  "noImplicitAny": false,
11
10
  "skipLibCheck": true,
12
- "esModuleInterop": true,
13
- "resolveJsonModule": true
11
+ "esModuleInterop": true
14
12
  }
15
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,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
- };