@object-ui/plugin-kanban 3.1.5 → 3.3.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.
- package/CHANGELOG.md +28 -0
- package/README.md +24 -0
- package/dist/{KanbanEnhanced-CvxO2soF.js → KanbanEnhanced-Do9ZB1Mh.js} +36 -33
- package/dist/{KanbanImpl-ii52_k8g.js → KanbanImpl-BdocXM5T.js} +2 -2
- package/dist/{chevron-down-DpXJN6OX.js → chevron-down-C0JUlGjk.js} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +35 -26
- package/dist/index.umd.cjs +4 -4
- package/dist/packages/plugin-kanban/src/CardTemplates.d.ts.map +1 -0
- package/dist/packages/plugin-kanban/src/InlineQuickAdd.d.ts.map +1 -0
- package/dist/packages/plugin-kanban/src/KanbanEnhanced.d.ts.map +1 -0
- package/dist/packages/plugin-kanban/src/KanbanImpl.d.ts.map +1 -0
- package/dist/packages/plugin-kanban/src/ObjectKanban.EdgeCases.stories.d.ts.map +1 -0
- package/dist/packages/plugin-kanban/src/ObjectKanban.d.ts.map +1 -0
- package/dist/packages/plugin-kanban/src/ObjectKanban.stories.d.ts.map +1 -0
- package/dist/packages/plugin-kanban/src/index.d.ts.map +1 -0
- package/dist/packages/plugin-kanban/src/types.d.ts.map +1 -0
- package/dist/packages/plugin-kanban/src/useColumnWidths.d.ts.map +1 -0
- package/dist/packages/plugin-kanban/src/useCrossSwimlaneMove.d.ts.map +1 -0
- package/dist/packages/plugin-kanban/src/useQuickAddReorder.d.ts.map +1 -0
- package/dist/{plus-CAtTu4zt.js → plus-CHsXVJSY.js} +39 -36
- package/dist/{sortable.esm-DzUCoMzQ.js → sortable.esm-LJG1TjKd.js} +4 -4
- package/package.json +35 -12
- package/.turbo/turbo-build.log +0 -32
- package/dist/src/CardTemplates.d.ts.map +0 -1
- package/dist/src/InlineQuickAdd.d.ts.map +0 -1
- package/dist/src/KanbanEnhanced.d.ts.map +0 -1
- package/dist/src/KanbanImpl.d.ts.map +0 -1
- package/dist/src/ObjectKanban.EdgeCases.stories.d.ts.map +0 -1
- package/dist/src/ObjectKanban.d.ts.map +0 -1
- package/dist/src/ObjectKanban.stories.d.ts.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/useColumnWidths.d.ts.map +0 -1
- package/dist/src/useCrossSwimlaneMove.d.ts.map +0 -1
- package/dist/src/useQuickAddReorder.d.ts.map +0 -1
- package/src/CardTemplates.tsx +0 -123
- package/src/InlineQuickAdd.tsx +0 -189
- package/src/KanbanEnhanced.tsx +0 -525
- package/src/KanbanImpl.tsx +0 -597
- package/src/ObjectKanban.EdgeCases.stories.tsx +0 -168
- package/src/ObjectKanban.msw.test.tsx +0 -91
- package/src/ObjectKanban.stories.tsx +0 -152
- package/src/ObjectKanban.tsx +0 -262
- package/src/__tests__/KanbanEnhanced.test.tsx +0 -260
- package/src/__tests__/KanbanGrouping.test.tsx +0 -164
- package/src/__tests__/KanbanSwimlanes.test.tsx +0 -194
- package/src/__tests__/ObjectKanbanTitle.test.tsx +0 -93
- package/src/__tests__/SwimlanePersistence.test.tsx +0 -159
- package/src/__tests__/accessibility.test.tsx +0 -296
- package/src/__tests__/dnd-undo-integration.test.tsx +0 -525
- package/src/__tests__/performance-benchmark.test.tsx +0 -306
- package/src/__tests__/phase13-features.test.tsx +0 -387
- package/src/__tests__/view-states.test.tsx +0 -403
- package/src/index.test.ts +0 -112
- package/src/index.tsx +0 -327
- package/src/registration.test.tsx +0 -26
- package/src/types.ts +0 -185
- package/src/useColumnWidths.ts +0 -125
- package/src/useCrossSwimlaneMove.ts +0 -116
- package/src/useQuickAddReorder.ts +0 -107
- package/tsconfig.json +0 -19
- package/vite.config.ts +0 -61
- package/vitest.config.ts +0 -12
- package/vitest.setup.ts +0 -1
- /package/dist/{src → packages/plugin-kanban/src}/CardTemplates.d.ts +0 -0
- /package/dist/{src → packages/plugin-kanban/src}/InlineQuickAdd.d.ts +0 -0
- /package/dist/{src → packages/plugin-kanban/src}/KanbanEnhanced.d.ts +0 -0
- /package/dist/{src → packages/plugin-kanban/src}/KanbanImpl.d.ts +0 -0
- /package/dist/{src → packages/plugin-kanban/src}/ObjectKanban.EdgeCases.stories.d.ts +0 -0
- /package/dist/{src → packages/plugin-kanban/src}/ObjectKanban.d.ts +0 -0
- /package/dist/{src → packages/plugin-kanban/src}/ObjectKanban.stories.d.ts +0 -0
- /package/dist/{src → packages/plugin-kanban/src}/index.d.ts +0 -0
- /package/dist/{src → packages/plugin-kanban/src}/types.d.ts +0 -0
- /package/dist/{src → packages/plugin-kanban/src}/useColumnWidths.d.ts +0 -0
- /package/dist/{src → packages/plugin-kanban/src}/useCrossSwimlaneMove.d.ts +0 -0
- /package/dist/{src → packages/plugin-kanban/src}/useQuickAddReorder.d.ts +0 -0
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* P3.3 Plugin View Robustness - Kanban View States
|
|
11
|
-
*
|
|
12
|
-
* Tests empty, populated, and edge-case states for KanbanEnhanced component.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
16
|
-
import { render, screen } from '@testing-library/react';
|
|
17
|
-
import '@testing-library/jest-dom';
|
|
18
|
-
import React from 'react';
|
|
19
|
-
import { KanbanEnhanced, type KanbanColumn } from '../KanbanEnhanced';
|
|
20
|
-
import KanbanBoard from '../KanbanImpl';
|
|
21
|
-
|
|
22
|
-
// Mock @tanstack/react-virtual
|
|
23
|
-
vi.mock('@tanstack/react-virtual', () => ({
|
|
24
|
-
useVirtualizer: () => ({
|
|
25
|
-
getTotalSize: () => 1000,
|
|
26
|
-
getVirtualItems: () => [],
|
|
27
|
-
measureElement: vi.fn(),
|
|
28
|
-
}),
|
|
29
|
-
}));
|
|
30
|
-
|
|
31
|
-
// Mock @dnd-kit/core
|
|
32
|
-
vi.mock('@dnd-kit/core', () => ({
|
|
33
|
-
DndContext: ({ children }: any) => <div data-testid="dnd-context">{children}</div>,
|
|
34
|
-
DragOverlay: ({ children }: any) => <div data-testid="drag-overlay">{children}</div>,
|
|
35
|
-
PointerSensor: vi.fn(),
|
|
36
|
-
TouchSensor: vi.fn(),
|
|
37
|
-
useSensor: vi.fn(),
|
|
38
|
-
useSensors: () => [],
|
|
39
|
-
closestCorners: vi.fn(),
|
|
40
|
-
}));
|
|
41
|
-
|
|
42
|
-
vi.mock('@dnd-kit/sortable', () => ({
|
|
43
|
-
SortableContext: ({ children }: any) => <div data-testid="sortable-context">{children}</div>,
|
|
44
|
-
useSortable: () => ({
|
|
45
|
-
attributes: {},
|
|
46
|
-
listeners: {},
|
|
47
|
-
setNodeRef: vi.fn(),
|
|
48
|
-
transform: null,
|
|
49
|
-
transition: null,
|
|
50
|
-
isDragging: false,
|
|
51
|
-
}),
|
|
52
|
-
arrayMove: (array: any[], from: number, to: number) => {
|
|
53
|
-
const newArray = [...array];
|
|
54
|
-
newArray.splice(to, 0, newArray.splice(from, 1)[0]);
|
|
55
|
-
return newArray;
|
|
56
|
-
},
|
|
57
|
-
verticalListSortingStrategy: vi.fn(),
|
|
58
|
-
}));
|
|
59
|
-
|
|
60
|
-
vi.mock('@dnd-kit/utilities', () => ({
|
|
61
|
-
CSS: {
|
|
62
|
-
Transform: {
|
|
63
|
-
toString: () => '',
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
}));
|
|
67
|
-
|
|
68
|
-
vi.mock('@object-ui/react', () => ({
|
|
69
|
-
useHasDndProvider: () => false,
|
|
70
|
-
useDnd: vi.fn(),
|
|
71
|
-
}));
|
|
72
|
-
|
|
73
|
-
describe('P3.3 Kanban View States', () => {
|
|
74
|
-
// ---------------------------------------------------------------
|
|
75
|
-
// Empty state
|
|
76
|
-
// ---------------------------------------------------------------
|
|
77
|
-
describe('empty state', () => {
|
|
78
|
-
it('renders with empty columns array', () => {
|
|
79
|
-
const { container } = render(
|
|
80
|
-
<KanbanEnhanced columns={[]} />
|
|
81
|
-
);
|
|
82
|
-
expect(container.firstElementChild).toBeInTheDocument();
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('renders columns with no cards', () => {
|
|
86
|
-
const emptyColumns: KanbanColumn[] = [
|
|
87
|
-
{ id: 'todo', title: 'To Do', cards: [] },
|
|
88
|
-
{ id: 'done', title: 'Done', cards: [] },
|
|
89
|
-
];
|
|
90
|
-
render(<KanbanEnhanced columns={emptyColumns} />);
|
|
91
|
-
expect(screen.getByText('To Do')).toBeInTheDocument();
|
|
92
|
-
expect(screen.getByText('Done')).toBeInTheDocument();
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('shows 0 count for empty columns', () => {
|
|
96
|
-
const emptyColumns: KanbanColumn[] = [
|
|
97
|
-
{ id: 'todo', title: 'To Do', cards: [] },
|
|
98
|
-
];
|
|
99
|
-
render(<KanbanEnhanced columns={emptyColumns} />);
|
|
100
|
-
expect(screen.getByText('0')).toBeInTheDocument();
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// ---------------------------------------------------------------
|
|
105
|
-
// Populated state
|
|
106
|
-
// ---------------------------------------------------------------
|
|
107
|
-
describe('populated state', () => {
|
|
108
|
-
const populatedColumns: KanbanColumn[] = [
|
|
109
|
-
{
|
|
110
|
-
id: 'todo',
|
|
111
|
-
title: 'To Do',
|
|
112
|
-
cards: [
|
|
113
|
-
{ id: 'c1', title: 'Task 1', description: 'First task' },
|
|
114
|
-
{ id: 'c2', title: 'Task 2' },
|
|
115
|
-
],
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
id: 'done',
|
|
119
|
-
title: 'Done',
|
|
120
|
-
cards: [
|
|
121
|
-
{ id: 'c3', title: 'Task 3', description: 'Completed' },
|
|
122
|
-
],
|
|
123
|
-
},
|
|
124
|
-
];
|
|
125
|
-
|
|
126
|
-
it('renders column titles', () => {
|
|
127
|
-
render(<KanbanEnhanced columns={populatedColumns} />);
|
|
128
|
-
expect(screen.getByText('To Do')).toBeInTheDocument();
|
|
129
|
-
expect(screen.getByText('Done')).toBeInTheDocument();
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('renders card titles', () => {
|
|
133
|
-
render(<KanbanEnhanced columns={populatedColumns} />);
|
|
134
|
-
expect(screen.getByText('Task 1')).toBeInTheDocument();
|
|
135
|
-
expect(screen.getByText('Task 2')).toBeInTheDocument();
|
|
136
|
-
expect(screen.getByText('Task 3')).toBeInTheDocument();
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('renders card descriptions', () => {
|
|
140
|
-
render(<KanbanEnhanced columns={populatedColumns} />);
|
|
141
|
-
expect(screen.getByText('First task')).toBeInTheDocument();
|
|
142
|
-
expect(screen.getByText('Completed')).toBeInTheDocument();
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('renders card counts', () => {
|
|
146
|
-
render(<KanbanEnhanced columns={populatedColumns} />);
|
|
147
|
-
expect(screen.getByText('2')).toBeInTheDocument(); // To Do has 2
|
|
148
|
-
expect(screen.getByText('1')).toBeInTheDocument(); // Done has 1
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// ---------------------------------------------------------------
|
|
153
|
-
// Columns with limits
|
|
154
|
-
// ---------------------------------------------------------------
|
|
155
|
-
describe('columns with limits', () => {
|
|
156
|
-
it('shows limit indicator', () => {
|
|
157
|
-
const columns: KanbanColumn[] = [
|
|
158
|
-
{
|
|
159
|
-
id: 'wip',
|
|
160
|
-
title: 'In Progress',
|
|
161
|
-
limit: 3,
|
|
162
|
-
cards: [
|
|
163
|
-
{ id: 'c1', title: 'Task 1' },
|
|
164
|
-
],
|
|
165
|
-
},
|
|
166
|
-
];
|
|
167
|
-
render(<KanbanEnhanced columns={columns} />);
|
|
168
|
-
expect(screen.getByText('In Progress')).toBeInTheDocument();
|
|
169
|
-
expect(screen.getByText(/1\s*\/\s*3/)).toBeInTheDocument();
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it('shows warning at 80% capacity', () => {
|
|
173
|
-
const columns: KanbanColumn[] = [
|
|
174
|
-
{
|
|
175
|
-
id: 'wip',
|
|
176
|
-
title: 'WIP',
|
|
177
|
-
limit: 5,
|
|
178
|
-
cards: Array.from({ length: 4 }, (_, i) => ({
|
|
179
|
-
id: `c${i}`,
|
|
180
|
-
title: `Task ${i}`,
|
|
181
|
-
})),
|
|
182
|
-
},
|
|
183
|
-
];
|
|
184
|
-
const { container } = render(<KanbanEnhanced columns={columns} />);
|
|
185
|
-
// At 80% (4/5), should show warning styling
|
|
186
|
-
expect(container.querySelector('[class*="text-yellow"]')).toBeInTheDocument();
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it('shows error when over limit', () => {
|
|
190
|
-
const columns: KanbanColumn[] = [
|
|
191
|
-
{
|
|
192
|
-
id: 'wip',
|
|
193
|
-
title: 'WIP',
|
|
194
|
-
limit: 2,
|
|
195
|
-
cards: Array.from({ length: 3 }, (_, i) => ({
|
|
196
|
-
id: `c${i}`,
|
|
197
|
-
title: `Task ${i}`,
|
|
198
|
-
})),
|
|
199
|
-
},
|
|
200
|
-
];
|
|
201
|
-
const { container } = render(<KanbanEnhanced columns={columns} />);
|
|
202
|
-
// Over limit uses text-destructive class
|
|
203
|
-
expect(container.querySelector('[class*="text-destructive"]')).toBeInTheDocument();
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// ---------------------------------------------------------------
|
|
208
|
-
// Edge cases
|
|
209
|
-
// ---------------------------------------------------------------
|
|
210
|
-
describe('edge cases', () => {
|
|
211
|
-
it('handles single column', () => {
|
|
212
|
-
const columns: KanbanColumn[] = [
|
|
213
|
-
{ id: 'only', title: 'Only Column', cards: [{ id: 'c1', title: 'Alone' }] },
|
|
214
|
-
];
|
|
215
|
-
render(<KanbanEnhanced columns={columns} />);
|
|
216
|
-
expect(screen.getByText('Only Column')).toBeInTheDocument();
|
|
217
|
-
expect(screen.getByText('Alone')).toBeInTheDocument();
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
it('handles many columns', () => {
|
|
221
|
-
const columns: KanbanColumn[] = Array.from({ length: 10 }, (_, i) => ({
|
|
222
|
-
id: `col-${i}`,
|
|
223
|
-
title: `Column ${i}`,
|
|
224
|
-
cards: [],
|
|
225
|
-
}));
|
|
226
|
-
render(<KanbanEnhanced columns={columns} />);
|
|
227
|
-
expect(screen.getByText('Column 0')).toBeInTheDocument();
|
|
228
|
-
expect(screen.getByText('Column 9')).toBeInTheDocument();
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it('handles cards with badges', () => {
|
|
232
|
-
const columns: KanbanColumn[] = [
|
|
233
|
-
{
|
|
234
|
-
id: 'todo',
|
|
235
|
-
title: 'To Do',
|
|
236
|
-
cards: [
|
|
237
|
-
{
|
|
238
|
-
id: 'c1',
|
|
239
|
-
title: 'Badged Task',
|
|
240
|
-
badges: [
|
|
241
|
-
{ label: 'Urgent', variant: 'destructive' },
|
|
242
|
-
{ label: 'Feature', variant: 'default' },
|
|
243
|
-
],
|
|
244
|
-
},
|
|
245
|
-
],
|
|
246
|
-
},
|
|
247
|
-
];
|
|
248
|
-
render(<KanbanEnhanced columns={columns} />);
|
|
249
|
-
expect(screen.getByText('Urgent')).toBeInTheDocument();
|
|
250
|
-
expect(screen.getByText('Feature')).toBeInTheDocument();
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it('handles card with empty title', () => {
|
|
254
|
-
const columns: KanbanColumn[] = [
|
|
255
|
-
{ id: 'col', title: 'Col', cards: [{ id: 'c1', title: '' }] },
|
|
256
|
-
];
|
|
257
|
-
const { container } = render(<KanbanEnhanced columns={columns} />);
|
|
258
|
-
expect(container).toBeInTheDocument();
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
it('accepts className prop', () => {
|
|
262
|
-
const { container } = render(
|
|
263
|
-
<KanbanEnhanced columns={[]} className="my-kanban" />
|
|
264
|
-
);
|
|
265
|
-
expect(container.innerHTML).toContain('my-kanban');
|
|
266
|
-
});
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
// ---------------------------------------------------------------
|
|
271
|
-
// KanbanBoard (from KanbanImpl) View States
|
|
272
|
-
// ---------------------------------------------------------------
|
|
273
|
-
describe('P3.3 KanbanBoard (KanbanImpl) View States', () => {
|
|
274
|
-
describe('empty state', () => {
|
|
275
|
-
it('renders with empty columns array', () => {
|
|
276
|
-
const { container } = render(<KanbanBoard columns={[]} />);
|
|
277
|
-
expect(container.querySelector('[role="region"]')).toBeInTheDocument();
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it('renders columns with no cards', () => {
|
|
281
|
-
const columns: KanbanColumn[] = [
|
|
282
|
-
{ id: 'backlog', title: 'Backlog', cards: [] },
|
|
283
|
-
{ id: 'active', title: 'Active', cards: [] },
|
|
284
|
-
];
|
|
285
|
-
render(<KanbanBoard columns={columns} />);
|
|
286
|
-
expect(screen.getByText('Backlog')).toBeInTheDocument();
|
|
287
|
-
expect(screen.getByText('Active')).toBeInTheDocument();
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
it('shows card count of 0 for empty columns', () => {
|
|
291
|
-
const columns: KanbanColumn[] = [
|
|
292
|
-
{ id: 'empty', title: 'Empty Col', cards: [] },
|
|
293
|
-
];
|
|
294
|
-
render(<KanbanBoard columns={columns} />);
|
|
295
|
-
expect(screen.getByText('0')).toBeInTheDocument();
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
describe('single column with many cards', () => {
|
|
300
|
-
it('renders column with 50 cards without crashing', () => {
|
|
301
|
-
const manyCards = Array.from({ length: 50 }, (_, i) => ({
|
|
302
|
-
id: `card-${i}`,
|
|
303
|
-
title: `Card ${i}`,
|
|
304
|
-
}));
|
|
305
|
-
const columns: KanbanColumn[] = [
|
|
306
|
-
{ id: 'big', title: 'Big Column', cards: manyCards },
|
|
307
|
-
];
|
|
308
|
-
render(<KanbanBoard columns={columns} />);
|
|
309
|
-
expect(screen.getByText('Big Column')).toBeInTheDocument();
|
|
310
|
-
expect(screen.getByText('Card 0')).toBeInTheDocument();
|
|
311
|
-
expect(screen.getByText('Card 49')).toBeInTheDocument();
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
it('shows correct count for many cards', () => {
|
|
315
|
-
const manyCards = Array.from({ length: 25 }, (_, i) => ({
|
|
316
|
-
id: `card-${i}`,
|
|
317
|
-
title: `Task ${i}`,
|
|
318
|
-
}));
|
|
319
|
-
const columns: KanbanColumn[] = [
|
|
320
|
-
{ id: 'col', title: 'Tasks', cards: manyCards },
|
|
321
|
-
];
|
|
322
|
-
render(<KanbanBoard columns={columns} />);
|
|
323
|
-
expect(screen.getByText('25')).toBeInTheDocument();
|
|
324
|
-
});
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
describe('WIP limit exceeded', () => {
|
|
328
|
-
it('shows Full badge when cards reach limit', () => {
|
|
329
|
-
const columns: KanbanColumn[] = [
|
|
330
|
-
{
|
|
331
|
-
id: 'wip',
|
|
332
|
-
title: 'In Progress',
|
|
333
|
-
limit: 3,
|
|
334
|
-
cards: Array.from({ length: 3 }, (_, i) => ({
|
|
335
|
-
id: `c${i}`,
|
|
336
|
-
title: `WIP Task ${i}`,
|
|
337
|
-
})),
|
|
338
|
-
},
|
|
339
|
-
];
|
|
340
|
-
render(<KanbanBoard columns={columns} />);
|
|
341
|
-
expect(screen.getByText('Full')).toBeInTheDocument();
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
it('shows Full badge when cards exceed limit', () => {
|
|
345
|
-
const columns: KanbanColumn[] = [
|
|
346
|
-
{
|
|
347
|
-
id: 'wip',
|
|
348
|
-
title: 'In Progress',
|
|
349
|
-
limit: 2,
|
|
350
|
-
cards: Array.from({ length: 5 }, (_, i) => ({
|
|
351
|
-
id: `c${i}`,
|
|
352
|
-
title: `Over Task ${i}`,
|
|
353
|
-
})),
|
|
354
|
-
},
|
|
355
|
-
];
|
|
356
|
-
render(<KanbanBoard columns={columns} />);
|
|
357
|
-
expect(screen.getByText('Full')).toBeInTheDocument();
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
it('does not show Full badge when under limit', () => {
|
|
361
|
-
const columns: KanbanColumn[] = [
|
|
362
|
-
{
|
|
363
|
-
id: 'wip',
|
|
364
|
-
title: 'In Progress',
|
|
365
|
-
limit: 10,
|
|
366
|
-
cards: [{ id: 'c1', title: 'Solo Task' }],
|
|
367
|
-
},
|
|
368
|
-
];
|
|
369
|
-
render(<KanbanBoard columns={columns} />);
|
|
370
|
-
expect(screen.queryByText('Full')).not.toBeInTheDocument();
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
it('shows count with limit format', () => {
|
|
374
|
-
const columns: KanbanColumn[] = [
|
|
375
|
-
{
|
|
376
|
-
id: 'wip',
|
|
377
|
-
title: 'WIP',
|
|
378
|
-
limit: 5,
|
|
379
|
-
cards: Array.from({ length: 3 }, (_, i) => ({
|
|
380
|
-
id: `c${i}`,
|
|
381
|
-
title: `Task ${i}`,
|
|
382
|
-
})),
|
|
383
|
-
},
|
|
384
|
-
];
|
|
385
|
-
render(<KanbanBoard columns={columns} />);
|
|
386
|
-
expect(screen.getByText(/3\s*\/\s*5/)).toBeInTheDocument();
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
describe('className and structure', () => {
|
|
391
|
-
it('applies className prop', () => {
|
|
392
|
-
const { container } = render(
|
|
393
|
-
<KanbanBoard columns={[]} className="custom-board" />
|
|
394
|
-
);
|
|
395
|
-
expect(container.innerHTML).toContain('custom-board');
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
it('renders kanban board with region role', () => {
|
|
399
|
-
render(<KanbanBoard columns={[]} />);
|
|
400
|
-
expect(screen.getByRole('region', { name: 'Kanban board' })).toBeInTheDocument();
|
|
401
|
-
});
|
|
402
|
-
});
|
|
403
|
-
});
|
package/src/index.test.ts
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { describe, it, expect, beforeAll } from 'vitest';
|
|
10
|
-
import { ComponentRegistry } from '@object-ui/core';
|
|
11
|
-
|
|
12
|
-
describe('Plugin Kanban', () => {
|
|
13
|
-
// Import all renderers to register them
|
|
14
|
-
beforeAll(async () => {
|
|
15
|
-
await import('./index');
|
|
16
|
-
}, 15000); // Increase timeout to 15 seconds for async import
|
|
17
|
-
|
|
18
|
-
describe('kanban component', () => {
|
|
19
|
-
it('should be registered in ComponentRegistry', () => {
|
|
20
|
-
const kanbanRenderer = ComponentRegistry.get('kanban-ui');
|
|
21
|
-
expect(kanbanRenderer).toBeDefined();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should have proper metadata', () => {
|
|
25
|
-
const config = ComponentRegistry.getConfig('kanban-ui');
|
|
26
|
-
expect(config).toBeDefined();
|
|
27
|
-
expect(config?.label).toBe('Kanban Board');
|
|
28
|
-
expect(config?.icon).toBe('LayoutDashboard');
|
|
29
|
-
expect(config?.category).toBe('plugin');
|
|
30
|
-
expect(config?.inputs).toBeDefined();
|
|
31
|
-
expect(config?.defaultProps).toBeDefined();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should have expected inputs', () => {
|
|
35
|
-
const config = ComponentRegistry.getConfig('kanban-ui');
|
|
36
|
-
const inputNames = config?.inputs?.map((input: any) => input.name) || [];
|
|
37
|
-
|
|
38
|
-
expect(inputNames).toContain('columns');
|
|
39
|
-
expect(inputNames).toContain('onCardMove');
|
|
40
|
-
expect(inputNames).toContain('className');
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should have columns as required input', () => {
|
|
44
|
-
const config = ComponentRegistry.getConfig('kanban-ui');
|
|
45
|
-
const columnsInput = config?.inputs?.find((input: any) => input.name === 'columns');
|
|
46
|
-
|
|
47
|
-
expect(columnsInput).toBeDefined();
|
|
48
|
-
expect(columnsInput?.required).toBe(true);
|
|
49
|
-
expect(columnsInput?.type).toBe('array');
|
|
50
|
-
expect(columnsInput?.description).toBeDefined();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('should have onCardMove as code input', () => {
|
|
54
|
-
const config = ComponentRegistry.getConfig('kanban-ui');
|
|
55
|
-
const onCardMoveInput = config?.inputs?.find((input: any) => input.name === 'onCardMove');
|
|
56
|
-
|
|
57
|
-
expect(onCardMoveInput).toBeDefined();
|
|
58
|
-
expect(onCardMoveInput?.type).toBe('code');
|
|
59
|
-
expect(onCardMoveInput?.advanced).toBe(true);
|
|
60
|
-
expect(onCardMoveInput?.description).toBeDefined();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should have sensible default props', () => {
|
|
64
|
-
const config = ComponentRegistry.getConfig('kanban-ui');
|
|
65
|
-
const defaults = config?.defaultProps;
|
|
66
|
-
|
|
67
|
-
expect(defaults).toBeDefined();
|
|
68
|
-
expect(defaults?.columns).toBeDefined();
|
|
69
|
-
expect(Array.isArray(defaults?.columns)).toBe(true);
|
|
70
|
-
expect(defaults?.columns.length).toBeGreaterThan(0);
|
|
71
|
-
expect(defaults?.className).toBe('w-full');
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('should have default columns with proper structure', () => {
|
|
75
|
-
const config = ComponentRegistry.getConfig('kanban-ui');
|
|
76
|
-
const defaults = config?.defaultProps;
|
|
77
|
-
const columns = defaults?.columns || [];
|
|
78
|
-
|
|
79
|
-
// Verify at least 3 columns exist (todo, in-progress, done)
|
|
80
|
-
expect(columns.length).toBeGreaterThanOrEqual(3);
|
|
81
|
-
|
|
82
|
-
// Verify each column has required properties
|
|
83
|
-
columns.forEach((column: any) => {
|
|
84
|
-
expect(column.id).toBeDefined();
|
|
85
|
-
expect(column.title).toBeDefined();
|
|
86
|
-
expect(column.cards).toBeDefined();
|
|
87
|
-
expect(Array.isArray(column.cards)).toBe(true);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// Verify at least one column has cards
|
|
91
|
-
const hasCards = columns.some((column: any) => column.cards.length > 0);
|
|
92
|
-
expect(hasCards).toBe(true);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should have cards with proper structure', () => {
|
|
96
|
-
const config = ComponentRegistry.getConfig('kanban-ui');
|
|
97
|
-
const defaults = config?.defaultProps;
|
|
98
|
-
const columns = defaults?.columns || [];
|
|
99
|
-
|
|
100
|
-
// Find a column with cards
|
|
101
|
-
const columnWithCards = columns.find((column: any) => column.cards.length > 0);
|
|
102
|
-
expect(columnWithCards).toBeDefined();
|
|
103
|
-
|
|
104
|
-
const card = columnWithCards.cards[0];
|
|
105
|
-
expect(card.id).toBeDefined();
|
|
106
|
-
expect(card.title).toBeDefined();
|
|
107
|
-
expect(card.description).toBeDefined();
|
|
108
|
-
expect(card.badges).toBeDefined();
|
|
109
|
-
expect(Array.isArray(card.badges)).toBe(true);
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
});
|