@intellegens/cornerstone-client 0.0.9999-alpha-30 → 0.0.9999-alpha-32

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 (39) hide show
  1. package/dist/adapters/CollectionViewAdapter/index.integration.test.d.ts +1 -0
  2. package/dist/adapters/CollectionViewAdapter/index.integration.test.js +163 -0
  3. package/dist/adapters/SearchAdapter/index.d.ts +5 -1
  4. package/dist/adapters/SearchAdapter/index.js +25 -13
  5. package/dist/data/auth/dto/index.d.ts +1 -0
  6. package/dist/data/auth/dto/index.js +1 -0
  7. package/dist/services/api/ApiCrudControllerClient/index.integration.test.d.ts +1 -0
  8. package/dist/services/api/ApiCrudControllerClient/index.integration.test.js +34 -0
  9. package/dist/services/api/ApiReadControllerClient/index.integration.test.d.ts +1 -0
  10. package/dist/services/api/ApiReadControllerClient/index.integration.test.js +59 -0
  11. package/dist/services/api/HttpService/FetchHttpService.integration.test.d.ts +1 -0
  12. package/dist/services/api/HttpService/FetchHttpService.integration.test.js +52 -0
  13. package/dist/services/api/UserManagementControllerClient/index.d.ts +0 -6
  14. package/dist/services/api/UserManagementControllerClient/index.integration.test.d.ts +1 -0
  15. package/dist/services/api/UserManagementControllerClient/index.integration.test.js +60 -0
  16. package/dist/services/api/UserManagementControllerClient/index.js +0 -29
  17. package/dist/services/auth/client/AuthService/index.d.ts +10 -2
  18. package/dist/services/auth/client/AuthService/index.js +40 -0
  19. package/dist/services/auth/client/AuthorizationManagementControllerClient/index.integration.test.d.ts +1 -0
  20. package/dist/services/auth/client/AuthorizationManagementControllerClient/index.integration.test.js +89 -0
  21. package/package.json +6 -8
  22. package/src/adapters/CollectionViewAdapter/index.integration.test.ts +197 -0
  23. package/src/adapters/SearchAdapter/index.ts +30 -13
  24. package/src/data/api/dto/response/ApiSuccessResponseDto.ts +1 -1
  25. package/src/data/auth/dto/index.ts +1 -0
  26. package/src/services/api/ApiCrudControllerClient/index.integration.test.ts +46 -0
  27. package/src/services/api/ApiReadControllerClient/index.integration.test.ts +71 -0
  28. package/src/services/api/HttpService/FetchHttpService.integration.test.ts +65 -0
  29. package/src/services/api/UserManagementControllerClient/index.integration.test.ts +69 -0
  30. package/src/services/api/UserManagementControllerClient/index.ts +0 -32
  31. package/src/services/auth/client/AuthService/index.ts +48 -2
  32. package/src/services/auth/client/AuthorizationManagementControllerClient/index.integration.test.ts +110 -0
  33. package/vitest-setup.ts +43 -0
  34. package/vitest.config.ts +59 -0
  35. package/jest.config.js +0 -29
  36. package/tests/ApiClients.test.ts +0 -284
  37. package/tests/CollectionViewAdapter.test.ts +0 -392
  38. package/tests/HttpService.test.ts +0 -303
  39. package/tests/setup.ts +0 -76
@@ -0,0 +1,69 @@
1
+ import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
2
+ import { UserManagementControllerClient } from '.';
3
+ import { IHttpService } from '../HttpService';
4
+ import fetchOrig from 'node-fetch';
5
+ import fetchCookie from 'fetch-cookie';
6
+ import { CookieJar } from 'tough-cookie';
7
+
8
+ // Create a fetch instance that handles auth cookies
9
+ const jar = new CookieJar();
10
+ const cookieFetch = fetchCookie(fetchOrig, jar);
11
+ // Custom IHttpService implementation for tests
12
+ class CookieFetchHttpService implements IHttpService {
13
+ async request(url: string, config?: any): Promise<any> {
14
+ const response = await cookieFetch(url, {
15
+ method: config?.method || 'GET',
16
+ headers: config?.headers,
17
+ body: config?.body,
18
+ signal: config?.signal,
19
+ });
20
+ const headers: Record<string, string> = {};
21
+ response.headers.forEach((value, key) => {
22
+ headers[key] = value;
23
+ });
24
+ return {
25
+ ok: response.ok,
26
+ status: response.status,
27
+ statusText: response.statusText,
28
+ headers,
29
+ json: () => response.json(),
30
+ text: () => response.text(),
31
+ };
32
+ }
33
+ }
34
+ const credentials = {
35
+ username: 'admin@test.com',
36
+ password: 'Password1234!',
37
+ };
38
+ const baseUrl = 'http://localhost:5000/api';
39
+
40
+ describe('UserManagementControllerClient', () => {
41
+ let client: UserManagementControllerClient<number, any, any, any, any>;
42
+ let fetchService: CookieFetchHttpService = new CookieFetchHttpService();
43
+
44
+ beforeAll(async () => {
45
+ await fetchService.request(`${baseUrl}/auth/signin`, {
46
+ method: 'POST',
47
+ headers: { 'Content-Type': 'application/json' },
48
+ body: JSON.stringify(credentials),
49
+ });
50
+ });
51
+
52
+ beforeEach(() => {
53
+ client = new UserManagementControllerClient('/users', fetchService);
54
+ });
55
+
56
+ it('should use injected HTTP service for getUserRoles', async () => {
57
+ const result = (await client.getUserRoles(1)) as { ok: boolean; result: any };
58
+
59
+ expect(result.ok).toBe(true);
60
+ expect(result.result).toBeDefined();
61
+ });
62
+
63
+ it('should use injected HTTP service for getUserClaims', async () => {
64
+ const result = (await client.getUserClaims(1)) as { ok: boolean; result: any };
65
+
66
+ expect(result.ok).toBe(true);
67
+ expect(result.result).toBeDefined();
68
+ });
69
+ });
@@ -94,38 +94,6 @@ export class UserManagementControllerClient<
94
94
  }
95
95
  }
96
96
 
97
- /**
98
- * Gets all available roles in the system
99
- * @param {AbortSignal} [signal] - Optional cancellation signal
100
- * @returns List of all role names
101
- */
102
- public async getAllRoles(signal?: AbortSignal): Promise<ApiResponseDto<string[], ReadMetadataDto>> {
103
- try {
104
- const url = await apiInitializationService.getApiUrl(this.baseControllerPath, 'GetAllRoles');
105
- const res = await this.httpService.request(url, {
106
- method: 'GET',
107
- credentials: 'include',
108
- signal,
109
- });
110
-
111
- if (!res.ok) {
112
- return fail<ApiSuccessResponseDto<string[], ReadMetadataDto>, ApiErrorResponseDto>(await res.json());
113
- }
114
-
115
- return ok<ApiSuccessResponseDto<string[], ReadMetadataDto>, ApiErrorResponseDto>(await res.json());
116
- } catch (err) {
117
- console.error(err);
118
-
119
- return fail<ApiSuccessResponseDto<string[], ReadMetadataDto>, ApiErrorResponseDto>({
120
- error: {
121
- code: ErrorCode.UnknownError,
122
- message: 'Unknown error while fetching all roles',
123
- metadata: {} as EmptyMetadataDto,
124
- },
125
- });
126
- }
127
- }
128
-
129
97
  /**
130
98
  * Changes the password for a user
131
99
  * @param id - The ID of the user
@@ -1,5 +1,5 @@
1
1
  import { apiInitializationService, IHttpService } from '@services';
2
- import { ApiErrorResponseDto, ApiResponseDto, ApiSuccessResponseDto, EmptyMetadataDto, ErrorCode, IPolicy, PolicyBase, UserDto, UserInfoDto } from '@data';
2
+ import { ApiErrorResponseDto, ApiResponseDto, ApiSuccessResponseDto, EmptyMetadataDto, ErrorCode, UserDto, UserInfoDto, RegisterRequestDto } from '@data';
3
3
  import { fail, ok } from '@utils';
4
4
 
5
5
  export { UserDto, UserInfoDto };
@@ -11,7 +11,7 @@ export { UserDto, UserInfoDto };
11
11
  * @export
12
12
  * @class AuthService
13
13
  */
14
- export class AuthService<TKey, TUser extends UserDto<TKey> = UserDto<TKey>> {
14
+ export class AuthService<TKey, TRegisterUser extends RegisterRequestDto = RegisterRequestDto, TUser extends UserDto<TKey> = UserDto<TKey>> {
15
15
  /**
16
16
  * Constructor
17
17
  * @param baseControllerPath Base path to Auth API controller
@@ -168,6 +168,52 @@ export class AuthService<TKey, TUser extends UserDto<TKey> = UserDto<TKey>> {
168
168
  }
169
169
  }
170
170
 
171
+ /**
172
+ * Registers a new user by sending user details to the API.
173
+ *
174
+ * @param {TRegisterUser} user User object containing registration data (e.g. username, password, and optionally firstName, lastName, etc.)
175
+ * @return {Promise<ApiResponseDto<TUser, EmptyMetadataDto>>} API response with registered user details or error info
176
+ * @throws {Error} Error if the request fails
177
+ */
178
+ public async register(user: TRegisterUser): Promise<ApiResponseDto<TUser, EmptyMetadataDto>> {
179
+ try {
180
+ const url = await apiInitializationService.getApiUrl(this.baseControllerPath, '/register');
181
+ const res = await this.httpService.request(url, {
182
+ method: 'POST',
183
+ headers: { 'Content-Type': 'application/json' },
184
+ body: JSON.stringify(user),
185
+ credentials: 'include',
186
+ });
187
+
188
+ if (!res.ok) {
189
+ return fail<ApiSuccessResponseDto<TUser, EmptyMetadataDto>, ApiErrorResponseDto>(await res.json());
190
+ }
191
+
192
+ // TODO: Handle tokens if not using cookies
193
+
194
+ const whoAmIRes = await this.whoAmI();
195
+
196
+ if (!whoAmIRes.ok) {
197
+ return whoAmIRes;
198
+ }
199
+
200
+ return ok<ApiSuccessResponseDto<TUser, EmptyMetadataDto>, ApiErrorResponseDto>({
201
+ result: whoAmIRes.result.user,
202
+ metadata: whoAmIRes.metadata,
203
+ });
204
+ } catch (err) {
205
+ console.error(err);
206
+
207
+ return fail<ApiSuccessResponseDto<TUser, EmptyMetadataDto>, ApiErrorResponseDto>({
208
+ error: {
209
+ code: ErrorCode.UnknownError,
210
+ message: 'Failed registering user',
211
+ metadata: {} as EmptyMetadataDto,
212
+ },
213
+ });
214
+ }
215
+ }
216
+
171
217
  /**
172
218
  * If any API response returns an "Unauthenticated" response, call this method
173
219
  * to update local authentication state to unauthenticated
@@ -0,0 +1,110 @@
1
+ import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
2
+ import { AuthorizationManagementControllerClient } from '.';
3
+ import fetchOrig from 'node-fetch';
4
+ import fetchCookie from 'fetch-cookie';
5
+ import { CookieJar } from 'tough-cookie';
6
+ import { IHttpService } from '@/services';
7
+ import { RoleDto } from '@/data';
8
+
9
+ // Create a fetch instance that handles auth cookies
10
+ const jar = new CookieJar();
11
+ const cookieFetch = fetchCookie(fetchOrig, jar);
12
+ // Custom IHttpService implementation for tests
13
+ class CookieFetchHttpService implements IHttpService {
14
+ async request(url: string, config?: any): Promise<any> {
15
+ const response = await cookieFetch(url, {
16
+ method: config?.method || 'GET',
17
+ headers: config?.headers,
18
+ body: config?.body,
19
+ signal: config?.signal,
20
+ });
21
+ const headers: Record<string, string> = {};
22
+ response.headers.forEach((value, key) => {
23
+ headers[key] = value;
24
+ });
25
+ return {
26
+ ok: response.ok,
27
+ status: response.status,
28
+ statusText: response.statusText,
29
+ headers,
30
+ json: () => response.json(),
31
+ text: () => response.text(),
32
+ };
33
+ }
34
+ }
35
+ const credentials = {
36
+ username: 'admin@test.com',
37
+ password: 'Password1234!',
38
+ };
39
+ const baseUrl = 'http://localhost:5000/api';
40
+
41
+ describe('AuthorizationManagementControllerClient', () => {
42
+ let client: AuthorizationManagementControllerClient;
43
+ let fetchService: CookieFetchHttpService = new CookieFetchHttpService();
44
+
45
+ beforeAll(async () => {
46
+ await fetchService.request(`${baseUrl}/auth/signin`, {
47
+ method: 'POST',
48
+ headers: { 'Content-Type': 'application/json' },
49
+ body: JSON.stringify(credentials),
50
+ });
51
+ });
52
+
53
+ beforeEach(() => {
54
+ client = new AuthorizationManagementControllerClient('/AuthorizationManagement', fetchService);
55
+ });
56
+
57
+ it('should fetch all roles', async () => {
58
+ const result = (await client.getAllRoles(false)) as { ok: boolean; result: any };
59
+
60
+ expect(result.ok).toBe(true);
61
+ expect(result.result).toBeDefined();
62
+ });
63
+
64
+ it('should fetch all roles with claims', async () => {
65
+ const result = (await client.getAllRoles(true)) as { ok: boolean; result: any };
66
+
67
+ expect(result.ok).toBe(true);
68
+ expect(result.result).toBeDefined();
69
+ expect(result.result[0].claims).toBeDefined();
70
+ });
71
+
72
+ it('should return role with claims by name', async () => {
73
+ const newRole: RoleDto = { name: 'New Role Test Claims', claims: [{ type: 'Test Claim Type', value: 'Test Claim Value' }] };
74
+
75
+ const create = (await client.upsertRole(newRole)) as { ok: boolean; result: any };
76
+
77
+ expect(create.ok).toBe(true);
78
+
79
+ const result = (await client.getRoleWithClaims(newRole.name)) as { ok: boolean; result: any };
80
+
81
+ expect(result.ok).toBe(true);
82
+ expect(result.result).toBeDefined();
83
+ expect(result.result.claims).toBeDefined();
84
+ expect(result.result.name).toBe(newRole.name);
85
+ expect(result.result.claims.length).toBe(newRole.claims.length);
86
+ expect(result.result.claims).toEqual(newRole.claims);
87
+ });
88
+
89
+ it('should create a new role with claims', async () => {
90
+ const newRole: RoleDto = { name: 'New Role', claims: [{ type: 'Test Claim Type', value: 'Test Claim Value' }] };
91
+
92
+ const result = (await client.upsertRole(newRole)) as { ok: boolean; result: any };
93
+
94
+ expect(result.ok).toBe(true);
95
+ expect(result.result).toBeDefined();
96
+ expect(result.result.name).toBe(newRole.name);
97
+ expect(result.result.claims.length).toBe(newRole.claims.length);
98
+ expect(result.result.claims).toEqual(newRole.claims);
99
+ });
100
+
101
+ it('should delete role', async () => {
102
+ const role: RoleDto = { name: 'Temp Role', claims: [] };
103
+
104
+ const create = (await client.upsertRole(role)) as { ok: boolean; result: any };
105
+ expect(create.ok).toBe(true);
106
+
107
+ const deleteResult = await client.deleteRole(role.name);
108
+ expect(deleteResult.ok).toBe(true);
109
+ });
110
+ });
@@ -0,0 +1,43 @@
1
+ import { vi } from 'vitest';
2
+ import fetch from 'node-fetch';
3
+
4
+ // Global fetch mock for Vitest integration tests.
5
+ // Purpose:
6
+ // - Provide deterministic configuration for app/service initialization that loads `websettings.json`
7
+ // - Only fetch requests for `websettings.json` are mocked; all other network requests are real
8
+ //
9
+ // Any fetch request that targets `websettings.json` (typically during app or service init) will receive a mocked response.
10
+ // All other requests are forwarded to the real `node-fetch` implementation, so real network requests are still possible in tests.
11
+
12
+ const MOCKED_WEBSETTINGS_JSON = {
13
+ api: 'http://localhost:5000/api',
14
+ };
15
+
16
+ // Use new Headers() to simulate Fetch API Headers behavior.
17
+ // This ensures compatibility with code that uses headers.forEach() for iteration.
18
+ const MOCKED_RESPONSE_HEADERS = new Headers({
19
+ 'Content-Type': 'application/json',
20
+ });
21
+
22
+ const mockFetch = vi.fn(async (url: string, config?: RequestInit) => {
23
+ if (url.includes('websettings.json')) {
24
+ return {
25
+ ok: true,
26
+ status: 200,
27
+ statusText: 'OK',
28
+
29
+ // Minimal Headers mock for compatibility with project code.
30
+ headers: MOCKED_RESPONSE_HEADERS,
31
+
32
+ // Mocked JSON payload returned by fetch().json()
33
+ json: vi.fn<() => Promise<any>>().mockResolvedValue(MOCKED_WEBSETTINGS_JSON),
34
+ };
35
+ }
36
+
37
+ // Forward all non-config requests to the real fetch implementation.
38
+ // `any` cast is intentional to avoid RequestInit type mismatches in Node.
39
+ return fetch(url, config as any);
40
+ });
41
+
42
+ // Override global fetch for all tests
43
+ global.fetch = mockFetch as any;
@@ -0,0 +1,59 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ import path from 'path';
3
+ import tsconfigPaths from 'vite-tsconfig-paths';
4
+
5
+ const aliasConfig = {
6
+ '@': path.resolve(__dirname, './src'),
7
+ '@adapters': path.resolve(__dirname, './src/adapters'),
8
+ '@data': path.resolve(__dirname, './src/data'),
9
+ '@data/*': path.resolve(__dirname, './src/data/*'),
10
+ '@services': path.resolve(__dirname, './src/services'),
11
+ '@utils': path.resolve(__dirname, './src/utils'),
12
+ };
13
+
14
+ export default defineConfig({
15
+ plugins: [tsconfigPaths()],
16
+ test: {
17
+ projects: [
18
+ {
19
+ resolve: {
20
+ alias: aliasConfig,
21
+ },
22
+ test: {
23
+ name: 'unit',
24
+ environment: 'jsdom',
25
+ testTimeout: 60000,
26
+ include: ['./**/*.unit.test.{ts,tsx,js}', '**/*.unit.test.{ts,tsx,js}'],
27
+ exclude: ['**/node_modules/**', '**/dist/**'],
28
+ },
29
+ },
30
+ {
31
+ resolve: {
32
+ alias: aliasConfig,
33
+ },
34
+ test: {
35
+ name: 'integration',
36
+ environment: 'jsdom',
37
+ testTimeout: 60000,
38
+ globalSetup: [path.resolve(__dirname, '../../vitest-setup-integration.ts')],
39
+ setupFiles: [path.resolve(__dirname, './vitest-setup.ts')],
40
+ include: ['./**/*.integration.test.{ts,tsx,js}', '**/*.integration.test.{ts,tsx,js}'],
41
+ exclude: ['**/node_modules/**', '**/dist/**'],
42
+ },
43
+ },
44
+ {
45
+ resolve: {
46
+ alias: aliasConfig,
47
+ },
48
+ test: {
49
+ name: 'debug',
50
+ testTimeout: 60000,
51
+ globalSetup: [path.resolve(__dirname, '../../vitest-setup-integration.ts')],
52
+ setupFiles: [path.resolve(__dirname, './vitest-setup.ts')],
53
+ include: ['./**/*.{test,spec,debug}.{js,ts}'],
54
+ exclude: ['**/node_modules/**', '**/dist/**'],
55
+ },
56
+ },
57
+ ],
58
+ },
59
+ });
package/jest.config.js DELETED
@@ -1,29 +0,0 @@
1
- export default {
2
- preset: 'ts-jest/presets/default-esm',
3
- extensionsToTreatAsEsm: ['.ts'],
4
- testEnvironment: 'jsdom',
5
- roots: ['<rootDir>/src', '<rootDir>/tests'],
6
- testMatch: ['**/__tests__/**/*.+(ts|tsx|js)', '**/*.(test|spec).+(ts|tsx|js)'],
7
- transform: {
8
- '^.+\\.(ts|tsx)$': [
9
- 'ts-jest',
10
- {
11
- useESM: true,
12
- },
13
- ],
14
- },
15
- collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/**/*.d.ts', '!src/**/index.ts'],
16
- moduleNameMapper: {
17
- '^@/(.*)$': '<rootDir>/src/$1',
18
- '^@adapters/(.*)$': '<rootDir>/src/adapters/$1',
19
- '^@adapters$': '<rootDir>/src/adapters',
20
- '^@data/(.*)$': '<rootDir>/src/data/$1',
21
- '^@data$': '<rootDir>/src/data',
22
- '^@services/(.*)$': '<rootDir>/src/services/$1',
23
- '^@services$': '<rootDir>/src/services',
24
- '^@utils/(.*)$': '<rootDir>/src/utils/$1',
25
- '^@utils$': '<rootDir>/src/utils',
26
- },
27
- setupFilesAfterEnv: ['<rootDir>/tests/setup.ts'],
28
- testTimeout: 10000,
29
- };