@akinon/ai-modal-table 1.0.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 (185) hide show
  1. package/dist/cjs/__tests__/index.test.d.ts +2 -0
  2. package/dist/cjs/__tests__/index.test.d.ts.map +1 -0
  3. package/dist/cjs/__tests__/index.test.js +82 -0
  4. package/dist/cjs/__tests__/index.test.tsx +94 -0
  5. package/dist/cjs/ai-modal-table/__tests__/index.test.d.ts +2 -0
  6. package/dist/cjs/ai-modal-table/__tests__/index.test.d.ts.map +1 -0
  7. package/dist/cjs/ai-modal-table/__tests__/index.test.js +59 -0
  8. package/dist/cjs/ai-modal-table/__tests__/index.test.tsx +98 -0
  9. package/dist/cjs/ai-modal-table/index.d.ts +4 -0
  10. package/dist/cjs/ai-modal-table/index.d.ts.map +1 -0
  11. package/dist/cjs/ai-modal-table/index.js +54 -0
  12. package/dist/cjs/ai-table/__tests__/index.test.d.ts +2 -0
  13. package/dist/cjs/ai-table/__tests__/index.test.d.ts.map +1 -0
  14. package/dist/cjs/ai-table/__tests__/index.test.js +348 -0
  15. package/dist/cjs/ai-table/__tests__/index.test.tsx +572 -0
  16. package/dist/cjs/ai-table/components/__tests__/content.test.d.ts +2 -0
  17. package/dist/cjs/ai-table/components/__tests__/content.test.d.ts.map +1 -0
  18. package/dist/cjs/ai-table/components/__tests__/content.test.js +1349 -0
  19. package/dist/cjs/ai-table/components/__tests__/content.test.tsx +1637 -0
  20. package/dist/cjs/ai-table/components/__tests__/filters.test.d.ts +2 -0
  21. package/dist/cjs/ai-table/components/__tests__/filters.test.d.ts.map +1 -0
  22. package/dist/cjs/ai-table/components/__tests__/filters.test.js +400 -0
  23. package/dist/cjs/ai-table/components/__tests__/filters.test.tsx +534 -0
  24. package/dist/cjs/ai-table/components/__tests__/footer.test.d.ts +2 -0
  25. package/dist/cjs/ai-table/components/__tests__/footer.test.d.ts.map +1 -0
  26. package/dist/cjs/ai-table/components/__tests__/footer.test.js +465 -0
  27. package/dist/cjs/ai-table/components/__tests__/footer.test.tsx +597 -0
  28. package/dist/cjs/ai-table/components/__tests__/mapper.test.d.ts +2 -0
  29. package/dist/cjs/ai-table/components/__tests__/mapper.test.d.ts.map +1 -0
  30. package/dist/cjs/ai-table/components/__tests__/mapper.test.js +453 -0
  31. package/dist/cjs/ai-table/components/__tests__/mapper.test.tsx +601 -0
  32. package/dist/cjs/ai-table/components/__tests__/pagination.test.d.ts +2 -0
  33. package/dist/cjs/ai-table/components/__tests__/pagination.test.d.ts.map +1 -0
  34. package/dist/cjs/ai-table/components/__tests__/pagination.test.js +430 -0
  35. package/dist/cjs/ai-table/components/__tests__/pagination.test.tsx +629 -0
  36. package/dist/cjs/ai-table/components/__tests__/row-actions.test.d.ts +2 -0
  37. package/dist/cjs/ai-table/components/__tests__/row-actions.test.d.ts.map +1 -0
  38. package/dist/cjs/ai-table/components/__tests__/row-actions.test.js +382 -0
  39. package/dist/cjs/ai-table/components/__tests__/row-actions.test.tsx +507 -0
  40. package/dist/cjs/ai-table/components/content.d.ts +11 -0
  41. package/dist/cjs/ai-table/components/content.d.ts.map +1 -0
  42. package/dist/cjs/ai-table/components/content.js +309 -0
  43. package/dist/cjs/ai-table/components/filters.d.ts +10 -0
  44. package/dist/cjs/ai-table/components/filters.d.ts.map +1 -0
  45. package/dist/cjs/ai-table/components/filters.js +55 -0
  46. package/dist/cjs/ai-table/components/footer.d.ts +12 -0
  47. package/dist/cjs/ai-table/components/footer.d.ts.map +1 -0
  48. package/dist/cjs/ai-table/components/footer.js +24 -0
  49. package/dist/cjs/ai-table/components/mapper.d.ts +11 -0
  50. package/dist/cjs/ai-table/components/mapper.d.ts.map +1 -0
  51. package/dist/cjs/ai-table/components/mapper.js +21 -0
  52. package/dist/cjs/ai-table/components/pagination.d.ts +11 -0
  53. package/dist/cjs/ai-table/components/pagination.d.ts.map +1 -0
  54. package/dist/cjs/ai-table/components/pagination.js +106 -0
  55. package/dist/cjs/ai-table/components/row-actions.d.ts +14 -0
  56. package/dist/cjs/ai-table/components/row-actions.d.ts.map +1 -0
  57. package/dist/cjs/ai-table/components/row-actions.js +52 -0
  58. package/dist/cjs/ai-table/constants/index.d.ts +17 -0
  59. package/dist/cjs/ai-table/constants/index.d.ts.map +1 -0
  60. package/dist/cjs/ai-table/constants/index.js +19 -0
  61. package/dist/cjs/ai-table/i18n/index.d.ts +3 -0
  62. package/dist/cjs/ai-table/i18n/index.d.ts.map +1 -0
  63. package/dist/cjs/ai-table/i18n/index.js +14 -0
  64. package/dist/cjs/ai-table/i18n/translations/en.d.ts +8 -0
  65. package/dist/cjs/ai-table/i18n/translations/en.d.ts.map +1 -0
  66. package/dist/cjs/ai-table/i18n/translations/en.js +9 -0
  67. package/dist/cjs/ai-table/i18n/translations/tr.d.ts +8 -0
  68. package/dist/cjs/ai-table/i18n/translations/tr.d.ts.map +1 -0
  69. package/dist/cjs/ai-table/i18n/translations/tr.js +9 -0
  70. package/dist/cjs/ai-table/index.d.ts +4 -0
  71. package/dist/cjs/ai-table/index.d.ts.map +1 -0
  72. package/dist/cjs/ai-table/index.js +71 -0
  73. package/dist/cjs/ai-table/utils/data-format/__tests__/index.test.d.ts +2 -0
  74. package/dist/cjs/ai-table/utils/data-format/__tests__/index.test.d.ts.map +1 -0
  75. package/dist/cjs/ai-table/utils/data-format/__tests__/index.test.js +146 -0
  76. package/dist/cjs/ai-table/utils/data-format/__tests__/index.test.ts +184 -0
  77. package/dist/cjs/ai-table/utils/data-format/index.d.ts +7 -0
  78. package/dist/cjs/ai-table/utils/data-format/index.d.ts.map +1 -0
  79. package/dist/cjs/ai-table/utils/data-format/index.js +43 -0
  80. package/dist/cjs/ai-table/utils/render-mapper-fields/__tests__/index.test.d.ts +2 -0
  81. package/dist/cjs/ai-table/utils/render-mapper-fields/__tests__/index.test.d.ts.map +1 -0
  82. package/dist/cjs/ai-table/utils/render-mapper-fields/__tests__/index.test.js +291 -0
  83. package/dist/cjs/ai-table/utils/render-mapper-fields/__tests__/index.test.tsx +399 -0
  84. package/dist/cjs/ai-table/utils/render-mapper-fields/index.d.ts +10 -0
  85. package/dist/cjs/ai-table/utils/render-mapper-fields/index.d.ts.map +1 -0
  86. package/dist/cjs/ai-table/utils/render-mapper-fields/index.js +48 -0
  87. package/dist/cjs/index.d.ts +4 -0
  88. package/dist/cjs/index.d.ts.map +1 -0
  89. package/dist/cjs/index.js +7 -0
  90. package/dist/cjs/types/index.d.ts +134 -0
  91. package/dist/cjs/types/index.d.ts.map +1 -0
  92. package/dist/cjs/types/index.js +2 -0
  93. package/dist/esm/__tests__/index.test.d.ts +2 -0
  94. package/dist/esm/__tests__/index.test.d.ts.map +1 -0
  95. package/dist/esm/__tests__/index.test.js +80 -0
  96. package/dist/esm/__tests__/index.test.tsx +94 -0
  97. package/dist/esm/ai-modal-table/__tests__/index.test.d.ts +2 -0
  98. package/dist/esm/ai-modal-table/__tests__/index.test.d.ts.map +1 -0
  99. package/dist/esm/ai-modal-table/__tests__/index.test.js +57 -0
  100. package/dist/esm/ai-modal-table/__tests__/index.test.tsx +98 -0
  101. package/dist/esm/ai-modal-table/index.d.ts +4 -0
  102. package/dist/esm/ai-modal-table/index.d.ts.map +1 -0
  103. package/dist/esm/ai-modal-table/index.js +50 -0
  104. package/dist/esm/ai-table/__tests__/index.test.d.ts +2 -0
  105. package/dist/esm/ai-table/__tests__/index.test.d.ts.map +1 -0
  106. package/dist/esm/ai-table/__tests__/index.test.js +346 -0
  107. package/dist/esm/ai-table/__tests__/index.test.tsx +572 -0
  108. package/dist/esm/ai-table/components/__tests__/content.test.d.ts +2 -0
  109. package/dist/esm/ai-table/components/__tests__/content.test.d.ts.map +1 -0
  110. package/dist/esm/ai-table/components/__tests__/content.test.js +1347 -0
  111. package/dist/esm/ai-table/components/__tests__/content.test.tsx +1637 -0
  112. package/dist/esm/ai-table/components/__tests__/filters.test.d.ts +2 -0
  113. package/dist/esm/ai-table/components/__tests__/filters.test.d.ts.map +1 -0
  114. package/dist/esm/ai-table/components/__tests__/filters.test.js +398 -0
  115. package/dist/esm/ai-table/components/__tests__/filters.test.tsx +534 -0
  116. package/dist/esm/ai-table/components/__tests__/footer.test.d.ts +2 -0
  117. package/dist/esm/ai-table/components/__tests__/footer.test.d.ts.map +1 -0
  118. package/dist/esm/ai-table/components/__tests__/footer.test.js +463 -0
  119. package/dist/esm/ai-table/components/__tests__/footer.test.tsx +597 -0
  120. package/dist/esm/ai-table/components/__tests__/mapper.test.d.ts +2 -0
  121. package/dist/esm/ai-table/components/__tests__/mapper.test.d.ts.map +1 -0
  122. package/dist/esm/ai-table/components/__tests__/mapper.test.js +451 -0
  123. package/dist/esm/ai-table/components/__tests__/mapper.test.tsx +601 -0
  124. package/dist/esm/ai-table/components/__tests__/pagination.test.d.ts +2 -0
  125. package/dist/esm/ai-table/components/__tests__/pagination.test.d.ts.map +1 -0
  126. package/dist/esm/ai-table/components/__tests__/pagination.test.js +428 -0
  127. package/dist/esm/ai-table/components/__tests__/pagination.test.tsx +629 -0
  128. package/dist/esm/ai-table/components/__tests__/row-actions.test.d.ts +2 -0
  129. package/dist/esm/ai-table/components/__tests__/row-actions.test.d.ts.map +1 -0
  130. package/dist/esm/ai-table/components/__tests__/row-actions.test.js +380 -0
  131. package/dist/esm/ai-table/components/__tests__/row-actions.test.tsx +507 -0
  132. package/dist/esm/ai-table/components/content.d.ts +11 -0
  133. package/dist/esm/ai-table/components/content.d.ts.map +1 -0
  134. package/dist/esm/ai-table/components/content.js +305 -0
  135. package/dist/esm/ai-table/components/filters.d.ts +10 -0
  136. package/dist/esm/ai-table/components/filters.d.ts.map +1 -0
  137. package/dist/esm/ai-table/components/filters.js +51 -0
  138. package/dist/esm/ai-table/components/footer.d.ts +12 -0
  139. package/dist/esm/ai-table/components/footer.d.ts.map +1 -0
  140. package/dist/esm/ai-table/components/footer.js +20 -0
  141. package/dist/esm/ai-table/components/mapper.d.ts +11 -0
  142. package/dist/esm/ai-table/components/mapper.d.ts.map +1 -0
  143. package/dist/esm/ai-table/components/mapper.js +17 -0
  144. package/dist/esm/ai-table/components/pagination.d.ts +11 -0
  145. package/dist/esm/ai-table/components/pagination.d.ts.map +1 -0
  146. package/dist/esm/ai-table/components/pagination.js +102 -0
  147. package/dist/esm/ai-table/components/row-actions.d.ts +14 -0
  148. package/dist/esm/ai-table/components/row-actions.d.ts.map +1 -0
  149. package/dist/esm/ai-table/components/row-actions.js +48 -0
  150. package/dist/esm/ai-table/constants/index.d.ts +17 -0
  151. package/dist/esm/ai-table/constants/index.d.ts.map +1 -0
  152. package/dist/esm/ai-table/constants/index.js +16 -0
  153. package/dist/esm/ai-table/i18n/index.d.ts +3 -0
  154. package/dist/esm/ai-table/i18n/index.d.ts.map +1 -0
  155. package/dist/esm/ai-table/i18n/index.js +11 -0
  156. package/dist/esm/ai-table/i18n/translations/en.d.ts +8 -0
  157. package/dist/esm/ai-table/i18n/translations/en.d.ts.map +1 -0
  158. package/dist/esm/ai-table/i18n/translations/en.js +7 -0
  159. package/dist/esm/ai-table/i18n/translations/tr.d.ts +8 -0
  160. package/dist/esm/ai-table/i18n/translations/tr.d.ts.map +1 -0
  161. package/dist/esm/ai-table/i18n/translations/tr.js +7 -0
  162. package/dist/esm/ai-table/index.d.ts +4 -0
  163. package/dist/esm/ai-table/index.d.ts.map +1 -0
  164. package/dist/esm/ai-table/index.js +67 -0
  165. package/dist/esm/ai-table/utils/data-format/__tests__/index.test.d.ts +2 -0
  166. package/dist/esm/ai-table/utils/data-format/__tests__/index.test.d.ts.map +1 -0
  167. package/dist/esm/ai-table/utils/data-format/__tests__/index.test.js +144 -0
  168. package/dist/esm/ai-table/utils/data-format/__tests__/index.test.ts +184 -0
  169. package/dist/esm/ai-table/utils/data-format/index.d.ts +7 -0
  170. package/dist/esm/ai-table/utils/data-format/index.d.ts.map +1 -0
  171. package/dist/esm/ai-table/utils/data-format/index.js +38 -0
  172. package/dist/esm/ai-table/utils/render-mapper-fields/__tests__/index.test.d.ts +2 -0
  173. package/dist/esm/ai-table/utils/render-mapper-fields/__tests__/index.test.d.ts.map +1 -0
  174. package/dist/esm/ai-table/utils/render-mapper-fields/__tests__/index.test.js +289 -0
  175. package/dist/esm/ai-table/utils/render-mapper-fields/__tests__/index.test.tsx +399 -0
  176. package/dist/esm/ai-table/utils/render-mapper-fields/index.d.ts +10 -0
  177. package/dist/esm/ai-table/utils/render-mapper-fields/index.d.ts.map +1 -0
  178. package/dist/esm/ai-table/utils/render-mapper-fields/index.js +44 -0
  179. package/dist/esm/index.d.ts +4 -0
  180. package/dist/esm/index.d.ts.map +1 -0
  181. package/dist/esm/index.js +2 -0
  182. package/dist/esm/types/index.d.ts +134 -0
  183. package/dist/esm/types/index.d.ts.map +1 -0
  184. package/dist/esm/types/index.js +1 -0
  185. package/package.json +60 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=filters.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filters.test.d.ts","sourceRoot":"","sources":["../../../../../src/ai-table/components/__tests__/filters.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,398 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ /* eslint-disable @typescript-eslint/no-explicit-any */
13
+ import { fireEvent, render, screen } from '@testing-library/react';
14
+ import * as React from 'react';
15
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
16
+ import { FILTER_TYPES } from '../../constants';
17
+ import { TableFilters } from '../filters';
18
+ vi.mock('@akinon/icons', () => ({
19
+ Icon: (_a) => {
20
+ var { icon, className, color, size } = _a, props = __rest(_a, ["icon", "className", "color", "size"]);
21
+ return (React.createElement("div", Object.assign({ "data-testid": `icon-${icon}`, className: className, "data-color": color, "data-size": size }, props), icon));
22
+ }
23
+ }));
24
+ vi.mock('@akinon/ui-input', () => ({
25
+ Input: (_a) => {
26
+ var { onChange, value, className, placeholder, name } = _a, props = __rest(_a, ["onChange", "value", "className", "placeholder", "name"]);
27
+ return (React.createElement("input", Object.assign({ onChange: onChange, value: value, className: className, placeholder: placeholder, name: name, "data-testid": `input-${name}` }, props)));
28
+ }
29
+ }));
30
+ vi.mock('@akinon/ui-layout', () => ({
31
+ Flex: (_a) => {
32
+ var { children, align, rootClassName, gap, wrap, flex } = _a, props = __rest(_a, ["children", "align", "rootClassName", "gap", "wrap", "flex"]);
33
+ const testId = flex === 1 ? 'flex-container' : 'flex-filter';
34
+ return (React.createElement("div", Object.assign({ "data-testid": testId, "data-align": align, "data-gap": gap, "data-wrap": wrap, "data-flex": flex, className: rootClassName }, props), children));
35
+ }
36
+ }));
37
+ vi.mock('lodash-es', () => ({
38
+ debounce: (fn) => {
39
+ const debounced = (...args) => {
40
+ fn(...args);
41
+ };
42
+ debounced.cancel = vi.fn();
43
+ return debounced;
44
+ }
45
+ }));
46
+ describe('TableFilters', () => {
47
+ const mockOnFilterChange = vi.fn();
48
+ const defaultProps = {
49
+ filters: [
50
+ {
51
+ key: 'name',
52
+ placeholder: 'Search by name',
53
+ type: FILTER_TYPES.INPUT
54
+ },
55
+ {
56
+ key: 'email',
57
+ placeholder: 'Search by email',
58
+ type: FILTER_TYPES.INPUT
59
+ }
60
+ ],
61
+ filterValues: {},
62
+ onFilterChange: mockOnFilterChange
63
+ };
64
+ beforeEach(() => {
65
+ vi.clearAllMocks();
66
+ });
67
+ const renderComponent = (props = {}) => {
68
+ return render(React.createElement(TableFilters, Object.assign({}, defaultProps, props)));
69
+ };
70
+ describe('Rendering', () => {
71
+ it('should render nothing when filters is null', () => {
72
+ const { container } = renderComponent({ filters: null });
73
+ expect(container.firstChild).toBeNull();
74
+ });
75
+ it('should render nothing when filters is undefined', () => {
76
+ const { container } = renderComponent({ filters: undefined });
77
+ expect(container.firstChild).toBeNull();
78
+ });
79
+ it('should render nothing when filters is empty array', () => {
80
+ const { container } = renderComponent({ filters: [] });
81
+ expect(container.firstChild).toBeNull();
82
+ });
83
+ it('should render Flex container when filters exist', () => {
84
+ renderComponent();
85
+ const flexContainer = screen.getByTestId('flex-container');
86
+ expect(flexContainer).toBeInTheDocument();
87
+ });
88
+ it('should render correct number of filters', () => {
89
+ renderComponent();
90
+ expect(screen.getByTestId('input-name')).toBeInTheDocument();
91
+ expect(screen.getByTestId('input-email')).toBeInTheDocument();
92
+ });
93
+ it('should apply correct Flex props', () => {
94
+ renderComponent();
95
+ const flexContainer = screen.getByTestId('flex-container');
96
+ expect(flexContainer).toHaveAttribute('data-flex', '1');
97
+ expect(flexContainer).toHaveAttribute('data-gap', '12');
98
+ expect(flexContainer).toHaveAttribute('data-wrap', 'true');
99
+ });
100
+ });
101
+ describe('Input Filters', () => {
102
+ it('should render input with correct placeholder', () => {
103
+ renderComponent();
104
+ expect(screen.getByPlaceholderText('Search by name')).toBeInTheDocument();
105
+ expect(screen.getByPlaceholderText('Search by email')).toBeInTheDocument();
106
+ });
107
+ it('should render input with correct name attribute', () => {
108
+ renderComponent();
109
+ const nameInput = screen.getByTestId('input-name');
110
+ expect(nameInput).toHaveAttribute('name', 'name');
111
+ });
112
+ it('should render input with correct className', () => {
113
+ renderComponent();
114
+ const nameInput = screen.getByTestId('input-name');
115
+ expect(nameInput).toHaveClass('h-9', 'w-44');
116
+ });
117
+ it('should render search icon for each input', () => {
118
+ renderComponent();
119
+ const searchIcons = screen.getAllByTestId('icon-search');
120
+ expect(searchIcons).toHaveLength(2);
121
+ });
122
+ it('should render search icon with correct props', () => {
123
+ renderComponent();
124
+ const searchIcon = screen.getAllByTestId('icon-search')[0];
125
+ expect(searchIcon).toHaveClass('absolute', 'cursor-pointer', 'right-2', 'top-2');
126
+ expect(searchIcon).toHaveAttribute('data-color', 'var(--color-gray-500)');
127
+ expect(searchIcon).toHaveAttribute('data-size', '16');
128
+ });
129
+ it('should render filter container with relative positioning', () => {
130
+ renderComponent();
131
+ const containers = screen.getAllByTestId('flex-filter');
132
+ expect(containers.length).toBeGreaterThan(0);
133
+ expect(containers[0]).toHaveClass('relative');
134
+ });
135
+ });
136
+ describe('Filter Values', () => {
137
+ it('should display initial filter values', () => {
138
+ const filterValues = {
139
+ name: 'John',
140
+ email: 'john@example.com'
141
+ };
142
+ renderComponent({ filterValues });
143
+ expect(screen.getByTestId('input-name')).toHaveValue('John');
144
+ expect(screen.getByTestId('input-email')).toHaveValue('john@example.com');
145
+ });
146
+ it('should display empty string when filter value is not set', () => {
147
+ renderComponent({ filterValues: {} });
148
+ expect(screen.getByTestId('input-name')).toHaveValue('');
149
+ expect(screen.getByTestId('input-email')).toHaveValue('');
150
+ });
151
+ it('should update when filterValues prop changes', () => {
152
+ const { rerender } = renderComponent({ filterValues: { name: 'John' } });
153
+ expect(screen.getByTestId('input-name')).toHaveValue('John');
154
+ rerender(React.createElement(TableFilters, Object.assign({}, defaultProps, { filterValues: { name: 'Jane' } })));
155
+ expect(screen.getByTestId('input-name')).toHaveValue('Jane');
156
+ });
157
+ });
158
+ describe('Input Change Handling', () => {
159
+ it('should update local state on input change', () => {
160
+ renderComponent();
161
+ const nameInput = screen.getByTestId('input-name');
162
+ fireEvent.change(nameInput, { target: { value: 'Test' } });
163
+ expect(nameInput).toHaveValue('Test');
164
+ });
165
+ it('should call onFilterChange immediately (debounced)', () => {
166
+ renderComponent();
167
+ const nameInput = screen.getByTestId('input-name');
168
+ fireEvent.change(nameInput, { target: { value: 'Test' } });
169
+ expect(mockOnFilterChange).toHaveBeenCalledWith('name', 'Test');
170
+ });
171
+ it('should handle multiple rapid changes', () => {
172
+ renderComponent();
173
+ const nameInput = screen.getByTestId('input-name');
174
+ fireEvent.change(nameInput, { target: { value: 'T' } });
175
+ fireEvent.change(nameInput, { target: { value: 'Te' } });
176
+ fireEvent.change(nameInput, { target: { value: 'Test' } });
177
+ expect(mockOnFilterChange).toHaveBeenCalledTimes(3);
178
+ expect(mockOnFilterChange).toHaveBeenLastCalledWith('name', 'Test');
179
+ });
180
+ it('should handle changes for different filters independently', () => {
181
+ renderComponent();
182
+ const nameInput = screen.getByTestId('input-name');
183
+ const emailInput = screen.getByTestId('input-email');
184
+ fireEvent.change(nameInput, { target: { value: 'John' } });
185
+ fireEvent.change(emailInput, { target: { value: 'john@example.com' } });
186
+ expect(mockOnFilterChange).toHaveBeenCalledWith('name', 'John');
187
+ expect(mockOnFilterChange).toHaveBeenCalledWith('email', 'john@example.com');
188
+ });
189
+ it('should handle empty string input', () => {
190
+ renderComponent({ filterValues: { name: 'Test' } });
191
+ const nameInput = screen.getByTestId('input-name');
192
+ fireEvent.change(nameInput, { target: { value: '' } });
193
+ expect(mockOnFilterChange).toHaveBeenCalledWith('name', '');
194
+ });
195
+ it('should handle special characters in input', () => {
196
+ renderComponent();
197
+ const nameInput = screen.getByTestId('input-name');
198
+ fireEvent.change(nameInput, { target: { value: '@#$%^&*()' } });
199
+ expect(mockOnFilterChange).toHaveBeenCalledWith('name', '@#$%^&*()');
200
+ });
201
+ });
202
+ describe('Debounce Cleanup', () => {
203
+ it('should not throw error on unmount', () => {
204
+ const { unmount } = renderComponent();
205
+ const nameInput = screen.getByTestId('input-name');
206
+ fireEvent.change(nameInput, { target: { value: 'Test' } });
207
+ expect(() => unmount()).not.toThrow();
208
+ });
209
+ it('should recreate debounced function when onFilterChange changes', () => {
210
+ const firstOnFilterChange = vi.fn();
211
+ const secondOnFilterChange = vi.fn();
212
+ const { rerender } = render(React.createElement(TableFilters, Object.assign({}, defaultProps, { onFilterChange: firstOnFilterChange })));
213
+ const nameInput = screen.getByTestId('input-name');
214
+ fireEvent.change(nameInput, { target: { value: 'Test1' } });
215
+ expect(firstOnFilterChange).toHaveBeenCalledWith('name', 'Test1');
216
+ rerender(React.createElement(TableFilters, Object.assign({}, defaultProps, { onFilterChange: secondOnFilterChange })));
217
+ fireEvent.change(nameInput, { target: { value: 'Test2' } });
218
+ expect(secondOnFilterChange).toHaveBeenCalledWith('name', 'Test2');
219
+ });
220
+ });
221
+ describe('Multiple Filters', () => {
222
+ it('should render single filter correctly', () => {
223
+ const filters = [
224
+ {
225
+ key: 'search',
226
+ placeholder: 'Search',
227
+ type: FILTER_TYPES.INPUT
228
+ }
229
+ ];
230
+ renderComponent({ filters });
231
+ expect(screen.getByTestId('input-search')).toBeInTheDocument();
232
+ expect(screen.getAllByTestId('icon-search')).toHaveLength(1);
233
+ });
234
+ it('should render multiple filters correctly', () => {
235
+ const filters = [
236
+ { key: 'name', placeholder: 'Name', type: FILTER_TYPES.INPUT },
237
+ { key: 'email', placeholder: 'Email', type: FILTER_TYPES.INPUT },
238
+ { key: 'phone', placeholder: 'Phone', type: FILTER_TYPES.INPUT }
239
+ ];
240
+ renderComponent({ filters });
241
+ expect(screen.getByTestId('input-name')).toBeInTheDocument();
242
+ expect(screen.getByTestId('input-email')).toBeInTheDocument();
243
+ expect(screen.getByTestId('input-phone')).toBeInTheDocument();
244
+ expect(screen.getAllByTestId('icon-search')).toHaveLength(3);
245
+ });
246
+ it('should handle filter order correctly', () => {
247
+ const filters = [
248
+ { key: 'first', placeholder: 'First', type: FILTER_TYPES.INPUT },
249
+ { key: 'second', placeholder: 'Second', type: FILTER_TYPES.INPUT }
250
+ ];
251
+ renderComponent({ filters });
252
+ const inputs = screen.getAllByRole('textbox');
253
+ expect(inputs[0]).toHaveAttribute('name', 'first');
254
+ expect(inputs[1]).toHaveAttribute('name', 'second');
255
+ });
256
+ });
257
+ describe('Filter Types', () => {
258
+ it('should render INPUT type filter', () => {
259
+ const filters = [
260
+ {
261
+ key: 'test',
262
+ placeholder: 'Test',
263
+ type: FILTER_TYPES.INPUT
264
+ }
265
+ ];
266
+ renderComponent({ filters });
267
+ expect(screen.getByTestId('input-test')).toBeInTheDocument();
268
+ });
269
+ it('should handle unknown filter type gracefully', () => {
270
+ const filters = [
271
+ {
272
+ key: 'test',
273
+ placeholder: 'Test',
274
+ type: 'unknown'
275
+ }
276
+ ];
277
+ renderComponent({ filters });
278
+ // Should still render the container but not the filter
279
+ expect(screen.getByTestId('flex-container')).toBeInTheDocument();
280
+ expect(screen.queryByTestId('input-test')).not.toBeInTheDocument();
281
+ });
282
+ it('should handle missing type property', () => {
283
+ const filters = [
284
+ {
285
+ key: 'test',
286
+ placeholder: 'Test'
287
+ }
288
+ ];
289
+ renderComponent({ filters });
290
+ // Should handle gracefully
291
+ expect(screen.getByTestId('flex-container')).toBeInTheDocument();
292
+ });
293
+ });
294
+ describe('Edge Cases', () => {
295
+ it('should handle filter with empty key', () => {
296
+ const filters = [
297
+ {
298
+ key: '',
299
+ placeholder: 'Empty key',
300
+ type: FILTER_TYPES.INPUT
301
+ }
302
+ ];
303
+ renderComponent({ filters });
304
+ expect(screen.getByPlaceholderText('Empty key')).toBeInTheDocument();
305
+ });
306
+ it('should handle filter with empty placeholder', () => {
307
+ const filters = [
308
+ {
309
+ key: 'test',
310
+ placeholder: '',
311
+ type: FILTER_TYPES.INPUT
312
+ }
313
+ ];
314
+ renderComponent({ filters });
315
+ expect(screen.getByTestId('input-test')).toBeInTheDocument();
316
+ });
317
+ it('should handle very long input values', () => {
318
+ renderComponent();
319
+ const nameInput = screen.getByTestId('input-name');
320
+ const longValue = 'a'.repeat(1000);
321
+ fireEvent.change(nameInput, { target: { value: longValue } });
322
+ expect(mockOnFilterChange).toHaveBeenCalledWith('name', longValue);
323
+ });
324
+ it('should handle unicode characters', () => {
325
+ renderComponent();
326
+ const nameInput = screen.getByTestId('input-name');
327
+ const unicodeValue = '你好世界 🌍 مرحبا';
328
+ fireEvent.change(nameInput, { target: { value: unicodeValue } });
329
+ expect(mockOnFilterChange).toHaveBeenCalledWith('name', unicodeValue);
330
+ });
331
+ it('should handle rapid mount/unmount', () => {
332
+ const { unmount } = renderComponent();
333
+ unmount();
334
+ expect(() => renderComponent()).not.toThrow();
335
+ });
336
+ });
337
+ describe('Filter Key Generation', () => {
338
+ it('should generate unique keys for each filter', () => {
339
+ renderComponent();
340
+ const filterContainers = screen.getAllByTestId('flex-filter');
341
+ expect(filterContainers.length).toBe(2);
342
+ });
343
+ it('should handle duplicate filter keys', () => {
344
+ const filters = [
345
+ { key: 'test', placeholder: 'First', type: FILTER_TYPES.INPUT },
346
+ { key: 'test', placeholder: 'Second', type: FILTER_TYPES.INPUT }
347
+ ];
348
+ renderComponent({ filters });
349
+ const inputs = screen.getAllByTestId('input-test');
350
+ expect(inputs).toHaveLength(2);
351
+ });
352
+ });
353
+ describe('Integration Tests', () => {
354
+ it('should handle complete user flow', () => {
355
+ const onFilterChange = vi.fn();
356
+ renderComponent({ onFilterChange });
357
+ const nameInput = screen.getByTestId('input-name');
358
+ const emailInput = screen.getByTestId('input-email');
359
+ // Type in name field
360
+ fireEvent.change(nameInput, { target: { value: 'John' } });
361
+ expect(nameInput).toHaveValue('John');
362
+ // Type in email field
363
+ fireEvent.change(emailInput, { target: { value: 'john@test.com' } });
364
+ expect(emailInput).toHaveValue('john@test.com');
365
+ expect(onFilterChange).toHaveBeenCalledWith('name', 'John');
366
+ expect(onFilterChange).toHaveBeenCalledWith('email', 'john@test.com');
367
+ });
368
+ it('should maintain state through prop updates', () => {
369
+ const { rerender } = renderComponent({
370
+ filterValues: { name: 'Initial' }
371
+ });
372
+ expect(screen.getByTestId('input-name')).toHaveValue('Initial');
373
+ rerender(React.createElement(TableFilters, Object.assign({}, defaultProps, { filterValues: { name: 'Updated' } })));
374
+ expect(screen.getByTestId('input-name')).toHaveValue('Updated');
375
+ });
376
+ it('should handle multiple filters with different values', () => {
377
+ const onFilterChange = vi.fn();
378
+ const filters = [
379
+ { key: 'name', placeholder: 'Name', type: FILTER_TYPES.INPUT },
380
+ { key: 'email', placeholder: 'Email', type: FILTER_TYPES.INPUT },
381
+ { key: 'phone', placeholder: 'Phone', type: FILTER_TYPES.INPUT }
382
+ ];
383
+ renderComponent({ filters, onFilterChange });
384
+ fireEvent.change(screen.getByTestId('input-name'), {
385
+ target: { value: 'John' }
386
+ });
387
+ fireEvent.change(screen.getByTestId('input-email'), {
388
+ target: { value: 'john@test.com' }
389
+ });
390
+ fireEvent.change(screen.getByTestId('input-phone'), {
391
+ target: { value: '1234567890' }
392
+ });
393
+ expect(onFilterChange).toHaveBeenCalledWith('name', 'John');
394
+ expect(onFilterChange).toHaveBeenCalledWith('email', 'john@test.com');
395
+ expect(onFilterChange).toHaveBeenCalledWith('phone', '1234567890');
396
+ });
397
+ });
398
+ });