datajunction-ui 0.0.92 → 0.0.94

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 (34) hide show
  1. package/package.json +1 -1
  2. package/src/app/components/NodeComponents.jsx +4 -0
  3. package/src/app/components/Tab.jsx +11 -16
  4. package/src/app/components/__tests__/Tab.test.jsx +4 -2
  5. package/src/app/hooks/useWorkspaceData.js +226 -0
  6. package/src/app/index.tsx +17 -1
  7. package/src/app/pages/MyWorkspacePage/ActiveBranchesSection.jsx +38 -107
  8. package/src/app/pages/MyWorkspacePage/MyNodesSection.jsx +31 -6
  9. package/src/app/pages/MyWorkspacePage/MyWorkspacePage.css +5 -0
  10. package/src/app/pages/MyWorkspacePage/NeedsAttentionSection.jsx +86 -100
  11. package/src/app/pages/MyWorkspacePage/TypeGroupGrid.jsx +7 -11
  12. package/src/app/pages/MyWorkspacePage/__tests__/ActiveBranchesSection.test.jsx +79 -11
  13. package/src/app/pages/MyWorkspacePage/__tests__/CollectionsSection.test.jsx +22 -0
  14. package/src/app/pages/MyWorkspacePage/__tests__/MaterializationsSection.test.jsx +57 -0
  15. package/src/app/pages/MyWorkspacePage/__tests__/MyNodesSection.test.jsx +60 -18
  16. package/src/app/pages/MyWorkspacePage/__tests__/MyWorkspacePage.test.jsx +156 -162
  17. package/src/app/pages/MyWorkspacePage/__tests__/NeedsAttentionSection.test.jsx +17 -18
  18. package/src/app/pages/MyWorkspacePage/__tests__/NotificationsSection.test.jsx +179 -0
  19. package/src/app/pages/MyWorkspacePage/__tests__/TypeGroupGrid.test.jsx +169 -49
  20. package/src/app/pages/MyWorkspacePage/index.jsx +41 -73
  21. package/src/app/pages/NodePage/NodeDataFlowTab.jsx +464 -0
  22. package/src/app/pages/NodePage/NodeDependenciesTab.jsx +1 -1
  23. package/src/app/pages/NodePage/NodeDimensionsTab.jsx +362 -0
  24. package/src/app/pages/NodePage/NodeLineageTab.jsx +1 -0
  25. package/src/app/pages/NodePage/NodesWithDimension.jsx +3 -3
  26. package/src/app/pages/NodePage/__tests__/NodeDataFlowTab.test.jsx +428 -0
  27. package/src/app/pages/NodePage/__tests__/NodeDependenciesTab.test.jsx +18 -1
  28. package/src/app/pages/NodePage/__tests__/NodeDimensionsTab.test.jsx +362 -0
  29. package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +28 -3
  30. package/src/app/pages/NodePage/__tests__/NodeWithDimension.test.jsx +2 -2
  31. package/src/app/pages/NodePage/index.jsx +15 -8
  32. package/src/app/services/DJService.js +73 -6
  33. package/src/app/services/__tests__/DJService.test.jsx +591 -0
  34. package/src/styles/index.css +32 -0
@@ -3,6 +3,7 @@ import { render, screen } from '@testing-library/react';
3
3
  import { MemoryRouter } from 'react-router-dom';
4
4
  import { MyWorkspacePage } from '../index';
5
5
  import * as useWorkspaceData from '../../../hooks/useWorkspaceData';
6
+ import * as UserProvider from '../../../providers/UserProvider';
6
7
 
7
8
  // Mock CSS imports
8
9
  jest.mock('../MyWorkspacePage.css', () => ({}));
@@ -33,14 +34,6 @@ jest.mock('../MyNodesSection', () => ({
33
34
  ),
34
35
  }));
35
36
 
36
- jest.mock('../CollectionsSection', () => ({
37
- CollectionsSection: ({ collections, loading }) => (
38
- <div data-testid="collections-section">
39
- {loading ? 'Loading...' : `${collections.length} collections`}
40
- </div>
41
- ),
42
- }));
43
-
44
37
  jest.mock('../MaterializationsSection', () => ({
45
38
  MaterializationsSection: ({ nodes, loading }) => (
46
39
  <div data-testid="materializations-section">
@@ -76,15 +69,6 @@ describe('<MyWorkspacePage />', () => {
76
69
  },
77
70
  ];
78
71
 
79
- const mockCollections = [
80
- {
81
- name: 'test_collection',
82
- description: 'Test Collection',
83
- nodeCount: 5,
84
- createdBy: 'test.user@example.com',
85
- },
86
- ];
87
-
88
72
  const mockNotifications = [
89
73
  {
90
74
  entity_name: 'default.test_metric',
@@ -111,23 +95,48 @@ describe('<MyWorkspacePage />', () => {
111
95
  },
112
96
  ];
113
97
 
114
- const mockNeedsAttention = {
115
- nodesMissingDescription: [],
116
- invalidNodes: [],
117
- staleDrafts: [],
118
- orphanedDimensions: [],
119
- };
98
+ const makeLoadingStates = (loading = false) => ({
99
+ myNodes: loading,
100
+ collections: loading,
101
+ notifications: loading,
102
+ materializations: loading,
103
+ needsAttention: loading,
104
+ namespace: loading,
105
+ });
106
+
107
+ const makeDashboardData = (overrides = {}) => ({
108
+ data: {
109
+ ownedNodes: [],
110
+ ownedHasMore: {},
111
+ recentlyEdited: [],
112
+ editedHasMore: {},
113
+ watchedNodes: [],
114
+ notifications: [],
115
+ materializedNodes: [],
116
+ needsAttention: {
117
+ nodesMissingDescription: [],
118
+ invalidNodes: [],
119
+ staleDrafts: [],
120
+ orphanedDimensions: [],
121
+ },
122
+ hasPersonalNamespace: true,
123
+ ...overrides,
124
+ },
125
+ loadingStates: makeLoadingStates(false),
126
+ });
120
127
 
121
128
  beforeEach(() => {
122
129
  jest.clearAllMocks();
123
130
  });
124
131
 
125
132
  it('should render loading state', () => {
126
- jest.spyOn(useWorkspaceData, 'useCurrentUser').mockReturnValue({
127
- data: null,
133
+ jest.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
134
+ currentUser: null,
128
135
  loading: true,
129
- error: null,
130
136
  });
137
+ jest
138
+ .spyOn(useWorkspaceData, 'useWorkspaceDashboardData')
139
+ .mockReturnValue(makeDashboardData());
131
140
 
132
141
  render(
133
142
  <MemoryRouter>
@@ -136,59 +145,22 @@ describe('<MyWorkspacePage />', () => {
136
145
  );
137
146
 
138
147
  expect(screen.getByText('Dashboard')).toBeInTheDocument();
139
- // Should show loading icon when user is loading
140
- expect(screen.queryByTestId('collections-section')).not.toBeInTheDocument();
148
+ // Sections are not shown while user is loading
149
+ expect(screen.queryByTestId('my-nodes-section')).not.toBeInTheDocument();
141
150
  });
142
151
 
143
152
  it('should render all sections when data is loaded', () => {
144
- // Mock all hooks with data
145
- jest.spyOn(useWorkspaceData, 'useCurrentUser').mockReturnValue({
146
- data: mockCurrentUser,
153
+ jest.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
154
+ currentUser: mockCurrentUser,
147
155
  loading: false,
148
- error: null,
149
- });
150
- jest.spyOn(useWorkspaceData, 'useWorkspaceOwnedNodes').mockReturnValue({
151
- data: mockOwnedNodes,
152
- loading: false,
153
- error: null,
154
- });
155
- jest.spyOn(useWorkspaceData, 'useWorkspaceRecentlyEdited').mockReturnValue({
156
- data: [],
157
- loading: false,
158
- error: null,
159
- });
160
- jest.spyOn(useWorkspaceData, 'useWorkspaceWatchedNodes').mockReturnValue({
161
- data: [],
162
- loading: false,
163
- error: null,
164
- });
165
- jest.spyOn(useWorkspaceData, 'useWorkspaceCollections').mockReturnValue({
166
- data: mockCollections,
167
- loading: false,
168
- error: null,
169
- });
170
- jest.spyOn(useWorkspaceData, 'useWorkspaceNotifications').mockReturnValue({
171
- data: mockNotifications,
172
- loading: false,
173
- error: null,
174
- });
175
- jest
176
- .spyOn(useWorkspaceData, 'useWorkspaceMaterializations')
177
- .mockReturnValue({
178
- data: mockMaterializations,
179
- loading: false,
180
- error: null,
181
- });
182
- jest.spyOn(useWorkspaceData, 'useWorkspaceNeedsAttention').mockReturnValue({
183
- data: mockNeedsAttention,
184
- loading: false,
185
- error: null,
186
- });
187
- jest.spyOn(useWorkspaceData, 'usePersonalNamespace').mockReturnValue({
188
- exists: true,
189
- loading: false,
190
- error: null,
191
156
  });
157
+ jest.spyOn(useWorkspaceData, 'useWorkspaceDashboardData').mockReturnValue(
158
+ makeDashboardData({
159
+ ownedNodes: mockOwnedNodes,
160
+ notifications: mockNotifications,
161
+ materializedNodes: mockMaterializations,
162
+ }),
163
+ );
192
164
 
193
165
  render(
194
166
  <MemoryRouter>
@@ -196,10 +168,6 @@ describe('<MyWorkspacePage />', () => {
196
168
  </MemoryRouter>,
197
169
  );
198
170
 
199
- // Check all sections are rendered
200
- expect(screen.getByTestId('collections-section')).toHaveTextContent(
201
- '1 collections',
202
- );
203
171
  expect(screen.getByTestId('my-nodes-section')).toHaveTextContent(
204
172
  '2 owned nodes',
205
173
  );
@@ -214,53 +182,121 @@ describe('<MyWorkspacePage />', () => {
214
182
  });
215
183
 
216
184
  it('should pass correct props to sections', () => {
217
- jest.spyOn(useWorkspaceData, 'useCurrentUser').mockReturnValue({
218
- data: mockCurrentUser,
219
- loading: false,
220
- error: null,
221
- });
222
- jest.spyOn(useWorkspaceData, 'useWorkspaceOwnedNodes').mockReturnValue({
223
- data: mockOwnedNodes,
224
- loading: false,
225
- error: null,
226
- });
227
- jest.spyOn(useWorkspaceData, 'useWorkspaceRecentlyEdited').mockReturnValue({
228
- data: [],
229
- loading: false,
230
- error: null,
231
- });
232
- jest.spyOn(useWorkspaceData, 'useWorkspaceWatchedNodes').mockReturnValue({
233
- data: [],
185
+ jest.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
186
+ currentUser: mockCurrentUser,
234
187
  loading: false,
235
- error: null,
236
188
  });
237
- jest.spyOn(useWorkspaceData, 'useWorkspaceCollections').mockReturnValue({
238
- data: mockCollections,
189
+ jest
190
+ .spyOn(useWorkspaceData, 'useWorkspaceDashboardData')
191
+ .mockReturnValue(makeDashboardData({ ownedNodes: mockOwnedNodes }));
192
+
193
+ render(
194
+ <MemoryRouter>
195
+ <MyWorkspacePage />
196
+ </MemoryRouter>,
197
+ );
198
+
199
+ expect(screen.getByTestId('my-nodes-section')).toBeInTheDocument();
200
+ expect(screen.getByTestId('notifications-section')).toBeInTheDocument();
201
+ expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
202
+ });
203
+
204
+ it('should filter out non-stale materializations from NeedsAttention', () => {
205
+ const now = Date.now();
206
+ const freshNode = {
207
+ name: 'default.fresh_cube',
208
+ type: 'CUBE',
209
+ current: {
210
+ availability: {
211
+ validThroughTs: now - 1000 * 60 * 60 * 10, // 10 hours ago (< 72h, not stale)
212
+ },
213
+ },
214
+ };
215
+
216
+ jest.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
217
+ currentUser: mockCurrentUser,
239
218
  loading: false,
240
- error: null,
241
219
  });
242
- jest.spyOn(useWorkspaceData, 'useWorkspaceNotifications').mockReturnValue({
243
- data: mockNotifications,
220
+ jest
221
+ .spyOn(useWorkspaceData, 'useWorkspaceDashboardData')
222
+ .mockReturnValue(makeDashboardData({ materializedNodes: [freshNode] }));
223
+
224
+ render(
225
+ <MemoryRouter>
226
+ <MyWorkspacePage />
227
+ </MemoryRouter>,
228
+ );
229
+
230
+ // Page renders without crash — stale filter ran without errors
231
+ expect(screen.getByTestId('materializations-section')).toHaveTextContent(
232
+ '1 materializations',
233
+ );
234
+ expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
235
+ });
236
+
237
+ it('should exclude nodes with null validThroughTs from stale list', () => {
238
+ const pendingNode = {
239
+ name: 'default.pending_cube',
240
+ type: 'CUBE',
241
+ current: {
242
+ availability: {
243
+ validThroughTs: null,
244
+ },
245
+ },
246
+ };
247
+
248
+ jest.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
249
+ currentUser: mockCurrentUser,
244
250
  loading: false,
245
- error: null,
246
251
  });
247
252
  jest
248
- .spyOn(useWorkspaceData, 'useWorkspaceMaterializations')
249
- .mockReturnValue({
250
- data: mockMaterializations,
251
- loading: false,
252
- error: null,
253
- });
254
- jest.spyOn(useWorkspaceData, 'useWorkspaceNeedsAttention').mockReturnValue({
255
- data: mockNeedsAttention,
253
+ .spyOn(useWorkspaceData, 'useWorkspaceDashboardData')
254
+ .mockReturnValue(makeDashboardData({ materializedNodes: [pendingNode] }));
255
+
256
+ render(
257
+ <MemoryRouter>
258
+ <MyWorkspacePage />
259
+ </MemoryRouter>,
260
+ );
261
+
262
+ // Pending node (null validThroughTs) should not be passed as stale
263
+ expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
264
+ });
265
+
266
+ it('should exclude nodes with no availability from stale list', () => {
267
+ const noAvailabilityNode = {
268
+ name: 'default.no_avail_cube',
269
+ type: 'CUBE',
270
+ current: {},
271
+ };
272
+
273
+ jest.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
274
+ currentUser: mockCurrentUser,
256
275
  loading: false,
257
- error: null,
258
276
  });
259
- jest.spyOn(useWorkspaceData, 'usePersonalNamespace').mockReturnValue({
260
- exists: true,
277
+ jest
278
+ .spyOn(useWorkspaceData, 'useWorkspaceDashboardData')
279
+ .mockReturnValue(
280
+ makeDashboardData({ materializedNodes: [noAvailabilityNode] }),
281
+ );
282
+
283
+ render(
284
+ <MemoryRouter>
285
+ <MyWorkspacePage />
286
+ </MemoryRouter>,
287
+ );
288
+
289
+ expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
290
+ });
291
+
292
+ it('should derive personal namespace from username', () => {
293
+ jest.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
294
+ currentUser: { username: 'jane.doe@company.com' },
261
295
  loading: false,
262
- error: null,
263
296
  });
297
+ jest
298
+ .spyOn(useWorkspaceData, 'useWorkspaceDashboardData')
299
+ .mockReturnValue(makeDashboardData());
264
300
 
265
301
  render(
266
302
  <MemoryRouter>
@@ -268,10 +304,8 @@ describe('<MyWorkspacePage />', () => {
268
304
  </MemoryRouter>,
269
305
  );
270
306
 
271
- // Verify sections receive correct data
272
- expect(screen.getByTestId('collections-section')).toBeInTheDocument();
273
- expect(screen.getByTestId('my-nodes-section')).toBeInTheDocument();
274
- expect(screen.getByTestId('notifications-section')).toBeInTheDocument();
307
+ // NeedsAttentionSection mock receives personalNamespace="users.jane.doe"
308
+ expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
275
309
  });
276
310
 
277
311
  it('should calculate stale materializations correctly', () => {
@@ -287,53 +321,13 @@ describe('<MyWorkspacePage />', () => {
287
321
  },
288
322
  };
289
323
 
290
- jest.spyOn(useWorkspaceData, 'useCurrentUser').mockReturnValue({
291
- data: mockCurrentUser,
292
- loading: false,
293
- error: null,
294
- });
295
- jest.spyOn(useWorkspaceData, 'useWorkspaceOwnedNodes').mockReturnValue({
296
- data: [],
297
- loading: false,
298
- error: null,
299
- });
300
- jest.spyOn(useWorkspaceData, 'useWorkspaceRecentlyEdited').mockReturnValue({
301
- data: [],
302
- loading: false,
303
- error: null,
304
- });
305
- jest.spyOn(useWorkspaceData, 'useWorkspaceWatchedNodes').mockReturnValue({
306
- data: [],
324
+ jest.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
325
+ currentUser: mockCurrentUser,
307
326
  loading: false,
308
- error: null,
309
- });
310
- jest.spyOn(useWorkspaceData, 'useWorkspaceCollections').mockReturnValue({
311
- data: [],
312
- loading: false,
313
- error: null,
314
- });
315
- jest.spyOn(useWorkspaceData, 'useWorkspaceNotifications').mockReturnValue({
316
- data: [],
317
- loading: false,
318
- error: null,
319
327
  });
320
328
  jest
321
- .spyOn(useWorkspaceData, 'useWorkspaceMaterializations')
322
- .mockReturnValue({
323
- data: [staleNode],
324
- loading: false,
325
- error: null,
326
- });
327
- jest.spyOn(useWorkspaceData, 'useWorkspaceNeedsAttention').mockReturnValue({
328
- data: mockNeedsAttention,
329
- loading: false,
330
- error: null,
331
- });
332
- jest.spyOn(useWorkspaceData, 'usePersonalNamespace').mockReturnValue({
333
- exists: true,
334
- loading: false,
335
- error: null,
336
- });
329
+ .spyOn(useWorkspaceData, 'useWorkspaceDashboardData')
330
+ .mockReturnValue(makeDashboardData({ materializedNodes: [staleNode] }));
337
331
 
338
332
  render(
339
333
  <MemoryRouter>
@@ -44,15 +44,15 @@ describe('<NeedsAttentionSection />', () => {
44
44
  expect(screen.getByText(/Orphaned Dimensions/)).toBeInTheDocument();
45
45
  });
46
46
 
47
- it('should show "All good!" when category has no items', () => {
47
+ it('should show "All good" when category has no items', () => {
48
48
  render(
49
49
  <MemoryRouter>
50
50
  <NeedsAttentionSection {...defaultProps} />
51
51
  </MemoryRouter>,
52
52
  );
53
53
 
54
- const allGood = screen.getAllByText('All good!');
55
- expect(allGood.length).toBe(5); // All 5 categories should show "All good!"
54
+ const allGood = screen.getAllByText('All good');
55
+ expect(allGood.length).toBe(5); // All 5 categories should show "All good"
56
56
  });
57
57
 
58
58
  it('should display invalid nodes', () => {
@@ -74,7 +74,7 @@ describe('<NeedsAttentionSection />', () => {
74
74
  </MemoryRouter>,
75
75
  );
76
76
 
77
- expect(screen.getByText('Invalid')).toBeInTheDocument();
77
+ expect(screen.getByText('Invalid')).toBeInTheDocument();
78
78
  expect(screen.getByText('(1)')).toBeInTheDocument();
79
79
  });
80
80
 
@@ -97,7 +97,7 @@ describe('<NeedsAttentionSection />', () => {
97
97
  </MemoryRouter>,
98
98
  );
99
99
 
100
- expect(screen.getByText('Stale Drafts')).toBeInTheDocument();
100
+ expect(screen.getByText('Stale Drafts')).toBeInTheDocument();
101
101
  expect(screen.getByText('(1)')).toBeInTheDocument();
102
102
  });
103
103
 
@@ -120,7 +120,7 @@ describe('<NeedsAttentionSection />', () => {
120
120
  </MemoryRouter>,
121
121
  );
122
122
 
123
- expect(screen.getByText('📝 No Description')).toBeInTheDocument();
123
+ expect(screen.getByText('No Description')).toBeInTheDocument();
124
124
  expect(screen.getByText('(1)')).toBeInTheDocument();
125
125
  });
126
126
 
@@ -143,7 +143,7 @@ describe('<NeedsAttentionSection />', () => {
143
143
  </MemoryRouter>,
144
144
  );
145
145
 
146
- const viewAllLinks = screen.getAllByText('View all →');
146
+ const viewAllLinks = screen.getAllByText('→');
147
147
  expect(viewAllLinks.length).toBeGreaterThan(0);
148
148
  });
149
149
 
@@ -154,7 +154,7 @@ describe('<NeedsAttentionSection />', () => {
154
154
  </MemoryRouter>,
155
155
  );
156
156
 
157
- expect(screen.queryByText('View all →')).not.toBeInTheDocument();
157
+ expect(screen.queryByText('→')).not.toBeInTheDocument();
158
158
  });
159
159
 
160
160
  it('should limit nodes to 10 per category', () => {
@@ -176,7 +176,7 @@ describe('<NeedsAttentionSection />', () => {
176
176
 
177
177
  // Should only display 10 nodes (via NodeChip component)
178
178
  // The 11th node should not be displayed
179
- expect(screen.getByText('Invalid')).toBeInTheDocument();
179
+ expect(screen.getByText('Invalid')).toBeInTheDocument();
180
180
  expect(screen.getByText('(15)')).toBeInTheDocument();
181
181
  });
182
182
 
@@ -187,9 +187,8 @@ describe('<NeedsAttentionSection />', () => {
187
187
  </MemoryRouter>,
188
188
  );
189
189
 
190
- expect(screen.getByText('Set up your namespace')).toBeInTheDocument();
191
- expect(screen.getByText('users.test.user')).toBeInTheDocument();
192
- expect(screen.getByText('Create →')).toBeInTheDocument();
190
+ expect(screen.getByText('Personal namespace')).toBeInTheDocument();
191
+ expect(screen.getByText('Create users.test.user')).toBeInTheDocument();
193
192
  });
194
193
 
195
194
  it('should not show personal namespace prompt when namespace exists', () => {
@@ -199,7 +198,7 @@ describe('<NeedsAttentionSection />', () => {
199
198
  </MemoryRouter>,
200
199
  );
201
200
 
202
- expect(screen.queryByText('Set up your namespace')).not.toBeInTheDocument();
201
+ expect(screen.queryByText('Personal namespace')).not.toBeInTheDocument();
203
202
  });
204
203
 
205
204
  it('should not show personal namespace prompt when loading', () => {
@@ -213,7 +212,7 @@ describe('<NeedsAttentionSection />', () => {
213
212
  </MemoryRouter>,
214
213
  );
215
214
 
216
- expect(screen.queryByText('Set up your namespace')).not.toBeInTheDocument();
215
+ expect(screen.queryByText('Personal namespace')).not.toBeInTheDocument();
217
216
  });
218
217
 
219
218
  it('should link to correct filter URLs', () => {
@@ -235,7 +234,7 @@ describe('<NeedsAttentionSection />', () => {
235
234
  </MemoryRouter>,
236
235
  );
237
236
 
238
- const viewAllLink = screen.getByText('View all →').closest('a');
237
+ const viewAllLink = screen.getByText('→').closest('a');
239
238
  expect(viewAllLink).toHaveAttribute(
240
239
  'href',
241
240
  '/?ownedBy=test.user@example.com&statuses=INVALID',
@@ -262,11 +261,11 @@ describe('<NeedsAttentionSection />', () => {
262
261
  </MemoryRouter>,
263
262
  );
264
263
 
265
- expect(screen.getByText('Invalid')).toBeInTheDocument();
264
+ expect(screen.getByText('Invalid')).toBeInTheDocument();
266
265
  expect(screen.getByText('(1)')).toBeInTheDocument();
267
- expect(screen.getByText('Stale Drafts')).toBeInTheDocument();
266
+ expect(screen.getByText('Stale Drafts')).toBeInTheDocument();
268
267
  expect(screen.getByText('(2)')).toBeInTheDocument();
269
- expect(screen.getByText('📝 No Description')).toBeInTheDocument();
268
+ expect(screen.getByText('No Description')).toBeInTheDocument();
270
269
  expect(screen.getByText('(3)')).toBeInTheDocument();
271
270
  });
272
271
  });