@sankhyalabs/core 5.20.0-dev.8 → 5.20.0-dev.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/.docs/classes/Base64Utils.md +39 -0
  2. package/.docs/classes/Change.md +11 -11
  3. package/.docs/classes/ColumnFilterManager.md +145 -0
  4. package/.docs/classes/DataUnit.md +429 -139
  5. package/.docs/classes/DataUnitInMemoryLoader.md +303 -0
  6. package/.docs/classes/DataUnitLoaderUtils.md +151 -0
  7. package/.docs/classes/DateUtils.md +8 -8
  8. package/.docs/classes/FieldComparator.md +2 -2
  9. package/.docs/classes/IDBRepository.md +22 -0
  10. package/.docs/classes/KeyboardManager.md +99 -9
  11. package/.docs/classes/LockManager.md +249 -0
  12. package/.docs/classes/MaskFormatter.md +66 -14
  13. package/.docs/classes/ObjectUtils.md +189 -0
  14. package/.docs/classes/OverflowWatcher.md +533 -0
  15. package/.docs/classes/SelectionInfo.md +25 -11
  16. package/.docs/classes/ServiceCanceledException.md +193 -0
  17. package/.docs/classes/ServiceUtils.md +67 -0
  18. package/.docs/classes/SilentException.md +193 -0
  19. package/.docs/classes/StringUtils.md +33 -9
  20. package/.docs/classes/UserAgentUtils.md +15 -1
  21. package/.docs/enumerations/Action.md +41 -21
  22. package/.docs/enumerations/ChangeOperation.md +4 -4
  23. package/.docs/enumerations/LockManagerOperation.md +33 -0
  24. package/.docs/enumerations/OverflowDirection.md +29 -0
  25. package/.docs/enumerations/RECORD_DATE_FORMAT.md +27 -0
  26. package/.docs/enumerations/SelectionMode.md +2 -2
  27. package/.docs/enumerations/StorageType.md +37 -0
  28. package/.docs/enumerations/UserInterface.md +15 -5
  29. package/.docs/globals.md +25 -0
  30. package/.docs/interfaces/DUActionInterceptor.md +1 -1
  31. package/.docs/interfaces/DataUnitInMemoryLoaderConfig.md +37 -0
  32. package/.docs/interfaces/IRepository.md +18 -0
  33. package/.docs/interfaces/LoadDataRequest.md +1 -1
  34. package/.docs/interfaces/OverFlowWatcherParams.md +67 -0
  35. package/.docs/interfaces/PageRequest.md +3 -3
  36. package/.docs/interfaces/PaginationInfo.md +25 -0
  37. package/.docs/interfaces/PaginationInfoBuilderParams.md +37 -0
  38. package/.docs/interfaces/QuickFilter.md +3 -3
  39. package/.docs/interfaces/Record.md +4 -4
  40. package/.docs/interfaces/SavedRecord.md +5 -5
  41. package/.docs/interfaces/WaitingChange.md +3 -3
  42. package/.docs/namespaces/MaskFormatter/type-aliases/MaskCharacter.md +1 -1
  43. package/.docs/namespaces/MaskFormatter/variables/MaskCharacter.md +1 -1
  44. package/.docs/type-aliases/DataUnitEventOptions.md +17 -0
  45. package/.docs/type-aliases/OnOverflowCallBack.md +25 -0
  46. package/.docs/variables/OVERFLOWED_CLASS_NAME.md +13 -0
  47. package/.releaserc +1 -0
  48. package/bun.lockb +0 -0
  49. package/dist/dataunit/DataUnit.d.ts +92 -13
  50. package/dist/dataunit/DataUnit.js +227 -71
  51. package/dist/dataunit/DataUnit.js.map +1 -1
  52. package/dist/dataunit/DataUnitHelper.js +6 -5
  53. package/dist/dataunit/DataUnitHelper.js.map +1 -1
  54. package/dist/dataunit/formatting/PrettyFormatter.js +17 -6
  55. package/dist/dataunit/formatting/PrettyFormatter.js.map +1 -1
  56. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.d.ts +9 -0
  57. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.js +6 -0
  58. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.js.map +1 -0
  59. package/dist/dataunit/loader/dataUnitInMemoryLoader.d.ts +25 -0
  60. package/dist/dataunit/loader/dataUnitInMemoryLoader.js +131 -0
  61. package/dist/dataunit/loader/dataUnitInMemoryLoader.js.map +1 -0
  62. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.d.ts +20 -0
  63. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.js +62 -0
  64. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.js.map +1 -0
  65. package/dist/dataunit/loading/LoadDataRequest.d.ts +1 -1
  66. package/dist/dataunit/loading/PaginationInfo.d.ts +8 -0
  67. package/dist/dataunit/metadata/DataType.js +7 -1
  68. package/dist/dataunit/metadata/DataType.js.map +1 -1
  69. package/dist/dataunit/metadata/UnitMetadata.d.ts +1 -0
  70. package/dist/dataunit/metadata/UnitMetadata.js +1 -0
  71. package/dist/dataunit/metadata/UnitMetadata.js.map +1 -1
  72. package/dist/dataunit/sorting/FieldComparator.d.ts +2 -2
  73. package/dist/dataunit/sorting/FieldComparator.js +4 -9
  74. package/dist/dataunit/sorting/FieldComparator.js.map +1 -1
  75. package/dist/dataunit/state/action/DataUnitAction.d.ts +2 -0
  76. package/dist/dataunit/state/action/DataUnitAction.js +2 -0
  77. package/dist/dataunit/state/action/DataUnitAction.js.map +1 -1
  78. package/dist/dataunit/state/slice/LoadingControlSlice.js +16 -0
  79. package/dist/dataunit/state/slice/LoadingControlSlice.js.map +1 -1
  80. package/dist/dataunit/state/slice/RecordsSlice.js +1 -1
  81. package/dist/dataunit/state/slice/RecordsSlice.js.map +1 -1
  82. package/dist/dataunit/state/slice/SelectionSlice.js +4 -4
  83. package/dist/dataunit/state/slice/SelectionSlice.js.map +1 -1
  84. package/dist/exceptions/ServiceCanceledException.d.ts +14 -0
  85. package/dist/exceptions/ServiceCanceledException.js +13 -0
  86. package/dist/exceptions/ServiceCanceledException.js.map +1 -0
  87. package/dist/exceptions/SilentException.d.ts +14 -0
  88. package/dist/exceptions/SilentException.js +13 -0
  89. package/dist/exceptions/SilentException.js.map +1 -0
  90. package/dist/index.d.ts +13 -2
  91. package/dist/index.js +12 -1
  92. package/dist/index.js.map +1 -1
  93. package/dist/repository/IRepository.d.ts +6 -0
  94. package/dist/repository/indexeddb/IDBRepository.d.ts +1 -0
  95. package/dist/repository/indexeddb/IDBRepository.js +3 -0
  96. package/dist/repository/indexeddb/IDBRepository.js.map +1 -1
  97. package/dist/utils/Base64Utils.d.ts +7 -0
  98. package/dist/utils/Base64Utils.js +13 -0
  99. package/dist/utils/Base64Utils.js.map +1 -0
  100. package/dist/utils/CacheManager/index.d.ts +52 -0
  101. package/dist/utils/CacheManager/index.js +101 -0
  102. package/dist/utils/CacheManager/index.js.map +1 -0
  103. package/dist/utils/CacheManager/interfaces/index.d.ts +5 -0
  104. package/dist/utils/CacheManager/interfaces/index.js +7 -0
  105. package/dist/utils/CacheManager/interfaces/index.js.map +1 -0
  106. package/dist/utils/ColumnFilterManager.d.ts +19 -0
  107. package/dist/utils/ColumnFilterManager.js +73 -0
  108. package/dist/utils/ColumnFilterManager.js.map +1 -0
  109. package/dist/utils/DateUtils.js +3 -0
  110. package/dist/utils/DateUtils.js.map +1 -1
  111. package/dist/utils/ElementUtils.d.ts +2 -0
  112. package/dist/utils/ElementUtils.js +9 -0
  113. package/dist/utils/ElementUtils.js.map +1 -0
  114. package/dist/utils/KeyboardManager/index.d.ts +9 -0
  115. package/dist/utils/KeyboardManager/index.js +45 -1
  116. package/dist/utils/KeyboardManager/index.js.map +1 -1
  117. package/dist/utils/KeyboardManager/interface.d.ts +1 -0
  118. package/dist/utils/LockManager.d.ts +58 -0
  119. package/dist/utils/LockManager.js +188 -0
  120. package/dist/utils/LockManager.js.map +1 -0
  121. package/dist/utils/MaskFormatter.d.ts +16 -1
  122. package/dist/utils/MaskFormatter.js +82 -2
  123. package/dist/utils/MaskFormatter.js.map +1 -1
  124. package/dist/utils/ObjectUtils.d.ts +52 -0
  125. package/dist/utils/ObjectUtils.js +71 -0
  126. package/dist/utils/ObjectUtils.js.map +1 -1
  127. package/dist/utils/OnboardingUtils.js +1 -1
  128. package/dist/utils/OnboardingUtils.js.map +1 -1
  129. package/dist/utils/OverflowWatcher/index.d.ts +59 -0
  130. package/dist/utils/OverflowWatcher/index.js +188 -0
  131. package/dist/utils/OverflowWatcher/index.js.map +1 -0
  132. package/dist/utils/OverflowWatcher/types/overflow-callback.d.ts +6 -0
  133. package/dist/utils/OverflowWatcher/types/overflow-callback.js +2 -0
  134. package/dist/utils/OverflowWatcher/types/overflow-callback.js.map +1 -0
  135. package/dist/utils/OverflowWatcher/types/overflow-direction.d.ts +7 -0
  136. package/dist/utils/OverflowWatcher/types/overflow-direction.js +9 -0
  137. package/dist/utils/OverflowWatcher/types/overflow-direction.js.map +1 -0
  138. package/dist/utils/ServiceUtils.d.ts +24 -0
  139. package/dist/utils/ServiceUtils.js +40 -0
  140. package/dist/utils/ServiceUtils.js.map +1 -0
  141. package/dist/utils/SortingUtils.d.ts +9 -0
  142. package/dist/utils/SortingUtils.js +24 -0
  143. package/dist/utils/SortingUtils.js.map +1 -0
  144. package/dist/utils/StringUtils.d.ts +6 -0
  145. package/dist/utils/StringUtils.js +23 -6
  146. package/dist/utils/StringUtils.js.map +1 -1
  147. package/dist/utils/UserAgentUtils/index.d.ts +1 -0
  148. package/dist/utils/UserAgentUtils/index.js +5 -0
  149. package/dist/utils/UserAgentUtils/index.js.map +1 -1
  150. package/jest.config.ts +2 -0
  151. package/package.json +2 -1
  152. package/reports/test-report.xml +760 -0
  153. package/setupTests.js +7 -0
  154. package/sonar-project.properties +6 -3
  155. package/src/dataunit/DataUnit.ts +278 -86
  156. package/src/dataunit/DataUnitHelper.ts +6 -5
  157. package/src/dataunit/formatting/PrettyFormatter.ts +19 -6
  158. package/src/dataunit/loader/DataUnitInMemoryLoaderConfig.ts +10 -0
  159. package/src/dataunit/loader/dataUnitInMemoryLoader.ts +176 -0
  160. package/src/dataunit/loader/utils/dataUnitLoaderUtils.ts +86 -0
  161. package/src/dataunit/loading/LoadDataRequest.ts +1 -1
  162. package/src/dataunit/loading/PaginationInfo.ts +10 -0
  163. package/src/dataunit/metadata/DataType.ts +8 -1
  164. package/src/dataunit/metadata/UnitMetadata.ts +1 -0
  165. package/src/dataunit/sorting/FieldComparator.ts +18 -32
  166. package/src/dataunit/state/action/DataUnitAction.ts +2 -0
  167. package/src/dataunit/state/slice/LoadingControlSlice.ts +42 -0
  168. package/src/dataunit/state/slice/RecordsSlice.ts +1 -1
  169. package/src/dataunit/state/slice/SelectionSlice.ts +4 -4
  170. package/src/dataunit/state/slice/test/RecordsSlice.spec.ts +45 -0
  171. package/src/dataunit/test/DataUnit.spec.ts +44 -0
  172. package/src/exceptions/ServiceCanceledException.ts +25 -0
  173. package/src/exceptions/SilentException.ts +25 -0
  174. package/src/index.ts +32 -1
  175. package/src/repository/IRepository.ts +7 -0
  176. package/src/repository/indexeddb/IDBRepository.ts +4 -0
  177. package/src/utils/Base64Utils.ts +13 -0
  178. package/src/utils/CacheManager/index.ts +103 -0
  179. package/src/utils/CacheManager/interfaces/index.ts +5 -0
  180. package/src/utils/ColumnFilterManager.ts +104 -0
  181. package/src/utils/DateUtils.ts +3 -0
  182. package/src/utils/ElementUtils.ts +10 -0
  183. package/src/utils/KeyboardManager/index.ts +57 -0
  184. package/src/utils/KeyboardManager/interface.ts +1 -0
  185. package/src/utils/LockManager.ts +207 -0
  186. package/src/utils/MaskFormatter.ts +93 -2
  187. package/src/utils/ObjectUtils.ts +77 -0
  188. package/src/utils/OnboardingUtils.ts +1 -1
  189. package/src/utils/OverflowWatcher/index.ts +243 -0
  190. package/src/utils/OverflowWatcher/types/overflow-callback.ts +6 -0
  191. package/src/utils/OverflowWatcher/types/overflow-direction.ts +7 -0
  192. package/src/utils/ServiceUtils.ts +36 -0
  193. package/src/utils/SortingUtils.ts +30 -0
  194. package/src/utils/StringUtils.ts +23 -6
  195. package/src/utils/UserAgentUtils/index.ts +6 -1
  196. package/test/dataunit/formatting/PrettyFormatter.spec.ts +177 -0
  197. package/test/dataunit/loader/dataUnitInMemoryLoader.spec.ts +221 -0
  198. package/test/dataunit/loader/utils/dataUnitLoaderUtils.spec.ts +158 -0
  199. package/test/testCases/NumberUtilsTestCases.ts +190 -0
  200. package/test/testCases/StringUtilsTestCases.ts +435 -0
  201. package/test/testCases/TimeFormatterTestUtils.ts +43 -0
  202. package/test/util/ColumnFilterManager.spec.ts +133 -0
  203. package/test/util/ElementUtils.spec.ts +34 -0
  204. package/test/util/NumberUtils.spec.ts +72 -150
  205. package/test/util/ObjectUtils.spec.ts +572 -0
  206. package/test/util/OverflowWatcher.spec.ts +152 -0
  207. package/test/util/StringUtils.spec.ts +260 -36
  208. package/test/util/TimeFormatter.spec.ts +65 -18
@@ -0,0 +1,36 @@
1
+ import { CacheManager } from './CacheManager/index.js';
2
+ import { StorageType } from './CacheManager/interfaces/index.js';
3
+
4
+
5
+ export class ServiceUtils {
6
+
7
+
8
+ /**
9
+ * Auxilia no uso do CacheManager, gerando automaticamente uma chave de cache com base no identificador.
10
+ *
11
+ * @template T Tipo do dado a ser retornado.
12
+ * @param identifier Identificadores únicos usados para compor a chave de cache.
13
+ * @param fetchFunction Função que retorna uma `Promise` com o valor a ser armazenado no cache caso ele não exista ou tenha expirado.
14
+ * @param storageType Tipo de armazenamento: `'sessionStorage'` ou `'localStorage'`. O padrão é `'sessionStorage'`.
15
+ * @returns Uma `Promise` com o valor armazenado ou obtido via `fetchFunction`.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const actions = await useCacheWithService(
20
+ * `${this.entityName} - ${this.resourceID}`,
21
+ * async () => {
22
+ * return await fetchActionsFromAPI();
23
+ * }
24
+ * );
25
+ * console.log(actions);
26
+ * ```
27
+ */
28
+ public static async useCacheWithService<T>(
29
+ identifier: string,
30
+ fetchFunction: () => Promise<T>,
31
+ storageType: StorageType = StorageType.IN_MEMORY_CACHE
32
+ ): Promise<T> {
33
+ const cacheKey = `${identifier}`;
34
+ return CacheManager.getOrSet(cacheKey, fetchFunction, storageType);
35
+ }
36
+ }
@@ -0,0 +1,30 @@
1
+ import DataUnit from "../dataunit/DataUnit.js";
2
+ import { FieldDescriptor, Sort, SortMode } from "../dataunit/metadata/UnitMetadata.js";
3
+ import { FieldComparator } from "../dataunit/sorting/FieldComparator.js";
4
+ import { Record } from '../dataunit/DataUnit.js';
5
+
6
+ /**
7
+ * `SortingUtils`: Utilizado para auxiliar na ordenacao de registros.
8
+ */
9
+ export default class SortingUtils {
10
+
11
+ public static getSortingFunction(dataUnit: DataUnit, sorting?: Array<Sort>): ((recordA: Record, recordB: Record) => number) | undefined {
12
+
13
+ if (sorting == undefined || sorting.length == 0) {
14
+ return undefined;
15
+ }
16
+
17
+ return (recordA, recordB) => {
18
+ for (const sort of sorting) {
19
+ if (sort.field){
20
+ const result = FieldComparator.compare(dataUnit.getField(sort.field) as FieldDescriptor, recordA, recordB, sort.mode === SortMode.ASC);
21
+ if (result != 0) {
22
+ return result;
23
+ }
24
+ }
25
+ }
26
+ return 0;
27
+ };
28
+ }
29
+
30
+ }
@@ -289,7 +289,7 @@ export class StringUtils {
289
289
  * @returns String convertida em PascalCase.
290
290
  */
291
291
  static toPascalCase(value: string): string{
292
- return value
292
+ return (value || "")
293
293
  .toLowerCase()
294
294
  .replace(/(?:^|\s)\w/g, (match: string) => match.toUpperCase())
295
295
  .replace(/[\s-_]/g,'');
@@ -301,7 +301,7 @@ export class StringUtils {
301
301
  * @returns String convertida em snake_case.
302
302
  */
303
303
  static toSnakeCase(value: string): string{
304
- return value
304
+ return (value || "")
305
305
  .toLowerCase()
306
306
  .replace(/[A-Z]/g, (match: string) => `_${match.toLowerCase()}`)
307
307
  .replace(/[\s-]/g, '_')
@@ -314,7 +314,7 @@ export class StringUtils {
314
314
  * @returns String convertida em KebabCase.
315
315
  */
316
316
  static toKebabCase(value: string): string{
317
- return value.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/[\s_]+/g, '-').toLowerCase();
317
+ return (value || "").replace(/([a-z])([A-Z])/g, '$1-$2').replace(/[\s_]+/g, '-').toLowerCase();
318
318
  }
319
319
 
320
320
  /**
@@ -336,13 +336,13 @@ export class StringUtils {
336
336
  const units = ["B", "KB", "MB", "GB"];
337
337
 
338
338
  if (bytes < 1024) {
339
- return `${bytes.toString()}B`;
339
+ return `${bytes?.toString()}B`;
340
340
  }
341
341
 
342
342
  const base = Math.log(bytes) / Math.log(1024);
343
343
  const offSet = Math.floor(base);
344
344
  if (offSet >= units.length) {
345
- return `${bytes.toString()}B`;
345
+ return `${bytes?.toString()}B`;
346
346
  }
347
347
 
348
348
  const value = this.prettyPrecision(Math.pow(1024, base - offSet).toFixed(2).toString());
@@ -389,6 +389,8 @@ export class StringUtils {
389
389
  * @return {boolean} Se a string pode ser convertida
390
390
  */
391
391
  static isCaseable(original: string): boolean {
392
+ if(original == null) return false;
393
+
392
394
  const uppercase = original.toUpperCase()
393
395
  const lowercase = original.toLowerCase()
394
396
 
@@ -402,6 +404,7 @@ export class StringUtils {
402
404
  * @return {boolean} Se a string é minúscula
403
405
  */
404
406
  static isLowerCase(original: string): boolean {
407
+ if(original == null) return false;
405
408
  const uppercase = original.toUpperCase()
406
409
 
407
410
  return this.isCaseable(original) && uppercase !== original
@@ -414,6 +417,7 @@ export class StringUtils {
414
417
  * @return {string} A string invertida
415
418
  */
416
419
  static getOppositeCase(original: string): string {
420
+ if(original == null) return "";
417
421
  return this.isLowerCase(original) ? original.toUpperCase() : original.toLowerCase()
418
422
  }
419
423
 
@@ -487,7 +491,7 @@ export class StringUtils {
487
491
  }
488
492
 
489
493
  public static highlightValue(argument: String, matchFields: any, value: string, fieldMD: any, forceMatch: boolean) {
490
- const startHighlightTag = "<span class='card-item__highlight'>";
494
+ const startHighlightTag = "<span class='card-item__highlight'>"; //FIXME: valor hardcoded, não podemos reaproveitar para outros cenários, dessa forma.
491
495
  const endHighlightTag = "</span>";
492
496
  let valueAux = JSUtils.replaceHtmlEntities(value);
493
497
 
@@ -538,4 +542,17 @@ export class StringUtils {
538
542
 
539
543
  return valueAux;
540
544
  }
545
+
546
+
547
+ /**
548
+ * Escapa caracteres especiais em uma string, usando sequencias de escape Unicode.
549
+ * @param str A string que deve sofrer alteração.
550
+ * @returns String com valores alterados.
551
+ */
552
+ public static escapeString(str: string): string {
553
+ // eslint-disable-next-line no-control-regex
554
+ return str.replace(/[\u0000-\u001F\u007F-\uFFFF<>=&"']/g, (char) => {
555
+ return "\\u" + char.charCodeAt(0).toString(16).padStart(4, "0");
556
+ });
557
+ }
541
558
  }
@@ -15,6 +15,11 @@ export class UserAgentUtils {
15
15
  return !!browser.firefox;
16
16
  }
17
17
 
18
+ public static isElectron() {
19
+ const browser = this.getBrowserInfo();
20
+ return !!browser.electron;
21
+ }
22
+
18
23
  /**
19
24
  * Obtém nome e versão do navegador que está sendo utilizado.
20
25
  * @returns Objeto com o nome e versão do navegador.
@@ -40,6 +45,7 @@ export class UserAgentUtils {
40
45
  }
41
46
  } catch (e) {
42
47
  //ignored
48
+ console.warn(e);
43
49
  }
44
50
 
45
51
  browser = {
@@ -49,7 +55,6 @@ export class UserAgentUtils {
49
55
  simpleVersion,
50
56
  ...(Array.isArray(type) ? type.reduce((acc, val) => ({ ...acc, [val]: true}), {}) : { [type]: true })
51
57
  }
52
-
53
58
  return !hasFound;
54
59
  }
55
60
  })
@@ -0,0 +1,177 @@
1
+ import { getFormattedValue } from '../../../src/dataunit/formatting/PrettyFormatter';
2
+ import { DataType, FieldDescriptor, UserInterface } from '../../../src';
3
+
4
+ /**
5
+ * É preciso importart o utilitário DateUtils para que seus métodos
6
+ * estáticos sejam executados no ambiente de testes
7
+ */
8
+
9
+ import { DateUtils } from '../../../src';
10
+
11
+ describe('getFormattedValue', () => {
12
+ it('should return empty string when value is null', () => {
13
+ const value = null;
14
+ const descriptor = getFileFieldDescriptor();
15
+ expect(getFormattedValue(value, descriptor)).toBe('');
16
+ });
17
+
18
+ it('should return empty string when value is not an array', () => {
19
+ const value = 'not an array';
20
+ const descriptor = getFileFieldDescriptor();
21
+ expect(getFormattedValue(value, descriptor)).toBe('');
22
+ });
23
+
24
+ it('should return empty string when value is an empty array', () => {
25
+ const value: any[] = [];
26
+ const descriptor = getFileFieldDescriptor();
27
+ expect(getFormattedValue(value, descriptor)).toBe('0 arquivos');
28
+ });
29
+
30
+ it('should return file name when value is an array with one file object', () => {
31
+ const value = [{ name: 'file1.txt' }];
32
+ const descriptor = getFileFieldDescriptor();
33
+ expect(getFormattedValue(value, descriptor)).toBe('file1.txt');
34
+ });
35
+
36
+ it('should return file count when value is an array with multiple file objects', () => {
37
+ const value = [{ name: 'file1.txt' }, { name: 'file2.txt' }];
38
+ const descriptor = getFileFieldDescriptor();
39
+ expect(getFormattedValue(value, descriptor)).toBe('2 arquivos');
40
+ });
41
+
42
+ it('should return empty string for undefined file', () => {
43
+ const value = undefined;
44
+ const descriptor = { userInterface: UserInterface.FILE } as FieldDescriptor;
45
+ expect(getFormattedValue(value, descriptor)).toBe('');
46
+ });
47
+
48
+ it('should handle OBJECT type with value field', () => {
49
+ const value = { value: 'code', label: 'label' };
50
+ const descriptor = { dataType: DataType.OBJECT, userInterface: UserInterface.SEARCH } as FieldDescriptor;
51
+ expect(getFormattedValue(value, descriptor)).toBe('code - label');
52
+ });
53
+
54
+ it('should return empty string when value is undefined', () => {
55
+ const value = undefined;
56
+ const descriptor = getObjectFieldDescriptor();
57
+ expect(getFormattedValue(value, descriptor)).toBe('');
58
+ });
59
+
60
+ it('should return value as string when value is not an object', () => {
61
+ const value = 12345;
62
+ const descriptor = getObjectFieldDescriptor();
63
+ expect(getFormattedValue(value, descriptor)).toBe('12345');
64
+ });
65
+
66
+ it('should return value.toString() when value is an object without value property', () => {
67
+ const value = { someProperty: 'someValue' };
68
+ const descriptor = getObjectFieldDescriptor();
69
+ expect(getFormattedValue(value, descriptor)).toBe(value.toString());
70
+ });
71
+
72
+ it('should handle BOOLEAN type', () => {
73
+ expect(getFormattedValue(true, { dataType: DataType.BOOLEAN } as FieldDescriptor)).toBe('Sim');
74
+ expect(getFormattedValue(false, { dataType: DataType.BOOLEAN } as FieldDescriptor)).toBe('Não');
75
+ });
76
+
77
+ it('should format numbers correctly', () => {
78
+ const value = 1234.567;
79
+ const descriptor = {
80
+ dataType: DataType.NUMBER,
81
+ properties: { precision: 2, prettyPrecision: 2 },
82
+ } as FieldDescriptor;
83
+ expect(getFormattedValue(value, descriptor)).toBe('1.234,57');
84
+ });
85
+
86
+ it('should format dates correctly', () => {
87
+ const value = new Date('2023-07-01T14:30:00');
88
+ const descriptor = { userInterface: UserInterface.DATE } as FieldDescriptor;
89
+ expect(getFormattedValue(value, descriptor)).toBe('01/07/2023');
90
+ });
91
+
92
+ it('should format times correctly', () => {
93
+ const value = new Date('2023-07-01T14:30:00');
94
+ const descriptor = { userInterface: UserInterface.TIME } as FieldDescriptor;
95
+ expect(getFormattedValue(value, descriptor)).toBe('14:30');
96
+ });
97
+
98
+ it('should format datetime correctly', () => {
99
+ const value = new Date('2023-07-01T14:30:00');
100
+ const descriptor = { userInterface: UserInterface.DATETIME } as FieldDescriptor;
101
+ expect(getFormattedValue(value, descriptor)).toBe('01/07/2023 14:30');
102
+ });
103
+
104
+ it('should call toString with correct parameters', () => {
105
+ const value = 123;
106
+ const descriptor = { dataType: DataType.NUMBER } as FieldDescriptor;
107
+ expect(getFormattedValue(value, descriptor)).toBe('123,00');
108
+ });
109
+
110
+ it('should handle undefined descriptor gracefully', () => {
111
+ const value = 123;
112
+ expect(getFormattedValue(value)).toBe('123');
113
+ });
114
+
115
+ it('should format value correctly with OPTIONSELECTOR and matching option', () => {
116
+ const value = 'option1';
117
+ const descriptor = buildOptionSelectorFieldDescriptor();
118
+ expect(getFormattedValue(value, descriptor)).toBe('option1');
119
+ });
120
+
121
+ it('should return value with OPTIONSELECTOR and no matching option', () => {
122
+ const value = 'option2';
123
+ const descriptor = buildOptionSelectorFieldDescriptor();
124
+ expect(getFormattedValue(value, descriptor)).toBe('option2');
125
+ });
126
+
127
+ it('should format value correctly with OPTIONSELECTOR and value as object', () => {
128
+ const value = { value: 'option1' };
129
+ const descriptor = buildOptionSelectorFieldDescriptor();
130
+ expect(getFormattedValue(value, descriptor)).toBe('option1');
131
+ });
132
+
133
+ it('should return empty string with OPTIONSELECTOR and value as null', () => {
134
+ const value = null;
135
+ const descriptor = buildOptionSelectorFieldDescriptor();
136
+ expect(getFormattedValue(value, descriptor)).toBe('');
137
+ });
138
+
139
+ it('should format value correctly with OPTIONSELECTOR and options as JSON string', () => {
140
+ const value = 'option1';
141
+ const descriptor: FieldDescriptor = {
142
+ userInterface: UserInterface.OPTIONSELECTOR,
143
+ properties: { options: JSON.stringify([{ label: 'Option 1', value: 'option1' }]) },
144
+ } as FieldDescriptor;
145
+ expect(getFormattedValue(value, descriptor)).toBe('option1');
146
+ });
147
+
148
+ it('should return value with OPTIONSELECTOR and options as empty array', () => {
149
+ const value = 'option1';
150
+ const descriptor: FieldDescriptor = {
151
+ userInterface: UserInterface.OPTIONSELECTOR,
152
+ properties: { options: [] },
153
+ } as FieldDescriptor;
154
+ expect(getFormattedValue(value, descriptor)).toBe('option1');
155
+ });
156
+
157
+ it('should format masked values correctly', () => {
158
+ const value = '12345678901';
159
+ const descriptor = { properties: { mask: 'cpf' } } as FieldDescriptor;
160
+ expect(getFormattedValue(value, descriptor)).toBe('123.456.789-01');
161
+ });
162
+ });
163
+
164
+ function buildOptionSelectorFieldDescriptor(): FieldDescriptor {
165
+ return {
166
+ userInterface: UserInterface.OPTIONSELECTOR,
167
+ properties: { options: [{ label: 'Option 1', value: 'option1' }] },
168
+ } as FieldDescriptor;
169
+ }
170
+
171
+ function getFileFieldDescriptor(): FieldDescriptor{
172
+ return { userInterface: UserInterface.FILE } as FieldDescriptor;
173
+ }
174
+
175
+ function getObjectFieldDescriptor(): FieldDescriptor{
176
+ return { dataType: DataType.OBJECT } as FieldDescriptor;
177
+ }
@@ -0,0 +1,221 @@
1
+ import { DataUnitInMemoryLoader } from '../../../src/dataunit/loader/dataUnitInMemoryLoader.js';
2
+ import {
3
+ DataUnitInMemoryLoaderConfig,
4
+ RECORD_DATE_FORMAT,
5
+ } from '../../../src/dataunit/loader/DataUnitInMemoryLoaderConfig.js';
6
+ import { FieldDescriptor, UnitMetadata } from '../../../src/dataunit/metadata/UnitMetadata.js';
7
+ import { DataType } from '../../../src/dataunit/metadata/DataType.js';
8
+ import DateUtils from '../../../src/utils/DateUtils.js';
9
+ import DataUnit, { Record } from '../../../src/dataunit/DataUnit.js';
10
+
11
+ describe('DataUnitInMemoryLoader - loadData', () => {
12
+ const dataUnitMetetadata: UnitMetadata = {
13
+ name: 'test',
14
+ label: 'test',
15
+ fields: [],
16
+ };
17
+
18
+ it('should be called load data when auto load is true', async () => {
19
+ const config: DataUnitInMemoryLoaderConfig = {
20
+ autoLoad: true,
21
+ };
22
+ const inMemoryLoader = new DataUnitInMemoryLoader(dataUnitMetetadata, [], config);
23
+ const loadData = jest.spyOn(inMemoryLoader.dataUnit, 'loadData');
24
+ await inMemoryLoader.dataUnit.loadMetadata();
25
+ expect(loadData).toHaveBeenCalled();
26
+ });
27
+
28
+ it('should be called load data when auto load is undefined', async () => {
29
+ const config: DataUnitInMemoryLoaderConfig = {
30
+ autoLoad: undefined,
31
+ };
32
+ const inMemoryLoader = new DataUnitInMemoryLoader(dataUnitMetetadata, [], config);
33
+ const loadData = jest.spyOn(inMemoryLoader.dataUnit, 'loadData');
34
+ await inMemoryLoader.dataUnit.loadMetadata();
35
+ expect(loadData).toHaveBeenCalled();
36
+ });
37
+
38
+ it('should not be called load data when auto load is false', async () => {
39
+ const config: DataUnitInMemoryLoaderConfig = {
40
+ autoLoad: false,
41
+ };
42
+ const inMemoryLoader = new DataUnitInMemoryLoader(dataUnitMetetadata, [], config);
43
+ const loadData = jest.spyOn(inMemoryLoader.dataUnit, 'loadData');
44
+ await inMemoryLoader.dataUnit.loadMetadata();
45
+ expect(loadData).not.toHaveBeenCalled();
46
+ });
47
+
48
+ it('should be called load data when config is undefined', async () => {
49
+ const inMemoryLoader = new DataUnitInMemoryLoader(dataUnitMetetadata, []);
50
+ const loadData = jest.spyOn(inMemoryLoader.dataUnit, 'loadData');
51
+ await inMemoryLoader.dataUnit.loadMetadata();
52
+ expect(loadData).toHaveBeenCalled();
53
+ });
54
+ });
55
+
56
+ describe('DataUnitInMemoryLoader - getConvertedValue', () => {
57
+ let descriptor: FieldDescriptor;
58
+
59
+ beforeEach(() => {
60
+ descriptor = { name: 'testField', dataType: DataType.TEXT, label: 'mock' }; // Valor padrão para inicialização
61
+ });
62
+
63
+ it('should return the original string if descriptor is undefined', () => {
64
+ const result = DataUnitInMemoryLoader.getConvertedValue(undefined as any, 'testValue');
65
+ expect(result).toBe('testValue');
66
+ });
67
+
68
+ it('should return the original string if dataType is TEXT', () => {
69
+ descriptor.dataType = DataType.TEXT;
70
+ const result = DataUnitInMemoryLoader.getConvertedValue(descriptor, 'testValue');
71
+ expect(result).toBe('testValue');
72
+ });
73
+
74
+ it('should convert to boolean when dataType is BOOLEAN', () => {
75
+ descriptor.dataType = DataType.BOOLEAN;
76
+ expect(DataUnitInMemoryLoader.getConvertedValue(descriptor, 'S')).toBe(true);
77
+ expect(DataUnitInMemoryLoader.getConvertedValue(descriptor, 'N')).toBe(false);
78
+ });
79
+
80
+ it('should convert to number when dataType is NUMBER', () => {
81
+ descriptor.dataType = DataType.NUMBER;
82
+ expect(DataUnitInMemoryLoader.getConvertedValue(descriptor, '123')).toBe(123);
83
+ expect(DataUnitInMemoryLoader.getConvertedValue(descriptor, '45.67')).toBe(45.67);
84
+ });
85
+
86
+ it('should parse JSON when dataType is OBJECT', () => {
87
+ descriptor.dataType = DataType.OBJECT;
88
+ const jsonString = '{"key": "value"}';
89
+ const expectedObject = { key: 'value' };
90
+ expect(DataUnitInMemoryLoader.getConvertedValue(descriptor, jsonString)).toEqual(expectedObject);
91
+ });
92
+
93
+ it('should convert to date when dataType is DATE and format is ISO', () => {
94
+ descriptor.dataType = DataType.DATE;
95
+
96
+ const isoDate = '2023-01-01T00:00:00Z';
97
+ jest.spyOn(DateUtils, 'validateDate').mockImplementation((date) => date);
98
+
99
+ const result = DataUnitInMemoryLoader.getConvertedValue(descriptor, isoDate, RECORD_DATE_FORMAT.ISO);
100
+ expect(DateUtils.validateDate).toHaveBeenCalledWith(new Date(isoDate), true);
101
+ expect(result).toEqual(new Date(isoDate));
102
+ });
103
+
104
+ it('should convert to date when dataType is DATE and format is not ISO', () => {
105
+ descriptor.dataType = DataType.DATE;
106
+
107
+ const dateString = '01/01/2023';
108
+ jest.spyOn(DateUtils, 'strToDate').mockImplementation(() => new Date(2023, 0, 1));
109
+
110
+ const result = DataUnitInMemoryLoader.getConvertedValue(descriptor, dateString, RECORD_DATE_FORMAT.DD_MM_YYYY);
111
+ expect(DateUtils.strToDate).toHaveBeenCalledWith(dateString, true);
112
+ expect(result).toEqual(new Date(2023, 0, 1));
113
+ });
114
+
115
+ it('should return the original string if no dataType matches', () => {
116
+ descriptor.dataType = undefined as any; // Simula um caso inválido
117
+ const result = DataUnitInMemoryLoader.getConvertedValue(descriptor, 'testValue');
118
+ expect(result).toBe('testValue');
119
+ });
120
+ });
121
+
122
+ describe('DataUnitInMemoryLoader - removeLoader', () => {
123
+ let loader: DataUnitInMemoryLoader;
124
+ const mockedDataUnit = {} as DataUnit;
125
+
126
+ beforeEach(() => {
127
+ loader = new DataUnitInMemoryLoader();
128
+ });
129
+
130
+ it('should resolve with the provided record IDs', async () => {
131
+ const mockRecordIds = ['record1', 'record2', 'record3'];
132
+
133
+ const result = await loader.removeLoader(mockedDataUnit, mockRecordIds);
134
+
135
+ expect(result).toEqual(mockRecordIds);
136
+ });
137
+
138
+ it('should handle empty record ID array', async () => {
139
+ const mockRecordIds: string[] = [];
140
+
141
+ const result = await loader.removeLoader(mockedDataUnit, mockRecordIds);
142
+
143
+ expect(result).toEqual([]);
144
+ });
145
+
146
+ it('should resolve the promise', async () => {
147
+ const mockRecordIds = ['record1'];
148
+
149
+ await expect(loader.removeLoader(mockedDataUnit, mockRecordIds)).resolves.toEqual(mockRecordIds);
150
+ });
151
+ });
152
+
153
+ describe('DataUnitInMemoryLoader - buildInitialRecords (indiretamente via set records)', () => {
154
+ let loader: DataUnitInMemoryLoader;
155
+ let mockRecords: Array<Record> = [
156
+ { id: '1', amount: '100', isActive: 'S', createdAt: '01/01/2023' },
157
+ { id: '2', amount: '200.50', isActive: 'N', createdAt: '02/01/2023' },
158
+ ] as unknown as Record[];
159
+
160
+ let mockMetadata = {
161
+ fields: [
162
+ { name: 'id', label: 'id', dataType: DataType.TEXT },
163
+ { name: 'amount', label: 'amount', dataType: DataType.NUMBER },
164
+ { name: 'isActive', label: 'isActive', dataType: DataType.BOOLEAN },
165
+ { name: 'createdAt', label: 'createdAt', dataType: DataType.DATE },
166
+ ],
167
+ };
168
+
169
+ beforeEach(() => {
170
+ loader = new DataUnitInMemoryLoader(mockMetadata as any, [], { recordDateFormat: RECORD_DATE_FORMAT.DD_MM_YYYY });
171
+ });
172
+
173
+ it('should build initial records and convert field values based on metadata', () => {
174
+ loader.records = mockRecords;
175
+ const initialRecords = loader['_initialRecords'];
176
+
177
+ expect(initialRecords).toHaveLength(2);
178
+
179
+ expect(initialRecords[0]).toEqual({
180
+ id: '1',
181
+ amount: 100,
182
+ isActive: true,
183
+ createdAt: expect.any(Date),
184
+ __record__id__: expect.any(String),
185
+ });
186
+
187
+ expect(initialRecords[1]).toEqual({
188
+ id: '2',
189
+ amount: 200.5,
190
+ isActive: false,
191
+ createdAt: expect.any(Date),
192
+ __record__id__: expect.any(String),
193
+ });
194
+ });
195
+
196
+ it('should generate unique IDs for records without "__record__id__"', () => {
197
+ loader.records = [{ id: '3', amount: '300' }] as unknown as Record[];
198
+
199
+ const builtRecords = loader['_initialRecords'];
200
+ expect(builtRecords).toHaveLength(1);
201
+
202
+ expect(builtRecords[0]).toHaveProperty('__record__id__');
203
+ expect(typeof builtRecords[0]['__record__id__']).toBe('string');
204
+ });
205
+
206
+ it('should leave fields untouched if no matching metadata exists', () => {
207
+ mockRecords[0]['extraField'] = 'unchanged';
208
+ loader.records = mockRecords;
209
+
210
+ const builtRecords = loader['_initialRecords'];
211
+ expect(builtRecords[0]).toHaveProperty('extraField', 'unchanged');
212
+ });
213
+
214
+ it('should skip conversion for non-string field values', () => {
215
+ mockRecords[0].amount = 500;
216
+ loader.records = mockRecords;
217
+
218
+ const builtRecords = loader['_initialRecords'];
219
+ expect(builtRecords[0].amount).toBe(500);
220
+ });
221
+ });