@linagora/linid-im-front-corelib 0.0.4 → 0.0.6

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.
Files changed (35) hide show
  1. package/.github/workflows/pull-request.yml +26 -1
  2. package/.github/workflows/release.yml +1 -1
  3. package/CHANGELOG.md +13 -0
  4. package/CONTRIBUTING.md +7 -2
  5. package/dist/core-lib.es.js +921 -851
  6. package/dist/core-lib.umd.js +9 -9
  7. package/dist/package.json +20 -12
  8. package/dist/types/src/index.d.ts +3 -0
  9. package/dist/types/src/services/httpClientService.d.ts +13 -0
  10. package/dist/types/src/services/linIdConfigurationService.d.ts +21 -0
  11. package/dist/types/src/stores/linIdConfigurationStore.d.ts +79 -0
  12. package/dist/types/src/types/linidConfiguration.d.ts +42 -0
  13. package/docs/services.md +39 -0
  14. package/docs/types-and-interfaces.md +56 -9
  15. package/eslint.config.js +2 -1
  16. package/package.json +19 -11
  17. package/src/index.ts +11 -0
  18. package/src/services/httpClientService.ts +61 -0
  19. package/src/services/linIdConfigurationService.ts +73 -0
  20. package/src/stores/linIdConfigurationStore.ts +116 -0
  21. package/src/types/linidConfiguration.ts +70 -0
  22. package/tests/unit/components/LinidZoneRenderer.spec.js +135 -0
  23. package/tests/unit/lifecycle/skeleton.spec.js +138 -0
  24. package/tests/unit/services/federationService.spec.js +146 -0
  25. package/tests/unit/services/httpClientService.spec.js +49 -0
  26. package/tests/unit/services/linIdConfigurationService.spec.js +113 -0
  27. package/tests/unit/stores/linIdConfigurationStore.spec.js +171 -0
  28. package/tests/unit/stores/linidZoneStore.spec.js +94 -0
  29. package/tsconfig.json +11 -27
  30. package/tsconfig.lib.json +20 -0
  31. package/tsconfig.node.json +9 -0
  32. package/tsconfig.spec.json +16 -0
  33. package/vite.config.ts +11 -16
  34. package/vitest.config.ts +19 -0
  35. package/dist/types/vite.config.d.ts +0 -2
@@ -0,0 +1,171 @@
1
+ import { createPinia, setActivePinia } from 'pinia';
2
+ import { useLinIdConfigurationStore } from 'src/stores/linIdConfigurationStore';
3
+ import * as linIdConfigurationService from 'src/services/linIdConfigurationService';
4
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
5
+
6
+ vi.mock('src/services/linIdConfigurationService', () => ({
7
+ getEntitiesConfiguration: vi.fn(),
8
+ getRoutesConfiguration: vi.fn(),
9
+ }));
10
+
11
+ describe('Test store: linIdConfigurationStore', () => {
12
+ let store;
13
+
14
+ beforeEach(() => {
15
+ setActivePinia(createPinia());
16
+ store = useLinIdConfigurationStore();
17
+ vi.clearAllMocks();
18
+ });
19
+
20
+ describe('Test initial state', () => {
21
+ it('should have empty initial state', () => {
22
+ expect(store.entities).toEqual([]);
23
+ expect(store.routes).toEqual([]);
24
+ expect(store.loading).toBe(false);
25
+ expect(store.error).toBeNull();
26
+ });
27
+ });
28
+
29
+ describe('Test getter: getEntityByName', () => {
30
+ it('should return undefined when entity is not found', () => {
31
+ store.entities = [{ name: 'user', attributes: [] }];
32
+
33
+ const result = store.getEntityByName('unknown');
34
+
35
+ expect(result).toBeUndefined();
36
+ });
37
+
38
+ it('should return the entity when found', () => {
39
+ const userEntity = { name: 'user', attributes: [{ name: 'email' }] };
40
+ store.entities = [userEntity, { name: 'group', attributes: [] }];
41
+
42
+ const result = store.getEntityByName('user');
43
+
44
+ expect(result).toEqual(userEntity);
45
+ });
46
+ });
47
+
48
+ describe('Test getter: getRoutesByEntity', () => {
49
+ it('should return empty array when no routes match', () => {
50
+ store.routes = [
51
+ { method: 'GET', path: '/groups', entity: 'group', variables: [] },
52
+ ];
53
+
54
+ const result = store.getRoutesByEntity('user');
55
+
56
+ expect(result).toEqual([]);
57
+ });
58
+
59
+ it('should return all routes for the specified entity', () => {
60
+ const userRoutes = [
61
+ { method: 'GET', path: '/users', entity: 'user', variables: [] },
62
+ { method: 'POST', path: '/users', entity: 'user', variables: [] },
63
+ ];
64
+ store.routes = [
65
+ ...userRoutes,
66
+ { method: 'GET', path: '/groups', entity: 'group', variables: [] },
67
+ ];
68
+
69
+ const result = store.getRoutesByEntity('user');
70
+
71
+ expect(result).toEqual(userRoutes);
72
+ });
73
+ });
74
+
75
+ describe('Test action: fetchConfiguration', () => {
76
+ it('should fetch entities and routes successfully', async () => {
77
+ const mockEntities = [{ name: 'user', attributes: [] }];
78
+ const mockRoutes = [
79
+ { method: 'GET', path: '/users', entity: 'user', variables: [] },
80
+ ];
81
+
82
+ vi.mocked(
83
+ linIdConfigurationService.getEntitiesConfiguration
84
+ ).mockResolvedValue(mockEntities);
85
+ vi.mocked(
86
+ linIdConfigurationService.getRoutesConfiguration
87
+ ).mockResolvedValue(mockRoutes);
88
+
89
+ await store.fetchConfiguration();
90
+
91
+ expect(store.entities).toEqual(mockEntities);
92
+ expect(store.routes).toEqual(mockRoutes);
93
+ expect(store.loading).toBe(false);
94
+ expect(store.error).toBeNull();
95
+ });
96
+
97
+ it('should set loading to true during fetch', async () => {
98
+ let loadingDuringFetch = false;
99
+
100
+ vi.mocked(
101
+ linIdConfigurationService.getEntitiesConfiguration
102
+ ).mockImplementation(async () => {
103
+ loadingDuringFetch = store.loading;
104
+ return [];
105
+ });
106
+ vi.mocked(
107
+ linIdConfigurationService.getRoutesConfiguration
108
+ ).mockResolvedValue([]);
109
+
110
+ await store.fetchConfiguration();
111
+
112
+ expect(loadingDuringFetch).toBe(true);
113
+ expect(store.loading).toBe(false);
114
+ });
115
+
116
+ it('should handle errors and set error message', async () => {
117
+ const consoleErrorSpy = vi
118
+ .spyOn(globalThis.console, 'error')
119
+ .mockImplementation(() => {});
120
+ const error = new Error('Network failure');
121
+
122
+ vi.mocked(
123
+ linIdConfigurationService.getEntitiesConfiguration
124
+ ).mockRejectedValue(error);
125
+
126
+ await store.fetchConfiguration();
127
+
128
+ expect(store.error).toBe('Network failure');
129
+ expect(store.loading).toBe(false);
130
+ expect(store.entities).toEqual([]);
131
+ expect(store.routes).toEqual([]);
132
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
133
+ '[LinID CoreLib] Failed to fetch configuration:',
134
+ error
135
+ );
136
+
137
+ consoleErrorSpy.mockRestore();
138
+ });
139
+
140
+ it('should handle non-Error exceptions', async () => {
141
+ const consoleErrorSpy = vi
142
+ .spyOn(globalThis.console, 'error')
143
+ .mockImplementation(() => {});
144
+
145
+ vi.mocked(
146
+ linIdConfigurationService.getEntitiesConfiguration
147
+ ).mockRejectedValue('String error');
148
+
149
+ await store.fetchConfiguration();
150
+
151
+ expect(store.error).toBe('Failed to fetch configuration');
152
+
153
+ consoleErrorSpy.mockRestore();
154
+ });
155
+
156
+ it('should reset error on new fetch', async () => {
157
+ store.error = 'Previous error';
158
+
159
+ vi.mocked(
160
+ linIdConfigurationService.getEntitiesConfiguration
161
+ ).mockResolvedValue([]);
162
+ vi.mocked(
163
+ linIdConfigurationService.getRoutesConfiguration
164
+ ).mockResolvedValue([]);
165
+
166
+ await store.fetchConfiguration();
167
+
168
+ expect(store.error).toBeNull();
169
+ });
170
+ });
171
+ });
@@ -0,0 +1,94 @@
1
+ import { createPinia, setActivePinia } from 'pinia';
2
+ import { useLinidZoneStore } from 'src/stores/linidZoneStore';
3
+ import { beforeEach, describe, expect, it } from 'vitest';
4
+
5
+ describe('Test store: linidZoneStore', () => {
6
+ beforeEach(() => {
7
+ setActivePinia(createPinia());
8
+ });
9
+
10
+ describe('Test initial state', () => {
11
+ it('should initialize with empty zones', () => {
12
+ const store = useLinidZoneStore();
13
+
14
+ expect(store.zones).toEqual({});
15
+ });
16
+ });
17
+
18
+ describe('Test function: register', () => {
19
+ it('should register an entry in a new zone', () => {
20
+ const store = useLinidZoneStore();
21
+ const entry = {
22
+ plugin: 'test-plugin/TestComponent',
23
+ props: {},
24
+ };
25
+
26
+ store.register('list-page.sidebar', entry);
27
+
28
+ expect(store.zones['list-page.sidebar']).toBeDefined();
29
+ expect(store.zones['list-page.sidebar']).toHaveLength(1);
30
+ expect(store.zones['list-page.sidebar'][0]).toEqual(entry);
31
+ });
32
+
33
+ it('should register multiple entries in the same zone', () => {
34
+ const store = useLinidZoneStore();
35
+ const entry1 = {
36
+ plugin: 'plugin-1/Component1',
37
+ props: {},
38
+ };
39
+ const entry2 = {
40
+ plugin: 'plugin-2/Component2',
41
+ props: { value: 42 },
42
+ };
43
+
44
+ store.register('list-page.sidebar', entry1);
45
+ store.register('list-page.sidebar', entry2);
46
+
47
+ expect(store.zones['list-page.sidebar']).toHaveLength(2);
48
+ expect(store.zones['list-page.sidebar'][0]).toEqual(entry1);
49
+ expect(store.zones['list-page.sidebar'][1]).toEqual(entry2);
50
+ });
51
+
52
+ it('should register entries in different zones independently', () => {
53
+ const store = useLinidZoneStore();
54
+ const headerEntry = {
55
+ plugin: 'header-plugin/HeaderComponent',
56
+ props: {},
57
+ };
58
+ const footerEntry = {
59
+ plugin: 'footer-plugin/FooterComponent',
60
+ props: {},
61
+ };
62
+
63
+ store.register('list-page.header', headerEntry);
64
+ store.register('list-page.footer', footerEntry);
65
+
66
+ expect(store.zones['list-page.header']).toHaveLength(1);
67
+ expect(store.zones['list-page.footer']).toHaveLength(1);
68
+ expect(store.zones['list-page.header'][0]).toEqual(headerEntry);
69
+ expect(store.zones['list-page.footer'][0]).toEqual(footerEntry);
70
+ });
71
+
72
+ it('should handle entries with complex props', () => {
73
+ const store = useLinidZoneStore();
74
+ const entry = {
75
+ plugin: 'complex-plugin/ComplexComponent',
76
+ props: {
77
+ title: 'Test Title',
78
+ count: 123,
79
+ enabled: true,
80
+ config: {
81
+ nested: {
82
+ value: 'deep',
83
+ },
84
+ },
85
+ items: ['a', 'b', 'c'],
86
+ },
87
+ };
88
+
89
+ store.register('list-page.body', entry);
90
+
91
+ expect(store.zones['list-page.body'][0].props).toEqual(entry.props);
92
+ });
93
+ });
94
+ });
package/tsconfig.json CHANGED
@@ -1,30 +1,14 @@
1
1
  {
2
- "compilerOptions": {
3
- "target": "ESNext",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "lib": [
7
- "ESNext",
8
- "DOM"
9
- ],
10
- "allowJs": true,
11
- "esModuleInterop": true,
12
- "strict": true,
13
- "skipLibCheck": true,
14
- "forceConsistentCasingInFileNames": true,
15
- "resolveJsonModule": true,
16
- "types": [
17
- "node",
18
- "vite/client",
19
- "vue"
20
- ],
21
- "declaration": true,
22
- "declarationDir": "dist/types",
23
- "outDir": "dist"
24
- },
25
- "include": [
26
- "src/**/*.ts",
27
- "src/**/*.vue",
28
- "vite.config.ts"
2
+ "files": [],
3
+ "references": [
4
+ {
5
+ "path": "./tsconfig.node.json"
6
+ },
7
+ {
8
+ "path": "./tsconfig.lib.json"
9
+ },
10
+ {
11
+ "path": "./tsconfig.spec.json"
12
+ }
29
13
  ]
30
14
  }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "target": "ESNext",
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "lib": ["ESNext", "DOM"],
8
+ "esModuleInterop": true,
9
+ "strict": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "types": ["node", "vite/client", "vue"],
14
+ "declaration": true,
15
+ "declarationDir": "dist/types",
16
+ "outDir": "dist"
17
+ },
18
+ "include": ["src"],
19
+ "exclude": ["vite.config.ts", "tests", "vitest.config.ts"]
20
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "module": "nodenext",
5
+ "strict": true,
6
+ "types": ["node"]
7
+ },
8
+ "include": ["vite.config.ts", "vitest.config.ts"]
9
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "baseUrl": ".",
5
+ "outDir": "./out-tsc/vitest",
6
+ "allowJs": true,
7
+ "module": "esnext",
8
+ "moduleResolution": "bundler"
9
+ },
10
+ "include": ["tests", "src"],
11
+ "references": [
12
+ {
13
+ "path": "./tsconfig.lib.json"
14
+ }
15
+ ]
16
+ }
package/vite.config.ts CHANGED
@@ -1,22 +1,17 @@
1
- /// <reference types="node" />
2
- import {defineConfig} from "vite";
3
- import vue from "@vitejs/plugin-vue";
4
- import path from "path";
5
- import fs from "fs";
6
- import {fileURLToPath} from "url";
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
1
+ import vue from '@vitejs/plugin-vue';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { defineConfig } from 'vite';
10
5
 
11
6
  export default defineConfig({
12
7
  plugins: [
13
8
  vue(),
14
9
 
15
10
  {
16
- name: "copy-package-json",
11
+ name: 'copy-package-json',
17
12
  closeBundle() {
18
- const src = path.resolve(__dirname, "package.json");
19
- const dest = path.resolve(__dirname, "dist", "package.json");
13
+ const src = path.resolve(__dirname, 'package.json');
14
+ const dest = path.resolve(__dirname, 'dist', 'package.json');
20
15
  if (fs.existsSync(src)) {
21
16
  fs.copyFileSync(src, dest);
22
17
  }
@@ -26,15 +21,15 @@ export default defineConfig({
26
21
 
27
22
  build: {
28
23
  lib: {
29
- entry: path.resolve(__dirname, "src/index.ts"),
30
- name: "CoreLib",
24
+ entry: path.resolve(__dirname, 'src/index.ts'),
25
+ name: 'CoreLib',
31
26
  fileName: (format) => `core-lib.${format}.js`,
32
27
  },
33
28
  rollupOptions: {
34
- external: ["vue"],
29
+ external: ['vue'],
35
30
  output: {
36
31
  globals: {
37
- vue: "Vue",
32
+ vue: 'Vue',
38
33
  },
39
34
  },
40
35
  },
@@ -0,0 +1,19 @@
1
+ import vue from '@vitejs/plugin-vue';
2
+ import tsconfigPaths from 'vite-tsconfig-paths';
3
+ import { defineConfig } from 'vitest/config';
4
+
5
+ export default defineConfig({
6
+ test: {
7
+ environment: 'happy-dom',
8
+ globals: true,
9
+ include: ['tests/unit/**/*.{test,spec}.js'],
10
+ coverage: {
11
+ provider: 'v8',
12
+ reporter: ['text', 'html', 'lcov'],
13
+ reportsDirectory: './coverage',
14
+ include: ['src/**/*.{ts,js,vue}'],
15
+ exclude: ['**/tests/**', 'src/types/**', 'src/index.ts'],
16
+ },
17
+ },
18
+ plugins: [vue(), tsconfigPaths()],
19
+ });
@@ -1,2 +0,0 @@
1
- declare const _default: import("vite").UserConfig;
2
- export default _default;