@@ -85,20 +85,38 @@ suite('DeepnoteTreeDataProvider', () => {
8585 assert . isArray ( children ) ;
8686 } ) ;
8787
88- test ( 'should return loading item on initial call' , async ( ) => {
88+ test ( 'should return loading item on first call with correct properties ' , async ( ) => {
8989 const newProvider = new DeepnoteTreeDataProvider ( ) ;
9090
91+ // First call should return loading item
9192 const children = await newProvider . getChildren ( ) ;
9293 assert . isArray ( children ) ;
94+ assert . isAtLeast ( children . length , 1 ) ;
9395
94- if ( children . length > 0 ) {
95- // If there are children, check if the first one is a loading item
96- const firstChild = children [ 0 ] ;
97- if ( firstChild . type === DeepnoteTreeItemType . Loading ) {
98- assert . strictEqual ( firstChild . type , DeepnoteTreeItemType . Loading ) ;
99- assert . strictEqual ( firstChild . contextValue , 'loading' ) ;
100- }
96+ const firstChild = children [ 0 ] ;
97+ assert . strictEqual ( firstChild . type , DeepnoteTreeItemType . Loading ) ;
98+ assert . strictEqual ( firstChild . contextValue , 'loading' ) ;
99+ assert . strictEqual ( firstChild . label , 'Scanning for Deepnote projects...' ) ;
100+ assert . isDefined ( firstChild . iconPath ) ;
101+
102+ if ( newProvider && typeof newProvider . dispose === 'function' ) {
103+ newProvider . dispose ( ) ;
101104 }
105+ } ) ;
106+
107+ test ( 'should complete initial scan and show projects after loading' , async ( ) => {
108+ const newProvider = new DeepnoteTreeDataProvider ( ) ;
109+
110+ // First call shows loading
111+ const loadingChildren = await newProvider . getChildren ( ) ;
112+ assert . isArray ( loadingChildren ) ;
113+
114+ // Wait a bit for the initial scan to complete
115+ await new Promise ( ( resolve ) => setTimeout ( resolve , 10 ) ) ;
116+
117+ // Second call should show actual projects (or empty array if no projects)
118+ const actualChildren = await newProvider . getChildren ( ) ;
119+ assert . isArray ( actualChildren ) ;
102120
103121 if ( newProvider && typeof newProvider . dispose === 'function' ) {
104122 newProvider . dispose ( ) ;
@@ -152,16 +170,96 @@ suite('DeepnoteTreeDataProvider', () => {
152170 } ) ;
153171
154172 test ( 'should reset initial scan state on refresh' , async ( ) => {
155- // First call to getChildren to trigger initial scan
156- const firstChildren = await provider . getChildren ( ) ;
173+ const newProvider = new DeepnoteTreeDataProvider ( ) ;
174+
175+ // First call shows loading
176+ const firstChildren = await newProvider . getChildren ( ) ;
157177 assert . isArray ( firstChildren ) ;
158178
179+ // Wait for initial scan to complete
180+ await new Promise ( ( resolve ) => setTimeout ( resolve , 10 ) ) ;
181+
182+ // After scan, should not show loading
183+ const afterScanChildren = await newProvider . getChildren ( ) ;
184+ assert . isArray ( afterScanChildren ) ;
185+
159186 // Call refresh to reset state
160- provider . refresh ( ) ;
187+ newProvider . refresh ( ) ;
161188
162- // After refresh, getChildren should show loading state again
163- const childrenAfterRefresh = await provider . getChildren ( ) ;
189+ // After refresh, should show loading again
190+ const childrenAfterRefresh = await newProvider . getChildren ( ) ;
164191 assert . isArray ( childrenAfterRefresh ) ;
192+ if ( childrenAfterRefresh . length > 0 ) {
193+ const firstItem = childrenAfterRefresh [ 0 ] ;
194+ if ( firstItem . type === DeepnoteTreeItemType . Loading ) {
195+ assert . strictEqual ( firstItem . label , 'Scanning for Deepnote projects...' ) ;
196+ }
197+ }
198+
199+ if ( newProvider && typeof newProvider . dispose === 'function' ) {
200+ newProvider . dispose ( ) ;
201+ }
202+ } ) ;
203+ } ) ;
204+
205+ suite ( 'loading state' , ( ) => {
206+ test ( 'should show loading on first call to empty tree' , async ( ) => {
207+ const newProvider = new DeepnoteTreeDataProvider ( ) ;
208+
209+ // Call getChildren without element (root level)
210+ const children = await newProvider . getChildren ( undefined ) ;
211+ assert . isArray ( children ) ;
212+ assert . isAtLeast ( children . length , 1 ) ;
213+
214+ // First child should be loading item
215+ assert . strictEqual ( children [ 0 ] . type , DeepnoteTreeItemType . Loading ) ;
216+
217+ if ( newProvider && typeof newProvider . dispose === 'function' ) {
218+ newProvider . dispose ( ) ;
219+ }
220+ } ) ;
221+
222+ test ( 'should transition from loading to projects' , async ( ) => {
223+ const newProvider = new DeepnoteTreeDataProvider ( ) ;
224+
225+ // First call shows loading
226+ const loadingResult = await newProvider . getChildren ( undefined ) ;
227+ assert . isArray ( loadingResult ) ;
228+ assert . isAtLeast ( loadingResult . length , 1 ) ;
229+ assert . strictEqual ( loadingResult [ 0 ] . type , DeepnoteTreeItemType . Loading ) ;
230+
231+ // Wait for scan to complete
232+ await new Promise ( ( resolve ) => setTimeout ( resolve , 50 ) ) ;
233+
234+ // Next call shows actual results
235+ const projectsResult = await newProvider . getChildren ( undefined ) ;
236+ assert . isArray ( projectsResult ) ;
237+ // In test environment without workspace, this will be empty
238+ // but should not contain loading item anymore
239+
240+ if ( newProvider && typeof newProvider . dispose === 'function' ) {
241+ newProvider . dispose ( ) ;
242+ }
243+ } ) ;
244+
245+ test ( 'should not show loading for child elements' , async ( ) => {
246+ // Create a mock project item
247+ const mockProjectItem = new DeepnoteTreeItem (
248+ DeepnoteTreeItemType . ProjectFile ,
249+ {
250+ filePath : '/workspace/project.deepnote' ,
251+ projectId : 'project-123'
252+ } ,
253+ mockProject ,
254+ 1
255+ ) ;
256+
257+ // Getting children of a project should never show loading
258+ const children = await provider . getChildren ( mockProjectItem ) ;
259+ assert . isArray ( children ) ;
260+ // Should not contain any loading items
261+ const hasLoadingItem = children . some ( ( child ) => child . type === DeepnoteTreeItemType . Loading ) ;
262+ assert . isFalse ( hasLoadingItem ) ;
165263 } ) ;
166264 } ) ;
167265
0 commit comments