55/* eslint-disable @typescript-eslint/no-explicit-any */
66import * as TypeMoq from 'typemoq' ;
77import * as sinon from 'sinon' ;
8+ import { reset , when } from 'ts-mockito' ;
9+ import * as vscode from 'vscode' ;
810import { Disposable , EventEmitter , NotebookDocument , Uri } from 'vscode' ;
911import { expect } from 'chai' ;
1012
@@ -16,6 +18,7 @@ import * as PythonServer from '../../client/repl/pythonServer';
1618import * as vscodeWorkspaceApis from '../../client/common/vscodeApis/workspaceApis' ;
1719import * as replController from '../../client/repl/replController' ;
1820import { executeCommand } from '../../client/common/vscodeApis/commandApis' ;
21+ import { mockedVSCodeNamespaces } from '../vscode-mock' ;
1922
2023suite ( 'REPL - Native REPL' , ( ) => {
2124 let interpreterService : TypeMoq . IMock < IInterpreterService > ;
@@ -114,6 +117,66 @@ suite('REPL - Native REPL', () => {
114117 expect ( createReplControllerStub . calledOnce ) . to . be . true ;
115118 } ) ;
116119
120+ test ( 'createReplController should publish stdout notebook output for REPL execution' , async ( ) => {
121+ const mockServer = {
122+ interrupt : sinon . stub ( ) ,
123+ execute : sinon . stub ( ) . resolves ( { status : true , output : 'hello\nworld' } ) ,
124+ dispose : sinon . stub ( ) ,
125+ } as any ;
126+ const createPythonServerStub = sinon . stub ( PythonServer , 'createPythonServer' ) . returns ( mockServer as any ) ;
127+
128+ const replaceOutputStub = sinon . stub ( ) ;
129+ const execStub = {
130+ start : sinon . stub ( ) ,
131+ replaceOutput : replaceOutputStub ,
132+ end : sinon . stub ( ) ,
133+ } as any ;
134+
135+ const createNotebookCellExecutionStub = sinon . stub ( ) . returns ( execStub ) ;
136+ const mockNotebookController = {
137+ id : 'mockController' ,
138+ dispose : sinon . stub ( ) ,
139+ updateNotebookAffinity : sinon . stub ( ) ,
140+ createNotebookCellExecution : createNotebookCellExecutionStub ,
141+ supportedLanguages : [ ] as string [ ] ,
142+ description : '' ,
143+ interruptHandler : undefined ,
144+ executeHandler : undefined ,
145+ } as any as vscode . NotebookController ;
146+
147+ when ( mockedVSCodeNamespaces . notebooks ! . createNotebookController ( 'pythonREPL' , 'jupyter-notebook' , 'Python REPL' ) ) . thenReturn (
148+ mockNotebookController ,
149+ ) ;
150+ createReplControllerStub . restore ( ) ;
151+
152+ const disposables : Disposable [ ] = [ ] ;
153+ try {
154+ const controller = replController . createReplController ( 'python' , disposables , '/cwd' ) ;
155+
156+ const mockTextDocument = { getText : sinon . stub ( ) . returns ( 'print("hi")' ) } as any ;
157+ const mockCell = { document : mockTextDocument } as any ;
158+ await ( controller . executeHandler as any ) ( [ mockCell ] ) ;
159+
160+ expect ( createPythonServerStub . calledOnce ) . to . be . true ;
161+ expect ( mockServer . execute . calledOnceWithExactly ( 'print("hi")' ) ) . to . be . true ;
162+ expect ( createNotebookCellExecutionStub . calledOnce ) . to . be . true ;
163+ expect ( replaceOutputStub . calledOnce ) . to . be . true ;
164+
165+ const outputs = replaceOutputStub . firstCall . args [ 0 ] as vscode . NotebookCellOutput [ ] ;
166+ expect ( outputs ) . to . have . lengthOf ( 1 ) ;
167+ const output = outputs [ 0 ] ;
168+ expect ( output . items ) . to . have . lengthOf ( 1 ) ;
169+ expect ( output . items [ 0 ] . mime ) . to . equal ( 'application/vnd.code.notebook.stdout' ) ;
170+ expect ( ( output . items [ 0 ] as any ) . metadata ) . to . deep . equal ( { scrollable : false } ) ;
171+ expect ( output . metadata ) . to . deep . equal ( { scrollable : false } ) ;
172+ const outputText = Buffer . from ( ( output . items [ 0 ] as any ) . data ) . toString ( ) ;
173+ expect ( outputText ) . to . equal ( 'hello\nworld' ) ;
174+ } finally {
175+ disposables . forEach ( ( disposable ) => disposable . dispose ( ) ) ;
176+ reset ( mockedVSCodeNamespaces . notebooks ! ) ;
177+ }
178+ } ) ;
179+
117180 test ( 'watchNotebookClosed should clean up resources when notebook is closed' , async ( ) => {
118181 const notebookCloseEmitter = new EventEmitter < NotebookDocument > ( ) ;
119182 sinon . stub ( vscodeWorkspaceApis , 'onDidCloseNotebookDocument' ) . callsFake ( ( handler ) => {
0 commit comments