@adaas/a-utils 0.1.29 → 0.1.31

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.
@@ -0,0 +1,195 @@
1
+ import { A_Context, A_Fragment, A_TYPES__Component_Constructor } from "@adaas/a-concept";
2
+ import { A_Signal } from "../entities/A-Signal.entity";
3
+ import { A_SignalVector } from "../entities/A-SignalVector.entity";
4
+
5
+ /**
6
+ * A_SignalState manages the latest state of all signals within a given scope.
7
+ *
8
+ * This class maintains a mapping between signal constructors and their most recently emitted values,
9
+ * providing a centralized state store for signal management within an application context.
10
+ *
11
+ * @template TSignalData - Union type of all possible signal data types that can be stored (must extend Record<string, any>)
12
+ *
13
+ * The generic ensures type safety by maintaining correspondence between:
14
+ * - Signal constructor types and their data types
15
+ * - Signal instances and their emitted value types
16
+ * - Vector structure and the data it contains
17
+ */
18
+ export class A_SignalState<
19
+ TSignalData extends Record<string, any> = Record<string, any>
20
+ > extends A_Fragment {
21
+
22
+ /**
23
+ * Internal map storing the relationship between signal constructors and their latest values
24
+ * Key: Signal constructor function
25
+ * Value: Latest emitted data from that signal type
26
+ */
27
+ protected _state: Map<A_TYPES__Component_Constructor<A_Signal>, A_Signal> = new Map();
28
+
29
+ /**
30
+ * Optional structure defining the ordered list of signal constructors
31
+ * Used for vector operations and initialization
32
+ */
33
+ protected _structure: Array<A_TYPES__Component_Constructor<A_Signal>>;
34
+
35
+
36
+ /**
37
+ * Gets the ordered structure of signal constructors
38
+ * @returns Array of signal constructors in their defined order
39
+ */
40
+ get structure(): Array<A_TYPES__Component_Constructor<A_Signal>> {
41
+ return this._structure || [];
42
+ }
43
+
44
+ /**
45
+ * Creates a new A_SignalState instance
46
+ *
47
+ * @param structure - Optional array defining the ordered structure of signal constructors
48
+ * This structure is used for vector operations and determines the order
49
+ * in which signals are processed and serialized
50
+ */
51
+ constructor(
52
+ structure: A_TYPES__Component_Constructor<A_Signal>[]
53
+ ) {
54
+ super({ name: "A_SignalState" });
55
+
56
+ this._structure = structure;
57
+
58
+ // Initialize the state map with undefined values for each signal in the structure
59
+ // This ensures all expected signals have entries in the state map from the start
60
+
61
+ }
62
+
63
+
64
+ /**
65
+ * Sets the latest value for a specific signal type
66
+ *
67
+ * @param signal - The signal constructor to associate the value with
68
+ * @param value - The data value emitted by the signal
69
+ */
70
+ set(
71
+ signal: A_Signal,
72
+ value: A_Signal
73
+ ): void
74
+ set(
75
+ signal: A_Signal
76
+ ): void
77
+ set(
78
+ signal: A_TYPES__Component_Constructor<A_Signal>,
79
+ value: A_Signal
80
+ ): void
81
+ set(
82
+ param1: A_TYPES__Component_Constructor<A_Signal> | A_Signal,
83
+ param2?: A_Signal
84
+ ): void {
85
+ const signal = param1 instanceof A_Signal ? param1.constructor as A_TYPES__Component_Constructor<A_Signal> : param1;
86
+ const value = param1 instanceof A_Signal ? param1 : param2!;
87
+
88
+ this._state.set(signal, value);
89
+ }
90
+
91
+ /**
92
+ * Retrieves the latest value for a specific signal type
93
+ *
94
+ * @param signal - The signal constructor to get the value for
95
+ * @returns The latest data value or undefined if no value has been set
96
+ */
97
+ get(
98
+ signal: A_Signal
99
+ ): A_Signal | undefined
100
+ get(
101
+ signal: A_TYPES__Component_Constructor<A_Signal>
102
+ ): A_Signal | undefined
103
+ get(
104
+ param: A_TYPES__Component_Constructor<A_Signal> | A_Signal
105
+ ): A_Signal | undefined {
106
+ const signal = param instanceof A_Signal ? param.constructor as A_TYPES__Component_Constructor<A_Signal> : param;
107
+ return this._state.get(signal);
108
+ }
109
+
110
+ /**
111
+ * Checks if a signal type has been registered in the state
112
+ *
113
+ * @param signal - The signal constructor to check for
114
+ * @returns True if the signal type exists in the state map
115
+ */
116
+ has(
117
+ signal: A_Signal
118
+ ): boolean
119
+ has(
120
+ signal: A_TYPES__Component_Constructor<A_Signal>
121
+ ): boolean
122
+ has(
123
+ param: A_TYPES__Component_Constructor<A_Signal> | A_Signal
124
+ ): boolean {
125
+ const signal = param instanceof A_Signal ? param.constructor as A_TYPES__Component_Constructor<A_Signal> : param;
126
+
127
+ return this.structure.includes(signal);
128
+ }
129
+
130
+ /**
131
+ * Removes a signal type and its associated value from the state
132
+ *
133
+ * @param signal - The signal constructor to remove
134
+ * @returns True if the signal was successfully deleted, false if it didn't exist
135
+ */
136
+ delete(
137
+ signal: A_Signal
138
+ ): boolean
139
+ delete(
140
+ signal: A_TYPES__Component_Constructor<A_Signal>
141
+ ): boolean
142
+ delete(
143
+ param: A_TYPES__Component_Constructor<A_Signal> | A_Signal
144
+ ): boolean {
145
+ const signal = param instanceof A_Signal ? param.constructor as A_TYPES__Component_Constructor<A_Signal> : param;
146
+ return this._state.delete(signal);
147
+ }
148
+
149
+
150
+ /**
151
+ * Converts the current state to a vector (ordered array) format
152
+ *
153
+ * The order is determined by the structure array provided during construction.
154
+ * Each position in the vector corresponds to a specific signal type's latest value.
155
+ *
156
+ * @returns Array of signal values in the order defined by the structure
157
+ * @throws Error if structure is not defined or if any signal value is undefined
158
+ */
159
+ toVector(): A_SignalVector {
160
+ const vector: Array<A_Signal> = [];
161
+
162
+ this._state.forEach((value, key) => {
163
+ vector.push(value);
164
+ });
165
+
166
+ return new A_SignalVector({
167
+ structure: this.structure,
168
+ values: vector
169
+ });
170
+ }
171
+
172
+ /**
173
+ * Converts the current state to an object with signal constructor names as keys
174
+ *
175
+ * This provides a more readable representation of the state where each signal
176
+ * type is identified by its constructor name.
177
+ *
178
+ * @returns Object mapping signal constructor names to their latest values
179
+ * @throws Error if any signal value is undefined
180
+ */
181
+ toObject(): Record<string, A_Signal> {
182
+ const obj: Record<string, A_Signal> = {};
183
+
184
+ this.structure.forEach((signalConstructor) => {
185
+ const value = this._state.get(signalConstructor);
186
+ if (value === undefined) {
187
+ throw new Error(`Signal ${signalConstructor.name} has no value in state`);
188
+ }
189
+ obj[signalConstructor.name] = value;
190
+ });
191
+
192
+ return obj;
193
+ }
194
+
195
+ }
@@ -0,0 +1,69 @@
1
+ import { A_Entity, A_Scope } from "@adaas/a-concept";
2
+ import { A_Signal_Init, A_Signal_Serialized } from "../A-Signal.types";
3
+ import { A_SignalFeatures } from "../A-Signal.constants";
4
+
5
+ /**
6
+ * A Signal Entity is an individual signal instance that carries data.
7
+ * Signals is a event types that uses for vectors of signals to be used for further processing.
8
+ *
9
+ * Comparing to standard events, signals should be used in case when the event impacts some "state"
10
+ * and the state should be used instead of the event itself.
11
+ *
12
+ * For example, a signal can represent the current status of a user (online/offline/away),
13
+ * while an event would represent a single action (user logged in/logged out).
14
+ *
15
+ * Signals are typically used in scenarios where the current state is more important than individual events,
16
+ * such as monitoring systems, real-time dashboards, or stateful applications.
17
+ */
18
+ export class A_Signal<
19
+ _TSignalDataType extends Record<string, any> = Record<string, any>
20
+ > extends A_Entity<A_Signal_Init<_TSignalDataType>, A_Signal_Serialized<_TSignalDataType>> {
21
+
22
+ data!: _TSignalDataType;
23
+
24
+
25
+ /**
26
+ * Allows to define default data for the signal.
27
+ *
28
+ * If no data is provided during initialization, the default data will be used.
29
+ *
30
+ * @returns
31
+ */
32
+ static async default(): Promise<A_Signal | undefined> {
33
+ return undefined;
34
+ }
35
+
36
+
37
+
38
+ fromJSON(serializedEntity: A_Signal_Serialized<_TSignalDataType>): void {
39
+ super.fromJSON(serializedEntity);
40
+ this.data = serializedEntity.data;
41
+ }
42
+
43
+
44
+ fromNew(newEntity: A_Signal_Init<_TSignalDataType>): void {
45
+ this.aseid = this.generateASEID({ entity: newEntity.name });
46
+ this.data = newEntity.data;
47
+ }
48
+
49
+ /**
50
+ * Emits this signal within the provided scope.
51
+ *
52
+ * Scope is mandatory since signal itself should not be registered in the scope,
53
+ * but should use particular scope context to use proper set of components
54
+ *
55
+ * @param scope
56
+ */
57
+ async emit(scope: A_Scope) {
58
+ await this.call(A_SignalFeatures.Emit, scope);
59
+ }
60
+
61
+
62
+ toJSON(): A_Signal_Serialized<_TSignalDataType> {
63
+ return {
64
+ ...super.toJSON(),
65
+ data: this.data
66
+ };
67
+ }
68
+
69
+ }
@@ -0,0 +1,198 @@
1
+ import { A_Entity, A_TYPES__Component_Constructor, A_TYPES__Entity_Constructor } from "@adaas/a-concept";
2
+ import { A_SignalVector_Serialized, A_SignalVector_Init } from "../A-Signal.types";
3
+ import { A_Signal } from "./A-Signal.entity";
4
+
5
+
6
+ /**
7
+ * A Signal Vector Entity is a collection of signals structured in a specific way.
8
+ * It allows grouping multiple signals together for batch processing or transmission.
9
+ *
10
+ * Signal Vectors are useful in scenarios where multiple related signals need to be handled together,
11
+ * as a state of the system or a snapshot of various parameters at a given time.
12
+ *
13
+ * @template TSignalsConstructors - Array of signal constructor types (e.g., [typeof MySignal, typeof CustomSignal])
14
+ * @template TSignals - Array of signal instances derived from constructors
15
+ */
16
+ export class A_SignalVector<
17
+ TSignals extends Array<A_Signal> = Array<A_Signal>,
18
+ TSignalsConstructors extends Array<A_TYPES__Entity_Constructor<A_Signal>> = TSignals extends Array<infer U> ? U extends A_Signal ? A_TYPES__Entity_Constructor<U>[] : never : never
19
+ > extends A_Entity<A_SignalVector_Init<TSignals[number][], TSignalsConstructors>, A_SignalVector_Serialized> {
20
+
21
+ /**
22
+ * The structure of the signal vector, defining the types of signals it contains.
23
+ *
24
+ * For example:
25
+ * [UserSignInSignal, UserStatusSignal, UserActivitySignal]
26
+ *
27
+ * [!] if not provided, it will be derived from the signals values.
28
+ */
29
+ protected _structure?: TSignalsConstructors;
30
+ /**
31
+ * It's actual vector Values of Signals like :
32
+ * [UserActionSignal, UserMousePositionSignal, ExternalDependencySignal]
33
+ */
34
+ protected _signals!: TSignals[number][]
35
+
36
+
37
+ fromNew(newEntity: A_SignalVector_Init<TSignals[number][], TSignalsConstructors>): void {
38
+ super.fromNew(newEntity);
39
+ this._structure = newEntity.structure;
40
+ this._signals = newEntity.values;
41
+ }
42
+
43
+ /**
44
+ * The structure of the signal vector, defining the types of signals it contains.
45
+ *
46
+ * For example:
47
+ * [UserSignInSignal, UserStatusSignal, UserActivitySignal]
48
+ *
49
+ */
50
+ get structure(): TSignalsConstructors {
51
+ return this._structure || this._signals.map(s => s.constructor as A_TYPES__Entity_Constructor<A_Signal>) as TSignalsConstructors;
52
+ }
53
+
54
+
55
+ get length(): number {
56
+ return this.structure.length;
57
+ }
58
+
59
+
60
+ /**
61
+ * Checks if the vector contains a signal of the specified type.
62
+ *
63
+ * @param signal
64
+ */
65
+ has(signal: A_Signal): boolean
66
+ has(signalConstructor: A_TYPES__Component_Constructor<A_Signal>): boolean
67
+ has(param1: A_Signal | A_TYPES__Component_Constructor<A_Signal>): boolean {
68
+ let signalConstructor: A_TYPES__Component_Constructor<A_Signal>;
69
+ if (param1 instanceof A_Entity) {
70
+ signalConstructor = param1.constructor as A_TYPES__Component_Constructor<A_Signal>;
71
+ } else {
72
+ signalConstructor = param1;
73
+ }
74
+ return this.structure.includes(signalConstructor);
75
+ }
76
+
77
+ get(signal: A_Signal): Record<string, any> | undefined
78
+ get(signalConstructor: A_TYPES__Component_Constructor<A_Signal>): Record<string, any> | undefined
79
+ get(param1: A_Signal | A_TYPES__Component_Constructor<A_Signal>): Record<string, any> | undefined {
80
+ let signalConstructor: A_TYPES__Component_Constructor<A_Signal>;
81
+
82
+ if (param1 instanceof A_Entity) {
83
+ signalConstructor = param1.constructor as A_TYPES__Component_Constructor<A_Signal>;
84
+ } else {
85
+ signalConstructor = param1;
86
+ }
87
+
88
+ const index = this._signals.findIndex(s => s.constructor === signalConstructor);
89
+ if (index === -1) {
90
+ return undefined;
91
+ }
92
+ return this._signals[index];
93
+ }
94
+
95
+
96
+ /**
97
+ * Converts to Array of values of signals in the vector
98
+ * Maintains the order specified in the structure/generic type
99
+ *
100
+ * @param structure - Optional structure to override the default ordering
101
+ * @returns Array of signal instances in the specified order
102
+ */
103
+ async toVector<
104
+ T extends Array<A_Signal> = TSignals,
105
+ >(
106
+ structure?: { [K in keyof T]: T[K] extends A_Signal ? A_TYPES__Entity_Constructor<T[K]> : never }
107
+ ): Promise<{ [K in keyof T]: T[K] }> {
108
+ const usedStructure = structure || this.structure;
109
+
110
+ return usedStructure.map((signalConstructor) => {
111
+ const signalIndex = this._signals.findIndex(s => s.constructor === signalConstructor);
112
+ return signalIndex !== -1 ? this._signals[signalIndex] : undefined;
113
+ }) as { [K in keyof T]: T[K] };
114
+ }
115
+
116
+
117
+ /**
118
+ * Converts to Array of data of signals in the vector
119
+ * Maintains the order specified in the structure/generic type
120
+ *
121
+ * @param structure - Optional structure to override the default ordering
122
+ * @returns Array of serialized signal data in the specified order
123
+ */
124
+ async toDataVector<
125
+ T extends Array<A_Signal> = TSignals,
126
+ >(
127
+ structure?: { [K in keyof T]: T[K] extends A_Signal ? A_TYPES__Entity_Constructor<T[K]> : never }
128
+ ): Promise<{ [K in keyof T]: T[K] extends A_Signal<infer D> ? D | undefined : never }> {
129
+
130
+ const usedStructure = structure || this.structure;
131
+
132
+ const results: Array<any> = [];
133
+
134
+ for (const signalConstructor of usedStructure) {
135
+ const signalIndex = this._signals.findIndex(s => s.constructor === signalConstructor);
136
+ let data: any;
137
+ if (signalIndex === -1) {
138
+
139
+ data = await (signalConstructor as typeof A_Signal).default()
140
+
141
+ } else {
142
+ const signal = this._signals[signalIndex];
143
+ data = signal;
144
+ }
145
+
146
+
147
+ results.push(data?.toJSON().data);
148
+ }
149
+
150
+ return results as { [K in keyof T]: T[K] extends A_Signal<infer D> ? D | undefined : never };
151
+ }
152
+
153
+ /**
154
+ * Converts to Object with signal constructor names as keys and their corresponding data values
155
+ * Uses the structure ordering to ensure consistent key ordering
156
+ *
157
+ * @returns Object with signal constructor names as keys and signal data as values
158
+ */
159
+ async toObject<
160
+ T extends Array<A_Signal> = TSignals,
161
+ >(
162
+ structure?: { [K in keyof T]: T[K] extends A_Signal ? A_TYPES__Entity_Constructor<T[K]> : never }
163
+ ): Promise<{ [key: string]: T[number] extends A_Signal<infer D> ? D | undefined : never }> {
164
+
165
+ const usedStructure = structure || this.structure;
166
+
167
+ const obj: { [key: string]: T[number] extends A_Signal<infer D> ? D | undefined : never } = {};
168
+ usedStructure.forEach((signalConstructor) => {
169
+ const signalName = signalConstructor.name;
170
+ const signalIndex = this._signals.findIndex(s => s.constructor === signalConstructor);
171
+
172
+ if (signalIndex !== -1) {
173
+ const signal = this._signals[signalIndex];
174
+ obj[signalName] = signal.toJSON().data as any;
175
+ } else {
176
+ obj[signalName] = undefined as any;
177
+ }
178
+ });
179
+
180
+ return obj;
181
+ }
182
+
183
+
184
+ /**
185
+ * Serializes the Signal Vector to a JSON-compatible format.
186
+ *
187
+ *
188
+ * @returns
189
+ */
190
+ toJSON(): A_SignalVector_Serialized {
191
+ return {
192
+ ...super.toJSON(),
193
+ structure: this.structure.map(s => s.name),
194
+ values: this._signals.map(s => s.toJSON())
195
+ };
196
+ }
197
+ }
198
+
@@ -215,7 +215,8 @@ describe('A_Logger Component', () => {
215
215
 
216
216
  const logs = getCapturedLogs();
217
217
  expect(logs[0]).toContain('Test error message');
218
- expect(logs[0]).toContain('"name": "Error"');
218
+ expect(logs[0]).toContain('ERROR: Error');
219
+ expect(logs[0]).toContain('STACK TRACE:');
219
220
  });
220
221
 
221
222
  test('should format A_Error instances with special formatting', () => {
@@ -253,7 +254,7 @@ describe('A_Logger Component', () => {
253
254
 
254
255
  colors.forEach(color => {
255
256
  clearCapturedLogs();
256
- logger.log(color, `${color} message`);
257
+ logger.info(color, `${color} message`);
257
258
 
258
259
  const logs = getCapturedLogs();
259
260
  expect(logs[0]).toContain(`${color} message`);
@@ -261,6 +262,26 @@ describe('A_Logger Component', () => {
261
262
  });
262
263
  });
263
264
 
265
+ test('should support extended color palette from A_LoggerColorName enum', () => {
266
+ const extendedColors: Array<keyof typeof A_LOGGER_COLORS> = [
267
+ 'brightBlue', 'brightCyan', 'brightMagenta',
268
+ 'indigo', 'violet', 'purple', 'lavender',
269
+ 'skyBlue', 'steelBlue', 'slateBlue', 'deepBlue',
270
+ 'lightBlue', 'periwinkle', 'cornflower', 'powder',
271
+ 'darkGray', 'lightGray', 'charcoal', 'silver', 'smoke', 'slate'
272
+ ];
273
+
274
+ extendedColors.forEach(color => {
275
+ clearCapturedLogs();
276
+ logger.info(color, `Extended ${color} message`);
277
+
278
+ const logs = getCapturedLogs();
279
+ // Clean the output to handle line wrapping
280
+ const cleanedOutput = logs[0].replace(/\n\s*\|\s*/g, ' ').replace(/\s+/g, ' ');
281
+ expect(cleanedOutput).toContain(`Extended ${color} message`);
282
+ });
283
+ });
284
+
264
285
  test('should default to blue color when no color specified', () => {
265
286
  logger.log('Default color message');
266
287
 
@@ -409,13 +430,19 @@ describe('A_Logger Component', () => {
409
430
  expect(logs[0]).toContain('[Circular Reference]');
410
431
  });
411
432
 
412
- test('should handle very long strings', () => {
433
+ test('should handle very long strings with wrapping', () => {
413
434
  const longString = 'A'.repeat(1000);
414
435
 
415
- logger.log('Long string:', longString);
436
+ logger.info('Long string:', longString);
416
437
 
417
438
  const logs = getCapturedLogs();
418
- expect(logs[0]).toContain(longString);
439
+ // The logger now wraps long strings, so we check for the presence of parts of the string
440
+ // rather than the entire string in one line
441
+ expect(logs[0]).toContain('Long string:');
442
+ expect(logs[0]).toContain('AAAAAAAAAAA'); // Should contain many A's
443
+ // The string should be wrapped across multiple lines
444
+ const logLines = logs[0].split('\n');
445
+ expect(logLines.length).toBeGreaterThan(5); // Should be wrapped into multiple lines
419
446
  });
420
447
 
421
448
  test('should handle empty scope name', () => {
@@ -466,6 +493,64 @@ describe('A_Logger Component', () => {
466
493
  expect(endTime - startTime).toBeLessThan(500); // Should complete within 500ms
467
494
  });
468
495
  });
496
+
497
+ // =============================================
498
+ // Terminal Width and Formatting Tests
499
+ // =============================================
500
+
501
+ describe('Terminal Width Detection and Formatting', () => {
502
+ test('should detect terminal width in Node.js environment', () => {
503
+ // The logger should initialize without errors and handle terminal width detection
504
+ expect(() => {
505
+ const testScope = new A_Scope({ name: 'TerminalTest' });
506
+ const terminalLogger = new A_Logger(testScope);
507
+ terminalLogger.info('Terminal width test message');
508
+ }).not.toThrow();
509
+ });
510
+
511
+ test('should wrap long messages appropriately', () => {
512
+ // Create a message that's extremely long to ensure wrapping even on wide terminals
513
+ // The message needs to be longer than most reasonable terminal widths (200+ chars)
514
+ const extremelyLongMessage = 'This is an extraordinarily and exceptionally long message designed specifically for testing text wrapping functionality in the A_Logger component, containing numerous words and phrases that together form a sentence of considerable length that should definitely exceed the available width in most terminal configurations, thereby demonstrating the logger\'s sophisticated text wrapping capabilities and ensuring proper formatting across diverse environments with varying screen sizes and terminal window dimensions, while maintaining readability and professional presentation standards.';
515
+
516
+ logger.info('cyan', extremelyLongMessage);
517
+
518
+ const logs = getCapturedLogs();
519
+
520
+ // Remove all newlines and extra spaces to get the actual content for verification
521
+ const cleanedOutput = logs[0].replace(/\n\s*\|\s*/g, ' ').replace(/\s+/g, ' ');
522
+
523
+ // Verify the message content is preserved regardless of wrapping
524
+ expect(cleanedOutput).toContain('extraordinarily and exceptionally long message');
525
+ expect(cleanedOutput).toContain('readability and professional presentation');
526
+
527
+ // The message should either be wrapped with newlines OR be very long on one line
528
+ const logOutput = logs[0];
529
+ const hasWrapping = logOutput.includes('\n') && logOutput.includes('|'); // Continuation markers
530
+ const isSingleLongLine = logOutput.length > 300; // Very long single line
531
+
532
+ // In narrow terminals, wrapping occurs with continuation markers
533
+ // In wide terminals, the message appears as one very long line
534
+ expect(hasWrapping || isSingleLongLine).toBe(true);
535
+
536
+ // Ensure the complete message is present (checking cleaned version)
537
+ expect(cleanedOutput).toContain('extraordinarily and exceptionally long message');
538
+ expect(cleanedOutput).toContain('professional presentation standards');
539
+ });
540
+
541
+ test('should handle multi-argument messages with proper indentation', () => {
542
+ logger.info('brightMagenta',
543
+ 'First long argument that might wrap across lines',
544
+ 'Second argument for testing indentation',
545
+ { complexObject: 'with nested data for formatting tests' }
546
+ );
547
+
548
+ const logs = getCapturedLogs();
549
+ expect(logs[0]).toContain('First long argument');
550
+ expect(logs[0]).toContain('Second argument');
551
+ expect(logs[0]).toContain('complexObject');
552
+ });
553
+ });
469
554
  });
470
555
 
471
556
  // =============================================
@@ -0,0 +1,34 @@
1
+ import { A_Route } from "@adaas/a-utils/lib/A-Route/A-Route.entity";
2
+
3
+
4
+
5
+
6
+ jest.retryTimes(0);
7
+
8
+ describe('A-Route tests', () => {
9
+ it('Should Allow to create a new A-Route', async () => {
10
+ let route = new A_Route('/test/route');
11
+
12
+ expect(route).toBeInstanceOf(A_Route);
13
+ expect(route.path).toBe('/test/route');
14
+ });
15
+ it('Should properly parse and extract path params', async () => {
16
+ let route = new A_Route('/test/route/:param1/:param2');
17
+
18
+ expect(route).toBeInstanceOf(A_Route);
19
+ expect(route.path).toBe('/test/route/:param1/:param2');
20
+ expect(route.params).toEqual(['param1', 'param2']);
21
+
22
+ const extractedParams = route.extractParams('/test/route/value1/value2');
23
+ expect(extractedParams).toEqual({ param1: 'value1', param2: 'value2' });
24
+ });
25
+ it('Should properly parse received URL', async () => {
26
+ let route = new A_Route('https://example.com/test/route?param1=value1&param2=value2');
27
+
28
+ expect(route).toBeInstanceOf(A_Route);
29
+ expect(route.path).toBe('/test/route');
30
+ const query = route.extractQuery('https://example.com/test/route?param1=value1&param2=value2');
31
+ expect(query).toEqual({ param1: 'value1', param2: 'value2' });
32
+ });
33
+
34
+ })