@centreon/js-config 24.4.21 → 24.4.22

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.
@@ -5,6 +5,7 @@ import { execSync } from 'child_process';
5
5
 
6
6
  import { defineConfig } from 'cypress';
7
7
  import installLogsPrinter from 'cypress-terminal-report/src/installLogsPrinter';
8
+ import { config as configDotenv } from 'dotenv';
8
9
 
9
10
  import esbuildPreprocessor from './esbuild-preprocessor';
10
11
  import plugins from './plugins';
@@ -12,8 +13,8 @@ import tasks from './tasks';
12
13
 
13
14
  interface ConfigurationOptions {
14
15
  cypressFolder?: string;
15
- dockerName?: string;
16
16
  env?: Record<string, unknown>;
17
+ envFile?: string;
17
18
  isDevelopment?: boolean;
18
19
  specPattern: string;
19
20
  }
@@ -22,9 +23,13 @@ export default ({
22
23
  specPattern,
23
24
  cypressFolder,
24
25
  isDevelopment,
25
- dockerName,
26
- env
26
+ env,
27
+ envFile
27
28
  }: ConfigurationOptions): Cypress.ConfigOptions => {
29
+ if (envFile) {
30
+ configDotenv({ path: envFile });
31
+ }
32
+
28
33
  const resultsFolder = `${cypressFolder || '.'}/results`;
29
34
 
30
35
  const webImageVersion = execSync('git rev-parse --abbrev-ref HEAD')
@@ -34,6 +39,7 @@ export default ({
34
39
  return defineConfig({
35
40
  chromeWebSecurity: false,
36
41
  defaultCommandTimeout: 6000,
42
+ downloadsFolder: `${resultsFolder}/downloads`,
37
43
  e2e: {
38
44
  excludeSpecPattern: ['*.js', '*.ts', '*.md'],
39
45
  fixturesFolder: 'fixtures',
@@ -53,16 +59,17 @@ export default ({
53
59
  },
54
60
  env: {
55
61
  ...env,
56
- OPENID_IMAGE_VERSION: '23.04',
62
+ DATABASE_IMAGE: 'bitnami/mariadb:10.5',
63
+ OPENID_IMAGE_VERSION: process.env.MAJOR || '24.04',
64
+ SAML_IMAGE_VERSION: process.env.MAJOR || '24.04',
57
65
  WEB_IMAGE_OS: 'alma9',
58
- WEB_IMAGE_VERSION: webImageVersion,
59
- dockerName: dockerName || 'centreon-dev'
66
+ WEB_IMAGE_VERSION: webImageVersion
60
67
  },
61
68
  execTimeout: 60000,
62
69
  requestTimeout: 10000,
63
70
  retries: 0,
64
71
  screenshotsFolder: `${resultsFolder}/screenshots`,
65
- video: true,
72
+ video: isDevelopment,
66
73
  videoCompression: 0,
67
74
  videosFolder: `${resultsFolder}/videos`
68
75
  });
@@ -11,7 +11,7 @@ export default (
11
11
  const width = 1920;
12
12
  const height = 1080;
13
13
 
14
- if (browser.name === 'chrome') {
14
+ if (browser.family === 'chromium' && browser.name !== 'electron') {
15
15
  if (browser.isHeadless) {
16
16
  launchOptions.args.push('--headless=new');
17
17
  }
@@ -1,10 +1,40 @@
1
+ /* eslint-disable no-console */
1
2
  import { execSync } from 'child_process';
2
3
  import { existsSync, mkdirSync } from 'fs';
4
+ import path from 'path';
3
5
 
4
- import Docker from 'dockerode';
6
+ import tar from 'tar-fs';
7
+ import {
8
+ DockerComposeEnvironment,
9
+ GenericContainer,
10
+ StartedDockerComposeEnvironment,
11
+ StartedTestContainer,
12
+ Wait,
13
+ getContainerRuntimeClient
14
+ } from 'testcontainers';
15
+ import { createConnection } from 'mysql2/promise';
16
+
17
+ interface Containers {
18
+ [key: string]: StartedTestContainer;
19
+ }
5
20
 
6
21
  export default (on: Cypress.PluginEvents): void => {
7
- const docker = new Docker();
22
+ let dockerEnvironment: StartedDockerComposeEnvironment | null = null;
23
+ const containers: Containers = {};
24
+
25
+ const getContainer = (containerName): StartedTestContainer => {
26
+ let container;
27
+
28
+ if (dockerEnvironment !== null) {
29
+ container = dockerEnvironment.getContainer(`${containerName}-1`);
30
+ } else if (containers[containerName]) {
31
+ container = containers[containerName];
32
+ } else {
33
+ throw new Error(`Cannot get container ${containerName}`);
34
+ }
35
+
36
+ return container;
37
+ };
8
38
 
9
39
  interface PortBinding {
10
40
  destination: number;
@@ -12,6 +42,7 @@ export default (on: Cypress.PluginEvents): void => {
12
42
  }
13
43
 
14
44
  interface StartContainerProps {
45
+ command?: string;
15
46
  image: string;
16
47
  name: string;
17
48
  portBindings: Array<PortBinding>;
@@ -22,6 +53,48 @@ export default (on: Cypress.PluginEvents): void => {
22
53
  }
23
54
 
24
55
  on('task', {
56
+ copyFromContainer: async ({ destination, serviceName, source }) => {
57
+ try {
58
+ if (dockerEnvironment !== null) {
59
+ const container = dockerEnvironment.getContainer(`${serviceName}-1`);
60
+
61
+ await container
62
+ .copyArchiveFromContainer(source)
63
+ .then((archiveStream) => {
64
+ return new Promise<void>((resolve) => {
65
+ const dest = tar.extract(destination);
66
+ archiveStream.pipe(dest);
67
+ dest.on('finish', resolve);
68
+ });
69
+ });
70
+ }
71
+ } catch (error) {
72
+ console.error(error);
73
+ }
74
+
75
+ return null;
76
+ },
77
+ copyToContainer: async ({ destination, serviceName, source, type }) => {
78
+ const container = getContainer(serviceName);
79
+
80
+ if (type === 'directory') {
81
+ await container.copyDirectoriesToContainer([
82
+ {
83
+ source,
84
+ target: destination
85
+ }
86
+ ]);
87
+ } else if (type === 'file') {
88
+ await container.copyFilesToContainer([
89
+ {
90
+ source,
91
+ target: destination
92
+ }
93
+ ]);
94
+ }
95
+
96
+ return null;
97
+ },
25
98
  createDirectory: async (directoryPath: string) => {
26
99
  if (!existsSync(directoryPath)) {
27
100
  mkdirSync(directoryPath, { recursive: true });
@@ -29,70 +102,150 @@ export default (on: Cypress.PluginEvents): void => {
29
102
 
30
103
  return null;
31
104
  },
105
+ execInContainer: async ({ command, name }) => {
106
+ const { exitCode, output } = await getContainer(name).exec([
107
+ 'bash',
108
+ '-c',
109
+ command
110
+ ]);
111
+
112
+ return { exitCode, output };
113
+ },
114
+ getContainerId: (containerName: string) =>
115
+ getContainer(containerName).getId(),
116
+ getContainerIpAddress: (containerName: string) => {
117
+ const container = getContainer(containerName);
118
+
119
+ const networkNames = container.getNetworkNames();
120
+
121
+ return container.getIpAddress(networkNames[0]);
122
+ },
123
+ getContainersLogs: async () => {
124
+ try {
125
+ const { dockerode } = (await getContainerRuntimeClient()).container;
126
+ const loggedContainers = await dockerode.listContainers();
127
+
128
+ return loggedContainers.reduce((acc, container) => {
129
+ const containerName = container.Names[0].replace('/', '');
130
+ acc[containerName] = execSync(`docker logs -t ${container.Id}`, {
131
+ stdio: 'pipe'
132
+ }).toString('utf8');
133
+
134
+ return acc;
135
+ }, {});
136
+ } catch (error) {
137
+ console.warn('Cannot get containers logs');
138
+ console.warn(error);
139
+
140
+ return null;
141
+ }
142
+ },
143
+ requestOnDatabase: async ({ database, query }) => {
144
+ let container: StartedTestContainer | null = null;
145
+
146
+ if (dockerEnvironment !== null) {
147
+ container = dockerEnvironment.getContainer('db-1');
148
+ } else {
149
+ container = getContainer('web');
150
+ }
151
+
152
+ const client = await createConnection({
153
+ database,
154
+ host: container.getHost(),
155
+ password: 'centreon',
156
+ port: container.getMappedPort(3306),
157
+ user: 'centreon'
158
+ });
159
+
160
+ const [rows, fields] = await client.execute(query);
161
+
162
+ await client.end();
163
+
164
+ return [rows, fields];
165
+ },
32
166
  startContainer: async ({
167
+ command,
33
168
  image,
34
169
  name,
35
170
  portBindings = []
36
171
  }: StartContainerProps) => {
37
- const imageList = execSync(
38
- 'docker image list --format "{{.Repository}}:{{.Tag}}"'
39
- ).toString('utf8');
40
-
41
- if (
42
- !imageList.match(
43
- new RegExp(
44
- `^${image.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}`,
45
- 'm'
46
- )
47
- )
48
- ) {
49
- execSync(`docker pull ${image}`);
50
- }
172
+ let container = await new GenericContainer(image).withName(name);
51
173
 
52
- const webContainers = await docker.listContainers({
53
- all: true,
54
- filters: { name: [name] }
174
+ portBindings.forEach(({ source, destination }) => {
175
+ container = container.withExposedPorts({
176
+ container: source,
177
+ host: destination
178
+ });
55
179
  });
56
- if (webContainers.length) {
57
- return webContainers[0];
58
- }
59
180
 
60
- const container = await docker.createContainer({
61
- AttachStderr: true,
62
- AttachStdin: false,
63
- AttachStdout: true,
64
- ExposedPorts: portBindings.reduce((accumulator, currentValue) => {
65
- accumulator[`${currentValue.source}/tcp`] = {};
66
-
67
- return accumulator;
68
- }, {}),
69
- HostConfig: {
70
- PortBindings: portBindings.reduce((accumulator, currentValue) => {
71
- accumulator[`${currentValue.source}/tcp`] = [
72
- {
73
- HostIP: '127.0.0.1',
74
- HostPort: `${currentValue.destination}`
75
- }
76
- ];
77
-
78
- return accumulator;
79
- }, {})
80
- },
81
- Image: image,
82
- OpenStdin: false,
83
- StdinOnce: false,
84
- Tty: true,
85
- name
86
- });
181
+ if (command) {
182
+ container
183
+ .withCommand(['bash', '-c', command])
184
+ .withWaitStrategy(Wait.forSuccessfulCommand('ls'));
185
+ }
87
186
 
88
- await container.start();
187
+ containers[name] = await container.start();
89
188
 
90
189
  return container;
91
190
  },
191
+ startContainers: async ({
192
+ composeFile,
193
+ databaseImage,
194
+ openidImage,
195
+ profiles,
196
+ samlImage,
197
+ webImage
198
+ }) => {
199
+ try {
200
+ const composeFileDir = path.dirname(composeFile);
201
+ const composeFileName = path.basename(composeFile);
202
+
203
+ dockerEnvironment = await new DockerComposeEnvironment(
204
+ composeFileDir,
205
+ composeFileName
206
+ )
207
+ .withEnvironment({
208
+ MYSQL_IMAGE: databaseImage,
209
+ OPENID_IMAGE: openidImage,
210
+ SAML_IMAGE: samlImage,
211
+ WEB_IMAGE: webImage
212
+ })
213
+ .withProfiles(...profiles)
214
+ .withWaitStrategy(
215
+ 'web-1',
216
+ Wait.forAll([
217
+ Wait.forHealthCheck(),
218
+ Wait.forLogMessage('Centreon is ready')
219
+ ])
220
+ )
221
+ .up();
222
+
223
+ return null;
224
+ } catch (error) {
225
+ if (error instanceof Error) {
226
+ console.error(error.message);
227
+ }
228
+
229
+ throw error;
230
+ }
231
+ },
92
232
  stopContainer: async ({ name }: StopContainerProps) => {
93
- const container = await docker.getContainer(name);
94
- await container.kill();
95
- await container.remove();
233
+ if (containers[name]) {
234
+ const container = containers[name];
235
+
236
+ await container.stop();
237
+
238
+ delete containers[name];
239
+ }
240
+
241
+ return null;
242
+ },
243
+ stopContainers: async () => {
244
+ if (dockerEnvironment !== null) {
245
+ await dockerEnvironment.down();
246
+
247
+ dockerEnvironment = null;
248
+ }
96
249
 
97
250
  return null;
98
251
  },
package/jest/index.js CHANGED
@@ -5,7 +5,6 @@ module.exports = {
5
5
  'jest-transform-stub',
6
6
  '^react($|/.+)': '<rootDir>/node_modules/react$1'
7
7
  },
8
- setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],
9
8
  testEnvironment: 'jsdom',
10
9
  testPathIgnorePatterns: ['/node_modules/', '!*.cypress.spec.tsx'],
11
10
  transform: {
package/package.json CHANGED
@@ -1,59 +1,66 @@
1
1
  {
2
- "name": "@centreon/js-config",
3
- "description": "Centreon Frontend shared build configuration",
4
- "version": "24.4.21",
5
- "repository": {
6
- "type": "git",
7
- "url": "git+https://github.com/centreon/centreon-frontend.git"
8
- },
9
- "keywords": [
10
- "centreon",
11
- "eslint"
12
- ],
13
- "author": "centreon@centreon.com",
14
- "license": "GPL-2.0",
15
- "bugs": {
16
- "url": "https://github.com/centreon/centreon-frontend/issues"
17
- },
18
- "devDependencies": {
19
- "@tsconfig/node16": "^16.1.1",
20
- "eslint": "^8.17.0",
21
- "eslint-config-airbnb": "19.0.4",
22
- "eslint-config-prettier": "^8.5.0",
23
- "eslint-import-resolver-alias": "^1.1.2",
24
- "eslint-import-resolver-typescript": "^3.5.5",
25
- "eslint-plugin-babel": "^5.3.1",
26
- "eslint-plugin-hooks": "^0.4.3",
27
- "eslint-plugin-import": "^2.26.0",
28
- "eslint-plugin-jest": "^26.1.5",
29
- "eslint-plugin-jsx-a11y": "^6.5.1",
30
- "eslint-plugin-node": "^11.1.0",
31
- "eslint-plugin-prefer-arrow-functions": "^3.1.4",
32
- "eslint-plugin-prettier": "^4.0.0",
33
- "eslint-plugin-react": "^7.29.4",
34
- "eslint-plugin-react-hooks": "^4.5.0",
35
- "eslint-plugin-sort-keys-fix": "^1.1.2",
36
- "eslint-plugin-typescript-sort-keys": "^2.1.0"
37
- },
38
- "homepage": "https://github.com/centreon/centreon-frontend#readme",
39
- "files": [
40
- "eslint",
41
- "jest",
42
- "tsconfig",
43
- "webpack",
44
- "cypress"
45
- ],
46
- "dependencies": {
47
- "@badeball/cypress-cucumber-preprocessor": "^19.1.0",
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.5",
52
- "@types/dockerode": "^3.3.23",
53
- "cypress-multi-reporters": "^1.6.4",
54
- "cypress-terminal-report": "^5.3.9",
55
- "dockerode": "^4.0.0",
56
- "esbuild": "^0.19.5",
57
- "mochawesome": "^7.1.3"
58
- }
2
+ "name": "@centreon/js-config",
3
+ "description": "Centreon Frontend shared build configuration",
4
+ "version": "24.4.22",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/centreon/centreon-frontend.git"
8
+ },
9
+ "keywords": [
10
+ "centreon",
11
+ "eslint"
12
+ ],
13
+ "author": "centreon@centreon.com",
14
+ "license": "GPL-2.0",
15
+ "bugs": {
16
+ "url": "https://github.com/centreon/centreon-frontend/issues"
17
+ },
18
+ "homepage": "https://github.com/centreon/centreon-frontend#readme",
19
+ "files": [
20
+ "eslint",
21
+ "jest",
22
+ "tsconfig",
23
+ "webpack",
24
+ "cypress"
25
+ ],
26
+ "peerDependencies": {
27
+ "eslint": "^8.53.0",
28
+ "prettier": "^3.0.0"
29
+ },
30
+ "dependencies": {
31
+ "@badeball/cypress-cucumber-preprocessor": "^20.0.1",
32
+ "@bahmutov/cypress-esbuild-preprocessor": "^2.2.0",
33
+ "@esbuild-plugins/node-globals-polyfill": "^0.2.3",
34
+ "@esbuild-plugins/node-modules-polyfill": "^0.2.2",
35
+ "@tsconfig/node16": "^16.1.1",
36
+ "@tsconfig/node20": "^20.1.2",
37
+ "@types/cypress-cucumber-preprocessor": "^4.0.5",
38
+ "cypress": "^13.6.4",
39
+ "cypress-multi-reporters": "^1.6.4",
40
+ "cypress-terminal-report": "^6.0.0",
41
+ "cypress-wait-until": "^3.0.1",
42
+ "dotenv": "^16.4.1",
43
+ "esbuild": "^0.20.0",
44
+ "eslint": "^8.53.0",
45
+ "eslint-config-airbnb": "19.0.4",
46
+ "eslint-config-prettier": "^8.5.0",
47
+ "eslint-import-resolver-alias": "^1.1.2",
48
+ "eslint-import-resolver-typescript": "^3.5.5",
49
+ "eslint-plugin-babel": "^5.3.1",
50
+ "eslint-plugin-hooks": "^0.4.3",
51
+ "eslint-plugin-import": "^2.26.0",
52
+ "eslint-plugin-jest": "^26.1.5",
53
+ "eslint-plugin-jsx-a11y": "^6.5.1",
54
+ "eslint-plugin-node": "^11.1.0",
55
+ "eslint-plugin-prefer-arrow-functions": "^3.1.4",
56
+ "eslint-plugin-prettier": "^5.0.0",
57
+ "eslint-plugin-react": "^7.29.4",
58
+ "eslint-plugin-react-hooks": "^4.5.0",
59
+ "eslint-plugin-sort-keys-fix": "^1.1.2",
60
+ "eslint-plugin-typescript-sort-keys": "^2.1.0",
61
+ "mochawesome": "^7.1.3",
62
+ "mysql2": "^3.9.1",
63
+ "tar-fs": "^3.0.4",
64
+ "testcontainers": "^10.7.1"
65
+ }
59
66
  }
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "@tsconfig/node20/tsconfig.json",
3
+ "compilerOptions": {
4
+ "sourceMap": true,
5
+ "allowJs": true,
6
+ "strictNullChecks": false,
7
+ "declaration": false,
8
+ "esModuleInterop": true,
9
+ "strict": true,
10
+ "types": ["@types/jest", "node"]
11
+ }
12
+ }
@@ -1,10 +1,10 @@
1
1
  const excludeNodeModulesExceptCentreonUi =
2
- /node_modules(\\|\/)\.pnpm(\\|\/)(?!(@centreon))/;
2
+ /node_modules(\\|\/)\.pnpm(\\|\/)(?!(@centreon|file\+packages\+ui-context))/;
3
3
 
4
4
  module.exports = {
5
5
  cache: false,
6
6
  excludeNodeModulesExceptCentreonUi,
7
- getModuleConfiguration: (jscTransformConfiguration) => ({
7
+ getModuleConfiguration: (jscTransformConfiguration, enableCoverage) => ({
8
8
  rules: [
9
9
  {
10
10
  parser: { system: false },
@@ -17,6 +17,11 @@ module.exports = {
17
17
  loader: 'swc-loader',
18
18
  options: {
19
19
  jsc: {
20
+ experimental: {
21
+ plugins: [
22
+ enableCoverage && ['swc-plugin-coverage-instrument', {}]
23
+ ].filter(Boolean)
24
+ },
20
25
  parser: {
21
26
  syntax: 'typescript',
22
27
  tsx: true
@@ -13,10 +13,11 @@ const {
13
13
  const getBaseConfiguration = ({
14
14
  moduleName,
15
15
  moduleFederationConfig,
16
- jscTransformConfiguration
16
+ jscTransformConfiguration,
17
+ enableCoverage
17
18
  }) => ({
18
19
  cache,
19
- module: getModuleConfiguration(jscTransformConfiguration),
20
+ module: getModuleConfiguration(jscTransformConfiguration, enableCoverage),
20
21
  optimization,
21
22
  output: {
22
23
  ...output,
@@ -33,19 +34,18 @@ const getBaseConfiguration = ({
33
34
  shared: [
34
35
  {
35
36
  '@centreon/ui-context': {
36
- requiredVersion: '22.10.0',
37
+ requiredVersion: '24.x',
37
38
  singleton: true
38
39
  }
39
40
  },
40
41
  {
41
42
  jotai: {
42
- requiredVersion: '1.x',
43
+ requiredVersion: '2.x',
43
44
  singleton: true
44
45
  }
45
46
  },
46
47
  {
47
48
  'jotai-suspense': {
48
- requiredVersion: '0.1.x',
49
49
  singleton: true
50
50
  }
51
51
  },