@@ -511,7 +511,7 @@ namespace FourSlash {
511
511
}
512
512
}
513
513
514
- private raiseError ( message : string ) {
514
+ private raiseError ( message : string ) : never {
515
515
throw new Error ( this . messageAtLastKnownMarker ( message ) ) ;
516
516
}
517
517
@@ -848,10 +848,10 @@ namespace FourSlash {
848
848
}
849
849
}
850
850
851
- public verifyCompletionsAt ( markerName : string , expected : string [ ] , options ?: FourSlashInterface . CompletionsAtOptions ) {
851
+ public verifyCompletionsAt ( markerName : string , expected : ReadonlyArray < FourSlashInterface . ExpectedCompletionEntry > , options ?: FourSlashInterface . CompletionsAtOptions ) {
852
852
this . goToMarker ( markerName ) ;
853
853
854
- const actualCompletions = this . getCompletionListAtCaret ( ) ;
854
+ const actualCompletions = this . getCompletionListAtCaret ( options ) ;
855
855
if ( ! actualCompletions ) {
856
856
this . raiseError ( `No completions at position '${ this . currentCaretPosition } '.` ) ;
857
857
}
@@ -867,9 +867,20 @@ namespace FourSlash {
867
867
}
868
868
869
869
ts . zipWith ( actual , expected , ( completion , expectedCompletion , index ) => {
870
- if ( completion . name !== expectedCompletion ) {
870
+ const { name, insertText, replacementSpan } = typeof expectedCompletion === "string" ? { name : expectedCompletion , insertText : undefined , replacementSpan : undefined } : expectedCompletion ;
871
+ if ( completion . name !== name ) {
871
872
this . raiseError ( `Expected completion at index ${ index } to be ${ expectedCompletion } , got ${ completion . name } ` ) ;
872
873
}
874
+ if ( completion . insertText !== insertText ) {
875
+ this . raiseError ( `Expected completion insert text at index ${ index } to be ${ insertText } , got ${ completion . insertText } ` ) ;
876
+ }
877
+ const convertedReplacementSpan = replacementSpan && textSpanFromRange ( replacementSpan ) ;
878
+ try {
879
+ assert . deepEqual ( completion . replacementSpan , convertedReplacementSpan ) ;
880
+ }
881
+ catch {
882
+ this . raiseError ( `Expected completion replacementSpan at index ${ index } to be ${ stringify ( convertedReplacementSpan ) } , got ${ stringify ( completion . replacementSpan ) } ` ) ;
883
+ }
873
884
} ) ;
874
885
}
875
886
@@ -1808,7 +1819,7 @@ Actual: ${stringify(fullActual)}`);
1808
1819
}
1809
1820
else if ( prevChar === " " && / A - Z a - z _ / . test ( ch ) ) {
1810
1821
/* Completions */
1811
- this . languageService . getCompletionsAtPosition ( this . activeFile . fileName , offset , { includeExternalModuleExports : false } ) ;
1822
+ this . languageService . getCompletionsAtPosition ( this . activeFile . fileName , offset , { includeExternalModuleExports : false , includeInsertTextCompletions : false } ) ;
1812
1823
}
1813
1824
1814
1825
if ( i % checkCadence === 0 ) {
@@ -2383,7 +2394,8 @@ Actual: ${stringify(fullActual)}`);
2383
2394
public applyCodeActionFromCompletion ( markerName : string , options : FourSlashInterface . VerifyCompletionActionOptions ) {
2384
2395
this . goToMarker ( markerName ) ;
2385
2396
2386
- const actualCompletion = this . getCompletionListAtCaret ( { includeExternalModuleExports : true } ) . entries . find ( e => e . name === options . name && e . source === options . source ) ;
2397
+ const actualCompletion = this . getCompletionListAtCaret ( { includeExternalModuleExports : true , includeInsertTextCompletions : false } ) . entries . find ( e =>
2398
+ e . name === options . name && e . source === options . source ) ;
2387
2399
2388
2400
if ( ! actualCompletion . hasAction ) {
2389
2401
this . raiseError ( `Completion for ${ options . name } does not have an associated action.` ) ;
@@ -3195,8 +3207,7 @@ Actual: ${stringify(fullActual)}`);
3195
3207
private getTextSpanForRangeAtIndex ( index : number ) : ts . TextSpan {
3196
3208
const ranges = this . getRanges ( ) ;
3197
3209
if ( ranges && ranges . length > index ) {
3198
- const range = ranges [ index ] ;
3199
- return { start : range . start , length : range . end - range . start } ;
3210
+ return textSpanFromRange ( ranges [ index ] ) ;
3200
3211
}
3201
3212
else {
3202
3213
this . raiseError ( "Supplied span index: " + index + " does not exist in range list of size: " + ( ranges ? 0 : ranges . length ) ) ;
@@ -3226,6 +3237,10 @@ Actual: ${stringify(fullActual)}`);
3226
3237
}
3227
3238
}
3228
3239
3240
+ function textSpanFromRange ( range : FourSlash . Range ) : ts . TextSpan {
3241
+ return ts . createTextSpanFromBounds ( range . start , range . end ) ;
3242
+ }
3243
+
3229
3244
export function runFourSlashTest ( basePath : string , testType : FourSlashTestType , fileName : string ) {
3230
3245
const content = Harness . IO . readFile ( fileName ) ;
3231
3246
runFourSlashTestContent ( basePath , testType , content , fileName ) ;
@@ -3967,7 +3982,7 @@ namespace FourSlashInterface {
3967
3982
super ( state ) ;
3968
3983
}
3969
3984
3970
- public completionsAt ( markerName : string , completions : string [ ] , options ?: CompletionsAtOptions ) {
3985
+ public completionsAt ( markerName : string , completions : ReadonlyArray < ExpectedCompletionEntry > , options ?: CompletionsAtOptions ) {
3971
3986
this . state . verifyCompletionsAt ( markerName , completions , options ) ;
3972
3987
}
3973
3988
@@ -4591,6 +4606,7 @@ namespace FourSlashInterface {
4591
4606
newContent : string ;
4592
4607
}
4593
4608
4609
+ export type ExpectedCompletionEntry = string | { name : string , insertText ?: string , replacementSpan ?: FourSlash . Range } ;
4594
4610
export interface CompletionsAtOptions extends ts . GetCompletionsAtPositionOptions {
4595
4611
isNewIdentifierLocation ?: boolean ;
4596
4612
}
0 commit comments