@thoughtspot/ts-chart-sdk 0.0.2-alpha.9 → 1.1.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.
Files changed (141) hide show
  1. package/README.md +126 -50
  2. package/dist/ts-chart-sdk.d.ts +330 -32
  3. package/lib/index.d.ts +3 -0
  4. package/lib/index.d.ts.map +1 -1
  5. package/lib/index.js +3 -0
  6. package/lib/index.js.map +1 -1
  7. package/lib/main/custom-chart-context.d.ts +17 -4
  8. package/lib/main/custom-chart-context.d.ts.map +1 -1
  9. package/lib/main/custom-chart-context.js +46 -16
  10. package/lib/main/custom-chart-context.js.map +1 -1
  11. package/lib/main/custom-chart-context.spec.js +302 -4
  12. package/lib/main/custom-chart-context.spec.js.map +1 -1
  13. package/lib/main/logger.d.ts +13 -0
  14. package/lib/main/logger.d.ts.map +1 -0
  15. package/lib/main/logger.js +64 -0
  16. package/lib/main/logger.js.map +1 -0
  17. package/lib/main/logger.spec.d.ts +2 -0
  18. package/lib/main/logger.spec.d.ts.map +1 -0
  19. package/lib/main/logger.spec.js +88 -0
  20. package/lib/main/logger.spec.js.map +1 -0
  21. package/lib/main/util.d.ts +2 -0
  22. package/lib/main/util.d.ts.map +1 -1
  23. package/lib/main/util.js +11 -0
  24. package/lib/main/util.js.map +1 -1
  25. package/lib/main/util.spec.d.ts +2 -0
  26. package/lib/main/util.spec.d.ts.map +1 -0
  27. package/lib/main/util.spec.js +73 -0
  28. package/lib/main/util.spec.js.map +1 -0
  29. package/lib/react/use-custom-chart-context.d.ts.map +1 -1
  30. package/lib/react/use-custom-chart-context.js +3 -1
  31. package/lib/react/use-custom-chart-context.js.map +1 -1
  32. package/lib/react/use-custom-chart-context.spec.js +0 -1
  33. package/lib/react/use-custom-chart-context.spec.js.map +1 -1
  34. package/lib/react/use-custom-chart-context.util.d.ts.map +1 -1
  35. package/lib/react/use-custom-chart-context.util.js +5 -3
  36. package/lib/react/use-custom-chart-context.util.js.map +1 -1
  37. package/lib/types/answer-column.types.d.ts +7 -4
  38. package/lib/types/answer-column.types.d.ts.map +1 -1
  39. package/lib/types/answer-column.types.js +3 -3
  40. package/lib/types/answer-column.types.js.map +1 -1
  41. package/lib/types/chart-to-ts-event.types.d.ts +2 -0
  42. package/lib/types/chart-to-ts-event.types.d.ts.map +1 -1
  43. package/lib/types/chart-to-ts-event.types.js +1 -0
  44. package/lib/types/chart-to-ts-event.types.js.map +1 -1
  45. package/lib/types/common.types.d.ts +65 -6
  46. package/lib/types/common.types.d.ts.map +1 -1
  47. package/lib/types/common.types.js.map +1 -1
  48. package/lib/types/conditional-formatting.types.d.ts +1 -16
  49. package/lib/types/conditional-formatting.types.d.ts.map +1 -1
  50. package/lib/types/conditional-formatting.types.js.map +1 -1
  51. package/lib/types/configurator.types.d.ts +1 -1
  52. package/lib/types/configurator.types.d.ts.map +1 -1
  53. package/lib/types/number-formatting.types.d.ts +55 -0
  54. package/lib/types/number-formatting.types.d.ts.map +1 -0
  55. package/lib/types/number-formatting.types.js +23 -0
  56. package/lib/types/number-formatting.types.js.map +1 -0
  57. package/lib/types/ts-to-chart-event.types.d.ts +20 -6
  58. package/lib/types/ts-to-chart-event.types.d.ts.map +1 -1
  59. package/lib/types/ts-to-chart-event.types.js +1 -0
  60. package/lib/types/ts-to-chart-event.types.js.map +1 -1
  61. package/lib/types/visual-prop.types.d.ts +71 -3
  62. package/lib/types/visual-prop.types.d.ts.map +1 -1
  63. package/lib/types/visual-prop.types.js +32 -1
  64. package/lib/types/visual-prop.types.js.map +1 -1
  65. package/lib/utils/date-formatting.d.ts +85 -1
  66. package/lib/utils/date-formatting.d.ts.map +1 -1
  67. package/lib/utils/date-formatting.js +344 -9
  68. package/lib/utils/date-formatting.js.map +1 -1
  69. package/lib/utils/date-formatting.spec.js +301 -31
  70. package/lib/utils/date-formatting.spec.js.map +1 -1
  71. package/lib/utils/date-utils.d.ts +6 -0
  72. package/lib/utils/date-utils.d.ts.map +1 -0
  73. package/lib/utils/date-utils.js +20 -0
  74. package/lib/utils/date-utils.js.map +1 -0
  75. package/lib/utils/date-utils.spec.d.ts +2 -0
  76. package/lib/utils/date-utils.spec.d.ts.map +1 -0
  77. package/lib/utils/date-utils.spec.js +63 -0
  78. package/lib/utils/date-utils.spec.js.map +1 -0
  79. package/lib/utils/formatting-util.d.ts +10 -0
  80. package/lib/utils/formatting-util.d.ts.map +1 -0
  81. package/lib/utils/formatting-util.js +78 -0
  82. package/lib/utils/formatting-util.js.map +1 -0
  83. package/lib/utils/formatting-util.spec.d.ts +2 -0
  84. package/lib/utils/formatting-util.spec.d.ts.map +1 -0
  85. package/lib/utils/formatting-util.spec.js +247 -0
  86. package/lib/utils/formatting-util.spec.js.map +1 -0
  87. package/lib/utils/globalize-Initializer/globalize-utils.d.ts +16 -0
  88. package/lib/utils/globalize-Initializer/globalize-utils.d.ts.map +1 -0
  89. package/lib/utils/globalize-Initializer/globalize-utils.js +101 -0
  90. package/lib/utils/globalize-Initializer/globalize-utils.js.map +1 -0
  91. package/lib/utils/globalize-Initializer/globalize-utils.spec.d.ts +2 -0
  92. package/lib/utils/globalize-Initializer/globalize-utils.spec.d.ts.map +1 -0
  93. package/lib/utils/globalize-Initializer/globalize-utils.spec.js +149 -0
  94. package/lib/utils/globalize-Initializer/globalize-utils.spec.js.map +1 -0
  95. package/lib/utils/number-formatting/number-formatting-utils.d.ts +20 -0
  96. package/lib/utils/number-formatting/number-formatting-utils.d.ts.map +1 -0
  97. package/lib/utils/number-formatting/number-formatting-utils.js +159 -0
  98. package/lib/utils/number-formatting/number-formatting-utils.js.map +1 -0
  99. package/lib/utils/number-formatting/number-formatting-utils.spec.d.ts +2 -0
  100. package/lib/utils/number-formatting/number-formatting-utils.spec.d.ts.map +1 -0
  101. package/lib/utils/number-formatting/number-formatting-utils.spec.js +221 -0
  102. package/lib/utils/number-formatting/number-formatting-utils.spec.js.map +1 -0
  103. package/lib/utils/number-formatting/number-formatting.d.ts +5 -0
  104. package/lib/utils/number-formatting/number-formatting.d.ts.map +1 -0
  105. package/lib/utils/number-formatting/number-formatting.js +128 -0
  106. package/lib/utils/number-formatting/number-formatting.js.map +1 -0
  107. package/lib/utils/number-formatting/number-formatting.spec.d.ts +2 -0
  108. package/lib/utils/number-formatting/number-formatting.spec.d.ts.map +1 -0
  109. package/lib/utils/number-formatting/number-formatting.spec.js +159 -0
  110. package/lib/utils/number-formatting/number-formatting.spec.js.map +1 -0
  111. package/package.json +4 -1
  112. package/src/index.ts +3 -0
  113. package/src/main/custom-chart-context.spec.ts +356 -6
  114. package/src/main/custom-chart-context.ts +205 -16
  115. package/src/main/logger.spec.ts +114 -0
  116. package/src/main/logger.ts +97 -0
  117. package/src/main/util.spec.ts +94 -0
  118. package/src/main/util.ts +20 -0
  119. package/src/react/use-custom-chart-context.spec.tsx +0 -1
  120. package/src/react/use-custom-chart-context.tsx +4 -1
  121. package/src/react/use-custom-chart-context.util.ts +6 -3
  122. package/src/types/answer-column.types.ts +9 -6
  123. package/src/types/chart-to-ts-event.types.ts +7 -0
  124. package/src/types/common.types.ts +100 -10
  125. package/src/types/conditional-formatting.types.ts +2 -17
  126. package/src/types/configurator.types.ts +1 -1
  127. package/src/types/number-formatting.types.ts +80 -0
  128. package/src/types/ts-to-chart-event.types.ts +63 -5
  129. package/src/types/visual-prop.types.ts +197 -3
  130. package/src/utils/date-formatting.spec.ts +375 -32
  131. package/src/utils/date-formatting.ts +587 -14
  132. package/src/utils/date-utils.spec.ts +93 -0
  133. package/src/utils/date-utils.ts +69 -0
  134. package/src/utils/formatting-util.spec.ts +312 -0
  135. package/src/utils/formatting-util.ts +234 -0
  136. package/src/utils/globalize-Initializer/globalize-utils.spec.ts +192 -0
  137. package/src/utils/globalize-Initializer/globalize-utils.ts +216 -0
  138. package/src/utils/number-formatting/number-formatting-utils.spec.ts +296 -0
  139. package/src/utils/number-formatting/number-formatting-utils.ts +260 -0
  140. package/src/utils/number-formatting/number-formatting.spec.ts +243 -0
  141. package/src/utils/number-formatting/number-formatting.ts +264 -0
@@ -6,6 +6,7 @@
6
6
  * Copyright: ThoughtSpot Inc. 2023
7
7
  */
8
8
 
9
+ import { DateTime } from 'luxon';
9
10
  import {
10
11
  ChartColumn,
11
12
  ChartSpecificColumnType,
@@ -14,18 +15,31 @@ import {
14
15
  DataType,
15
16
  } from '../types/answer-column.types';
16
17
  import {
18
+ assignQuarterValueToString,
17
19
  CustomCalendarDate,
18
- dateFormatter,
20
+ dateNumTypes,
21
+ formatDate,
22
+ formatDateNum,
23
+ formatDateTime,
19
24
  getCustomCalendarGuidFromColumn,
25
+ getCustomCalendarValueFromEpoch,
20
26
  getDisplayString,
27
+ getEffectiveDateNumDataType,
28
+ getMonthOfYear,
29
+ getOrdinalSuffixedValue,
30
+ getSpecialFormatData,
21
31
  getStartEpoch,
22
32
  hasCustomCalendar,
23
33
  isAttribute,
24
34
  isDateColumn,
25
35
  isDateFamilyColumn,
26
36
  isDateNumColumn,
37
+ isDateTimeColumn,
27
38
  isTimeColumn,
39
+ sanitizeDate,
40
+ useQuarterStart,
28
41
  } from './date-formatting';
42
+ import * as DateFormatting from './date-formatting';
29
43
 
30
44
  describe('date-formatting', () => {
31
45
  let col: ChartColumn;
@@ -40,6 +54,60 @@ describe('date-formatting', () => {
40
54
  calenderGuid: '12345',
41
55
  };
42
56
  });
57
+ const options = {
58
+ quarterStartMonth: 1,
59
+ tsLocaleBasedStringsFormats: {
60
+ null_value_placeholder_label: '{Null}',
61
+ empty_value_placeholder_label: '{Empty}',
62
+ other_value_placeholder_label: '{Other}',
63
+ unavailabe_column_sample_value: '{Unavailable}',
64
+ weekOfDay: {
65
+ Friday: 'Friday',
66
+ Monday: 'Monday',
67
+ Saturday: 'Saturday',
68
+ Sunday: 'Sunday',
69
+ Thursday: 'Thursday',
70
+ Tuesday: 'Tuesday',
71
+ Wednesday: 'Wednesday',
72
+ },
73
+ monthOfYear: {
74
+ April: 'April',
75
+ August: 'August',
76
+ December: 'December',
77
+ February: 'February',
78
+ January: 'January',
79
+ July: 'July',
80
+ June: 'June',
81
+ March: 'March',
82
+ May: 'May',
83
+ November: 'November',
84
+ October: 'October',
85
+ September: 'September',
86
+ },
87
+ quarter_of_year: 'Q{1}',
88
+ },
89
+ tsDateConstants: {
90
+ day_in_month_format: 'e',
91
+ day_in_quarter_format: 'e',
92
+ day_in_year_format: 'j',
93
+ day_of_week_format: 'e',
94
+ month_in_quarter_format: 'm',
95
+ month_in_year_format: 'm',
96
+ special_value_unavailable: 'N/A',
97
+ week_in_year_format: 'V',
98
+ },
99
+ tsLocaleBasedDateFormats: {
100
+ DATE_SHORT: 'MM/dd/yyyy',
101
+ },
102
+ quarter_of_year: 'Q{1}',
103
+ tsDefinedCustomCalenders: {
104
+ '43121d86-347a-4dbb-bea8-5e5bb899e427': {
105
+ calendar: '7573c08b-753b-478b-84fd-6e702d481ff6',
106
+ fiscal: 'bfa39848-ba4f-46d8-80fd-b695064e61b7',
107
+ french: 'a7316e8d-d4dd-4eaf-9294-396db951b422',
108
+ },
109
+ },
110
+ };
43
111
  test('isDateColumn should return true for DATE data type', () => {
44
112
  col.dataType = DataType.DATE;
45
113
  expect(isDateColumn(col)).toBe(true);
@@ -124,45 +192,320 @@ describe('date-formatting', () => {
124
192
  expect(getDisplayString(date)).toBe(null);
125
193
  });
126
194
 
127
- test('dateFormatter should return custom calendar display string if present', () => {
128
- const dataValue = {
129
- v: { s: 1625097600, e: 1625184000 },
130
- d: '01-07-2021',
131
- } as CustomCalendarDate;
195
+ test('should return false for columns with dataType other than DATE_TIME', () => {
132
196
  col.dataType = DataType.DATE;
133
- col.calenderGuid = '12345';
134
- expect(dateFormatter(dataValue, col)).toBe('01-07-2021');
197
+ expect(isDateTimeColumn(col)).toBe(false);
198
+ col.dataType = DataType.INT64;
199
+ expect(isDateTimeColumn(col)).toBe(false);
200
+ col.dataType = DataType.DATE_TIME;
201
+ expect(isDateTimeColumn(col)).toBe(true);
202
+ });
203
+ test('should return DATE_NUM_DAY_OF_WEEK for ColumnTimeBucket.DAY_OF_WEEK', () => {
204
+ const column = {
205
+ timeBucket: ColumnTimeBucket.DAY_OF_WEEK,
206
+ } as ChartColumn;
207
+ expect(getEffectiveDateNumDataType(column)).toBe(
208
+ dateNumTypes.DATE_NUM_DAY_OF_WEEK,
209
+ );
135
210
  });
136
211
 
137
- test('dateFormatter should return formatted date from start epoch if custom calendar display string is not present', () => {
138
- const dataValue = {
139
- v: { s: 1625097600, e: 1625184000 },
140
- } as CustomCalendarDate;
141
- col.dataType = DataType.DATE;
142
- col.calenderGuid = '12345';
143
- expect(dateFormatter(dataValue, col)).toBe('01-07-2021');
212
+ test('should return DATE_NUM_DAY_IN_MONTH for ColumnTimeBucket.DAY_OF_MONTH', () => {
213
+ const column = {
214
+ timeBucket: ColumnTimeBucket.DAY_OF_MONTH,
215
+ } as ChartColumn;
216
+ expect(getEffectiveDateNumDataType(column)).toBe(
217
+ dateNumTypes.DATE_NUM_DAY_IN_MONTH,
218
+ );
144
219
  });
145
220
 
146
- test('dateFormatter should return null if start epoch is not present', () => {
147
- const dataValue = { v: { e: 1625184000 } } as CustomCalendarDate;
148
- col.dataType = DataType.DATE;
149
- col.calenderGuid = '12345';
150
- expect(dateFormatter(dataValue, col)).toBe(null);
221
+ test('should return DATE_NUM_DAY_IN_QUARTER for ColumnTimeBucket.DAY_OF_QUARTER', () => {
222
+ const column = {
223
+ timeBucket: ColumnTimeBucket.DAY_OF_QUARTER,
224
+ } as ChartColumn;
225
+ expect(getEffectiveDateNumDataType(column)).toBe(
226
+ dateNumTypes.DATE_NUM_DAY_IN_QUARTER,
227
+ );
151
228
  });
152
229
 
153
- test('dateFormatter should return formatted date for non-custom calendar column', () => {
154
- const dataValue = 1625097600;
155
- col.dataType = DataType.DATE;
156
- col.calenderGuid = undefined;
157
- expect(dateFormatter(dataValue, col)).toBe('01-07-2021');
230
+ test('should return DATE_NUM_DAY_IN_YEAR for ColumnTimeBucket.DAY_OF_YEAR', () => {
231
+ const column = {
232
+ timeBucket: ColumnTimeBucket.DAY_OF_YEAR,
233
+ } as ChartColumn;
234
+ expect(getEffectiveDateNumDataType(column)).toBe(
235
+ dateNumTypes.DATE_NUM_DAY_IN_YEAR,
236
+ );
237
+ });
238
+
239
+ test('should return DATE_NUM_WEEK_IN_MONTH for ColumnTimeBucket.WEEK_OF_MONTH', () => {
240
+ const column = {
241
+ timeBucket: ColumnTimeBucket.WEEK_OF_MONTH,
242
+ } as ChartColumn;
243
+ expect(getEffectiveDateNumDataType(column)).toBe(
244
+ dateNumTypes.DATE_NUM_WEEK_IN_MONTH,
245
+ );
246
+ });
247
+
248
+ test('should return DATE_NUM_WEEK_IN_QUARTER for ColumnTimeBucket.WEEK_OF_QUARTER', () => {
249
+ const column = {
250
+ timeBucket: ColumnTimeBucket.WEEK_OF_QUARTER,
251
+ } as ChartColumn;
252
+ expect(getEffectiveDateNumDataType(column)).toBe(
253
+ dateNumTypes.DATE_NUM_WEEK_IN_QUARTER,
254
+ );
255
+ });
256
+
257
+ test('should return DATE_NUM_WEEK_IN_YEAR for ColumnTimeBucket.WEEK_OF_YEAR', () => {
258
+ const column = {
259
+ timeBucket: ColumnTimeBucket.WEEK_OF_YEAR,
260
+ } as ChartColumn;
261
+ expect(getEffectiveDateNumDataType(column)).toBe(
262
+ dateNumTypes.DATE_NUM_WEEK_IN_YEAR,
263
+ );
158
264
  });
159
- test('dateFormatter should format the date based on custom calendar', () => {
265
+
266
+ test('should return DATE_NUM_MONTH_IN_QUARTER for ColumnTimeBucket.MONTH_OF_QUARTER', () => {
267
+ const column = {
268
+ timeBucket: ColumnTimeBucket.MONTH_OF_QUARTER,
269
+ } as ChartColumn;
270
+ expect(getEffectiveDateNumDataType(column)).toBe(
271
+ dateNumTypes.DATE_NUM_MONTH_IN_QUARTER,
272
+ );
273
+ });
274
+
275
+ test('should return DATE_NUM_MONTH_IN_YEAR for ColumnTimeBucket.MONTH_OF_YEAR', () => {
276
+ const column = {
277
+ timeBucket: ColumnTimeBucket.MONTH_OF_YEAR,
278
+ } as ChartColumn;
279
+ expect(getEffectiveDateNumDataType(column)).toBe(
280
+ dateNumTypes.DATE_NUM_MONTH_IN_YEAR,
281
+ );
282
+ });
283
+
284
+ test('should return DATE_NUM_QUARTER_IN_YEAR for ColumnTimeBucket.QUARTER_OF_YEAR', () => {
285
+ const column = {
286
+ timeBucket: ColumnTimeBucket.QUARTER_OF_YEAR,
287
+ } as ChartColumn;
288
+ expect(getEffectiveDateNumDataType(column)).toBe(
289
+ dateNumTypes.DATE_NUM_QUARTER_IN_YEAR,
290
+ );
291
+ });
292
+ test('should replace placeholder with value', () => {
293
+ const result = assignQuarterValueToString('Q{1}', '1');
294
+ expect(result).toBe('Q1');
295
+ });
296
+ test('should return correct month for normal case', () => {
297
+ const monthOfYear = {
298
+ January: 'Jan',
299
+ February: 'Feb',
300
+ March: 'Mar',
301
+ April: 'Apr',
302
+ May: 'May',
303
+ June: 'Jun',
304
+ July: 'Jul',
305
+ August: 'Aug',
306
+ September: 'Sep',
307
+ October: 'oct',
308
+ November: 'Nov',
309
+ December: 'Dec',
310
+ };
311
+ const result = getMonthOfYear(1, 1, monthOfYear);
312
+ expect(result).toBe('Jan');
313
+ });
314
+ test('should return the value from displayToCustomCalendarValueMap if custom calendar exists and dateEpoch is present', () => {
315
+ const dateEpoch = 1234567890;
316
+ const displayToCustomCalendarValueMap = {
317
+ 1234567890: {
318
+ v: {
319
+ s: '1234567890',
320
+ e: '1234567890',
321
+ },
322
+ d: 'Custom Date Value',
323
+ },
324
+ };
160
325
  col.dataType = DataType.DATE;
161
- col.calenderGuid = '12345';
162
- const date = {
163
- v: { s: 12345, e: 12346 },
164
- d: 'Custom_Date',
165
- } as CustomCalendarDate;
166
- expect(dateFormatter(date, col)).toBe(date.d);
326
+ const result = getCustomCalendarValueFromEpoch(
327
+ col,
328
+ dateEpoch,
329
+ displayToCustomCalendarValueMap,
330
+ );
331
+ expect(result).toEqual({
332
+ v: { s: '1234567890', e: '1234567890' },
333
+ d: 'Custom Date Value',
334
+ });
335
+ });
336
+ test('should return null_value_placeholder_label if value matches null_value_placeholder_label', () => {
337
+ const result = getSpecialFormatData('{Null}', options);
338
+ expect(result).toBe('{Null}');
339
+ });
340
+
341
+ test('should return empty_value_placeholder_label if value matches empty_value_placeholder_label', () => {
342
+ const result = getSpecialFormatData('{Empty}', options);
343
+ expect(result).toBe('{Empty}');
344
+ });
345
+
346
+ test('should return unavailabe_column_sample_value if value matches special_value_unavailable', () => {
347
+ const result = getSpecialFormatData('N/A', options);
348
+ expect(result).toBe('{Unavailable}');
349
+ });
350
+
351
+ test('should return empty_value_placeholder_label if value is an empty string', () => {
352
+ const result = getSpecialFormatData('', options);
353
+ expect(result).toBe('{Empty}');
354
+ });
355
+
356
+ test('should return null if value does not match any special condtestion', () => {
357
+ const result = getSpecialFormatData('Some other value', options);
358
+ expect(result).toBeNull();
359
+ });
360
+ test('should return special value if getSpecialFormatData provides it', () => {
361
+ const result = sanitizeDate('{Null}', 'yyyy', options);
362
+ expect(result).toBe('{Null}');
363
+ });
364
+ test('should return parsed integer if inputDate is a numeric string', () => {
365
+ const result = sanitizeDate('12345', 'MM/dd/yyyy', options);
366
+ expect(result).toBe(12345);
367
+ });
368
+ test('should parse date if inputDate is a non-numeric string', () => {
369
+ const result = sanitizeDate('12/25/2022', 'DATE_SHORT', options);
370
+ expect(result).toEqual(new Date(2022, 11, 25));
371
+ });
372
+ test('should return "Invalid Date" for an invalid epochMillis', () => {
373
+ const result = formatDateTime(NaN, 'MM-dd-yyyy', false, options);
374
+ expect(result).toBe('Invalid DateTime');
375
+ });
376
+ test('should return a formatted date string for a valid epochMillis with default options', () => {
377
+ const epochMillis = 1043452800; // January 25, 2003
378
+ const expectedDate = '01-25-2003';
379
+ const luxonDate = DateTime.fromMillis(epochMillis * 1000);
380
+
381
+ jest.spyOn(DateTime, 'fromMillis').mockReturnValue(luxonDate);
382
+ jest.spyOn(luxonDate, 'toLocaleString').mockReturnValue(expectedDate);
383
+
384
+ const result = formatDateTime(
385
+ epochMillis,
386
+ 'MM-dd-yyyy',
387
+ false,
388
+ options,
389
+ );
390
+ expect(result).toBe(expectedDate);
391
+ });
392
+ test('should apply fiscal year format when quarterStartMonth is not default and useSystemCalendar is false', () => {
393
+ const epochMillis = 1043452800; // January 25, 2003
394
+ options.quarterStartMonth = 4; // Custom fiscal year
395
+ const expectedDate = 'FY 2003';
396
+ const luxonDate = DateTime.fromMillis(epochMillis * 1000);
397
+ jest.spyOn(DateFormatting, 'useQuarterStart').mockReturnValue(
398
+ luxonDate,
399
+ );
400
+ jest.spyOn(luxonDate, 'toFormat').mockReturnValue(expectedDate);
401
+ const result = formatDateTime(epochMillis, 'yyyy', false, options);
402
+ expect(result).toBe(expectedDate);
403
+ expect(useQuarterStart).toHaveBeenCalledWith(
404
+ luxonDate,
405
+ options.quarterStartMonth,
406
+ );
407
+ });
408
+ test('should replace unsupported "qqq" with fiscal quarter format', () => {
409
+ const epochMillis = 1043452800; // January 25, 2003
410
+ const format = 'qqq yyyy';
411
+ const expectedFormat = "'Q'q yyyy";
412
+ const luxonDate = DateTime.fromMillis(epochMillis * 1000);
413
+ jest.spyOn(DateFormatting, 'useQuarterStart').mockReturnValue(
414
+ luxonDate,
415
+ );
416
+ jest.spyOn(luxonDate, 'toFormat').mockReturnValue('Q1 2003');
417
+
418
+ const result = formatDateTime(epochMillis, format, true, options);
419
+ expect(result).toBe('Q1 2003');
420
+ expect(luxonDate.toFormat).toHaveBeenCalledWith(expectedFormat);
421
+ });
422
+ test('should return the correct ordinal suffix for numbers ending in 1', () => {
423
+ expect(getOrdinalSuffixedValue(1)).toBe('1st');
424
+ expect(getOrdinalSuffixedValue(21)).toBe('21st');
425
+ expect(getOrdinalSuffixedValue('1')).toBe('1st'); // Test with string input
426
+ expect(getOrdinalSuffixedValue('21')).toBe('21st');
427
+ });
428
+
429
+ test('should return the correct ordinal suffix for numbers ending in 2', () => {
430
+ expect(getOrdinalSuffixedValue(2)).toBe('2nd');
431
+ expect(getOrdinalSuffixedValue(22)).toBe('22nd');
432
+ expect(getOrdinalSuffixedValue('2')).toBe('2nd'); // Test with string input
433
+ expect(getOrdinalSuffixedValue('22')).toBe('22nd');
434
+ });
435
+
436
+ test('should return the correct ordinal suffix for numbers ending in 3', () => {
437
+ expect(getOrdinalSuffixedValue(3)).toBe('3rd');
438
+ expect(getOrdinalSuffixedValue(23)).toBe('23rd');
439
+ expect(getOrdinalSuffixedValue('3')).toBe('3rd'); // Test with string input
440
+ expect(getOrdinalSuffixedValue('23')).toBe('23rd');
441
+ });
442
+
443
+ test('should return the correct ordinal suffix for all other numbers', () => {
444
+ expect(getOrdinalSuffixedValue(4)).toBe('4th');
445
+ expect(getOrdinalSuffixedValue(11)).toBe('11th');
446
+ expect(getOrdinalSuffixedValue(100)).toBe('100th');
447
+ expect(getOrdinalSuffixedValue(112)).toBe('112th');
448
+ expect(getOrdinalSuffixedValue('4')).toBe('4th');
449
+ expect(getOrdinalSuffixedValue('11')).toBe('11th');
450
+ expect(getOrdinalSuffixedValue('100')).toBe('100th');
451
+ expect(getOrdinalSuffixedValue('112')).toBe('112th');
452
+ });
453
+
454
+ test('should handle negative numbers correctly', () => {
455
+ expect(getOrdinalSuffixedValue(-1)).toBe('-1th');
456
+ expect(getOrdinalSuffixedValue(-11)).toBe('-11th');
457
+ expect(getOrdinalSuffixedValue('-1')).toBe('-1th');
458
+ expect(getOrdinalSuffixedValue('-11')).toBe('-11th');
459
+ });
460
+ test('should return special format data if applicable', () => {
461
+ jest.spyOn(DateFormatting, 'getSpecialFormatData').mockReturnValue(
462
+ 'Special Format',
463
+ );
464
+ const result = formatDateNum(undefined, '{Null}', '', options);
465
+ expect(result).toBe('{Null}');
466
+ });
467
+ test('should return value as string for absolute day, month, quarter, and year types', () => {
468
+ const result = formatDateNum('DATE_NUM_ABS_DAY', 123, '', options);
469
+ expect(result).toBe('123');
470
+ });
471
+ test("should return ordinal suffixed value for day of month when format doesn't match", () => {
472
+ const result = formatDateNum('DATE_NUM_DAY_IN_MONTH', 2, '', options);
473
+ expect(result).toBe('2nd day of month');
474
+ });
475
+ test('should return formatted date for day of week', () => {
476
+ const result = formatDateNum('DATE_NUM_DAY_OF_WEEK', 1, 'e', options);
477
+ expect(result).toBe('Monday');
478
+ });
479
+ test('should return formatted month name for month in year', () => {
480
+ const result = formatDateNum('DATE_NUM_MONTH_IN_YEAR', 1, 'm', options);
481
+ expect(result).toBe('April');
482
+ });
483
+ test('should return ordinal suffixed value for week of year', () => {
484
+ const result = formatDateNum('DATE_NUM_WEEK_IN_YEAR', 2, '', options);
485
+ expect(result).toBe('2nd week of year');
486
+ });
487
+ test('should handle special cases for quarter value', () => {
488
+ const result = formatDateNum(
489
+ 'DATE_NUM_QUARTER_IN_YEAR',
490
+ 1,
491
+ '',
492
+ options,
493
+ );
494
+ expect(result).toBe('Q1');
495
+ });
496
+ test('should return value for unhandled cases', () => {
497
+ const result = formatDateNum('UNKNOWN_TYPE', 999, '', options);
498
+ expect(result).toBe(999);
499
+ });
500
+ test('should return special placeholder values if input matches', () => {
501
+ const resultEmpty = formatDate('{Empty}', 'DD-MM-YYYY', true, options);
502
+ expect(resultEmpty).toBe('{Empty}');
503
+
504
+ const resultOther = formatDate('{Other}', 'DD-MM-YYYY', true, options);
505
+ expect(resultOther).toBe('{Other}');
506
+ });
507
+ it('should return null placeholder if the sanitized date is invalid', () => {
508
+ const result = formatDate('{Null}', 'DD-MM-YYYY', true, options);
509
+ expect(result).toBe('{Null}');
167
510
  });
168
511
  });