@@ -9,6 +9,7 @@ import * as path from 'path';
9
9
import * as TypeMoq from 'typemoq' ;
10
10
import { Disposable , Memento , Selection , TextDocument , TextEditor , Uri } from 'vscode' ;
11
11
12
+ import { nbformat } from '@jupyterlab/coreutils' ;
12
13
import { ReactWrapper } from 'enzyme' ;
13
14
import { anything , when } from 'ts-mockito' ;
14
15
import { IApplicationShell , IDocumentManager } from '../../client/common/application/types' ;
@@ -17,11 +18,12 @@ import { createDeferred, sleep, waitForPromise } from '../../client/common/utils
17
18
import { noop } from '../../client/common/utils/misc' ;
18
19
import { EXTENSION_ROOT_DIR } from '../../client/constants' ;
19
20
import { generateCellsFromDocument } from '../../client/datascience/cellFactory' ;
21
+ import { AllowedCellOutputKeys } from '../../client/datascience/common' ;
20
22
import { EditorContexts } from '../../client/datascience/constants' ;
21
23
import { InteractiveWindowMessages } from '../../client/datascience/interactive-common/interactiveWindowTypes' ;
22
24
import { InteractiveWindow } from '../../client/datascience/interactive-window/interactiveWindow' ;
23
25
import { AskedForPerFileSettingKey } from '../../client/datascience/interactive-window/interactiveWindowProvider' ;
24
- import { IInteractiveWindowProvider } from '../../client/datascience/types' ;
26
+ import { IDataScienceFileSystem , IInteractiveWindowProvider } from '../../client/datascience/types' ;
25
27
import { IInterpreterService } from '../../client/interpreter/contracts' ;
26
28
import { concatMultilineString } from '../../datascience-ui/common' ;
27
29
import { InteractivePanel } from '../../datascience-ui/history-react/interactivePanel' ;
@@ -635,53 +637,81 @@ for i in range(0, 100):
635
637
return ;
636
638
}
637
639
} ;
638
- let exportCalled = false ;
639
- const appShell = TypeMoq . Mock . ofType < IApplicationShell > ( ) ;
640
- appShell
641
- . setup ( ( a ) => a . showErrorMessage ( TypeMoq . It . isAnyString ( ) ) )
642
- . returns ( ( e ) => {
643
- throw e ;
644
- } ) ;
645
- appShell
646
- . setup ( ( a ) => a . showInformationMessage ( TypeMoq . It . isAny ( ) , TypeMoq . It . isAny ( ) ) )
647
- . returns ( ( ) => Promise . resolve ( '' ) ) ;
648
- appShell
649
- . setup ( ( a ) => a . showSaveDialog ( TypeMoq . It . isAny ( ) ) )
650
- . returns ( ( ) => {
651
- exportCalled = true ;
652
- return Promise . resolve ( undefined ) ;
653
- } ) ;
654
- appShell . setup ( ( a ) => a . setStatusBarMessage ( TypeMoq . It . isAny ( ) ) ) . returns ( ( ) => dummyDisposable ) ;
655
- ioc . serviceManager . rebindInstance < IApplicationShell > ( IApplicationShell , appShell . object ) ;
656
-
657
- // Make sure to create the interactive window after the rebind or it gets the wrong application shell.
658
- await addCode ( ioc , 'a=1\na' ) ;
659
- const { window, mount } = await getOrCreateInteractiveWindow ( ioc ) ;
660
-
661
- // Export should cause exportCalled to change to true
662
- const exportPromise = mount . waitForMessage ( InteractiveWindowMessages . ReturnAllCells ) ;
663
- window . exportCells ( ) ;
664
- await exportPromise ;
665
- await sleep ( 100 ) ; // Give time for appshell to come up
666
- assert . equal ( exportCalled , true , 'Export is not being called during export' ) ;
640
+ const dsfs = ioc . get < IDataScienceFileSystem > ( IDataScienceFileSystem ) ;
641
+ const tf = await dsfs . createTemporaryLocalFile ( '.ipynb' ) ;
642
+ try {
643
+ let exportCalled = false ;
644
+ const appShell = TypeMoq . Mock . ofType < IApplicationShell > ( ) ;
645
+ appShell
646
+ . setup ( ( a ) => a . showErrorMessage ( TypeMoq . It . isAnyString ( ) ) )
647
+ . returns ( ( e ) => {
648
+ throw e ;
649
+ } ) ;
650
+ appShell
651
+ . setup ( ( a ) => a . showInformationMessage ( TypeMoq . It . isAny ( ) , TypeMoq . It . isAny ( ) ) )
652
+ . returns ( ( ) => Promise . resolve ( '' ) ) ;
653
+ appShell
654
+ . setup ( ( a ) => a . showSaveDialog ( TypeMoq . It . isAny ( ) ) )
655
+ . returns ( ( ) => {
656
+ exportCalled = true ;
657
+ return Promise . resolve ( Uri . file ( tf . filePath ) ) ;
658
+ } ) ;
659
+ appShell . setup ( ( a ) => a . setStatusBarMessage ( TypeMoq . It . isAny ( ) ) ) . returns ( ( ) => dummyDisposable ) ;
660
+ ioc . serviceManager . rebindInstance < IApplicationShell > ( IApplicationShell , appShell . object ) ;
661
+ const exportCode = `
662
+ for i in range(100):
663
+ time.sleep(0.1)
664
+ raise Exception('test')
665
+ ` ;
667
666
668
- // Remove the cell
669
- const exportButton = findButton ( mount . wrapper , InteractivePanel , 6 ) ;
670
- const undo = findButton ( mount . wrapper , InteractivePanel , 2 ) ;
667
+ // Make sure to create the interactive window after the rebind or it gets the wrong application shell.
668
+ addMockData ( ioc , exportCode , 'NameError' , 'type/error' , 'error' , [
669
+ '\u001b[1;31m---------------------------------------------------------------------------\u001b[0m' ,
670
+ '\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)' ,
671
+ "\u001b[1;32md:\\Source\\Testing_3\\manualTestFile.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m100\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mtime\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msleep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m0.1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[1;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'test'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n" ,
672
+ "\u001b[1;31mNameError\u001b[0m: name 'time' is not defined"
673
+ ] ) ;
674
+ await addCode ( ioc , exportCode ) ;
675
+ const { window, mount } = await getOrCreateInteractiveWindow ( ioc ) ;
671
676
672
- // Now verify if we undo, we have no cells
673
- const afterUndo = await getInteractiveCellResults ( ioc , ( ) => {
674
- undo ! . simulate ( 'click' ) ;
675
- return Promise . resolve ( ) ;
676
- } ) ;
677
+ // Export should cause exportCalled to change to true
678
+ const exportPromise = mount . waitForMessage ( InteractiveWindowMessages . ReturnAllCells ) ;
679
+ window . exportCells ( ) ;
680
+ await exportPromise ;
681
+ await sleep ( 100 ) ; // Give time for appshell to come up
682
+ assert . equal ( exportCalled , true , 'Export is not being called during export' ) ;
683
+
684
+ // Read file contents into a jupyter structure. Make sure we have only the expected values
685
+ const contents = await dsfs . readLocalFile ( tf . filePath ) ;
686
+ const struct = JSON . parse ( contents ) as nbformat . INotebookContent ;
687
+ assert . strictEqual ( struct . cells . length , 1 , 'Wrong number of cells' ) ;
688
+ const outputs = struct . cells [ 0 ] . outputs as nbformat . IOutput [ ] ;
689
+ assert . strictEqual ( outputs . length , 1 , 'Not correct number of outputs' ) ;
690
+ assert . strictEqual ( outputs [ 0 ] . output_type , 'error' , 'Error not found' ) ;
691
+ const allowedKeys = [ ...AllowedCellOutputKeys . error ] ;
692
+ const actualKeys = Object . keys ( outputs [ 0 ] ) ;
693
+ assert . deepStrictEqual ( allowedKeys , actualKeys , 'Invalid keys in output' ) ;
694
+
695
+ // Remove the cell
696
+ const exportButton = findButton ( mount . wrapper , InteractivePanel , 6 ) ;
697
+ const undo = findButton ( mount . wrapper , InteractivePanel , 2 ) ;
698
+
699
+ // Now verify if we undo, we have no cells
700
+ const afterUndo = await getInteractiveCellResults ( ioc , ( ) => {
701
+ undo ! . simulate ( 'click' ) ;
702
+ return Promise . resolve ( ) ;
703
+ } ) ;
677
704
678
- assert . equal ( afterUndo . length , 1 , 'Undo should remove cells' ) ;
705
+ assert . equal ( afterUndo . length , 1 , 'Undo should remove cells' ) ;
679
706
680
- // Then verify we cannot click the button (it should be disabled)
681
- exportCalled = false ;
682
- exportButton ! . simulate ( 'click' ) ;
683
- await sleep ( 100 ) ;
684
- assert . equal ( exportCalled , false , 'Export should not be called when no cells visible' ) ;
707
+ // Then verify we cannot click the button (it should be disabled)
708
+ exportCalled = false ;
709
+ exportButton ! . simulate ( 'click' ) ;
710
+ await sleep ( 100 ) ;
711
+ assert . equal ( exportCalled , false , 'Export should not be called when no cells visible' ) ;
712
+ } finally {
713
+ tf . dispose ( ) ;
714
+ }
685
715
} ,
686
716
( ) => {
687
717
return ioc ;
0 commit comments