@moontra/moonui 5.0.0 → 5.0.1

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 (33) hide show
  1. package/dist/index.d.mts +2 -2
  2. package/dist/index.d.ts +2 -2
  3. package/dist/index.global.js +9 -9
  4. package/dist/index.global.js.map +1 -1
  5. package/dist/index.js +17 -11
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +17 -11
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/lib/theme.global.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/__tests__/use-intersection-observer.test.tsx +18 -4
  12. package/src/__tests__/use-local-storage.test.tsx +34 -20
  13. package/src/components/ui/__tests__/avatar.test.tsx +5 -7
  14. package/src/components/ui/__tests__/badge.test.tsx +19 -12
  15. package/src/components/ui/__tests__/breadcrumb.test.tsx +4 -7
  16. package/src/components/ui/__tests__/button.test.tsx +6 -3
  17. package/src/components/ui/__tests__/card.test.tsx +4 -1
  18. package/src/components/ui/__tests__/checkbox.test.tsx +4 -1
  19. package/src/components/ui/__tests__/command.test.tsx +268 -124
  20. package/src/components/ui/__tests__/data-table-basic.test.tsx +271 -0
  21. package/src/components/ui/__tests__/date-picker.test.tsx +184 -197
  22. package/src/components/ui/__tests__/progress.test.tsx +0 -1
  23. package/src/components/ui/__tests__/table.test.tsx +8 -2
  24. package/src/components/ui/__tests__/tabs.test.tsx +5 -3
  25. package/src/components/ui/__tests__/toast.test.tsx +461 -159
  26. package/src/components/ui/__tests__/tooltip.test.tsx +387 -264
  27. package/src/components/ui/command.tsx +11 -7
  28. package/src/components/ui/date-picker.tsx +12 -6
  29. package/src/components/ui/toast.tsx +3 -0
  30. package/src/use-intersection-observer.tsx +9 -0
  31. package/src/use-local-storage.tsx +35 -1
  32. package/src/components/ui/__tests__/data-table.test.tsx +0 -256
  33. package/src/components/ui/data-table.stories.tsx +0 -511
@@ -0,0 +1,271 @@
1
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
2
+ import { DataTableBasic } from '../data-table-basic';
3
+ import { ColumnDef } from '@tanstack/react-table';
4
+ import '@testing-library/jest-dom';
5
+
6
+ /**
7
+ * NOT (#283): Bu dosya eskiden `../data-table`'ı import ediyordu — free pakette
8
+ * ÖYLE BİR MODÜL YOK, bu yüzden suite hiç yüklenemiyordu (0 test koşuyordu).
9
+ * Free paketin dışa açtığı tablo `DataTableBasic` (bkz. ui/index.ts).
10
+ *
11
+ * Testlerin bir kısmı Pro `DataTable`'a ait özellikleri ölçüyordu ve free
12
+ * yüzeyde karşılıkları YOK — `filterable`, `exportable`, `loading` prop'ları ve
13
+ * `data-table-container` test-id'si `@moontra/moonui-pro`'daki
14
+ * `components/data-table/index.tsx`'te bulunuyor. O testler bu suite'ten
15
+ * çıkarıldı ve şu an hiçbir yerde kapsanmıyorlar: pro paketinin test altyapısı
16
+ * çalışır durumda (29 suite / 415 test) ama `components/data-table/` altında tek
17
+ * bir test dosyası yok — ayrı bir iş olarak ele alınmalı.
18
+ *
19
+ * Geri kalan her test korundu ve `DataTableBasic`'in GERÇEK yüzeyine hizalandı:
20
+ * enableSorting / enablePagination / enableSearch / pageSize /
21
+ * searchPlaceholder ("Search...") / emptyMessage ("No results found.") / className
22
+ */
23
+
24
+ type TestData = {
25
+ id: string;
26
+ name: string;
27
+ email: string;
28
+ age: number;
29
+ status: 'active' | 'inactive';
30
+ };
31
+
32
+ const mockData: TestData[] = [
33
+ { id: '1', name: 'John Doe', email: 'john@example.com', age: 30, status: 'active' },
34
+ { id: '2', name: 'Jane Smith', email: 'jane@example.com', age: 25, status: 'inactive' },
35
+ { id: '3', name: 'Bob Johnson', email: 'bob@example.com', age: 35, status: 'active' },
36
+ ];
37
+
38
+ const mockColumns: ColumnDef<TestData>[] = [
39
+ { accessorKey: 'name', header: 'Name' },
40
+ { accessorKey: 'email', header: 'Email' },
41
+ { accessorKey: 'age', header: 'Age' },
42
+ { accessorKey: 'status', header: 'Status' },
43
+ ];
44
+
45
+ describe('DataTableBasic', () => {
46
+ it('renders correctly with basic data', () => {
47
+ render(<DataTableBasic columns={mockColumns} data={mockData} />);
48
+
49
+ // Başlıklar
50
+ expect(screen.getByText('Name')).toBeInTheDocument();
51
+ expect(screen.getByText('Email')).toBeInTheDocument();
52
+ expect(screen.getByText('Age')).toBeInTheDocument();
53
+ expect(screen.getByText('Status')).toBeInTheDocument();
54
+
55
+ // Satır verisi
56
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
57
+ expect(screen.getByText('john@example.com')).toBeInTheDocument();
58
+ expect(screen.getByText('30')).toBeInTheDocument();
59
+ // Fixture'da iki kayıt 'active' — tekil sorgu belirsiz kalıyordu
60
+ expect(screen.getAllByText('active')).toHaveLength(2);
61
+ expect(screen.getByText('inactive')).toBeInTheDocument();
62
+ });
63
+
64
+ it('renders empty state when no data', () => {
65
+ render(<DataTableBasic columns={mockColumns} data={[]} />);
66
+
67
+ expect(screen.getByText('No results found.')).toBeInTheDocument();
68
+ });
69
+
70
+ it('honours a custom empty message', () => {
71
+ render(
72
+ <DataTableBasic columns={mockColumns} data={[]} emptyMessage="Nothing here yet" />
73
+ );
74
+
75
+ expect(screen.getByText('Nothing here yet')).toBeInTheDocument();
76
+ });
77
+
78
+ it('shows search input when enableSearch is true', () => {
79
+ render(<DataTableBasic columns={mockColumns} data={mockData} enableSearch />);
80
+
81
+ expect(screen.getByPlaceholderText('Search...')).toBeInTheDocument();
82
+ });
83
+
84
+ it('hides search input when enableSearch is false', () => {
85
+ render(
86
+ <DataTableBasic columns={mockColumns} data={mockData} enableSearch={false} />
87
+ );
88
+
89
+ expect(screen.queryByPlaceholderText('Search...')).not.toBeInTheDocument();
90
+ });
91
+
92
+ it('filters data based on search input', async () => {
93
+ render(<DataTableBasic columns={mockColumns} data={mockData} enableSearch />);
94
+
95
+ fireEvent.change(screen.getByPlaceholderText('Search...'), {
96
+ target: { value: 'Jane' },
97
+ });
98
+
99
+ await waitFor(() => {
100
+ expect(screen.getByText('Jane Smith')).toBeInTheDocument();
101
+ expect(screen.queryByText('John Doe')).not.toBeInTheDocument();
102
+ expect(screen.queryByText('Bob Johnson')).not.toBeInTheDocument();
103
+ });
104
+ });
105
+
106
+ it('handles pagination correctly', () => {
107
+ const largeData = Array.from({ length: 25 }, (_, i) => ({
108
+ id: `${i + 1}`,
109
+ name: `User ${i + 1}`,
110
+ email: `user${i + 1}@example.com`,
111
+ age: 20 + i,
112
+ status: i % 2 === 0 ? ('active' as const) : ('inactive' as const),
113
+ }));
114
+
115
+ render(<DataTableBasic columns={mockColumns} data={largeData} pageSize={10} />);
116
+
117
+ expect(screen.getByText('Previous')).toBeInTheDocument();
118
+ expect(screen.getByText('Next')).toBeInTheDocument();
119
+ // Metin birden çok düğüme bölünüyor: `Page {n} of{" "}{m}`
120
+ expect(
121
+ screen.getByText((_, el) => el?.textContent?.replace(/\s+/g, ' ').trim() === 'Page 1 of 3')
122
+ ).toBeInTheDocument();
123
+ });
124
+
125
+ it('advances to the next page', async () => {
126
+ const largeData = Array.from({ length: 25 }, (_, i) => ({
127
+ id: `${i + 1}`,
128
+ name: `User ${i + 1}`,
129
+ email: `user${i + 1}@example.com`,
130
+ age: 20 + i,
131
+ status: 'active' as const,
132
+ }));
133
+
134
+ render(<DataTableBasic columns={mockColumns} data={largeData} pageSize={10} />);
135
+
136
+ expect(screen.getByText('User 1')).toBeInTheDocument();
137
+
138
+ fireEvent.click(screen.getByText('Next'));
139
+
140
+ await waitFor(() => {
141
+ expect(screen.getByText('User 11')).toBeInTheDocument();
142
+ expect(screen.queryByText('User 1')).not.toBeInTheDocument();
143
+ });
144
+ });
145
+
146
+ it('handles sorting correctly', async () => {
147
+ const sortableColumns: ColumnDef<TestData>[] = [
148
+ {
149
+ accessorKey: 'name',
150
+ header: ({ column }) => (
151
+ <button onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}>
152
+ Name
153
+ </button>
154
+ ),
155
+ },
156
+ {
157
+ accessorKey: 'age',
158
+ header: ({ column }) => (
159
+ <button onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}>
160
+ Age
161
+ </button>
162
+ ),
163
+ },
164
+ ];
165
+
166
+ render(<DataTableBasic columns={sortableColumns} data={mockData} />);
167
+
168
+ fireEvent.click(screen.getByText('Name'));
169
+
170
+ await waitFor(() => {
171
+ const rows = screen.getAllByRole('row');
172
+ // İlk satır başlık; ikinci satır alfabetik olarak ilk kayıt olmalı
173
+ expect(rows[1]).toHaveTextContent('Bob Johnson');
174
+ });
175
+ });
176
+
177
+ it('handles row selection', () => {
178
+ const selectableColumns: ColumnDef<TestData>[] = [
179
+ {
180
+ id: 'select',
181
+ header: ({ table }) => (
182
+ <input
183
+ type="checkbox"
184
+ checked={table.getIsAllPageRowsSelected()}
185
+ onChange={(e) => table.toggleAllPageRowsSelected(e.target.checked)}
186
+ />
187
+ ),
188
+ cell: ({ row }) => (
189
+ <input
190
+ type="checkbox"
191
+ checked={row.getIsSelected()}
192
+ onChange={(e) => row.toggleSelected(e.target.checked)}
193
+ />
194
+ ),
195
+ },
196
+ ...mockColumns,
197
+ ];
198
+
199
+ render(<DataTableBasic columns={selectableColumns} data={mockData} />);
200
+
201
+ const checkboxes = screen.getAllByRole('checkbox');
202
+ expect(checkboxes).toHaveLength(4); // 1 başlık + 3 satır
203
+
204
+ fireEvent.click(checkboxes[1]);
205
+ expect(checkboxes[1]).toBeChecked();
206
+ });
207
+
208
+ it('renders every column by default', () => {
209
+ render(<DataTableBasic columns={mockColumns} data={mockData} />);
210
+
211
+ expect(screen.getAllByRole('columnheader')).toHaveLength(mockColumns.length);
212
+ });
213
+
214
+ it('handles custom cell rendering', () => {
215
+ const customColumns: ColumnDef<TestData>[] = [
216
+ {
217
+ accessorKey: 'name',
218
+ header: 'Name',
219
+ cell: ({ row }) => <div className="font-bold">{row.getValue('name')}</div>,
220
+ },
221
+ {
222
+ accessorKey: 'status',
223
+ header: 'Status',
224
+ cell: ({ row }) => {
225
+ const status = row.getValue('status') as string;
226
+ return (
227
+ <span className={status === 'active' ? 'text-green-600' : 'text-red-600'}>
228
+ {status}
229
+ </span>
230
+ );
231
+ },
232
+ },
233
+ ];
234
+
235
+ render(<DataTableBasic columns={customColumns} data={mockData} />);
236
+
237
+ expect(screen.getByText('John Doe')).toHaveClass('font-bold');
238
+ expect(screen.getAllByText('active')[0]).toHaveClass('text-green-600');
239
+ });
240
+
241
+ it('handles empty columns gracefully', () => {
242
+ render(<DataTableBasic columns={[]} data={mockData} />);
243
+
244
+ // Boş mesaj VERİ boşken çıkar, kolon boşken değil: veri dolu olduğu için
245
+ // tablo satırları kurulur, yalnızca hücre/başlık üretilmez. Buradaki
246
+ // gereksinim "patlamadan render etsin".
247
+ expect(screen.getByRole('table')).toBeInTheDocument();
248
+ expect(screen.queryAllByRole('columnheader')).toHaveLength(0);
249
+ // Başlık satırı + veri satırları
250
+ expect(screen.getAllByRole('row')).toHaveLength(mockData.length + 1);
251
+ });
252
+
253
+ it('renders a semantic, keyboard-reachable table', () => {
254
+ render(<DataTableBasic columns={mockColumns} data={mockData} enableSearch />);
255
+
256
+ expect(screen.getByRole('table')).toBeInTheDocument();
257
+ expect(screen.getAllByRole('columnheader')).toHaveLength(mockColumns.length);
258
+
259
+ const search = screen.getByPlaceholderText('Search...');
260
+ search.focus();
261
+ expect(search).toHaveFocus();
262
+ });
263
+
264
+ it('applies custom className', () => {
265
+ const { container } = render(
266
+ <DataTableBasic columns={mockColumns} data={mockData} className="custom-class" />
267
+ );
268
+
269
+ expect(container.querySelector('.custom-class')).toBeInTheDocument();
270
+ });
271
+ });