@@ -6,7 +6,12 @@ import * as path from 'path';
66import { SemVer } from 'semver' ;
77import * as TypeMoq from 'typemoq' ;
88import { Disposable , Uri , WorkspaceFolder } from 'vscode' ;
9- import { ICommandManager , IDocumentManager , IWorkspaceService } from '../../../client/common/application/types' ;
9+ import {
10+ IApplicationShell ,
11+ ICommandManager ,
12+ IDocumentManager ,
13+ IWorkspaceService ,
14+ } from '../../../client/common/application/types' ;
1015import { IFileSystem , IPlatformService } from '../../../client/common/platform/types' ;
1116import { createCondaEnv } from '../../../client/common/process/pythonEnvironment' ;
1217import { createPythonProcessService } from '../../../client/common/process/pythonProcess' ;
@@ -47,6 +52,7 @@ suite('Terminal - Code Execution', () => {
4752 let pythonExecutionFactory : TypeMoq . IMock < IPythonExecutionFactory > ;
4853 let interpreterService : TypeMoq . IMock < IInterpreterService > ;
4954 let isDjangoRepl : boolean ;
55+ let applicationShell : TypeMoq . IMock < IApplicationShell > ;
5056
5157 teardown ( ( ) => {
5258 disposables . forEach ( ( disposable ) => {
@@ -71,6 +77,7 @@ suite('Terminal - Code Execution', () => {
7177 fileSystem = TypeMoq . Mock . ofType < IFileSystem > ( ) ;
7278 pythonExecutionFactory = TypeMoq . Mock . ofType < IPythonExecutionFactory > ( ) ;
7379 interpreterService = TypeMoq . Mock . ofType < IInterpreterService > ( ) ;
80+ applicationShell = TypeMoq . Mock . ofType < IApplicationShell > ( ) ;
7481 settings = TypeMoq . Mock . ofType < IPythonSettings > ( ) ;
7582 settings . setup ( ( s ) => s . terminal ) . returns ( ( ) => terminalSettings . object ) ;
7683 configService . setup ( ( c ) => c . getSettings ( TypeMoq . It . isAny ( ) ) ) . returns ( ( ) => settings . object ) ;
@@ -85,6 +92,7 @@ suite('Terminal - Code Execution', () => {
8592 platform . object ,
8693 interpreterService . object ,
8794 commandManager . object ,
95+ applicationShell . object ,
8896 ) ;
8997 break ;
9098 }
@@ -97,6 +105,7 @@ suite('Terminal - Code Execution', () => {
97105 platform . object ,
98106 interpreterService . object ,
99107 commandManager . object ,
108+ applicationShell . object ,
100109 ) ;
101110 expectedTerminalTitle = 'REPL' ;
102111 break ;
@@ -120,6 +129,7 @@ suite('Terminal - Code Execution', () => {
120129 fileSystem . object ,
121130 disposables ,
122131 interpreterService . object ,
132+ applicationShell . object ,
123133 ) ;
124134 expectedTerminalTitle = 'Django Shell' ;
125135 break ;
@@ -590,7 +600,7 @@ suite('Terminal - Code Execution', () => {
590600 ) ;
591601 } ) ;
592602
593- test ( 'Ensure repl is re-initialized when terminal is closed ' , async ( ) => {
603+ test ( 'Ensure REPL launches after reducing risk of command being ignored or duplicated ' , async ( ) => {
594604 const pythonPath = 'usr/bin/python1234' ;
595605 const terminalArgs = [ '-a' , 'b' , 'c' ] ;
596606 platform . setup ( ( p ) => p . isWindows ) . returns ( ( ) => false ) ;
@@ -599,43 +609,27 @@ suite('Terminal - Code Execution', () => {
599609 . returns ( ( ) => Promise . resolve ( ( { path : pythonPath } as unknown ) as PythonEnvironment ) ) ;
600610 terminalSettings . setup ( ( t ) => t . launchArgs ) . returns ( ( ) => terminalArgs ) ;
601611
602- let closeTerminalCallback : undefined | ( ( ) => void ) ;
603- terminalService
604- . setup ( ( t ) => t . onDidCloseTerminal ( TypeMoq . It . isAny ( ) , TypeMoq . It . isAny ( ) , TypeMoq . It . isAny ( ) ) )
605- . returns ( ( callback ) => {
606- closeTerminalCallback = callback ;
607- return {
608- dispose : noop ,
609- } ;
610- } ) ;
611-
612612 await executor . execute ( 'cmd1' ) ;
613613 await executor . execute ( 'cmd2' ) ;
614614 await executor . execute ( 'cmd3' ) ;
615615
616- const expectedTerminalArgs = isDjangoRepl ? terminalArgs . concat ( [ 'manage.py' , 'shell' ] ) : terminalArgs ;
617-
618- expect ( closeTerminalCallback ) . not . to . be . an ( 'undefined' , 'Callback not initialized' ) ;
619- terminalService . verify (
620- async ( t ) =>
621- t . sendCommand ( TypeMoq . It . isValue ( pythonPath ) , TypeMoq . It . isValue ( expectedTerminalArgs ) ) ,
622- TypeMoq . Times . once ( ) ,
616+ // Now check if sendCommand from the initializeRepl is called atLeastOnce.
617+ // This is due to newly added Promise race and fallback to lower risk of swollen first command.
618+ applicationShell . verify (
619+ async ( t ) => t . onDidWriteTerminalData ( TypeMoq . It . isAny ( ) , TypeMoq . It . isAny ( ) ) ,
620+ TypeMoq . Times . atLeastOnce ( ) ,
623621 ) ;
624622
625- closeTerminalCallback ! . call ( terminalService . object ) ;
626623 await executor . execute ( 'cmd4' ) ;
627- terminalService . verify (
628- async ( t ) =>
629- t . sendCommand ( TypeMoq . It . isValue ( pythonPath ) , TypeMoq . It . isValue ( expectedTerminalArgs ) ) ,
630- TypeMoq . Times . exactly ( 2 ) ,
624+ applicationShell . verify (
625+ async ( t ) => t . onDidWriteTerminalData ( TypeMoq . It . isAny ( ) , TypeMoq . It . isAny ( ) ) ,
626+ TypeMoq . Times . atLeastOnce ( ) ,
631627 ) ;
632628
633- closeTerminalCallback ! . call ( terminalService . object ) ;
634629 await executor . execute ( 'cmd5' ) ;
635- terminalService . verify (
636- async ( t ) =>
637- t . sendCommand ( TypeMoq . It . isValue ( pythonPath ) , TypeMoq . It . isValue ( expectedTerminalArgs ) ) ,
638- TypeMoq . Times . exactly ( 3 ) ,
630+ applicationShell . verify (
631+ async ( t ) => t . onDidWriteTerminalData ( TypeMoq . It . isAny ( ) , TypeMoq . It . isAny ( ) ) ,
632+ TypeMoq . Times . atLeastOnce ( ) ,
639633 ) ;
640634 } ) ;
641635
0 commit comments