@@ -31,17 +31,27 @@ suite('OpenInDeepnoteHandler', () => {
3131
3232 suite ( 'activate' , ( ) => {
3333 test ( 'should register command when activated' , ( ) => {
34- const registerCommandStub = sandbox . stub ( mockedVSCodeNamespaces . commands , 'registerCommand' ) ;
34+ let registeredCommandId : string | undefined ;
35+ let registeredCallback : Function | undefined ;
36+
37+ when ( mockedVSCodeNamespaces . commands . registerCommand ( anything ( ) , anything ( ) ) ) . thenCall ( ( id , callback ) => {
38+ registeredCommandId = id ;
39+ registeredCallback = callback ;
40+ return {
41+ dispose : ( ) => {
42+ /* no-op */
43+ }
44+ } ;
45+ } ) ;
3546
3647 handler . activate ( ) ;
3748
38- assert . isTrue ( registerCommandStub . calledOnce , 'registerCommand should be called once' ) ;
3949 assert . strictEqual (
40- registerCommandStub . firstCall . args [ 0 ] ,
50+ registeredCommandId ,
4151 'deepnote.openInDeepnote' ,
4252 'Command should be registered with correct ID'
4353 ) ;
44- assert . isFunction ( registerCommandStub . firstCall . args [ 1 ] , 'Second argument should be a function' ) ;
54+ assert . isFunction ( registeredCallback , 'Second argument should be a function' ) ;
4555 } ) ;
4656 } ) ;
4757
@@ -74,55 +84,61 @@ suite('OpenInDeepnoteHandler', () => {
7484 }
7585
7686 test ( 'should handle no active editor or notebook' , async ( ) => {
87+ let errorMessage : string | undefined ;
88+
7789 when ( mockedVSCodeNamespaces . window . activeNotebookEditor ) . thenReturn ( undefined ) ;
7890 when ( mockedVSCodeNamespaces . window . activeTextEditor ) . thenReturn ( undefined ) ;
79- const showErrorStub = sandbox . stub ( mockedVSCodeNamespaces . window , 'showErrorMessage' ) ;
91+ when ( mockedVSCodeNamespaces . window . showErrorMessage ( anything ( ) ) ) . thenCall ( ( message ) => {
92+ errorMessage = message ;
93+ return Promise . resolve ( undefined ) ;
94+ } ) ;
8095
8196 await ( handler as any ) . handleOpenInDeepnote ( ) ;
8297
83- assert . isTrue ( showErrorStub . calledOnce , 'Should show error message' ) ;
98+ assert . isDefined ( errorMessage , 'Should show error message' ) ;
8499 assert . isTrue (
85- showErrorStub . firstCall . args [ 0 ] . includes ( 'Please open a .deepnote file first' ) ,
100+ errorMessage ! . includes ( 'Please open a .deepnote file first' ) ,
86101 'Error message should mention opening a .deepnote file'
87102 ) ;
88103 } ) ;
89104
90105 test ( 'should handle Deepnote notebook editor' , async ( ) => {
91106 const notebookUri = testFileUri . with ( { query : 'notebook=123' } ) ;
92107 const mockNotebookEditor = createMockNotebookEditor ( notebookUri , 'deepnote' ) ;
108+ let withProgressCalled = false ;
93109
94110 when ( mockedVSCodeNamespaces . window . activeNotebookEditor ) . thenReturn ( mockNotebookEditor ) ;
95111 when ( mockedVSCodeNamespaces . commands . executeCommand ( anything ( ) ) ) . thenReturn ( Promise . resolve ( undefined ) ) ;
96112
97113 const statStub = sandbox . stub ( fs . promises , 'stat' ) . resolves ( { size : 1000 } as fs . Stats ) ;
98114 const readFileStub = sandbox . stub ( fs . promises , 'readFile' ) . resolves ( testFileBuffer ) ;
99- const withProgressStub = sandbox
100- . stub ( mockedVSCodeNamespaces . window , 'withProgress' )
101- . callsFake ( ( _options , callback ) => {
102- return callback (
103- {
104- report : sinon . stub ( )
105- } as any ,
106- { } as any
107- ) ;
108- } ) ;
115+ when ( mockedVSCodeNamespaces . window . withProgress ( anything ( ) , anything ( ) ) ) . thenCall ( ( _options , callback ) => {
116+ withProgressCalled = true ;
117+ return callback (
118+ {
119+ report : ( ) => {
120+ /* no-op */
121+ }
122+ } as any ,
123+ { } as any
124+ ) ;
125+ } ) ;
109126 const initImportStub = sandbox . stub ( importClient , 'initImport' ) . resolves ( {
110127 importId : 'test-import-id' ,
111128 uploadUrl : 'https://test.com/upload' ,
112129 expiresAt : '2025-12-31T23:59:59Z'
113130 } ) ;
114131 const uploadFileStub = sandbox . stub ( importClient , 'uploadFile' ) . resolves ( ) ;
115132 sandbox . stub ( importClient , 'getDeepnoteDomain' ) . returns ( 'app.deepnote.com' ) ;
116- const openExternalStub = sandbox . stub ( mockedVSCodeNamespaces . env , ' openExternal' ) . resolves ( ) ;
133+ when ( mockedVSCodeNamespaces . env . openExternal ( anything ( ) ) ) . thenReturn ( Promise . resolve ( true ) ) ;
117134
118135 await ( handler as any ) . handleOpenInDeepnote ( ) ;
119136
120137 assert . isTrue ( statStub . calledOnce , 'Should stat the file' ) ;
121138 assert . isTrue ( readFileStub . calledOnce , 'Should read the file' ) ;
122- assert . isTrue ( withProgressStub . calledOnce , 'Should show progress' ) ;
139+ assert . isTrue ( withProgressCalled , 'Should show progress' ) ;
123140 assert . isTrue ( initImportStub . calledOnce , 'Should initialize import' ) ;
124141 assert . isTrue ( uploadFileStub . calledOnce , 'Should upload file' ) ;
125- assert . isTrue ( openExternalStub . calledOnce , 'Should open external URL' ) ;
126142 } ) ;
127143
128144 test ( 'should fall back to text editor when notebook is not Deepnote type' , async ( ) => {
@@ -135,10 +151,12 @@ suite('OpenInDeepnoteHandler', () => {
135151
136152 const statStub = sandbox . stub ( fs . promises , 'stat' ) . resolves ( { size : 1000 } as fs . Stats ) ;
137153 const readFileStub = sandbox . stub ( fs . promises , 'readFile' ) . resolves ( testFileBuffer ) ;
138- sandbox . stub ( mockedVSCodeNamespaces . window , 'withProgress' ) . callsFake ( ( _options , callback ) => {
154+ when ( mockedVSCodeNamespaces . window . withProgress ( anything ( ) , anything ( ) ) ) . thenCall ( ( _options , callback ) => {
139155 return callback (
140156 {
141- report : sinon . stub ( )
157+ report : ( ) => {
158+ /* no-op */
159+ }
142160 } as any ,
143161 { } as any
144162 ) ;
@@ -150,7 +168,7 @@ suite('OpenInDeepnoteHandler', () => {
150168 } ) ;
151169 sandbox . stub ( importClient , 'uploadFile' ) . resolves ( ) ;
152170 sandbox . stub ( importClient , 'getDeepnoteDomain' ) . returns ( 'app.deepnote.com' ) ;
153- sandbox . stub ( mockedVSCodeNamespaces . env , ' openExternal' ) . resolves ( ) ;
171+ when ( mockedVSCodeNamespaces . env . openExternal ( anything ( ) ) ) . thenReturn ( Promise . resolve ( true ) ) ;
154172
155173 await ( handler as any ) . handleOpenInDeepnote ( ) ;
156174
@@ -166,10 +184,12 @@ suite('OpenInDeepnoteHandler', () => {
166184
167185 const statStub = sandbox . stub ( fs . promises , 'stat' ) . resolves ( { size : 1000 } as fs . Stats ) ;
168186 const readFileStub = sandbox . stub ( fs . promises , 'readFile' ) . resolves ( testFileBuffer ) ;
169- sandbox . stub ( mockedVSCodeNamespaces . window , 'withProgress' ) . callsFake ( ( _options , callback ) => {
187+ when ( mockedVSCodeNamespaces . window . withProgress ( anything ( ) , anything ( ) ) ) . thenCall ( ( _options , callback ) => {
170188 return callback (
171189 {
172- report : sinon . stub ( )
190+ report : ( ) => {
191+ /* no-op */
192+ }
173193 } as any ,
174194 { } as any
175195 ) ;
@@ -181,7 +201,7 @@ suite('OpenInDeepnoteHandler', () => {
181201 } ) ;
182202 sandbox . stub ( importClient , 'uploadFile' ) . resolves ( ) ;
183203 sandbox . stub ( importClient , 'getDeepnoteDomain' ) . returns ( 'app.deepnote.com' ) ;
184- sandbox . stub ( mockedVSCodeNamespaces . env , ' openExternal' ) . resolves ( ) ;
204+ when ( mockedVSCodeNamespaces . env . openExternal ( anything ( ) ) ) . thenReturn ( Promise . resolve ( true ) ) ;
185205
186206 await ( handler as any ) . handleOpenInDeepnote ( ) ;
187207
@@ -192,16 +212,20 @@ suite('OpenInDeepnoteHandler', () => {
192212 test ( 'should reject non-.deepnote files' , async ( ) => {
193213 const otherFileUri = Uri . file ( '/test/notebook.ipynb' ) ;
194214 const mockTextEditor = createMockTextEditor ( otherFileUri ) ;
215+ let errorMessage : string | undefined ;
195216
196217 when ( mockedVSCodeNamespaces . window . activeNotebookEditor ) . thenReturn ( undefined ) ;
197218 when ( mockedVSCodeNamespaces . window . activeTextEditor ) . thenReturn ( mockTextEditor ) ;
198- const showErrorStub = sandbox . stub ( mockedVSCodeNamespaces . window , 'showErrorMessage' ) ;
219+ when ( mockedVSCodeNamespaces . window . showErrorMessage ( anything ( ) ) ) . thenCall ( ( message ) => {
220+ errorMessage = message ;
221+ return Promise . resolve ( undefined ) ;
222+ } ) ;
199223
200224 await ( handler as any ) . handleOpenInDeepnote ( ) ;
201225
202- assert . isTrue ( showErrorStub . calledOnce , 'Should show error message' ) ;
226+ assert . isDefined ( errorMessage , 'Should show error message' ) ;
203227 assert . isTrue (
204- showErrorStub . firstCall . args [ 0 ] . includes ( 'only works with .deepnote files' ) ,
228+ errorMessage ! . includes ( 'only works with .deepnote files' ) ,
205229 'Error message should mention .deepnote files'
206230 ) ;
207231 } ) ;
@@ -216,10 +240,12 @@ suite('OpenInDeepnoteHandler', () => {
216240 const saveStub = sandbox . stub ( mockDocument , 'save' ) . resolves ( true ) ;
217241 sandbox . stub ( fs . promises , 'stat' ) . resolves ( { size : 1000 } as fs . Stats ) ;
218242 sandbox . stub ( fs . promises , 'readFile' ) . resolves ( testFileBuffer ) ;
219- sandbox . stub ( mockedVSCodeNamespaces . window , 'withProgress' ) . callsFake ( ( _options , callback ) => {
243+ when ( mockedVSCodeNamespaces . window . withProgress ( anything ( ) , anything ( ) ) ) . thenCall ( ( _options , callback ) => {
220244 return callback (
221245 {
222- report : sinon . stub ( )
246+ report : ( ) => {
247+ /* no-op */
248+ }
223249 } as any ,
224250 { } as any
225251 ) ;
@@ -231,7 +257,7 @@ suite('OpenInDeepnoteHandler', () => {
231257 } ) ;
232258 sandbox . stub ( importClient , 'uploadFile' ) . resolves ( ) ;
233259 sandbox . stub ( importClient , 'getDeepnoteDomain' ) . returns ( 'app.deepnote.com' ) ;
234- sandbox . stub ( mockedVSCodeNamespaces . env , ' openExternal' ) . resolves ( ) ;
260+ when ( mockedVSCodeNamespaces . env . openExternal ( anything ( ) ) ) . thenReturn ( Promise . resolve ( true ) ) ;
235261
236262 await ( handler as any ) . handleOpenInDeepnote ( ) ;
237263
@@ -241,80 +267,91 @@ suite('OpenInDeepnoteHandler', () => {
241267 test ( 'should handle file save failure' , async ( ) => {
242268 const mockTextEditor = createMockTextEditor ( testFileUri , true ) ;
243269 const mockDocument = mockTextEditor . document ;
270+ let errorMessage : string | undefined ;
244271
245272 when ( mockedVSCodeNamespaces . window . activeNotebookEditor ) . thenReturn ( undefined ) ;
246273 when ( mockedVSCodeNamespaces . window . activeTextEditor ) . thenReturn ( mockTextEditor ) ;
247274
248275 const saveStub = sandbox . stub ( mockDocument , 'save' ) . resolves ( false ) ;
249- const showErrorStub = sandbox . stub ( mockedVSCodeNamespaces . window , 'showErrorMessage' ) ;
276+ when ( mockedVSCodeNamespaces . window . showErrorMessage ( anything ( ) ) ) . thenCall ( ( message ) => {
277+ errorMessage = message ;
278+ return Promise . resolve ( undefined ) ;
279+ } ) ;
250280
251281 await ( handler as any ) . handleOpenInDeepnote ( ) ;
252282
253283 assert . isTrue ( saveStub . calledOnce , 'Should attempt to save' ) ;
254- assert . isTrue ( showErrorStub . calledOnce , 'Should show error message' ) ;
255- assert . isTrue (
256- showErrorStub . firstCall . args [ 0 ] . includes ( 'save the file' ) ,
257- 'Error message should mention saving'
258- ) ;
284+ assert . isDefined ( errorMessage , 'Should show error message' ) ;
285+ assert . isTrue ( errorMessage ! . includes ( 'save the file' ) , 'Error message should mention saving' ) ;
259286 } ) ;
260287
261288 test ( 'should reject files exceeding size limit' , async ( ) => {
262289 const mockTextEditor = createMockTextEditor ( testFileUri ) ;
290+ let errorMessage : string | undefined ;
263291
264292 when ( mockedVSCodeNamespaces . window . activeNotebookEditor ) . thenReturn ( undefined ) ;
265293 when ( mockedVSCodeNamespaces . window . activeTextEditor ) . thenReturn ( mockTextEditor ) ;
266294
267295 const largeSize = importClient . MAX_FILE_SIZE + 1 ;
268296 const statStub = sandbox . stub ( fs . promises , 'stat' ) . resolves ( { size : largeSize } as fs . Stats ) ;
269- const showErrorStub = sandbox . stub ( mockedVSCodeNamespaces . window , 'showErrorMessage' ) ;
297+ when ( mockedVSCodeNamespaces . window . showErrorMessage ( anything ( ) ) ) . thenCall ( ( message ) => {
298+ errorMessage = message ;
299+ return Promise . resolve ( undefined ) ;
300+ } ) ;
270301
271302 await ( handler as any ) . handleOpenInDeepnote ( ) ;
272303
273304 assert . isTrue ( statStub . calledOnce , 'Should stat the file' ) ;
274- assert . isTrue ( showErrorStub . calledOnce , 'Should show error message' ) ;
275- assert . isTrue (
276- showErrorStub . firstCall . args [ 0 ] . includes ( 'exceeds' ) ,
277- 'Error message should mention file size limit'
278- ) ;
305+ assert . isDefined ( errorMessage , 'Should show error message' ) ;
306+ assert . isTrue ( errorMessage ! . includes ( 'exceeds' ) , 'Error message should mention file size limit' ) ;
279307 } ) ;
280308
281309 test ( 'should handle import initialization error' , async ( ) => {
282310 const mockTextEditor = createMockTextEditor ( testFileUri ) ;
311+ let errorMessage : string | undefined ;
283312
284313 when ( mockedVSCodeNamespaces . window . activeNotebookEditor ) . thenReturn ( undefined ) ;
285314 when ( mockedVSCodeNamespaces . window . activeTextEditor ) . thenReturn ( mockTextEditor ) ;
286315
287316 sandbox . stub ( fs . promises , 'stat' ) . resolves ( { size : 1000 } as fs . Stats ) ;
288317 sandbox . stub ( fs . promises , 'readFile' ) . resolves ( testFileBuffer ) ;
289- sandbox . stub ( mockedVSCodeNamespaces . window , 'withProgress' ) . callsFake ( ( _options , callback ) => {
318+ when ( mockedVSCodeNamespaces . window . withProgress ( anything ( ) , anything ( ) ) ) . thenCall ( ( _options , callback ) => {
290319 return callback (
291320 {
292- report : sinon . stub ( )
321+ report : ( ) => {
322+ /* no-op */
323+ }
293324 } as any ,
294325 { } as any
295326 ) ;
296327 } ) ;
297328 const initImportStub = sandbox . stub ( importClient , 'initImport' ) . rejects ( new Error ( 'Network error' ) ) ;
298- const showErrorStub = sandbox . stub ( mockedVSCodeNamespaces . window , 'showErrorMessage' ) ;
329+ when ( mockedVSCodeNamespaces . window . showErrorMessage ( anything ( ) ) ) . thenCall ( ( message ) => {
330+ errorMessage = message ;
331+ return Promise . resolve ( undefined ) ;
332+ } ) ;
299333
300334 await ( handler as any ) . handleOpenInDeepnote ( ) ;
301335
302336 assert . isTrue ( initImportStub . calledOnce , 'Should attempt to initialize import' ) ;
303- assert . isTrue ( showErrorStub . calledOnce , 'Should show error message' ) ;
337+ assert . isDefined ( errorMessage , 'Should show error message' ) ;
304338 } ) ;
305339
306340 test ( 'should handle upload error' , async ( ) => {
307341 const mockTextEditor = createMockTextEditor ( testFileUri ) ;
342+ let errorMessage : string | undefined ;
308343
309344 when ( mockedVSCodeNamespaces . window . activeNotebookEditor ) . thenReturn ( undefined ) ;
310345 when ( mockedVSCodeNamespaces . window . activeTextEditor ) . thenReturn ( mockTextEditor ) ;
311346
312347 sandbox . stub ( fs . promises , 'stat' ) . resolves ( { size : 1000 } as fs . Stats ) ;
313348 sandbox . stub ( fs . promises , 'readFile' ) . resolves ( testFileBuffer ) ;
314- sandbox . stub ( mockedVSCodeNamespaces . window , 'withProgress' ) . callsFake ( ( _options , callback ) => {
349+ when ( mockedVSCodeNamespaces . window . withProgress ( anything ( ) , anything ( ) ) ) . thenCall ( ( _options , callback ) => {
315350 return callback (
316351 {
317- report : sinon . stub ( )
352+ report : ( ) => {
353+ /* no-op */
354+ }
318355 } as any ,
319356 { } as any
320357 ) ;
@@ -325,12 +362,15 @@ suite('OpenInDeepnoteHandler', () => {
325362 expiresAt : '2025-12-31T23:59:59Z'
326363 } ) ;
327364 const uploadFileStub = sandbox . stub ( importClient , 'uploadFile' ) . rejects ( new Error ( 'Upload failed' ) ) ;
328- const showErrorStub = sandbox . stub ( mockedVSCodeNamespaces . window , 'showErrorMessage' ) ;
365+ when ( mockedVSCodeNamespaces . window . showErrorMessage ( anything ( ) ) ) . thenCall ( ( message ) => {
366+ errorMessage = message ;
367+ return Promise . resolve ( undefined ) ;
368+ } ) ;
329369
330370 await ( handler as any ) . handleOpenInDeepnote ( ) ;
331371
332372 assert . isTrue ( uploadFileStub . calledOnce , 'Should attempt to upload' ) ;
333- assert . isTrue ( showErrorStub . calledOnce , 'Should show error message' ) ;
373+ assert . isDefined ( errorMessage , 'Should show error message' ) ;
334374 } ) ;
335375
336376 test ( 'should remove query params from notebook URI' , async ( ) => {
@@ -342,10 +382,12 @@ suite('OpenInDeepnoteHandler', () => {
342382
343383 const statStub = sandbox . stub ( fs . promises , 'stat' ) . resolves ( { size : 1000 } as fs . Stats ) ;
344384 sandbox . stub ( fs . promises , 'readFile' ) . resolves ( testFileBuffer ) ;
345- sandbox . stub ( mockedVSCodeNamespaces . window , 'withProgress' ) . callsFake ( ( _options , callback ) => {
385+ when ( mockedVSCodeNamespaces . window . withProgress ( anything ( ) , anything ( ) ) ) . thenCall ( ( _options , callback ) => {
346386 return callback (
347387 {
348- report : sinon . stub ( )
388+ report : ( ) => {
389+ /* no-op */
390+ }
349391 } as any ,
350392 { } as any
351393 ) ;
@@ -357,7 +399,7 @@ suite('OpenInDeepnoteHandler', () => {
357399 } ) ;
358400 sandbox . stub ( importClient , 'uploadFile' ) . resolves ( ) ;
359401 sandbox . stub ( importClient , 'getDeepnoteDomain' ) . returns ( 'app.deepnote.com' ) ;
360- sandbox . stub ( mockedVSCodeNamespaces . env , ' openExternal' ) . resolves ( ) ;
402+ when ( mockedVSCodeNamespaces . env . openExternal ( anything ( ) ) ) . thenReturn ( Promise . resolve ( true ) ) ;
361403
362404 await ( handler as any ) . handleOpenInDeepnote ( ) ;
363405
0 commit comments