@futdevpro/nts-dynamo 1.15.8 → 1.15.9
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/__documentations/nts-integration-tests-2026-03-17.md +26 -0
- package/build/_collections/default-fallback-cache-max-age.const.d.ts +3 -0
- package/build/_collections/default-fallback-cache-max-age.const.d.ts.map +1 -0
- package/build/_collections/default-fallback-cache-max-age.const.js +6 -0
- package/build/_collections/default-fallback-cache-max-age.const.js.map +1 -0
- package/build/_collections/default-not-found-page.const.d.ts +6 -0
- package/build/_collections/default-not-found-page.const.d.ts.map +1 -0
- package/build/_collections/default-not-found-page.const.js +25 -0
- package/build/_collections/default-not-found-page.const.js.map +1 -0
- package/build/_collections/default-socket-path.const.d.ts +3 -0
- package/build/_collections/default-socket-path.const.d.ts.map +1 -0
- package/build/_collections/default-socket-path.const.js +6 -0
- package/build/_collections/default-socket-path.const.js.map +1 -0
- package/build/_models/control-models/http-settings.control-model.d.ts +7 -0
- package/build/_models/control-models/http-settings.control-model.d.ts.map +1 -1
- package/build/_models/control-models/http-settings.control-model.js +7 -0
- package/build/_models/control-models/http-settings.control-model.js.map +1 -1
- package/build/_models/interfaces/static-client-settings.interface.d.ts +29 -0
- package/build/_models/interfaces/static-client-settings.interface.d.ts.map +1 -0
- package/build/_models/interfaces/static-client-settings.interface.js +3 -0
- package/build/_models/interfaces/static-client-settings.interface.js.map +1 -0
- package/build/_modules/mock/app-extended-server.mock.js +2 -2
- package/build/_modules/mock/app-extended-server.mock.js.map +1 -1
- package/build/_modules/mock/app-integration-test.mock.d.ts +20 -0
- package/build/_modules/mock/app-integration-test.mock.d.ts.map +1 -0
- package/build/_modules/mock/app-integration-test.mock.js +46 -0
- package/build/_modules/mock/app-integration-test.mock.js.map +1 -0
- package/build/_modules/mock/app-server.mock.js +2 -2
- package/build/_modules/mock/app-server.mock.js.map +1 -1
- package/build/_modules/mock/socket-client.mock.js +1 -1
- package/build/_modules/mock/socket-client.mock.js.map +1 -1
- package/build/_modules/mock/socket-server.mock.d.ts +1 -1
- package/build/_modules/mock/socket-server.mock.d.ts.map +1 -1
- package/build/_modules/mock/socket-server.mock.js +2 -8
- package/build/_modules/mock/socket-server.mock.js.map +1 -1
- package/build/_modules/socket/_services/socket-server.service.d.ts.map +1 -1
- package/build/_modules/socket/_services/socket-server.service.js +3 -1
- package/build/_modules/socket/_services/socket-server.service.js.map +1 -1
- package/build/_modules/socket/app-extended.server.d.ts +1 -0
- package/build/_modules/socket/app-extended.server.d.ts.map +1 -1
- package/build/_modules/socket/app-extended.server.js +6 -2
- package/build/_modules/socket/app-extended.server.js.map +1 -1
- package/build/_services/base/data.service.d.ts.map +1 -1
- package/build/_services/base/data.service.js +4 -5
- package/build/_services/base/data.service.js.map +1 -1
- package/build/_services/base/db.service.d.ts.map +1 -1
- package/build/_services/base/db.service.js +8 -0
- package/build/_services/base/db.service.js.map +1 -1
- package/build/_services/server/app.server.d.ts +18 -0
- package/build/_services/server/app.server.d.ts.map +1 -1
- package/build/_services/server/app.server.js +74 -2
- package/build/_services/server/app.server.js.map +1 -1
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -0
- package/build/index.js.map +1 -1
- package/nodemon.json +2 -1
- package/package.json +1 -1
- package/src/_collections/default-fallback-cache-max-age.const.spec.ts +11 -0
- package/src/_collections/default-fallback-cache-max-age.const.ts +2 -0
- package/src/_collections/default-not-found-page.const.spec.ts +19 -0
- package/src/_collections/default-not-found-page.const.ts +22 -0
- package/src/_collections/default-socket-path.const.spec.ts +12 -0
- package/src/_collections/default-socket-path.const.ts +2 -0
- package/src/_models/control-models/http-settings.control-model.spec.ts +11 -0
- package/src/_models/control-models/http-settings.control-model.ts +8 -0
- package/src/_models/interfaces/static-client-settings.interface.spec.ts +29 -0
- package/src/_models/interfaces/static-client-settings.interface.ts +28 -0
- package/src/_modules/mock/app-extended-server.mock.ts +2 -2
- package/src/_modules/mock/app-integration-test.mock.ts +51 -0
- package/src/_modules/mock/app-server.mock.ts +2 -2
- package/src/_modules/mock/socket-client.mock.spec.ts +1 -1
- package/src/_modules/mock/socket-client.mock.ts +1 -1
- package/src/_modules/mock/socket-server.mock.spec.ts +1 -1
- package/src/_modules/mock/socket-server.mock.ts +5 -13
- package/src/_modules/socket/_services/socket-server.service.ts +6 -2
- package/src/_modules/socket/app-extended.integration.spec.ts +85 -0
- package/src/_modules/socket/app-extended.server.ts +6 -2
- package/src/_services/base/data.service.ts +4 -7
- package/src/_services/base/db.service.ts +11 -3
- package/src/_services/route/routing-module.service.spec.ts +15 -0
- package/src/_services/server/app.server.ts +107 -2
- package/src/index.ts +4 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alapértelmezett "Page not found" (404) HTML, amit a static client default fallbackjaként
|
|
3
|
+
* szolgálunk ki, ha nincs fallbackPath (nem-SPA mód) és a kérés nem egy létező static fájlra mutat.
|
|
4
|
+
*/
|
|
5
|
+
export const DyNTS_defaultNotFoundPageHtml: string =
|
|
6
|
+
'<!DOCTYPE html>\n' +
|
|
7
|
+
'<html lang="en">\n' +
|
|
8
|
+
'<head>\n' +
|
|
9
|
+
' <meta charset="utf-8">\n' +
|
|
10
|
+
' <meta name="viewport" content="width=device-width, initial-scale=1">\n' +
|
|
11
|
+
' <title>Page not found</title>\n' +
|
|
12
|
+
' <style>\n' +
|
|
13
|
+
' body { font-family: system-ui, sans-serif; margin: 2rem; text-align: center; }\n' +
|
|
14
|
+
' h1 { font-size: 1.5rem; color: #333; }\n' +
|
|
15
|
+
' p { color: #666; }\n' +
|
|
16
|
+
' </style>\n' +
|
|
17
|
+
'</head>\n' +
|
|
18
|
+
'<body>\n' +
|
|
19
|
+
' <h1>Page not found</h1>\n' +
|
|
20
|
+
' <p>The requested resource could not be found.</p>\n' +
|
|
21
|
+
'</body>\n' +
|
|
22
|
+
'</html>\n';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DyNTS_defaultSocketPath } from './default-socket-path.const';
|
|
2
|
+
|
|
3
|
+
describe('| DyNTS_defaultSocketPath', () => {
|
|
4
|
+
it('| should export default socket path as \'/socket\'', () => {
|
|
5
|
+
expect(DyNTS_defaultSocketPath).toBe('/socket');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('| should be a non-empty string', () => {
|
|
9
|
+
expect(typeof DyNTS_defaultSocketPath).toBe('string');
|
|
10
|
+
expect(DyNTS_defaultSocketPath.length).toBeGreaterThan(0);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -8,6 +8,7 @@ describe('| DyNTS_Http_Settings', () => {
|
|
|
8
8
|
|
|
9
9
|
expect(settings.httpPort).toBeUndefined();
|
|
10
10
|
expect(settings.httpsPort).toBeUndefined();
|
|
11
|
+
expect(settings.socketPath).toBeUndefined();
|
|
11
12
|
expect(settings.httpUrlencoded).toEqual({
|
|
12
13
|
limit: '50mb',
|
|
13
14
|
extended: true,
|
|
@@ -63,4 +64,14 @@ describe('| DyNTS_Http_Settings', () => {
|
|
|
63
64
|
limit: '100mb',
|
|
64
65
|
} as BodyParser.OptionsJson);
|
|
65
66
|
});
|
|
67
|
+
|
|
68
|
+
it('| should have socketPath undefined when not provided', () => {
|
|
69
|
+
const settings = new DyNTS_Http_Settings();
|
|
70
|
+
expect(settings.socketPath).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('| should set socketPath when provided in constructor', () => {
|
|
74
|
+
const settings = new DyNTS_Http_Settings({ socketPath: '/ws' });
|
|
75
|
+
expect(settings.socketPath).toBe('/ws');
|
|
76
|
+
});
|
|
66
77
|
});
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
|
|
2
2
|
import * as BodyParser from 'body-parser';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* HTTP/HTTPS és Socket.IO port és body parser beállítások.
|
|
6
|
+
* socketPath: ha nincs megadva, DyNTS_defaultSocketPath marad;
|
|
7
|
+
* a kliensnek ugyanazt a path-ot kell használnia.
|
|
8
|
+
*/
|
|
3
9
|
export class DyNTS_Http_Settings {
|
|
4
10
|
httpPort?: number;
|
|
5
11
|
httpsPort?: number;
|
|
12
|
+
/** Socket.IO path (pl. '/ws'); ha üres, default: DyNTS_defaultSocketPath. */
|
|
13
|
+
socketPath?: string;
|
|
6
14
|
|
|
7
15
|
httpUrlencoded?: BodyParser.OptionsUrlencoded = {
|
|
8
16
|
limit: '50mb',
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { DyNTS_StaticClient_Settings } from './static-client-settings.interface';
|
|
2
|
+
|
|
3
|
+
describe('| DyNTS_StaticClient_Settings', () => {
|
|
4
|
+
it('| should allow minimal settings with only root', () => {
|
|
5
|
+
const s: DyNTS_StaticClient_Settings = { root: '/dist' };
|
|
6
|
+
expect(s.root).toBe('/dist');
|
|
7
|
+
expect(s.fallbackPath).toBeUndefined();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('| should allow optional fallbackPath', () => {
|
|
11
|
+
const s: DyNTS_StaticClient_Settings = {
|
|
12
|
+
root: '/dist',
|
|
13
|
+
fallbackPath: 'index.html',
|
|
14
|
+
};
|
|
15
|
+
expect(s.fallbackPath).toBe('index.html');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('| should allow SPA cache options', () => {
|
|
19
|
+
const s: DyNTS_StaticClient_Settings = {
|
|
20
|
+
root: '/dist',
|
|
21
|
+
assetCacheMaxAge: 31536000,
|
|
22
|
+
assetCacheImmutable: true,
|
|
23
|
+
fallbackCacheMaxAge: 0,
|
|
24
|
+
};
|
|
25
|
+
expect(s.assetCacheMaxAge).toBe(31536000);
|
|
26
|
+
expect(s.assetCacheImmutable).toBe(true);
|
|
27
|
+
expect(s.fallbackCacheMaxAge).toBe(0);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beállítások a client static fájlok kiszolgálásához (pl. SPA) a '/' path alatt.
|
|
3
|
+
* Ha megadva, a getStaticClientSettings() által visszaadott értéket a base app
|
|
4
|
+
* a mountStaticClient() során használja (API route-ok után).
|
|
5
|
+
* A cache mezők SPA (pl. Angular) optimalizáláshoz opcionálisak; ha nincs kitöltve,
|
|
6
|
+
* viselkedés változatlan (alkalmas nem-SPA kiszolgálásra is).
|
|
7
|
+
*/
|
|
8
|
+
export interface DyNTS_StaticClient_Settings {
|
|
9
|
+
/** A static fájlok könyvtárának path-ja (abszolút vagy process.cwd()-hez képest). */
|
|
10
|
+
root: string;
|
|
11
|
+
/** SPA fallback: ha a kérés nem egy fájlra mutat, ezt a fájlt szolgáljuk ki (pl. 'index.html'). */
|
|
12
|
+
fallbackPath?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Static asset-ek (pl. JS, CSS) Cache-Control max-age másodpercben.
|
|
15
|
+
* SPA (Angular) hashed fájloknál pl. 1 év (31536000).
|
|
16
|
+
*/
|
|
17
|
+
assetCacheMaxAge?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Ha true és assetCacheMaxAge is megadva, Cache-Control-hoz hozzáadódik az immutable direktíva
|
|
20
|
+
* (Angular hashed fájlokra ideális).
|
|
21
|
+
*/
|
|
22
|
+
assetCacheImmutable?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Fallback (pl. index.html) Cache-Control max-age másodpercben.
|
|
25
|
+
* SPA esetén ajánlott 0, hogy a böngésző ne cache-elje az index.html-t (deploy után friss).
|
|
26
|
+
*/
|
|
27
|
+
fallbackCacheMaxAge?: number;
|
|
28
|
+
}
|
|
@@ -96,7 +96,7 @@ export class DyNTS_AppExtendedFull_Mock extends DyNTS_AppExtended {
|
|
|
96
96
|
|
|
97
97
|
getPortSettings(): DyNTS_Http_Settings {
|
|
98
98
|
return {
|
|
99
|
-
httpPort:
|
|
99
|
+
httpPort: 0,
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -167,7 +167,7 @@ export class DyNTS_AppWbMock_Mock extends DyNTS_AppExtended {
|
|
|
167
167
|
|
|
168
168
|
getPortSettings(): DyNTS_Http_Settings {
|
|
169
169
|
return {
|
|
170
|
-
httpPort:
|
|
170
|
+
httpPort: 0,
|
|
171
171
|
};
|
|
172
172
|
}
|
|
173
173
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { DyNTS_App_Params } from '../../_models/control-models/app-params.control-model';
|
|
2
|
+
import { DyNTS_Http_Settings } from '../../_models/control-models/http-settings.control-model';
|
|
3
|
+
import { DyNTS_StaticClient_Settings } from '../../_models/interfaces/static-client-settings.interface';
|
|
4
|
+
import { DyNTS_AppWbMock_Mock } from './app-extended-server.mock';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Integrációs tesztekhez használt mock app: DB nélkül indul, unified host beállításokkal
|
|
8
|
+
* (static client root, API base path, socket path). A static root-ot a spec állítja
|
|
9
|
+
* beforeAll-ban az integrationStaticRoot statikus property-n keresztül.
|
|
10
|
+
*/
|
|
11
|
+
export class DyNTS_AppIntegrationTest_Mock extends DyNTS_AppWbMock_Mock {
|
|
12
|
+
|
|
13
|
+
/** A spec beforeAll-ban beállítja; getStaticClientSettings() ezt használja root-ként. */
|
|
14
|
+
static integrationStaticRoot: string = '';
|
|
15
|
+
|
|
16
|
+
override getAppParams(): DyNTS_App_Params {
|
|
17
|
+
return new DyNTS_App_Params({
|
|
18
|
+
name: 'nts-integration-test',
|
|
19
|
+
version: '1.0.0',
|
|
20
|
+
systemShortCodeName: 'NIT',
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override getPortSettings(): DyNTS_Http_Settings {
|
|
25
|
+
return {
|
|
26
|
+
httpPort: 0,
|
|
27
|
+
socketPath: '/socket',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Az OS által kiosztott tényleges port; ready() után elérhető. */
|
|
32
|
+
get resolvedPort(): number {
|
|
33
|
+
const addr = this.httpServer?.address?.();
|
|
34
|
+
|
|
35
|
+
return (typeof addr === 'object' && addr) ? addr.port : 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
override getApiBasePath(): string {
|
|
39
|
+
return '/api';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override getStaticClientSettings(): DyNTS_StaticClient_Settings | undefined {
|
|
43
|
+
if (!DyNTS_AppIntegrationTest_Mock.integrationStaticRoot) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
root: DyNTS_AppIntegrationTest_Mock.integrationStaticRoot,
|
|
48
|
+
fallbackPath: undefined,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -85,7 +85,7 @@ export class DyNTS_AppFull_Mock extends DyNTS_App {
|
|
|
85
85
|
|
|
86
86
|
getPortSettings(): DyNTS_Http_Settings {
|
|
87
87
|
return {
|
|
88
|
-
httpPort:
|
|
88
|
+
httpPort: 0,
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -172,7 +172,7 @@ export class DyNTS_AppTEST_Mock extends DyNTS_App {
|
|
|
172
172
|
|
|
173
173
|
getPortSettings(): DyNTS_Http_Settings {
|
|
174
174
|
return {
|
|
175
|
-
httpPort:
|
|
175
|
+
httpPort: 0,
|
|
176
176
|
};
|
|
177
177
|
}
|
|
178
178
|
|
|
@@ -34,7 +34,7 @@ describe('| SocketClient_Mock', () => {
|
|
|
34
34
|
expect(params).toEqual(jasmine.any(DyNTS_SocketClientService_Params));
|
|
35
35
|
expect(params.service).toBe('-test-socket-target-');
|
|
36
36
|
expect(params.name).toBe('socket-client-mock');
|
|
37
|
-
expect(params.port).toBe(
|
|
37
|
+
expect(params.port).toBe(0);
|
|
38
38
|
expect(params.socketOptions.reconnection).toBeTrue();
|
|
39
39
|
});
|
|
40
40
|
});
|
|
@@ -34,7 +34,7 @@ export class SocketClient_Mock extends DyNTS_SocketClient_ServiceBase {
|
|
|
34
34
|
return new DyNTS_SocketClientService_Params({
|
|
35
35
|
service: '-test-socket-target-',
|
|
36
36
|
name: 'socket-client-mock',
|
|
37
|
-
port:
|
|
37
|
+
port: 0,
|
|
38
38
|
socketOptions: {
|
|
39
39
|
reconnection: true,
|
|
40
40
|
},
|
|
@@ -20,7 +20,7 @@ describe('| DyNTS_SocketServer_Mock', () => {
|
|
|
20
20
|
|
|
21
21
|
expect(params).toBeInstanceOf(DyNTS_SocketServerService_Params);
|
|
22
22
|
expect(params.name).toBe('test');
|
|
23
|
-
expect(params.port).toBe(
|
|
23
|
+
expect(params.port).toBe(0);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
it('| should return an empty array for incoming events', () => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { DyFM_SocketEvent } from '@futdevpro/fsm-dynamo/socket';
|
|
2
2
|
import { Socket } from 'socket.io';
|
|
3
|
-
import * as net from 'net';
|
|
4
3
|
|
|
5
4
|
import {
|
|
6
5
|
DyNTS_SocketPresence
|
|
@@ -10,28 +9,21 @@ import {
|
|
|
10
9
|
} from '../socket/_models/socket-server-service-params.control-model';
|
|
11
10
|
import { DyNTS_SocketServerService } from '../socket/_services/socket-server.service';
|
|
12
11
|
|
|
13
|
-
/**
|
|
14
|
-
* Utility function to find an available port starting from a base port
|
|
15
|
-
*/
|
|
16
|
-
const findAvailablePort = (basePort: number): number => {
|
|
17
|
-
return basePort; // For now, return the base port, but this could be enhanced
|
|
18
|
-
};
|
|
19
|
-
|
|
20
12
|
/**
|
|
21
13
|
* Mock Socket Server Service for testing purposes
|
|
22
|
-
* Uses
|
|
14
|
+
* Uses port 0 so the OS assigns a random available port
|
|
23
15
|
*/
|
|
24
|
-
export class DyNTS_SocketServer_Mock extends
|
|
16
|
+
export class DyNTS_SocketServer_Mock extends
|
|
25
17
|
DyNTS_SocketServerService<DyNTS_SocketPresence> {
|
|
26
|
-
|
|
18
|
+
|
|
27
19
|
static getInstance(): DyNTS_SocketServer_Mock {
|
|
28
20
|
return DyNTS_SocketServer_Mock.getSingletonInstance();
|
|
29
21
|
}
|
|
30
|
-
|
|
22
|
+
|
|
31
23
|
getServiceParams(): DyNTS_SocketServerService_Params<any> {
|
|
32
24
|
return new DyNTS_SocketServerService_Params({
|
|
33
25
|
name: 'test',
|
|
34
|
-
port:
|
|
26
|
+
port: 0,
|
|
35
27
|
});
|
|
36
28
|
}
|
|
37
29
|
|
|
@@ -508,8 +508,12 @@ export abstract class DyNTS_SocketServerService<
|
|
|
508
508
|
await this.closeSocket(socket, `${this.params.name} on connection error`, error);
|
|
509
509
|
}
|
|
510
510
|
});
|
|
511
|
-
|
|
512
|
-
|
|
511
|
+
|
|
512
|
+
const isAttach: boolean =
|
|
513
|
+
options?.attachedToExistingServer === true ||
|
|
514
|
+
(this.params.port === undefined && options?.effectivePort !== undefined);
|
|
515
|
+
|
|
516
|
+
if (isAttach) {
|
|
513
517
|
DyFM_Log.success(
|
|
514
518
|
`\nsocket server setup finished: "${this.params.name}"` +
|
|
515
519
|
(effectivePort !== undefined ? ` (attached to server on port: ${effectivePort})` : ' (attached to existing server)')
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as Fs from 'fs';
|
|
2
|
+
import * as Os from 'os';
|
|
3
|
+
import * as Path from 'path';
|
|
4
|
+
|
|
5
|
+
import Axios from 'axios';
|
|
6
|
+
|
|
7
|
+
import { DyNTS_defaultNotFoundPageHtml } from '../../_collections/default-not-found-page.const';
|
|
8
|
+
import { DyNTS_AppIntegrationTest_Mock } from '../mock/app-integration-test.mock';
|
|
9
|
+
|
|
10
|
+
let INTEGRATION_BASE_URL: string = '';
|
|
11
|
+
const INTEGRATION_READY_TIMEOUT_MS: number = 10000;
|
|
12
|
+
|
|
13
|
+
describe('| DyNTS_AppExtended (integration)', (): void => {
|
|
14
|
+
beforeAll((): void => {
|
|
15
|
+
jasmine.DEFAULT_TIMEOUT_INTERVAL = INTEGRATION_READY_TIMEOUT_MS + 5000;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
let app: DyNTS_AppIntegrationTest_Mock;
|
|
19
|
+
let tempDir: string = '';
|
|
20
|
+
|
|
21
|
+
beforeAll(async (): Promise<void> => {
|
|
22
|
+
tempDir = Fs.mkdtempSync(Path.join(Os.tmpdir(), 'dynts-int-'));
|
|
23
|
+
const indexContent: string = '<!DOCTYPE html><html><body>Integration test index</body></html>';
|
|
24
|
+
Fs.writeFileSync(Path.join(tempDir, 'index.html'), indexContent, { encoding: 'utf-8' });
|
|
25
|
+
|
|
26
|
+
DyNTS_AppIntegrationTest_Mock.integrationStaticRoot = tempDir;
|
|
27
|
+
app = new DyNTS_AppIntegrationTest_Mock();
|
|
28
|
+
await app.ready(INTEGRATION_READY_TIMEOUT_MS);
|
|
29
|
+
|
|
30
|
+
INTEGRATION_BASE_URL = `http://localhost:${app.resolvedPort}`;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
afterAll(async (): Promise<void> => {
|
|
34
|
+
try {
|
|
35
|
+
if (app?.started) {
|
|
36
|
+
await app.stop();
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// stop() hiba (pl. socket server már leállt) ne szakítsa meg a suite-ot
|
|
40
|
+
}
|
|
41
|
+
if (tempDir && Fs.existsSync(tempDir)) {
|
|
42
|
+
Fs.rmSync(tempDir, { recursive: true });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('| app elindul és started true', (): void => {
|
|
47
|
+
expect(app.started).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('| GET nem létező path -> 404 és default "Page not found" HTML', async (): Promise<void> => {
|
|
51
|
+
const response = await Axios.get(`${INTEGRATION_BASE_URL}/nonexistent-path-xyz`, {
|
|
52
|
+
validateStatus: (): boolean => true,
|
|
53
|
+
responseType: 'text',
|
|
54
|
+
});
|
|
55
|
+
expect(response.status).toBe(404);
|
|
56
|
+
expect(response.headers['content-type']).toContain('html');
|
|
57
|
+
expect(typeof response.data).toBe('string');
|
|
58
|
+
expect((response.data as string).trim()).toContain('Page not found');
|
|
59
|
+
expect(response.data).toBe(DyNTS_defaultNotFoundPageHtml);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('| GET /index.html -> 200 és static tartalom', async (): Promise<void> => {
|
|
63
|
+
const response = await Axios.get(`${INTEGRATION_BASE_URL}/index.html`, {
|
|
64
|
+
responseType: 'text',
|
|
65
|
+
});
|
|
66
|
+
expect(response.status).toBe(200);
|
|
67
|
+
expect(response.data).toContain('Integration test index');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('| GET API base path alatt (mock route) -> 200', async (): Promise<void> => {
|
|
71
|
+
const response = await Axios.get(`${INTEGRATION_BASE_URL}/api/test-0/test-base`, {
|
|
72
|
+
responseType: 'text',
|
|
73
|
+
});
|
|
74
|
+
expect(response.status).toBe(200);
|
|
75
|
+
expect(response.data).toBe('test-base');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('| GET API másik endpoint -> 200', async (): Promise<void> => {
|
|
79
|
+
const response = await Axios.get(`${INTEGRATION_BASE_URL}/api/test-0/test-simple`, {
|
|
80
|
+
responseType: 'text',
|
|
81
|
+
});
|
|
82
|
+
expect(response.status).toBe(200);
|
|
83
|
+
expect(response.data).toBe('test-simple');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
DyFM_Log,
|
|
13
13
|
} from '@futdevpro/fsm-dynamo';
|
|
14
14
|
|
|
15
|
+
import { DyNTS_defaultSocketPath } from '../../_collections/default-socket-path.const';
|
|
15
16
|
import { DyNTS_global_settings } from '../../_collections/global-settings.const';
|
|
16
17
|
import { DyNTS_RouteSecurity } from '../../_enums/route-security.enum';
|
|
17
18
|
import {
|
|
@@ -438,6 +439,7 @@ export abstract class DyNTS_AppExtended extends DyNTS_App {
|
|
|
438
439
|
* ha a service.port nincs megadva, a getPortSettings() httpPort/httpsPort értékét használjuk.
|
|
439
440
|
* Ha a base app már listenel (httpServer/httpsServer), arra attacholjuk a Socket.IO-t,
|
|
440
441
|
* különben külön httpSocketServer-t hozunk létre és listenelünk.
|
|
442
|
+
* A Socket.IO path a portSettings.socketPath-ből jön (default: DyNTS_defaultSocketPath); a kliensnek ugyanazt kell használnia.
|
|
441
443
|
*/
|
|
442
444
|
private async setupSocketServerServices(): Promise<void> {
|
|
443
445
|
try {
|
|
@@ -519,9 +521,10 @@ export abstract class DyNTS_AppExtended extends DyNTS_App {
|
|
|
519
521
|
this.httpSocketSettingUpCount++;
|
|
520
522
|
this.systemControlsExt.httpSocketServer.started = false;
|
|
521
523
|
|
|
524
|
+
const socketPath: string = this.portSettings.socketPath ?? DyNTS_defaultSocketPath;
|
|
522
525
|
this.allSocketServers.push(
|
|
523
526
|
await service.setupSocketServer(
|
|
524
|
-
new SocketIO.Server(serverForOpen),
|
|
527
|
+
new SocketIO.Server(serverForOpen, { path: socketPath }),
|
|
525
528
|
DyNTS_SocketSecurity.open,
|
|
526
529
|
(): void => {
|
|
527
530
|
this.httpSocketSettingUpCount--;
|
|
@@ -546,9 +549,10 @@ export abstract class DyNTS_AppExtended extends DyNTS_App {
|
|
|
546
549
|
this.httpsSocketSettingUpCount++;
|
|
547
550
|
this.systemControlsExt.httpsSocketServer.started = false;
|
|
548
551
|
|
|
552
|
+
const socketPathSecure: string = this.portSettings.socketPath ?? DyNTS_defaultSocketPath;
|
|
549
553
|
this.allSocketServers.push(
|
|
550
554
|
await service.setupSocketServer(
|
|
551
|
-
new SocketIO.Server(this.httpsServer),
|
|
555
|
+
new SocketIO.Server(this.httpsServer, { path: socketPathSecure }),
|
|
552
556
|
DyNTS_SocketSecurity.secure,
|
|
553
557
|
(): void => {
|
|
554
558
|
this.httpsSocketSettingUpCount--;
|
|
@@ -1327,7 +1327,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
|
|
|
1327
1327
|
...this._getDefaultErrorSettings(
|
|
1328
1328
|
'validateByPropertyParams',
|
|
1329
1329
|
new Error(
|
|
1330
|
-
|
|
1330
|
+
`Validation failed! (multiple validation errors for ${this.dataParams.dataName})` +
|
|
1331
1331
|
validationErrors.map((error: DyFM_Error) => `\n ${DyFM_Error.getAnyMessage(error)}`).join('')
|
|
1332
1332
|
)
|
|
1333
1333
|
),
|
|
@@ -1367,10 +1367,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
|
|
|
1367
1367
|
): void {
|
|
1368
1368
|
// basic required validations
|
|
1369
1369
|
if (
|
|
1370
|
-
(
|
|
1371
|
-
propertyParams.required ||
|
|
1372
|
-
propertyParams.index
|
|
1373
|
-
) && (
|
|
1370
|
+
propertyParams.required && (
|
|
1374
1371
|
propertyValue === null ||
|
|
1375
1372
|
propertyValue === undefined
|
|
1376
1373
|
)
|
|
@@ -1380,7 +1377,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
|
|
|
1380
1377
|
'validateProperty',
|
|
1381
1378
|
new Error(
|
|
1382
1379
|
`validateProperty failed, "${this.getPropertyKey(propertyParams, isSubObjectOf)}" is missing! ` +
|
|
1383
|
-
`(
|
|
1380
|
+
`(required in "${this.dataParams.dataName}" dataParams) ` +
|
|
1384
1381
|
((data as any)?.name ? `\n The failed data's name: ${(data as any).name}` : '')
|
|
1385
1382
|
)
|
|
1386
1383
|
),
|
|
@@ -1391,7 +1388,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
|
|
|
1391
1388
|
validationErrors: {
|
|
1392
1389
|
[propertyParams.key]: {
|
|
1393
1390
|
message: `validateProperty failed, "${this.getPropertyKey(propertyParams, isSubObjectOf)}" is missing! ` +
|
|
1394
|
-
`(
|
|
1391
|
+
`(required in "${this.dataParams.dataName}" dataParams) ` +
|
|
1395
1392
|
((data as any)?.name ? `\n The failed data's name: ${(data as any).name}` : ''),
|
|
1396
1393
|
code: `${this.ecBase}DyNTS-DS0-VP1`,
|
|
1397
1394
|
userMessage: 'The property is required and must be a valid value!',
|
|
@@ -1495,11 +1495,17 @@ export class DyNTS_DBService<T extends DyFM_Metadata> {
|
|
|
1495
1495
|
}
|
|
1496
1496
|
|
|
1497
1497
|
if (!properties._deletedBy) {
|
|
1498
|
-
properties._deletedBy = {
|
|
1498
|
+
properties._deletedBy = {
|
|
1499
1499
|
key: '_deletedBy', type: DyFM_BasicProperty_Type.string,
|
|
1500
1500
|
};
|
|
1501
1501
|
}
|
|
1502
1502
|
|
|
1503
|
+
if (!properties._archived) {
|
|
1504
|
+
properties._archived = {
|
|
1505
|
+
key: '_archived', type: DyFM_BasicProperty_Type.date,
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1503
1509
|
return properties;
|
|
1504
1510
|
}
|
|
1505
1511
|
|
|
@@ -1521,10 +1527,12 @@ export class DyNTS_DBService<T extends DyFM_Metadata> {
|
|
|
1521
1527
|
}
|
|
1522
1528
|
|
|
1523
1529
|
if (!properties._archived) {
|
|
1524
|
-
properties._archived = {
|
|
1530
|
+
properties._archived = {
|
|
1525
1531
|
key: '_archived', type: DyFM_BasicProperty_Type.date,
|
|
1526
|
-
required: true,
|
|
1532
|
+
required: true,
|
|
1527
1533
|
};
|
|
1534
|
+
} else if (properties._archived.required === undefined) {
|
|
1535
|
+
properties._archived.required = true;
|
|
1528
1536
|
}
|
|
1529
1537
|
|
|
1530
1538
|
return properties;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import { DyFM_Error, DyFM_HttpCallType } from '@futdevpro/fsm-dynamo';
|
|
3
3
|
|
|
4
|
+
import { DyNTS_global_settings } from '../../_collections/global-settings.const';
|
|
4
5
|
import { DyNTS_RouteSecurity } from '../../_enums/route-security.enum';
|
|
5
6
|
import { DyNTS_Endpoint_Params } from '../../_models/control-models/endpoint-params.control-model';
|
|
6
7
|
import {
|
|
@@ -80,4 +81,18 @@ describe('| DyNTS_RoutingModule', () => {
|
|
|
80
81
|
routingModule.endpoints = [ mockEndpoint, mockEndpoint ];
|
|
81
82
|
expect(() => routingModule['mountRoutes']()).toThrowError(/ENDPOINT DUPLICATION/);
|
|
82
83
|
});
|
|
84
|
+
|
|
85
|
+
it('| should use DyNTS_global_settings.baseUrl as route prefix', () => {
|
|
86
|
+
const originalBaseUrl: string = DyNTS_global_settings.baseUrl;
|
|
87
|
+
try {
|
|
88
|
+
DyNTS_global_settings.baseUrl = '/custom-api';
|
|
89
|
+
const moduleWithCustomBase: DyNTS_RoutingModule = new DyNTS_RoutingModule({
|
|
90
|
+
route: '/foo',
|
|
91
|
+
controllers: [ mockController ],
|
|
92
|
+
});
|
|
93
|
+
expect(moduleWithCustomBase.route).toBe('/custom-api/foo');
|
|
94
|
+
} finally {
|
|
95
|
+
DyNTS_global_settings.baseUrl = originalBaseUrl;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
83
98
|
});
|