@thoughtspot/ts-chart-sdk 0.0.2-alpha.6 → 0.0.2-alpha.8

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 (32) hide show
  1. package/dist/ts-chart-sdk.d.ts +20 -1
  2. package/lib/index.d.ts +1 -0
  3. package/lib/index.d.ts.map +1 -1
  4. package/lib/index.js +1 -0
  5. package/lib/index.js.map +1 -1
  6. package/lib/main/custom-chart-context.spec.js +53 -2
  7. package/lib/main/custom-chart-context.spec.js.map +1 -1
  8. package/lib/react/use-custom-chart-context.spec.js +54 -2
  9. package/lib/react/use-custom-chart-context.spec.js.map +1 -1
  10. package/lib/types/answer-column.types.d.ts +1 -0
  11. package/lib/types/answer-column.types.d.ts.map +1 -1
  12. package/lib/types/common.types.d.ts +1 -1
  13. package/lib/types/common.types.d.ts.map +1 -1
  14. package/lib/utils/conditional-formatting/conditional-formatting.spec.js +20 -1
  15. package/lib/utils/conditional-formatting/conditional-formatting.spec.js.map +1 -1
  16. package/lib/utils/date-formatting.d.ts +19 -0
  17. package/lib/utils/date-formatting.d.ts.map +1 -0
  18. package/lib/utils/date-formatting.js +56 -0
  19. package/lib/utils/date-formatting.js.map +1 -0
  20. package/lib/utils/date-formatting.spec.d.ts +2 -0
  21. package/lib/utils/date-formatting.spec.d.ts.map +1 -0
  22. package/lib/utils/date-formatting.spec.js +123 -0
  23. package/lib/utils/date-formatting.spec.js.map +1 -0
  24. package/package.json +3 -1
  25. package/src/index.ts +1 -0
  26. package/src/main/custom-chart-context.spec.ts +64 -4
  27. package/src/react/use-custom-chart-context.spec.tsx +65 -2
  28. package/src/types/answer-column.types.ts +7 -0
  29. package/src/types/common.types.ts +9 -3
  30. package/src/utils/conditional-formatting/conditional-formatting.spec.ts +52 -0
  31. package/src/utils/date-formatting.spec.ts +166 -0
  32. package/src/utils/date-formatting.ts +109 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-formatting.spec.d.ts","sourceRoot":"","sources":["../../src/utils/date-formatting.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,123 @@
1
+ import { ColumnTimeBucket, ColumnType, DataType, } from '../types/answer-column.types';
2
+ import { dateFormatter, getCustomCalendarGuidFromColumn, getDisplayString, getStartEpoch, hasCustomCalendar, isAttribute, isDateColumn, isDateFamilyColumn, isDateNumColumn, isTimeColumn, } from './date-formatting';
3
+ describe('date-formatting', () => {
4
+ let col;
5
+ beforeEach(() => {
6
+ col = {
7
+ id: 'testId',
8
+ name: 'test',
9
+ type: ColumnType.MEASURE,
10
+ timeBucket: ColumnTimeBucket.AUTO,
11
+ dataType: DataType.UNKNOWN,
12
+ calenderGuid: '12345',
13
+ };
14
+ });
15
+ test('isDateColumn should return true for DATE data type', () => {
16
+ col.dataType = DataType.DATE;
17
+ expect(isDateColumn(col)).toBe(true);
18
+ });
19
+ test('isDateColumn should return true for DATE_TIME data type', () => {
20
+ col.dataType = DataType.DATE_TIME;
21
+ expect(isDateColumn(col)).toBe(true);
22
+ });
23
+ test('isAttribute should return true for ATTRIBUTE column type', () => {
24
+ col.type = ColumnType.ATTRIBUTE;
25
+ expect(isAttribute(col)).toBe(true);
26
+ });
27
+ test('isAttribute should return false for non-ATTRIBUTE column type', () => {
28
+ col.type = ColumnType.MEASURE;
29
+ expect(isAttribute(col)).toBe(false);
30
+ });
31
+ test('getCustomCalendarGuidFromColumn should return the calendarGuid', () => {
32
+ col.calenderGuid = '12345';
33
+ expect(getCustomCalendarGuidFromColumn(col)).toBe('12345');
34
+ });
35
+ test('isDateNumColumn should return true for ATTRIBUTE type with specific time buckets', () => {
36
+ col.type = ColumnType.ATTRIBUTE;
37
+ col.timeBucket = ColumnTimeBucket.HOUR_OF_DAY;
38
+ expect(isDateNumColumn(col)).toBe(true);
39
+ });
40
+ test('isDateNumColumn should return false for non-ATTRIBUTE type', () => {
41
+ col.type = ColumnType.MEASURE;
42
+ col.timeBucket = ColumnTimeBucket.DAY_OF_WEEK;
43
+ expect(isDateNumColumn(col)).toBe(false);
44
+ });
45
+ test('isDateFamilyColumn should return true for DATE data type', () => {
46
+ col.dataType = DataType.DATE;
47
+ expect(isDateFamilyColumn(col)).toBe(true);
48
+ });
49
+ test('isDateFamilyColumn should return true for DATE_NUM column', () => {
50
+ col.type = ColumnType.ATTRIBUTE;
51
+ col.timeBucket = ColumnTimeBucket.DAY_OF_WEEK;
52
+ expect(isDateFamilyColumn(col)).toBe(true);
53
+ });
54
+ test('isTimeColumn should return true for TIME data type', () => {
55
+ col.dataType = DataType.TIME;
56
+ expect(isTimeColumn(col)).toBe(true);
57
+ });
58
+ test('hasCustomCalendar should return true for date family columns with custom calendar', () => {
59
+ col.dataType = DataType.DATE;
60
+ col.calenderGuid = '12345';
61
+ expect(hasCustomCalendar(col)).toBe(true);
62
+ });
63
+ test('getStartEpoch should return the start epoch from CustomCalendarDate', () => {
64
+ const date = {
65
+ v: { s: 12345, e: 12346 },
66
+ d: 'Custom_Date',
67
+ };
68
+ expect(getStartEpoch(date)).toBe(date.v.s);
69
+ });
70
+ test('getStartEpoch should return null if start epoch is not present', () => {
71
+ const date = { v: {}, d: '01-07-2021' };
72
+ expect(getStartEpoch(date)).toBe(null);
73
+ });
74
+ test('getDisplayString should return display string if present', () => {
75
+ const date = { v: { s: 1625097600, e: 1625184000 }, d: '01-07-2021' };
76
+ expect(getDisplayString(date)).toBe('01-07-2021');
77
+ });
78
+ test('getDisplayString should return null if display string is not present', () => {
79
+ const date = {
80
+ v: { s: 1625097600, e: 1625184000 },
81
+ };
82
+ expect(getDisplayString(date)).toBe(null);
83
+ });
84
+ test('dateFormatter should return custom calendar display string if present', () => {
85
+ const dataValue = {
86
+ v: { s: 1625097600, e: 1625184000 },
87
+ d: '01-07-2021',
88
+ };
89
+ col.dataType = DataType.DATE;
90
+ col.calenderGuid = '12345';
91
+ expect(dateFormatter(dataValue, col)).toBe('01-07-2021');
92
+ });
93
+ test('dateFormatter should return formatted date from start epoch if custom calendar display string is not present', () => {
94
+ const dataValue = {
95
+ v: { s: 1625097600, e: 1625184000 },
96
+ };
97
+ col.dataType = DataType.DATE;
98
+ col.calenderGuid = '12345';
99
+ expect(dateFormatter(dataValue, col)).toBe('01-07-2021');
100
+ });
101
+ test('dateFormatter should return null if start epoch is not present', () => {
102
+ const dataValue = { v: { e: 1625184000 } };
103
+ col.dataType = DataType.DATE;
104
+ col.calenderGuid = '12345';
105
+ expect(dateFormatter(dataValue, col)).toBe(null);
106
+ });
107
+ test('dateFormatter should return formatted date for non-custom calendar column', () => {
108
+ const dataValue = 1625097600;
109
+ col.dataType = DataType.DATE;
110
+ col.calenderGuid = undefined;
111
+ expect(dateFormatter(dataValue, col)).toBe('01-07-2021');
112
+ });
113
+ test('dateFormatter should format the date based on custom calendar', () => {
114
+ col.dataType = DataType.DATE;
115
+ col.calenderGuid = '12345';
116
+ const date = {
117
+ v: { s: 12345, e: 12346 },
118
+ d: 'Custom_Date',
119
+ };
120
+ expect(dateFormatter(date, col)).toBe(date.d);
121
+ });
122
+ });
123
+ //# sourceMappingURL=date-formatting.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-formatting.spec.js","sourceRoot":"","sources":["../../src/utils/date-formatting.spec.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@thoughtspot/ts-chart-sdk",
3
3
  "private": false,
4
- "version": "0.0.2-alpha.6",
4
+ "version": "0.0.2-alpha.8",
5
5
  "module": "lib/index",
6
6
  "main": "lib/index",
7
7
  "types": "lib/index",
@@ -36,6 +36,7 @@
36
36
  "@testing-library/react-hooks": "^7.0.2",
37
37
  "@types/jest": "^27.0.3",
38
38
  "@types/lodash": "4.14.175",
39
+ "@types/luxon": "^3.4.2",
39
40
  "@types/node": "18.16.3",
40
41
  "@types/react": "^17.0.2",
41
42
  "@types/react-dom": "^17.0.11",
@@ -74,6 +75,7 @@
74
75
  },
75
76
  "dependencies": {
76
77
  "lodash": "^4.17.21",
78
+ "luxon": "^3.4.4",
77
79
  "promise-postmessage": "^3.5.0",
78
80
  "react": "^17.0.2",
79
81
  "react-dom": "^17.0.2"
package/src/index.ts CHANGED
@@ -7,4 +7,5 @@ export * from './types/ts-to-chart-event.types';
7
7
  export * from './main/custom-chart-context';
8
8
  export * from './react/use-custom-chart-context';
9
9
  export * from './types/conditional-formatting.types';
10
+ export * from './utils/date-formatting';
10
11
  export * from './utils/conditional-formatting/conditional-formatting';
@@ -112,23 +112,83 @@ describe('CustomChartContext', () => {
112
112
  expect(mockPostMessageToHost).not.toHaveBeenCalled();
113
113
  });
114
114
 
115
- test('multiple intializations should throw an error', async () => {
115
+ test('type check string for visualProps on initialize payload should not throw an error.', async () => {
116
+ expect(mockInitMessage).toHaveBeenCalled();
117
+
116
118
  // Call the initialize function and wait for it to resolve
117
119
  const promise = customChartContext.initialize();
118
120
 
119
121
  // Check that the hasInitializedPromise has resolved
120
- eventProcessor({
121
- payload: mockInitializeContextPayload,
122
+
123
+ const mockInitializeContextPayloadWithVisualProps = {
124
+ ...mockInitializeContextPayload,
125
+ chartModel: {
126
+ ...mockInitializeContextPayload.chartModel,
127
+ visualProps: 'visualPropStringPayload',
128
+ },
129
+ };
130
+
131
+ await eventProcessor({
132
+ payload: mockInitializeContextPayloadWithVisualProps,
122
133
  eventType: TSToChartEvent.Initialize,
123
134
  });
124
-
125
135
  eventProcessor({
126
136
  payload: {},
127
137
  eventType: TSToChartEvent.InitializeComplete,
128
138
  });
139
+ await expect(promise).resolves.toBeUndefined();
140
+ const chartModel = customChartContext.getChartModel();
141
+ expect(typeof chartModel.visualProps).toEqual('string');
142
+ expect(chartModel.visualProps).toEqual('visualPropStringPayload');
143
+ expect(mockPostMessageToHost).not.toHaveBeenCalled();
144
+ });
145
+
146
+ test('type check object for visualProps on initialize payload should not throw an error.', async () => {
147
+ expect(mockInitMessage).toHaveBeenCalled();
129
148
 
149
+ // Call the initialize function and wait for it to resolve
150
+ const promise = customChartContext.initialize();
151
+
152
+ // Check that the hasInitializedPromise has resolved
153
+
154
+ const mockInitializeContextPayloadWithVisualProps = {
155
+ ...mockInitializeContextPayload,
156
+ chartModel: {
157
+ ...mockInitializeContextPayload.chartModel,
158
+ visualProps: {
159
+ data: 'sample data',
160
+ },
161
+ },
162
+ };
163
+
164
+ await eventProcessor({
165
+ payload: mockInitializeContextPayloadWithVisualProps,
166
+ eventType: TSToChartEvent.Initialize,
167
+ });
168
+ eventProcessor({
169
+ payload: {},
170
+ eventType: TSToChartEvent.InitializeComplete,
171
+ });
130
172
  await expect(promise).resolves.toBeUndefined();
173
+ const chartModel = customChartContext.getChartModel();
174
+ expect(typeof chartModel.visualProps).toEqual('object');
175
+ expect(chartModel.visualProps).toEqual({
176
+ data: 'sample data',
177
+ });
178
+ expect(mockPostMessageToHost).not.toHaveBeenCalled();
179
+ });
131
180
 
181
+ test('multiple intializations should throw an error', async () => {
182
+ // Call the initialize function and wait for it to resolve
183
+ getChartContext({
184
+ getDefaultChartConfig,
185
+ getQueriesFromChartConfig,
186
+ renderChart,
187
+ });
188
+ eventProcessor({
189
+ payload: {},
190
+ eventType: TSToChartEvent.InitializeComplete,
191
+ });
132
192
  let error;
133
193
  try {
134
194
  customChartContext = new CustomChartContext({
@@ -3,6 +3,7 @@ import { renderHook } from '@testing-library/react-hooks';
3
3
  import React from 'react';
4
4
  import * as PostMessageEventBridge from '../main/post-message-event-bridge';
5
5
  import { mockInitializeContextPayload } from '../test/test-utils';
6
+ import { ColumnType } from '../types/answer-column.types';
6
7
  import { ChartToTSEvent } from '../types/chart-to-ts-event.types';
7
8
  import { TSToChartEvent } from '../types/ts-to-chart-event.types';
8
9
  import { contextChartProps } from './mocks/custom-chart-context-mock';
@@ -12,7 +13,10 @@ describe('useChartContext initialization', () => {
12
13
  let eventProcessor: any;
13
14
  let mockInitMessage;
14
15
  let mockPostMessageToHost;
15
- const mockedChartModel = { columns: [], config: {} };
16
+ const mockedChartModel = {
17
+ columns: [{ type: ColumnType.MEASURE }, { type: ColumnType.ATTRIBUTE }],
18
+ config: {},
19
+ };
16
20
  beforeEach(() => {
17
21
  mockInitMessage = jest.spyOn(
18
22
  PostMessageEventBridge,
@@ -67,6 +71,66 @@ describe('useChartContext initialization', () => {
67
71
  });
68
72
  });
69
73
 
74
+ test('should trigger getDataQuery and fetch correct query response', async () => {
75
+ // Render the hook with the custom chart context props
76
+ const { result, waitFor } = renderHook(() =>
77
+ useChartContext(contextChartProps),
78
+ );
79
+
80
+ // Assert that the context is not initialized initially
81
+ expect(result.current.hasInitialized).toBe(false);
82
+ expect(result.current.chartModel).toBeUndefined();
83
+ await eventProcessor({
84
+ payload: {
85
+ componentId: 'COMPONENT_ID',
86
+ hostUrl: 'https://some.chart.app',
87
+ chartModel: mockedChartModel,
88
+ },
89
+ eventType: TSToChartEvent.Initialize,
90
+ });
91
+ const response = await eventProcessor({
92
+ payload: {
93
+ config: [
94
+ {
95
+ key: 'column',
96
+ dimensions: [
97
+ {
98
+ key: 'x',
99
+ columns: [mockedChartModel.columns[0]],
100
+ },
101
+ {
102
+ key: 'y',
103
+ columns: [mockedChartModel.columns[1]],
104
+ },
105
+ ],
106
+ },
107
+ ],
108
+ },
109
+ eventType: TSToChartEvent.GetDataQuery,
110
+ source: 'ts-host-app',
111
+ });
112
+ await eventProcessor({
113
+ payload: {},
114
+ eventType: TSToChartEvent.TriggerRenderChart,
115
+ source: 'ts-host-app',
116
+ });
117
+ await eventProcessor({
118
+ payload: {},
119
+ eventType: TSToChartEvent.InitializeComplete,
120
+ source: 'ts-host-app',
121
+ });
122
+
123
+ await waitFor(() => {
124
+ expect(response.queries[0].queryColumns[0]).toBe(
125
+ mockedChartModel.columns[0],
126
+ );
127
+ expect(response.queries[0].queryColumns[1]).toBe(
128
+ mockedChartModel.columns[1],
129
+ );
130
+ expect(result.current.hasInitialized).toBeTruthy();
131
+ });
132
+ });
133
+
70
134
  test('should make sure hasInitialized to remain false when context initialization failed', async () => {
71
135
  jest.mock('../main/custom-chart-context', () => ({
72
136
  CustomChartContext: jest.fn().mockImplementation(() => ({
@@ -76,7 +140,6 @@ describe('useChartContext initialization', () => {
76
140
  emitEvent: jest.fn(),
77
141
  on: jest.fn(),
78
142
  getChartModel: jest.fn(),
79
- renderChart: jest.fn(),
80
143
  destroy: jest.fn(),
81
144
  })),
82
145
  }));
@@ -242,4 +242,11 @@ export interface ChartColumn {
242
242
  * @version SDK: 0.1 | ThoughtSpot:
243
243
  */
244
244
  customOrder?: Array<string>;
245
+
246
+ /**
247
+ * Guid of Custom calender for the column if defined in worksheet else null
248
+ *
249
+ * @version SDK: 0.1 | ThoughtSpot: sdcwdc
250
+ */
251
+ calenderGuid?: string;
245
252
  }
@@ -179,15 +179,21 @@ export type ValidationResponse = {
179
179
  /**
180
180
  * Custom Visual props is the stored metadata for the visual props definition
181
181
  * configured by the user in the visual prop editor
182
- * The JSON is defined by the visual prop types. See VisualPropEditorDefinition.
183
- *
182
+ * The object is defined by the visual prop types. See VisualPropEditorDefinition.
183
+ * If there is any local state specific to charts needs to be maintained on save answer, store it
184
+ * in VisualProps, with visualProps.clientState variable. The clientState variable should be a
185
+ * string, preferrably a result of JSON.stringify(<yourlocalClientState>).
186
+ * @remark
187
+ * only values stored in clientSate variable will be preserved on changing the
188
+ * visualPropeditorDefinition, any other variable store would not be preserved
184
189
  * @group Chart Model
185
190
  * @version SDK: 0.1 | ThoughtSpot:
186
191
  */
187
- export type VisualProps = JSON;
192
+ export type VisualProps = unknown;
188
193
 
189
194
  /**
190
195
  * Custom Font Faces type from TS.
196
+ *
191
197
  */
192
198
 
193
199
  export type CustomFontFaces = {
@@ -21,7 +21,9 @@ import { DataPointsArray } from '../../types/common.types';
21
21
  import {
22
22
  ConditionalFormatting,
23
23
  ConditionalFormattingComparisonTypes,
24
+ FalconDataType,
24
25
  Operators,
26
+ ParameterValueType,
25
27
  } from '../../types/conditional-formatting.types';
26
28
  import {
27
29
  applicableConditionalFormatting,
@@ -64,12 +66,26 @@ const doesNotContainOperator = createAttributeOperator(
64
66
  const startsWithOperator = createAttributeOperator(Operators.StartsWith);
65
67
  const endsWithOperator = createAttributeOperator(Operators.EndsWith);
66
68
 
69
+ const invalidOperator = createMetricOperator('invalid-operator' as any);
70
+
67
71
  const parameter = undefined;
68
72
 
69
73
  const mockConditionalFormatting: ConditionalFormatting = {
70
74
  rows: [lessThanOperator, greaterThanOperator, isBetweenOperator],
71
75
  };
72
76
 
77
+ const parameters = [
78
+ {
79
+ id: 'parameter1',
80
+ defaultValue: 'abc',
81
+ dataType: FalconDataType.Char,
82
+ description: '',
83
+ owner: null as any,
84
+ valueType: ParameterValueType.Any,
85
+ name: 'parameter1',
86
+ },
87
+ ];
88
+
73
89
  describe('validateCfCondition', () => {
74
90
  test('verify validateCfCondition util', () => {
75
91
  expect(
@@ -115,6 +131,19 @@ describe('validateCfCondition', () => {
115
131
  expect(
116
132
  validateCfCondition(isBetweenOperator, 4, 'col1', mockDataAttr),
117
133
  ).toBe(false);
134
+ expect(
135
+ validateCfCondition(invalidOperator, 4, 'col1', mockDataAttr),
136
+ ).toBe(false);
137
+
138
+ const operatorWithColId = createMetricOperator(
139
+ Operators.LessThan,
140
+ 'col1',
141
+ 'col2',
142
+ );
143
+
144
+ expect(
145
+ validateCfCondition(operatorWithColId, 4, '', mockDataAttr),
146
+ ).toBe(false);
118
147
  });
119
148
  });
120
149
 
@@ -220,6 +249,9 @@ describe('isConditionSatisfied', () => {
220
249
  expect(isConditionSatisfied(notEqualToOperator, parameter, 200)).toBe(
221
250
  false,
222
251
  );
252
+ expect(isConditionSatisfied(notEqualToOperator, parameter, null)).toBe(
253
+ true,
254
+ );
223
255
  expect(isConditionSatisfied(isBetweenOperator, parameter, 200)).toBe(
224
256
  true,
225
257
  );
@@ -232,6 +264,9 @@ describe('isConditionSatisfied', () => {
232
264
  expect(isConditionSatisfied(isBetweenOperator, parameter, 50)).toBe(
233
265
  false,
234
266
  );
267
+ expect(isConditionSatisfied(isBetweenOperator, parameter, 50)).toBe(
268
+ false,
269
+ );
235
270
 
236
271
  expect(
237
272
  isConditionSatisfied(
@@ -411,5 +446,22 @@ describe('isConditionSatisfied', () => {
411
446
  expect(
412
447
  isConditionSatisfied(columnBasedOperator, undefined, 'abc', 'def'),
413
448
  ).toBe(false);
449
+
450
+ // Parameter Based
451
+ const parameterBasedOperator = createMetricOperator(
452
+ Operators.EqualTo,
453
+ 'col1',
454
+ 'col2',
455
+ 'parameter1',
456
+ ConditionalFormattingComparisonTypes.ParameterBased,
457
+ );
458
+ expect(
459
+ isConditionSatisfied(
460
+ parameterBasedOperator,
461
+ parameters,
462
+ 'abc',
463
+ 'abc',
464
+ ),
465
+ ).toBe(true);
414
466
  });
415
467
  });
@@ -0,0 +1,166 @@
1
+ /**
2
+ * @file: Date Formatting Spec
3
+ *
4
+ * @author Yashvardhan Nehra <yashvardhan.nehra@thoughtspot.com>
5
+ *
6
+ * Copyright: ThoughtSpot Inc. 2023
7
+ */
8
+
9
+ import {
10
+ ChartColumn,
11
+ ColumnTimeBucket,
12
+ ColumnType,
13
+ DataType,
14
+ } from '../types/answer-column.types';
15
+ import {
16
+ CustomCalendarDate,
17
+ dateFormatter,
18
+ getCustomCalendarGuidFromColumn,
19
+ getDisplayString,
20
+ getStartEpoch,
21
+ hasCustomCalendar,
22
+ isAttribute,
23
+ isDateColumn,
24
+ isDateFamilyColumn,
25
+ isDateNumColumn,
26
+ isTimeColumn,
27
+ } from './date-formatting';
28
+
29
+ describe('date-formatting', () => {
30
+ let col: ChartColumn;
31
+ beforeEach(() => {
32
+ col = {
33
+ id: 'testId',
34
+ name: 'test',
35
+ type: ColumnType.MEASURE,
36
+ timeBucket: ColumnTimeBucket.AUTO,
37
+ dataType: DataType.UNKNOWN,
38
+ calenderGuid: '12345',
39
+ };
40
+ });
41
+ test('isDateColumn should return true for DATE data type', () => {
42
+ col.dataType = DataType.DATE;
43
+ expect(isDateColumn(col)).toBe(true);
44
+ });
45
+
46
+ test('isDateColumn should return true for DATE_TIME data type', () => {
47
+ col.dataType = DataType.DATE_TIME;
48
+ expect(isDateColumn(col)).toBe(true);
49
+ });
50
+
51
+ test('isAttribute should return true for ATTRIBUTE column type', () => {
52
+ col.type = ColumnType.ATTRIBUTE;
53
+ expect(isAttribute(col)).toBe(true);
54
+ });
55
+
56
+ test('isAttribute should return false for non-ATTRIBUTE column type', () => {
57
+ col.type = ColumnType.MEASURE;
58
+ expect(isAttribute(col)).toBe(false);
59
+ });
60
+
61
+ test('getCustomCalendarGuidFromColumn should return the calendarGuid', () => {
62
+ col.calenderGuid = '12345';
63
+ expect(getCustomCalendarGuidFromColumn(col)).toBe('12345');
64
+ });
65
+
66
+ test('isDateNumColumn should return true for ATTRIBUTE type with specific time buckets', () => {
67
+ col.type = ColumnType.ATTRIBUTE;
68
+ col.timeBucket = ColumnTimeBucket.HOUR_OF_DAY;
69
+ expect(isDateNumColumn(col)).toBe(true);
70
+ });
71
+
72
+ test('isDateNumColumn should return false for non-ATTRIBUTE type', () => {
73
+ col.type = ColumnType.MEASURE;
74
+ col.timeBucket = ColumnTimeBucket.DAY_OF_WEEK;
75
+ expect(isDateNumColumn(col)).toBe(false);
76
+ });
77
+
78
+ test('isDateFamilyColumn should return true for DATE data type', () => {
79
+ col.dataType = DataType.DATE;
80
+ expect(isDateFamilyColumn(col)).toBe(true);
81
+ });
82
+
83
+ test('isDateFamilyColumn should return true for DATE_NUM column', () => {
84
+ col.type = ColumnType.ATTRIBUTE;
85
+ col.timeBucket = ColumnTimeBucket.DAY_OF_WEEK;
86
+ expect(isDateFamilyColumn(col)).toBe(true);
87
+ });
88
+
89
+ test('isTimeColumn should return true for TIME data type', () => {
90
+ col.dataType = DataType.TIME;
91
+ expect(isTimeColumn(col)).toBe(true);
92
+ });
93
+
94
+ test('hasCustomCalendar should return true for date family columns with custom calendar', () => {
95
+ col.dataType = DataType.DATE;
96
+ col.calenderGuid = '12345';
97
+ expect(hasCustomCalendar(col)).toBe(true);
98
+ });
99
+
100
+ test('getStartEpoch should return the start epoch from CustomCalendarDate', () => {
101
+ const date = {
102
+ v: { s: 12345, e: 12346 },
103
+ d: 'Custom_Date',
104
+ } as CustomCalendarDate;
105
+ expect(getStartEpoch(date)).toBe(date.v.s);
106
+ });
107
+
108
+ test('getStartEpoch should return null if start epoch is not present', () => {
109
+ const date = { v: {}, d: '01-07-2021' } as CustomCalendarDate;
110
+ expect(getStartEpoch(date)).toBe(null);
111
+ });
112
+
113
+ test('getDisplayString should return display string if present', () => {
114
+ const date = { v: { s: 1625097600, e: 1625184000 }, d: '01-07-2021' };
115
+ expect(getDisplayString(date)).toBe('01-07-2021');
116
+ });
117
+
118
+ test('getDisplayString should return null if display string is not present', () => {
119
+ const date = {
120
+ v: { s: 1625097600, e: 1625184000 },
121
+ } as CustomCalendarDate;
122
+ expect(getDisplayString(date)).toBe(null);
123
+ });
124
+
125
+ test('dateFormatter should return custom calendar display string if present', () => {
126
+ const dataValue = {
127
+ v: { s: 1625097600, e: 1625184000 },
128
+ d: '01-07-2021',
129
+ } as CustomCalendarDate;
130
+ col.dataType = DataType.DATE;
131
+ col.calenderGuid = '12345';
132
+ expect(dateFormatter(dataValue, col)).toBe('01-07-2021');
133
+ });
134
+
135
+ test('dateFormatter should return formatted date from start epoch if custom calendar display string is not present', () => {
136
+ const dataValue = {
137
+ v: { s: 1625097600, e: 1625184000 },
138
+ } as CustomCalendarDate;
139
+ col.dataType = DataType.DATE;
140
+ col.calenderGuid = '12345';
141
+ expect(dateFormatter(dataValue, col)).toBe('01-07-2021');
142
+ });
143
+
144
+ test('dateFormatter should return null if start epoch is not present', () => {
145
+ const dataValue = { v: { e: 1625184000 } } as CustomCalendarDate;
146
+ col.dataType = DataType.DATE;
147
+ col.calenderGuid = '12345';
148
+ expect(dateFormatter(dataValue, col)).toBe(null);
149
+ });
150
+
151
+ test('dateFormatter should return formatted date for non-custom calendar column', () => {
152
+ const dataValue = 1625097600;
153
+ col.dataType = DataType.DATE;
154
+ col.calenderGuid = undefined;
155
+ expect(dateFormatter(dataValue, col)).toBe('01-07-2021');
156
+ });
157
+ test('dateFormatter should format the date based on custom calendar', () => {
158
+ col.dataType = DataType.DATE;
159
+ col.calenderGuid = '12345';
160
+ const date = {
161
+ v: { s: 12345, e: 12346 },
162
+ d: 'Custom_Date',
163
+ } as CustomCalendarDate;
164
+ expect(dateFormatter(date, col)).toBe(date.d);
165
+ });
166
+ });