@platform-mesh/portal-server-lib 0.11.17 → 0.12.0
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.
- package/AGENTS.md +2 -2
- package/CONTRIBUTING.md +1 -1
- package/README.md +1 -1
- package/package.json +18 -21
- package/src/portal-options/auth-config-provider.spec.ts +20 -19
- package/src/portal-options/logout-callback.service.spec.ts +14 -13
- package/src/portal-options/pm-portal-context.service.spec.ts +17 -16
- package/src/portal-options/pm-request-context-provider.spec.ts +15 -14
- package/src/portal-options/service-providers/content-configuration-service-providers.service.spec.ts +15 -10
- package/src/portal-options/service-providers/kubernetes-service-providers.service.spec.ts +32 -29
- package/src/portal-options/services/kcp-k8s.service.spec.ts +43 -37
- package/src/portal-options/services/permissions/adapters/authz-webhook.service.spec.ts +4 -3
- package/src/portal-options/services/permissions/permissions-proxy.service.spec.ts +3 -2
- package/src/portal-options/services/permissions/permissions.controller.spec.ts +4 -3
- package/src/portal-options/utils/domain.spec.ts +2 -2
- package/src/portal-options/utils/portal-web-component-modules.spec.ts +3 -3
- package/tsconfig.build.json +1 -2
- package/tsconfig.json +1 -1
- package/vitest.config.ts +20 -0
- package/base.jest.config.js +0 -15
- package/jest.config.ts +0 -42
- package/tsconfig.test.json +0 -3
package/AGENTS.md
CHANGED
|
@@ -36,7 +36,7 @@ npm run test:cov # alias for npm run test
|
|
|
36
36
|
npm run test:watch # run tests in watch mode (no coverage)
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Tests use **
|
|
39
|
+
Tests use **Vitest** (`vitest.config.ts`). Coverage is collected with the V8 provider and enforced at:
|
|
40
40
|
|
|
41
41
|
- **Branches: 75%**
|
|
42
42
|
- **Functions: 89%**
|
|
@@ -87,7 +87,7 @@ portal-server-lib/
|
|
|
87
87
|
│ ├── account-hierarchy-resolver.ts # account path / entity type manipulation
|
|
88
88
|
│ ├── domain.ts # getOrganization, getDiscoveryEndpoint
|
|
89
89
|
│ └── replace-string-deep.ts # deep string replacement utility
|
|
90
|
-
├──
|
|
90
|
+
├── vitest.config.ts
|
|
91
91
|
├── nest-cli.json
|
|
92
92
|
├── tsconfig.json
|
|
93
93
|
└── package.json
|
package/CONTRIBUTING.md
CHANGED
|
@@ -27,7 +27,7 @@ The build artifacts will be stored in the `dist/` directory.
|
|
|
27
27
|
|
|
28
28
|
> **NOTE:** You should always add tests, if you are adding code to our repository.
|
|
29
29
|
|
|
30
|
-
Run `npm test` to execute the unit tests via [
|
|
30
|
+
Run `npm test` to execute the unit tests via [Vitest](https://vitest.dev/) in the root directory of the repository.
|
|
31
31
|
|
|
32
32
|
## Issues
|
|
33
33
|
|
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platform-mesh/portal-server-lib",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"author": "Platform Mesh",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -31,19 +31,19 @@
|
|
|
31
31
|
"build:watch": "mkdirp dist && nodemon --ignore dist --ext js,yml,yaml,ts,html,css,scss,json,md --exec \"rimraf dist && npm run build && yalc publish --push --sig\"",
|
|
32
32
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" \"libs/**/*.ts\"",
|
|
33
33
|
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
|
34
|
-
"test": "
|
|
35
|
-
"test:watch": "
|
|
36
|
-
"test:cov": "
|
|
37
|
-
"test:debug": "
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"test:watch": "vitest --coverage.enabled=false",
|
|
36
|
+
"test:cov": "vitest run",
|
|
37
|
+
"test:debug": "vitest run --inspect-brk --no-file-parallelism --coverage.enabled=false"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"@kubernetes/client-node": "^2.0.0",
|
|
41
|
-
"@nestjs/axios": "^4.0.1",
|
|
42
|
-
"@nestjs/common": "^11.1.17",
|
|
43
|
-
"@nestjs/core": "^11.1.9",
|
|
44
|
-
"@nestjs/platform-express": "^11.1.18",
|
|
45
|
-
"@nestjs/serve-static": "^5.0.5",
|
|
46
|
-
"@openmfp/portal-server-lib": "^0.163.7 || ^0.164.0 || ^0.165.1",
|
|
41
|
+
"@nestjs/axios": "^4.0.1 || ^12.0.0",
|
|
42
|
+
"@nestjs/common": "^11.1.17 || ^12.0.0",
|
|
43
|
+
"@nestjs/core": "^11.1.9 || ^12.0.0",
|
|
44
|
+
"@nestjs/platform-express": "^11.1.18 || ^12.0.0",
|
|
45
|
+
"@nestjs/serve-static": "^5.0.5 || ^12.0.0",
|
|
46
|
+
"@openmfp/portal-server-lib": "^0.163.7 || ^0.164.0 || ^0.165.1 || ^0.166.0",
|
|
47
47
|
"axios": "^1.15.0",
|
|
48
48
|
"cookie-parser": "^1.4.7",
|
|
49
49
|
"express": "^5.2.1",
|
|
@@ -53,31 +53,28 @@
|
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@eslint/js": "10.0.1",
|
|
55
55
|
"@kubernetes/client-node": "2.0.0",
|
|
56
|
-
"@nestjs/cli": "
|
|
57
|
-
"@nestjs/testing": "
|
|
56
|
+
"@nestjs/cli": "12.0.11",
|
|
57
|
+
"@nestjs/testing": "12.3.3",
|
|
58
58
|
"@openmfp/config-prettier": "0.9.3",
|
|
59
|
-
"@types/jest": "30.0.0",
|
|
60
59
|
"@types/node": "26.6.5",
|
|
61
60
|
"@types/supertest": "7.2.1",
|
|
62
61
|
"eslint": "10.8.0",
|
|
63
62
|
"eslint-config-prettier": "10.1.8",
|
|
64
63
|
"globals": "17.9.0",
|
|
65
|
-
"jest": "30.4.2",
|
|
66
|
-
"jest-junit": "16.0.0",
|
|
67
|
-
"jest-mock-extended": "4.0.1",
|
|
68
64
|
"mkdirp": "3.0.1",
|
|
69
|
-
"nock": "
|
|
65
|
+
"nock": "15.0.5",
|
|
70
66
|
"nodemon": "3.1.14",
|
|
71
67
|
"prettier": "3.9.6",
|
|
72
68
|
"rimraf": "6.1.3",
|
|
73
69
|
"supertest": "7.2.2",
|
|
74
|
-
"ts-jest": "29.4.12",
|
|
75
70
|
"ts-loader": "9.6.2",
|
|
76
|
-
"ts-node": "10.9.2",
|
|
77
71
|
"tsconfig-paths": "4.2.0",
|
|
78
72
|
"typescript": "5.9.3",
|
|
79
73
|
"typescript-eslint": "8.65.0",
|
|
80
|
-
"uri-js": "4.4.1"
|
|
74
|
+
"uri-js": "4.4.1",
|
|
75
|
+
"vitest": "5.1.0",
|
|
76
|
+
"@vitest/coverage-v8": "5.1.0",
|
|
77
|
+
"vitest-mock-extended": "5.1.1"
|
|
81
78
|
},
|
|
82
79
|
"type": "module",
|
|
83
80
|
"overrides": {
|
|
@@ -5,37 +5,38 @@ import * as domainUtils from './utils/domain.js';
|
|
|
5
5
|
import { HttpException, HttpStatus } from '@nestjs/common';
|
|
6
6
|
import { DiscoveryService } from '@openmfp/portal-server-lib';
|
|
7
7
|
import type { Request } from 'express';
|
|
8
|
-
import { mock } from '
|
|
8
|
+
import { mock } from 'vitest-mock-extended';
|
|
9
|
+
import type { Mocked } from 'vitest';
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
const mockReadNamespacedSecret =
|
|
11
|
+
vi.mock('@kubernetes/client-node', () => {
|
|
12
|
+
const mockReadNamespacedSecret = vi.fn();
|
|
12
13
|
class KubeConfig {
|
|
13
|
-
loadFromDefault =
|
|
14
|
-
loadFromFile =
|
|
15
|
-
getCurrentCluster =
|
|
14
|
+
loadFromDefault = vi.fn();
|
|
15
|
+
loadFromFile = vi.fn();
|
|
16
|
+
getCurrentCluster = vi.fn().mockReturnValue({
|
|
16
17
|
server: 'https://k8s.example.com',
|
|
17
18
|
name: 'test-cluster',
|
|
18
19
|
});
|
|
19
|
-
makeApiClient =
|
|
20
|
+
makeApiClient = vi.fn().mockReturnValue({
|
|
20
21
|
readNamespacedSecret: mockReadNamespacedSecret,
|
|
21
22
|
});
|
|
22
|
-
addUser =
|
|
23
|
-
addContext =
|
|
24
|
-
setCurrentContext =
|
|
23
|
+
addUser = vi.fn();
|
|
24
|
+
addContext = vi.fn();
|
|
25
|
+
setCurrentContext = vi.fn();
|
|
25
26
|
}
|
|
26
27
|
class CoreV1Api {}
|
|
27
28
|
class CustomObjectsApi {}
|
|
28
29
|
return { KubeConfig, CoreV1Api, CustomObjectsApi, mockReadNamespacedSecret };
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
vi.mock('@kubernetes/client-node/dist/gen/middleware.js', () => ({
|
|
32
33
|
PromiseMiddlewareWrapper: class {},
|
|
33
34
|
}));
|
|
34
35
|
|
|
35
36
|
describe('PMAuthConfigProvider', () => {
|
|
36
37
|
let provider: PMAuthConfigProvider;
|
|
37
|
-
let discoveryService:
|
|
38
|
-
let kcpKubernetesService:
|
|
38
|
+
let discoveryService: Mocked<DiscoveryService>;
|
|
39
|
+
let kcpKubernetesService: Mocked<KcpKubernetesService>;
|
|
39
40
|
let mockRequest: Request;
|
|
40
41
|
|
|
41
42
|
const mockOidcDiscovery = {
|
|
@@ -58,18 +59,18 @@ describe('PMAuthConfigProvider', () => {
|
|
|
58
59
|
TOKEN_URL_DEFAULT: 'https://default-auth.com/token',
|
|
59
60
|
};
|
|
60
61
|
|
|
61
|
-
|
|
62
|
+
vi
|
|
62
63
|
.spyOn(domainUtils, 'getDiscoveryEndpoint')
|
|
63
64
|
.mockReturnValue(
|
|
64
65
|
'https://oidc.example.com/.well-known/openid-configuration',
|
|
65
66
|
);
|
|
66
|
-
|
|
67
|
+
vi.spyOn(domainUtils, 'getOrganization').mockReturnValue('org1');
|
|
67
68
|
|
|
68
69
|
discoveryService.getOIDC.mockResolvedValue(mockOidcDiscovery);
|
|
69
70
|
});
|
|
70
71
|
|
|
71
72
|
afterEach(() => {
|
|
72
|
-
|
|
73
|
+
vi.clearAllMocks();
|
|
73
74
|
});
|
|
74
75
|
|
|
75
76
|
describe('getAuthConfig', () => {
|
|
@@ -118,7 +119,7 @@ describe('PMAuthConfigProvider', () => {
|
|
|
118
119
|
});
|
|
119
120
|
|
|
120
121
|
it('should handle welcome organization', async () => {
|
|
121
|
-
|
|
122
|
+
vi.spyOn(domainUtils, 'getOrganization').mockReturnValue('welcome');
|
|
122
123
|
|
|
123
124
|
const mockIdpConfig: IdentityProviderConfiguration = {
|
|
124
125
|
status: {
|
|
@@ -300,7 +301,7 @@ describe('PMAuthConfigProvider', () => {
|
|
|
300
301
|
|
|
301
302
|
try {
|
|
302
303
|
await provider.getAuthConfig(mockRequest);
|
|
303
|
-
fail('Should have thrown HttpException');
|
|
304
|
+
expect.fail('Should have thrown HttpException');
|
|
304
305
|
} catch (error) {
|
|
305
306
|
expect(error).toBeInstanceOf(HttpException);
|
|
306
307
|
const response = (error as HttpException).getResponse() as any;
|
|
@@ -481,7 +482,7 @@ describe('PMAuthConfigProvider', () => {
|
|
|
481
482
|
|
|
482
483
|
try {
|
|
483
484
|
await provider.getAuthConfig(mockRequest);
|
|
484
|
-
fail('Should have thrown');
|
|
485
|
+
expect.fail('Should have thrown');
|
|
485
486
|
} catch (error) {
|
|
486
487
|
const response = (error as HttpException).getResponse() as any;
|
|
487
488
|
expect(response.error).toContain('has client secret: false');
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from '@openmfp/portal-server-lib';
|
|
9
9
|
import { Request, Response } from 'express';
|
|
10
10
|
import { of, throwError } from 'rxjs';
|
|
11
|
+
import type { Mock } from 'vitest';
|
|
11
12
|
|
|
12
13
|
describe('PMLogoutService', () => {
|
|
13
14
|
let service: PMLogoutService;
|
|
@@ -21,15 +22,15 @@ describe('PMLogoutService', () => {
|
|
|
21
22
|
PMLogoutService,
|
|
22
23
|
{
|
|
23
24
|
provide: HttpService,
|
|
24
|
-
useValue: { post:
|
|
25
|
+
useValue: { post: vi.fn() },
|
|
25
26
|
},
|
|
26
27
|
{
|
|
27
28
|
provide: AUTH_CONFIG_INJECTION_TOKEN,
|
|
28
|
-
useValue: { getAuthConfig:
|
|
29
|
+
useValue: { getAuthConfig: vi.fn() },
|
|
29
30
|
},
|
|
30
31
|
{
|
|
31
32
|
provide: CookiesService,
|
|
32
|
-
useValue: { getAuthCookie:
|
|
33
|
+
useValue: { getAuthCookie: vi.fn() },
|
|
33
34
|
},
|
|
34
35
|
{
|
|
35
36
|
provide: 'AUTH_CONFIG_INJECTION_TOKEN',
|
|
@@ -48,15 +49,15 @@ describe('PMLogoutService', () => {
|
|
|
48
49
|
const mockRequest = {} as Request;
|
|
49
50
|
const mockResponse = {} as Response;
|
|
50
51
|
|
|
51
|
-
(authConfigService.getAuthConfig as
|
|
52
|
+
(authConfigService.getAuthConfig as Mock).mockResolvedValue({
|
|
52
53
|
clientId: 'client-id',
|
|
53
54
|
clientSecret: 'secret',
|
|
54
55
|
endSessionUrl: 'https://keycloak/logout',
|
|
55
56
|
});
|
|
56
|
-
(cookiesService.getAuthCookie as
|
|
57
|
+
(cookiesService.getAuthCookie as Mock).mockReturnValue(
|
|
57
58
|
'refresh-token',
|
|
58
59
|
);
|
|
59
|
-
(httpService.post as
|
|
60
|
+
(httpService.post as Mock).mockReturnValue(of({ data: {} }));
|
|
60
61
|
|
|
61
62
|
await service.handleLogout(mockRequest, mockResponse);
|
|
62
63
|
|
|
@@ -74,19 +75,19 @@ describe('PMLogoutService', () => {
|
|
|
74
75
|
const mockRequest = {} as Request;
|
|
75
76
|
const mockResponse = {} as Response;
|
|
76
77
|
|
|
77
|
-
(authConfigService.getAuthConfig as
|
|
78
|
+
(authConfigService.getAuthConfig as Mock).mockResolvedValue({
|
|
78
79
|
clientId: 'client-id',
|
|
79
80
|
clientSecret: 'secret',
|
|
80
81
|
endSessionUrl: 'https://keycloak/logout',
|
|
81
82
|
});
|
|
82
|
-
(cookiesService.getAuthCookie as
|
|
83
|
+
(cookiesService.getAuthCookie as Mock).mockReturnValue(
|
|
83
84
|
'refresh-token',
|
|
84
85
|
);
|
|
85
|
-
(httpService.post as
|
|
86
|
+
(httpService.post as Mock).mockReturnValue(of({ data: {} }));
|
|
86
87
|
|
|
87
88
|
await service.handleLogout(mockRequest, mockResponse);
|
|
88
89
|
|
|
89
|
-
const body = (httpService.post as
|
|
90
|
+
const body = (httpService.post as Mock).mock
|
|
90
91
|
.calls[0][1] as URLSearchParams;
|
|
91
92
|
expect(body.get('refresh_token')).toBe('refresh-token');
|
|
92
93
|
expect(body.get('client_secret')).toBeNull();
|
|
@@ -102,15 +103,15 @@ describe('PMLogoutService', () => {
|
|
|
102
103
|
} as unknown as Request;
|
|
103
104
|
const mockResponse = {} as Response;
|
|
104
105
|
|
|
105
|
-
(authConfigService.getAuthConfig as
|
|
106
|
+
(authConfigService.getAuthConfig as Mock).mockResolvedValue({
|
|
106
107
|
clientId: 'client-id',
|
|
107
108
|
clientSecret: 'secret',
|
|
108
109
|
endSessionUrl: 'https://keycloak/logout',
|
|
109
110
|
});
|
|
110
|
-
(cookiesService.getAuthCookie as
|
|
111
|
+
(cookiesService.getAuthCookie as Mock).mockReturnValue(
|
|
111
112
|
'refresh-token',
|
|
112
113
|
);
|
|
113
|
-
(httpService.post as
|
|
114
|
+
(httpService.post as Mock).mockReturnValue(
|
|
114
115
|
throwError(() => new Error('Network error')),
|
|
115
116
|
);
|
|
116
117
|
|
|
@@ -3,38 +3,39 @@ import { KcpKubernetesService } from './services/kcp-k8s.service.js';
|
|
|
3
3
|
import { getOrganization } from './utils/domain.js';
|
|
4
4
|
import { Test, TestingModule } from '@nestjs/testing';
|
|
5
5
|
import { Request } from 'express';
|
|
6
|
-
import { mock } from '
|
|
6
|
+
import { mock } from 'vitest-mock-extended';
|
|
7
7
|
import process from 'node:process';
|
|
8
|
+
import type { Mocked } from 'vitest';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
vi.mock('@kubernetes/client-node', () => {
|
|
10
11
|
class KubeConfig {
|
|
11
|
-
loadFromDefault =
|
|
12
|
-
loadFromFile =
|
|
13
|
-
getCurrentCluster =
|
|
12
|
+
loadFromDefault = vi.fn();
|
|
13
|
+
loadFromFile = vi.fn();
|
|
14
|
+
getCurrentCluster = vi.fn().mockReturnValue({
|
|
14
15
|
server: 'https://k8s.example.com/base',
|
|
15
16
|
name: 'test-cluster',
|
|
16
17
|
});
|
|
17
|
-
makeApiClient =
|
|
18
|
-
addUser =
|
|
19
|
-
addContext =
|
|
20
|
-
setCurrentContext =
|
|
18
|
+
makeApiClient = vi.fn();
|
|
19
|
+
addUser = vi.fn();
|
|
20
|
+
addContext = vi.fn();
|
|
21
|
+
setCurrentContext = vi.fn();
|
|
21
22
|
}
|
|
22
23
|
class CustomObjectsApi {}
|
|
23
24
|
return { KubeConfig, CustomObjectsApi };
|
|
24
25
|
});
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
getOrganization:
|
|
27
|
+
vi.mock('./utils/domain.js', () => ({
|
|
28
|
+
getOrganization: vi.fn(),
|
|
28
29
|
}));
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
vi.mock('@kubernetes/client-node/dist/gen/middleware.js', () => ({
|
|
31
32
|
PromiseMiddlewareWrapper: class {},
|
|
32
33
|
}));
|
|
33
34
|
|
|
34
35
|
describe('PMPortalContextService', () => {
|
|
35
36
|
let service: PMPortalContextService;
|
|
36
|
-
let kcpKubernetesServiceMock:
|
|
37
|
-
const mockedGetDomainAndOrganization =
|
|
37
|
+
let kcpKubernetesServiceMock: Mocked<KcpKubernetesService>;
|
|
38
|
+
const mockedGetDomainAndOrganization = vi.mocked(getOrganization);
|
|
38
39
|
let mockRequest: any;
|
|
39
40
|
|
|
40
41
|
beforeEach(async () => {
|
|
@@ -54,11 +55,11 @@ describe('PMPortalContextService', () => {
|
|
|
54
55
|
hostname: 'test.example.com',
|
|
55
56
|
};
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
58
59
|
});
|
|
59
60
|
|
|
60
61
|
afterEach(() => {
|
|
61
|
-
|
|
62
|
+
vi.restoreAllMocks();
|
|
62
63
|
});
|
|
63
64
|
|
|
64
65
|
it('should be defined', () => {
|
|
@@ -2,39 +2,40 @@ import { PMRequestContextProvider } from './pm-request-context-provider.js';
|
|
|
2
2
|
import { getOrganization } from './utils/domain.js';
|
|
3
3
|
import { PortalContextProviderImpl } from '@openmfp/portal-server-lib';
|
|
4
4
|
import type { Request } from 'express';
|
|
5
|
-
import { mock } from '
|
|
5
|
+
import { mock } from 'vitest-mock-extended';
|
|
6
|
+
import type { Mock } from 'vitest';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
vi.mock('@kubernetes/client-node', () => {
|
|
8
9
|
class KubeConfig {
|
|
9
|
-
loadFromDefault =
|
|
10
|
-
loadFromFile =
|
|
11
|
-
getCurrentCluster =
|
|
10
|
+
loadFromDefault = vi.fn();
|
|
11
|
+
loadFromFile = vi.fn();
|
|
12
|
+
getCurrentCluster = vi.fn().mockReturnValue({
|
|
12
13
|
server: 'https://k8s.example.com/base',
|
|
13
14
|
name: 'test-cluster',
|
|
14
15
|
});
|
|
15
|
-
makeApiClient =
|
|
16
|
-
addUser =
|
|
17
|
-
addContext =
|
|
18
|
-
setCurrentContext =
|
|
16
|
+
makeApiClient = vi.fn();
|
|
17
|
+
addUser = vi.fn();
|
|
18
|
+
addContext = vi.fn();
|
|
19
|
+
setCurrentContext = vi.fn();
|
|
19
20
|
}
|
|
20
21
|
class CustomObjectsApi {}
|
|
21
22
|
return { KubeConfig, CustomObjectsApi };
|
|
22
23
|
});
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
getOrganization:
|
|
25
|
+
vi.mock('./utils/domain.js', () => ({
|
|
26
|
+
getOrganization: vi.fn(),
|
|
26
27
|
}));
|
|
27
28
|
|
|
28
29
|
describe('PMRequestContextProvider', () => {
|
|
29
30
|
let provider: PMRequestContextProvider;
|
|
30
31
|
const portalContextService = mock<PortalContextProviderImpl>();
|
|
31
|
-
const mockedGetOrganization =
|
|
32
|
+
const mockedGetOrganization = vi.mocked(getOrganization);
|
|
32
33
|
|
|
33
34
|
beforeEach(() => {
|
|
34
|
-
|
|
35
|
+
vi.resetAllMocks();
|
|
35
36
|
mockedGetOrganization.mockReturnValue('org1');
|
|
36
37
|
(
|
|
37
|
-
portalContextService.getContextValues as unknown as
|
|
38
|
+
portalContextService.getContextValues as unknown as Mock
|
|
38
39
|
).mockResolvedValue({
|
|
39
40
|
crdGatewayApiUrl: 'http://gateway/graphql',
|
|
40
41
|
other: 'x',
|
package/src/portal-options/service-providers/content-configuration-service-providers.service.spec.ts
CHANGED
|
@@ -3,12 +3,15 @@ import { PermissionsProxyService } from '../services/permissions/permissions-pro
|
|
|
3
3
|
import { ContentConfigurationServiceProvidersService } from './content-configuration-service-providers.service.js';
|
|
4
4
|
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
5
5
|
import { GraphQLClient } from 'graphql-request';
|
|
6
|
+
import type { Mock, Mocked } from 'vitest';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
vi.mock('graphql-request', () => {
|
|
8
9
|
return {
|
|
9
|
-
GraphQLClient:
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
GraphQLClient: vi.fn().mockImplementation(function () {
|
|
11
|
+
return {
|
|
12
|
+
request: vi.fn(),
|
|
13
|
+
};
|
|
14
|
+
}),
|
|
12
15
|
gql(query: TemplateStringsArray) {
|
|
13
16
|
return query[0];
|
|
14
17
|
},
|
|
@@ -17,19 +20,21 @@ jest.mock('graphql-request', () => {
|
|
|
17
20
|
|
|
18
21
|
describe('ContentConfigurationServiceProvidersService', () => {
|
|
19
22
|
let service: ContentConfigurationServiceProvidersService;
|
|
20
|
-
let mockClient:
|
|
23
|
+
let mockClient: Mocked<GraphQLClient>;
|
|
21
24
|
let context: RequestContext;
|
|
22
|
-
let permissionsProxyService:
|
|
25
|
+
let permissionsProxyService: Mocked<PermissionsProxyService>;
|
|
23
26
|
|
|
24
27
|
beforeEach(() => {
|
|
25
28
|
permissionsProxyService = {
|
|
26
|
-
resolvePermissions:
|
|
27
|
-
} as unknown as
|
|
29
|
+
resolvePermissions: vi.fn().mockResolvedValue([]),
|
|
30
|
+
} as unknown as Mocked<PermissionsProxyService>;
|
|
28
31
|
service = new ContentConfigurationServiceProvidersService(
|
|
29
32
|
permissionsProxyService,
|
|
30
33
|
);
|
|
31
34
|
mockClient = new GraphQLClient('') as any;
|
|
32
|
-
(GraphQLClient as
|
|
35
|
+
(GraphQLClient as Mock).mockImplementation(function () {
|
|
36
|
+
return mockClient;
|
|
37
|
+
});
|
|
33
38
|
context = {
|
|
34
39
|
isSubDomain: true,
|
|
35
40
|
organization: 'org1',
|
|
@@ -46,7 +51,7 @@ describe('ContentConfigurationServiceProvidersService', () => {
|
|
|
46
51
|
});
|
|
47
52
|
|
|
48
53
|
it.each([{ entities: [] }, { entities: ['core_platform-mesh_io_account'] }])(
|
|
49
|
-
'normalizes root and entity configuration through the GraphQL provider for %
|
|
54
|
+
'normalizes root and entity configuration through the GraphQL provider for %o',
|
|
50
55
|
async ({ entities }) => {
|
|
51
56
|
const config = {
|
|
52
57
|
name: 'accounts',
|
|
@@ -5,37 +5,38 @@ import { KubernetesServiceProvidersService } from './kubernetes-service-provider
|
|
|
5
5
|
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
6
6
|
import { Test, TestingModule } from '@nestjs/testing';
|
|
7
7
|
import { ContentConfiguration } from '@openmfp/portal-server-lib';
|
|
8
|
-
import { mock } from '
|
|
8
|
+
import { mock } from 'vitest-mock-extended';
|
|
9
|
+
import type { Mocked } from 'vitest';
|
|
9
10
|
|
|
10
|
-
const listClusterCustomObject =
|
|
11
|
+
const listClusterCustomObject = vi.fn();
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
vi.mock('@kubernetes/client-node', () => {
|
|
13
14
|
class KubeConfig {
|
|
14
|
-
loadFromDefault =
|
|
15
|
-
loadFromFile =
|
|
16
|
-
getCurrentCluster =
|
|
15
|
+
loadFromDefault = vi.fn();
|
|
16
|
+
loadFromFile = vi.fn();
|
|
17
|
+
getCurrentCluster = vi.fn().mockReturnValue({
|
|
17
18
|
server: 'https://k8s.example.com/base',
|
|
18
19
|
name: 'test-cluster',
|
|
19
20
|
});
|
|
20
|
-
makeApiClient =
|
|
21
|
+
makeApiClient = vi.fn().mockImplementation(() => ({
|
|
21
22
|
listClusterCustomObject,
|
|
22
23
|
}));
|
|
23
|
-
addUser =
|
|
24
|
-
addContext =
|
|
25
|
-
setCurrentContext =
|
|
24
|
+
addUser = vi.fn();
|
|
25
|
+
addContext = vi.fn();
|
|
26
|
+
setCurrentContext = vi.fn();
|
|
26
27
|
}
|
|
27
28
|
class CustomObjectsApi {}
|
|
28
29
|
return { KubeConfig, CustomObjectsApi };
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
vi.mock('@kubernetes/client-node/dist/gen/middleware.js', () => ({
|
|
32
33
|
PromiseMiddlewareWrapper: class {},
|
|
33
34
|
}));
|
|
34
35
|
|
|
35
36
|
describe('KubernetesServiceProvidersService', () => {
|
|
36
37
|
let service: KubernetesServiceProvidersService;
|
|
37
|
-
let kcpKubernetesServiceMock:
|
|
38
|
-
let permissionsProxyServiceMock:
|
|
38
|
+
let kcpKubernetesServiceMock: Mocked<KcpKubernetesService>;
|
|
39
|
+
let permissionsProxyServiceMock: Mocked<PermissionsProxyService>;
|
|
39
40
|
|
|
40
41
|
const mockToken = 'test-token-123';
|
|
41
42
|
const mockEntities = ['test-entity'];
|
|
@@ -47,8 +48,8 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
47
48
|
beforeEach(async () => {
|
|
48
49
|
kcpKubernetesServiceMock = mock<KcpKubernetesService>();
|
|
49
50
|
permissionsProxyServiceMock = {
|
|
50
|
-
resolvePermissions:
|
|
51
|
-
} as unknown as
|
|
51
|
+
resolvePermissions: vi.fn().mockResolvedValue([]),
|
|
52
|
+
} as unknown as Mocked<PermissionsProxyService>;
|
|
52
53
|
|
|
53
54
|
const module: TestingModule = await Test.createTestingModule({
|
|
54
55
|
providers: [
|
|
@@ -71,7 +72,7 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
71
72
|
|
|
72
73
|
describe('getServiceProviders', () => {
|
|
73
74
|
it.each([{ entities: [] }, { entities: ['core_platform-mesh_io_account'] }])(
|
|
74
|
-
'normalizes built-in and provider bundle nodes for entity selection %
|
|
75
|
+
'normalizes built-in and provider bundle nodes for entity selection %o',
|
|
75
76
|
async ({ entities }) => {
|
|
76
77
|
const portalOrigin = 'https://portal.example.test';
|
|
77
78
|
const config = {
|
|
@@ -391,9 +392,9 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
391
392
|
.mockRejectedValueOnce(error)
|
|
392
393
|
.mockResolvedValueOnce(mockResponse as any);
|
|
393
394
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
395
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
396
|
+
vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
397
|
+
vi.spyOn(global, 'setTimeout');
|
|
397
398
|
|
|
398
399
|
await service.getServiceProviders(mockToken, mockEntities, mockContext);
|
|
399
400
|
|
|
@@ -402,7 +403,7 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
402
403
|
).toHaveBeenCalledTimes(2);
|
|
403
404
|
expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 1000);
|
|
404
405
|
|
|
405
|
-
|
|
406
|
+
vi.restoreAllMocks();
|
|
406
407
|
});
|
|
407
408
|
|
|
408
409
|
it('should retry once on statusCode 429 error', async () => {
|
|
@@ -413,8 +414,8 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
413
414
|
.mockRejectedValueOnce(error)
|
|
414
415
|
.mockResolvedValueOnce(mockResponse as any);
|
|
415
416
|
|
|
416
|
-
|
|
417
|
-
|
|
417
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
418
|
+
vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
418
419
|
|
|
419
420
|
await service.getServiceProviders(mockToken, mockEntities, mockContext);
|
|
420
421
|
|
|
@@ -422,7 +423,7 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
422
423
|
kcpKubernetesServiceMock.listClusterCustomObjectInKcpVirtualWorkspace,
|
|
423
424
|
).toHaveBeenCalledTimes(2);
|
|
424
425
|
|
|
425
|
-
|
|
426
|
+
vi.restoreAllMocks();
|
|
426
427
|
});
|
|
427
428
|
|
|
428
429
|
it('should log error on kubernetes service failure', async () => {
|
|
@@ -431,7 +432,9 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
431
432
|
error,
|
|
432
433
|
);
|
|
433
434
|
|
|
434
|
-
const consoleSpy =
|
|
435
|
+
const consoleSpy = vi
|
|
436
|
+
.spyOn(console, 'error')
|
|
437
|
+
.mockImplementation(() => {});
|
|
435
438
|
|
|
436
439
|
await service.getServiceProviders(mockToken, mockEntities, mockContext);
|
|
437
440
|
|
|
@@ -446,7 +449,7 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
446
449
|
error,
|
|
447
450
|
);
|
|
448
451
|
|
|
449
|
-
|
|
452
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
450
453
|
|
|
451
454
|
await service.getServiceProviders(mockToken, mockEntities, mockContext);
|
|
452
455
|
|
|
@@ -454,7 +457,7 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
454
457
|
kcpKubernetesServiceMock.listClusterCustomObjectInKcpVirtualWorkspace,
|
|
455
458
|
).toHaveBeenCalledTimes(1);
|
|
456
459
|
|
|
457
|
-
|
|
460
|
+
vi.restoreAllMocks();
|
|
458
461
|
});
|
|
459
462
|
|
|
460
463
|
it('should return result after successful retry', async () => {
|
|
@@ -477,8 +480,8 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
477
480
|
.mockRejectedValueOnce(error)
|
|
478
481
|
.mockResolvedValueOnce(mockResponse as any);
|
|
479
482
|
|
|
480
|
-
|
|
481
|
-
|
|
483
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
484
|
+
vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
482
485
|
|
|
483
486
|
const result = await service.getServiceProviders(
|
|
484
487
|
mockToken,
|
|
@@ -493,7 +496,7 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
493
496
|
'https://test.com',
|
|
494
497
|
);
|
|
495
498
|
|
|
496
|
-
|
|
499
|
+
vi.restoreAllMocks();
|
|
497
500
|
});
|
|
498
501
|
});
|
|
499
502
|
|
|
@@ -2,37 +2,43 @@ import { K8sRequestContext, K8sResourceDescriptor } from '../models/k8s.js';
|
|
|
2
2
|
import { KcpKubernetesService } from './kcp-k8s.service.js';
|
|
3
3
|
import type { Request } from 'express';
|
|
4
4
|
|
|
5
|
-
const mockListClusterCustomObject =
|
|
6
|
-
const mockReadNamespacedSecret =
|
|
7
|
-
const mockMakeApiClient =
|
|
8
|
-
const mockGetCurrentCluster =
|
|
9
|
-
const mockLoadFromFile =
|
|
10
|
-
const mockAddUser =
|
|
11
|
-
const mockAddContext =
|
|
12
|
-
const mockSetCurrentContext =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
CustomObjectsApi:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
5
|
+
const mockListClusterCustomObject = vi.fn();
|
|
6
|
+
const mockReadNamespacedSecret = vi.fn();
|
|
7
|
+
const mockMakeApiClient = vi.fn();
|
|
8
|
+
const mockGetCurrentCluster = vi.fn();
|
|
9
|
+
const mockLoadFromFile = vi.fn();
|
|
10
|
+
const mockAddUser = vi.fn();
|
|
11
|
+
const mockAddContext = vi.fn();
|
|
12
|
+
const mockSetCurrentContext = vi.fn();
|
|
13
|
+
|
|
14
|
+
vi.mock('@kubernetes/client-node', () => ({
|
|
15
|
+
CustomObjectsApi: vi.fn().mockImplementation(function () {
|
|
16
|
+
return {
|
|
17
|
+
listClusterCustomObject: mockListClusterCustomObject,
|
|
18
|
+
};
|
|
19
|
+
}),
|
|
20
|
+
CoreV1Api: vi.fn().mockImplementation(function () {
|
|
21
|
+
return {
|
|
22
|
+
readNamespacedSecret: mockReadNamespacedSecret,
|
|
23
|
+
};
|
|
24
|
+
}),
|
|
25
|
+
KubeConfig: vi.fn().mockImplementation(function () {
|
|
26
|
+
return {
|
|
27
|
+
loadFromFile: mockLoadFromFile,
|
|
28
|
+
addUser: mockAddUser,
|
|
29
|
+
addContext: mockAddContext,
|
|
30
|
+
setCurrentContext: mockSetCurrentContext,
|
|
31
|
+
getCurrentCluster: mockGetCurrentCluster,
|
|
32
|
+
makeApiClient: mockMakeApiClient,
|
|
33
|
+
};
|
|
34
|
+
}),
|
|
29
35
|
}));
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
getOrganization:
|
|
37
|
+
vi.mock('../utils/domain.js', () => ({
|
|
38
|
+
getOrganization: vi.fn(() => 'org-1'),
|
|
33
39
|
}));
|
|
34
40
|
|
|
35
|
-
|
|
41
|
+
vi.mock('@kubernetes/client-node/dist/gen/middleware.js', () => ({
|
|
36
42
|
PromiseMiddlewareWrapper: class {
|
|
37
43
|
constructor(public options: any) {}
|
|
38
44
|
},
|
|
@@ -42,7 +48,7 @@ describe('KcpKubernetesService', () => {
|
|
|
42
48
|
const OLD_ENV = process.env;
|
|
43
49
|
|
|
44
50
|
beforeEach(() => {
|
|
45
|
-
|
|
51
|
+
vi.clearAllMocks();
|
|
46
52
|
process.env = {
|
|
47
53
|
...OLD_ENV,
|
|
48
54
|
KUBECONFIG_KCP: '/tmp/kcp.kubeconfig',
|
|
@@ -367,7 +373,7 @@ describe('KcpKubernetesService', () => {
|
|
|
367
373
|
mockListClusterCustomObject.mockImplementation(async (_gvr, options) => {
|
|
368
374
|
const middleware = options.middleware[0];
|
|
369
375
|
const mockContext = {
|
|
370
|
-
setUrl:
|
|
376
|
+
setUrl: vi.fn(),
|
|
371
377
|
};
|
|
372
378
|
await middleware.options.pre(mockContext);
|
|
373
379
|
postResult = await middleware.options.post(mockContext);
|
|
@@ -397,7 +403,7 @@ describe('KcpKubernetesService', () => {
|
|
|
397
403
|
async (gvrParam, options) => {
|
|
398
404
|
const middleware = options.middleware[0];
|
|
399
405
|
const mockContext = {
|
|
400
|
-
setUrl:
|
|
406
|
+
setUrl: vi.fn(),
|
|
401
407
|
};
|
|
402
408
|
capturedContext = mockContext;
|
|
403
409
|
await middleware.options.pre(mockContext);
|
|
@@ -429,7 +435,7 @@ describe('KcpKubernetesService', () => {
|
|
|
429
435
|
async (gvrParam, options) => {
|
|
430
436
|
const middleware = options.middleware[0];
|
|
431
437
|
const mockContext = {
|
|
432
|
-
setUrl:
|
|
438
|
+
setUrl: vi.fn(),
|
|
433
439
|
};
|
|
434
440
|
capturedContext = mockContext;
|
|
435
441
|
await middleware.options.pre(mockContext);
|
|
@@ -490,8 +496,8 @@ describe('KcpKubernetesService', () => {
|
|
|
490
496
|
async (gvrParam, options) => {
|
|
491
497
|
const middleware = options.middleware[0];
|
|
492
498
|
const mockContext = {
|
|
493
|
-
setUrl:
|
|
494
|
-
setHeaderParam:
|
|
499
|
+
setUrl: vi.fn(),
|
|
500
|
+
setHeaderParam: vi.fn(),
|
|
495
501
|
};
|
|
496
502
|
capturedContext = mockContext;
|
|
497
503
|
await middleware.options.pre(mockContext);
|
|
@@ -529,8 +535,8 @@ describe('KcpKubernetesService', () => {
|
|
|
529
535
|
async (gvrParam, options) => {
|
|
530
536
|
const middleware = options.middleware[0];
|
|
531
537
|
const mockContext = {
|
|
532
|
-
setUrl:
|
|
533
|
-
setHeaderParam:
|
|
538
|
+
setUrl: vi.fn(),
|
|
539
|
+
setHeaderParam: vi.fn(),
|
|
534
540
|
};
|
|
535
541
|
capturedContext = mockContext;
|
|
536
542
|
await middleware.options.pre(mockContext);
|
|
@@ -604,7 +610,7 @@ describe('KcpKubernetesService', () => {
|
|
|
604
610
|
mockReadNamespacedSecret.mockImplementation(async (params, options) => {
|
|
605
611
|
const middleware = options.middleware[0];
|
|
606
612
|
const mockContext = {
|
|
607
|
-
setUrl:
|
|
613
|
+
setUrl: vi.fn(),
|
|
608
614
|
};
|
|
609
615
|
capturedContext = mockContext;
|
|
610
616
|
await middleware.options.pre(mockContext);
|
|
@@ -630,7 +636,7 @@ describe('KcpKubernetesService', () => {
|
|
|
630
636
|
mockReadNamespacedSecret.mockImplementation(async (_params, options) => {
|
|
631
637
|
const middleware = options.middleware[0];
|
|
632
638
|
const mockContext = {
|
|
633
|
-
setUrl:
|
|
639
|
+
setUrl: vi.fn(),
|
|
634
640
|
};
|
|
635
641
|
await middleware.options.pre(mockContext);
|
|
636
642
|
postResult = await middleware.options.post(mockContext);
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
SubjectAccessReview,
|
|
7
7
|
} from '../models/permissions.model.js';
|
|
8
8
|
import { AuthzWebhookService } from './authz-webhook.service.js';
|
|
9
|
+
import type { Mock } from 'vitest';
|
|
9
10
|
|
|
10
11
|
// Build a valid JWT token with the given payload
|
|
11
12
|
function makeJwt(payload: Record<string, unknown>): string {
|
|
@@ -21,7 +22,7 @@ const WEBHOOK_URL = 'https://authz.example.com';
|
|
|
21
22
|
const BATCH_URL = `${WEBHOOK_URL}/batch-authz`;
|
|
22
23
|
|
|
23
24
|
// The posted body is the SubjectAccessReview[] array itself.
|
|
24
|
-
function postedItems(post:
|
|
25
|
+
function postedItems(post: Mock): SubjectAccessReview[] {
|
|
25
26
|
return post.mock.calls[0][1] as SubjectAccessReview[];
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -73,14 +74,14 @@ function makeInstanceRequest(
|
|
|
73
74
|
|
|
74
75
|
describe('AuthzWebhookService', () => {
|
|
75
76
|
let service: AuthzWebhookService;
|
|
76
|
-
let httpService: { post:
|
|
77
|
+
let httpService: { post: Mock };
|
|
77
78
|
const OLD_ENV = process.env;
|
|
78
79
|
|
|
79
80
|
beforeEach(async () => {
|
|
80
81
|
process.env = { ...OLD_ENV };
|
|
81
82
|
process.env['OPENMFP_PORTAL_CONTEXT_AUTHZ_WEBHOOK_URL'] = WEBHOOK_URL;
|
|
82
83
|
|
|
83
|
-
httpService = { post:
|
|
84
|
+
httpService = { post: vi.fn() };
|
|
84
85
|
|
|
85
86
|
const module: TestingModule = await Test.createTestingModule({
|
|
86
87
|
providers: [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ContentConfiguration } from '@openmfp/portal-server-lib';
|
|
2
|
-
import { mock } from '
|
|
2
|
+
import { mock } from 'vitest-mock-extended';
|
|
3
3
|
import { AuthzWebhookService } from './adapters/authz-webhook.service.js';
|
|
4
4
|
import {
|
|
5
5
|
AuthorizationRequest,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
PermissionsDefinition,
|
|
8
8
|
} from './models/permissions.model.js';
|
|
9
9
|
import { PermissionsProxyService } from './permissions-proxy.service.js';
|
|
10
|
+
import type { Mocked } from 'vitest';
|
|
10
11
|
|
|
11
12
|
function makeCC(
|
|
12
13
|
nodes: ContentConfiguration['luigiConfigFragment']['data']['nodes'] = [],
|
|
@@ -66,7 +67,7 @@ function makeAuthzRequest(
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
describe('PermissionsProxyService', () => {
|
|
69
|
-
let authzWebhook:
|
|
70
|
+
let authzWebhook: Mocked<AuthzWebhookService>;
|
|
70
71
|
let svc: PermissionsProxyService;
|
|
71
72
|
|
|
72
73
|
beforeEach(() => {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { UnauthorizedException } from '@nestjs/common';
|
|
2
2
|
import { HeaderParserService } from '@openmfp/portal-server-lib';
|
|
3
3
|
import { Test, TestingModule } from '@nestjs/testing';
|
|
4
|
-
import { mock } from '
|
|
4
|
+
import { mock } from 'vitest-mock-extended';
|
|
5
5
|
import { PermissionsController } from './permissions.controller.js';
|
|
6
6
|
import { PermissionsProxyService } from './permissions-proxy.service.js';
|
|
7
7
|
import { AuthorizationRequest, Permission } from './models/permissions.model.js';
|
|
8
|
+
import type { Mocked } from 'vitest';
|
|
8
9
|
|
|
9
10
|
function makeBody(
|
|
10
11
|
overrides: Partial<AuthorizationRequest> = {},
|
|
@@ -30,8 +31,8 @@ const request = {} as Request;
|
|
|
30
31
|
|
|
31
32
|
describe('PermissionsController', () => {
|
|
32
33
|
let controller: PermissionsController;
|
|
33
|
-
let proxyService:
|
|
34
|
-
let headerParser:
|
|
34
|
+
let proxyService: Mocked<PermissionsProxyService>;
|
|
35
|
+
let headerParser: Mocked<HeaderParserService>;
|
|
35
36
|
|
|
36
37
|
beforeEach(async () => {
|
|
37
38
|
proxyService = mock<PermissionsProxyService>();
|
|
@@ -5,7 +5,7 @@ describe('getOrganization', () => {
|
|
|
5
5
|
const OLD_ENV = process.env;
|
|
6
6
|
|
|
7
7
|
beforeEach(() => {
|
|
8
|
-
|
|
8
|
+
vi.resetModules();
|
|
9
9
|
process.env = { ...OLD_ENV };
|
|
10
10
|
process.env.OIDC_CLIENT_ID_DEFAULT = 'default-client';
|
|
11
11
|
process.env.BASE_DOMAINS_DEFAULT = 'example.com';
|
|
@@ -53,7 +53,7 @@ describe('getDiscoveryEndpoint', () => {
|
|
|
53
53
|
({ hostname }) as unknown as Request;
|
|
54
54
|
|
|
55
55
|
beforeEach(() => {
|
|
56
|
-
|
|
56
|
+
vi.resetModules();
|
|
57
57
|
process.env = { ...OLD_ENV };
|
|
58
58
|
process.env.OIDC_CLIENT_ID_DEFAULT = 'default-client';
|
|
59
59
|
process.env.BASE_DOMAINS_DEFAULT = 'example.com';
|
|
@@ -151,7 +151,7 @@ describe('normalizePortalWebComponentModules', () => {
|
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
it.each(['module', 'classic', '', null])(
|
|
154
|
-
'preserves explicitly configured type %
|
|
154
|
+
'preserves explicitly configured type %o',
|
|
155
155
|
(type) => {
|
|
156
156
|
const config = configuration([
|
|
157
157
|
node({ webcomponent: { selfRegistered: true, type } }),
|
|
@@ -165,7 +165,7 @@ describe('normalizePortalWebComponentModules', () => {
|
|
|
165
165
|
);
|
|
166
166
|
|
|
167
167
|
it.each([undefined, false, true, { selfRegistered: false }])(
|
|
168
|
-
'preserves non-self-registered setting %
|
|
168
|
+
'preserves non-self-registered setting %o',
|
|
169
169
|
(webcomponent) => {
|
|
170
170
|
const config = configuration([node({ webcomponent })]);
|
|
171
171
|
normalizePortalWebComponentModules(config);
|
|
@@ -259,7 +259,7 @@ describe('normalizePortalWebComponentModules', () => {
|
|
|
259
259
|
{},
|
|
260
260
|
{ luigiConfigFragment: {} },
|
|
261
261
|
{ luigiConfigFragment: { data: { nodes: null } } },
|
|
262
|
-
])('ignores absent node structures %
|
|
262
|
+
])('ignores absent node structures %o', (value) => {
|
|
263
263
|
expect(() =>
|
|
264
264
|
normalizePortalWebComponentModules(value as ContentConfiguration),
|
|
265
265
|
).not.toThrow();
|
package/tsconfig.build.json
CHANGED
package/tsconfig.json
CHANGED
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
include: ['src/**/*.spec.ts'],
|
|
7
|
+
coverage: {
|
|
8
|
+
enabled: true,
|
|
9
|
+
provider: 'v8',
|
|
10
|
+
reporter: ['text', 'cobertura', 'lcov'],
|
|
11
|
+
reportsDirectory: 'test-run-reports/coverage/unit',
|
|
12
|
+
thresholds: {
|
|
13
|
+
branches: 75,
|
|
14
|
+
functions: 89,
|
|
15
|
+
lines: 90,
|
|
16
|
+
statements: -12,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
package/base.jest.config.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
testEnvironment: 'node',
|
|
3
|
-
coverageReporters: ['text', 'cobertura', 'lcov'],
|
|
4
|
-
transform: {
|
|
5
|
-
'^.+\\.(t|j)s$': [
|
|
6
|
-
'ts-jest',
|
|
7
|
-
{
|
|
8
|
-
tsconfig: 'tsconfig.test.json',
|
|
9
|
-
},
|
|
10
|
-
],
|
|
11
|
-
},
|
|
12
|
-
moduleNameMapper: {
|
|
13
|
-
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
14
|
-
},
|
|
15
|
-
};
|
package/jest.config.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
2
|
-
import baseConfig from './base.jest.config.js';
|
|
3
|
-
|
|
4
|
-
export default {
|
|
5
|
-
...baseConfig,
|
|
6
|
-
rootDir: 'src',
|
|
7
|
-
testRegex: '.spec.ts$',
|
|
8
|
-
collectCoverage: true,
|
|
9
|
-
reporters: ['default'],
|
|
10
|
-
coverageThreshold: {
|
|
11
|
-
global: {
|
|
12
|
-
branches: 75,
|
|
13
|
-
functions: 89,
|
|
14
|
-
lines: 90,
|
|
15
|
-
statements: -12,
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
coveragePathIgnorePatterns: ['/node_modules/', '/integration-tests/'],
|
|
19
|
-
coverageDirectory: '../test-run-reports/coverage/unit',
|
|
20
|
-
transformIgnorePatterns: [
|
|
21
|
-
'/node_modules/(?!(@openmfp/portal-server-lib|graphql-request)/)',
|
|
22
|
-
],
|
|
23
|
-
transform: {
|
|
24
|
-
'^.+\\.(t|j)s$': [
|
|
25
|
-
'ts-jest',
|
|
26
|
-
{
|
|
27
|
-
tsconfig: 'tsconfig.test.json',
|
|
28
|
-
useESM: true,
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
|
-
},
|
|
32
|
-
testEnvironment: 'node',
|
|
33
|
-
passWithNoTests: true,
|
|
34
|
-
roots: ['<rootDir>'],
|
|
35
|
-
moduleNameMapper: {
|
|
36
|
-
'^@openmfp/portal-lib(|/.*)$': '<rootDir>/libs/portal-lib/src/$1',
|
|
37
|
-
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
38
|
-
},
|
|
39
|
-
preset: 'ts-jest/presets/default-esm',
|
|
40
|
-
extensionsToTreatAsEsm: ['.ts'],
|
|
41
|
-
moduleFileExtensions: ['js', 'json', 'ts'],
|
|
42
|
-
};
|
package/tsconfig.test.json
DELETED