|
1 | 1 | import { assert } from 'chai'; |
| 2 | +import { l10n } from 'vscode'; |
2 | 3 |
|
3 | 4 | import { DeepnoteTreeDataProvider } from './deepnoteTreeDataProvider'; |
4 | 5 | import { DeepnoteTreeItem, DeepnoteTreeItemType } from './deepnoteTreeItem'; |
@@ -85,6 +86,31 @@ suite('DeepnoteTreeDataProvider', () => { |
85 | 86 | assert.isArray(children); |
86 | 87 | }); |
87 | 88 |
|
| 89 | + test('should not throw on first getChildren call with new provider instance', async () => { |
| 90 | + const newProvider = new DeepnoteTreeDataProvider(); |
| 91 | + |
| 92 | + // First call - just verify it returns an array and doesn't throw |
| 93 | + const children = await newProvider.getChildren(); |
| 94 | + assert.isArray(children); |
| 95 | + |
| 96 | + if (newProvider && typeof newProvider.dispose === 'function') { |
| 97 | + newProvider.dispose(); |
| 98 | + } |
| 99 | + }); |
| 100 | + |
| 101 | + test('should return empty array when no workspace is available', async () => { |
| 102 | + const newProvider = new DeepnoteTreeDataProvider(); |
| 103 | + |
| 104 | + // In test environment without workspace, returns empty array |
| 105 | + const children = await newProvider.getChildren(); |
| 106 | + assert.isArray(children); |
| 107 | + assert.strictEqual(children.length, 0, 'Should return empty array when no workspace folders exist'); |
| 108 | + |
| 109 | + if (newProvider && typeof newProvider.dispose === 'function') { |
| 110 | + newProvider.dispose(); |
| 111 | + } |
| 112 | + }); |
| 113 | + |
88 | 114 | test('should return array when called with project item parent', async () => { |
89 | 115 | // Create a mock project item |
90 | 116 | const mockProjectItem = new DeepnoteTreeItem( |
@@ -130,6 +156,112 @@ suite('DeepnoteTreeDataProvider', () => { |
130 | 156 | // Call refresh to verify it doesn't throw |
131 | 157 | assert.doesNotThrow(() => provider.refresh()); |
132 | 158 | }); |
| 159 | + |
| 160 | + test('should reset initial scan state on refresh', async () => { |
| 161 | + const newProvider = new DeepnoteTreeDataProvider(); |
| 162 | + const firstChildren = await newProvider.getChildren(); |
| 163 | + assert.isArray(firstChildren); |
| 164 | + |
| 165 | + await new Promise((resolve) => setTimeout(resolve, 10)); |
| 166 | + |
| 167 | + // After scan |
| 168 | + const afterScanChildren = await newProvider.getChildren(); |
| 169 | + assert.isArray(afterScanChildren); |
| 170 | + |
| 171 | + // Call refresh to reset state - this exercises the refresh logic |
| 172 | + newProvider.refresh(); |
| 173 | + |
| 174 | + // After refresh - should return to initial state (loading or empty) |
| 175 | + const childrenAfterRefresh = await newProvider.getChildren(); |
| 176 | + assert.isArray(childrenAfterRefresh); |
| 177 | + |
| 178 | + // Verify that refresh reset to initial scan state |
| 179 | + // The post-refresh state should match the initial state |
| 180 | + assert.strictEqual( |
| 181 | + childrenAfterRefresh.length, |
| 182 | + firstChildren.length, |
| 183 | + 'After refresh, should return to initial state with same number of children' |
| 184 | + ); |
| 185 | + |
| 186 | + // If initial state had a loading item, post-refresh should too |
| 187 | + if (firstChildren.length > 0 && firstChildren[0].contextValue === 'loading') { |
| 188 | + assert.strictEqual( |
| 189 | + childrenAfterRefresh[0].contextValue, |
| 190 | + 'loading', |
| 191 | + 'After refresh, should show loading item again' |
| 192 | + ); |
| 193 | + assert.strictEqual( |
| 194 | + childrenAfterRefresh[0].label, |
| 195 | + firstChildren[0].label, |
| 196 | + 'Loading item label should match initial state' |
| 197 | + ); |
| 198 | + } |
| 199 | + |
| 200 | + if (newProvider && typeof newProvider.dispose === 'function') { |
| 201 | + newProvider.dispose(); |
| 202 | + } |
| 203 | + }); |
| 204 | + }); |
| 205 | + |
| 206 | + suite('loading state', () => { |
| 207 | + test('should call getChildren and execute loading logic', async () => { |
| 208 | + const newProvider = new DeepnoteTreeDataProvider(); |
| 209 | + |
| 210 | + // Call getChildren without element (root level) - exercises loading code path |
| 211 | + const children = await newProvider.getChildren(undefined); |
| 212 | + assert.isArray(children); |
| 213 | + // In test environment may be empty or have loading item depending on timing |
| 214 | + |
| 215 | + if (newProvider && typeof newProvider.dispose === 'function') { |
| 216 | + newProvider.dispose(); |
| 217 | + } |
| 218 | + }); |
| 219 | + |
| 220 | + test('should handle multiple getChildren calls', async () => { |
| 221 | + const newProvider = new DeepnoteTreeDataProvider(); |
| 222 | + |
| 223 | + // First call |
| 224 | + const firstResult = await newProvider.getChildren(undefined); |
| 225 | + assert.isArray(firstResult); |
| 226 | + |
| 227 | + // Wait a bit |
| 228 | + await new Promise((resolve) => setTimeout(resolve, 50)); |
| 229 | + |
| 230 | + // Second call |
| 231 | + const secondResult = await newProvider.getChildren(undefined); |
| 232 | + assert.isArray(secondResult); |
| 233 | + |
| 234 | + if (newProvider && typeof newProvider.dispose === 'function') { |
| 235 | + newProvider.dispose(); |
| 236 | + } |
| 237 | + }); |
| 238 | + |
| 239 | + test('should not show loading for child elements', async () => { |
| 240 | + // Create a mock project item |
| 241 | + const mockProjectItem = new DeepnoteTreeItem( |
| 242 | + DeepnoteTreeItemType.ProjectFile, |
| 243 | + { |
| 244 | + filePath: '/workspace/project.deepnote', |
| 245 | + projectId: 'project-123' |
| 246 | + }, |
| 247 | + mockProject, |
| 248 | + 1 |
| 249 | + ); |
| 250 | + |
| 251 | + // Getting children of a project exercises the non-loading code path |
| 252 | + const children = await provider.getChildren(mockProjectItem); |
| 253 | + assert.isArray(children); |
| 254 | + |
| 255 | + // Verify no loading items are present |
| 256 | + const hasLoadingType = children.some((child) => child.type === DeepnoteTreeItemType.Loading); |
| 257 | + assert.isFalse(hasLoadingType, 'Children should not contain any loading type items'); |
| 258 | + |
| 259 | + // Also verify no loading labels |
| 260 | + const hasLoadingLabel = children.some( |
| 261 | + (child) => child.label === l10n.t('Scanning for Deepnote projects...') || child.label === 'Loading' |
| 262 | + ); |
| 263 | + assert.isFalse(hasLoadingLabel, 'Children should not contain any loading labels'); |
| 264 | + }); |
133 | 265 | }); |
134 | 266 |
|
135 | 267 | suite('data management', () => { |
|
0 commit comments