1-
2- import { createEditor , monaco , registerEditorOpenHandler } from '@codingame/monaco-editor-wrapper'
1+ import { createEditor , initializePromise , monaco , registerEditorOpenHandler } from '@codingame/monaco-editor-wrapper'
32import { CompletionTriggerKind , ServerCapabilities , TextDocumentSyncKind , Range } from 'vscode-languageserver-protocol'
43import {
54 _Connection ,
65 _
76} from 'vscode-languageserver/lib/common/api'
7+ import { createModelReference } from 'vscode/monaco'
8+ import * as vscode from 'vscode'
9+ import { RegisteredFileSystemProvider , RegisteredMemoryFile , registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'
10+ import { ExtensionHostKind , registerExtension } from 'vscode/extensions'
811import pDefer , { TestInfrastructure , waitClientNotification , waitClientRequest } from './tools'
9- import { GetTextDocumentParams , getTextDocumentRequestType , GetTextDocumentResult , SaveTextDocumentParams , saveTextDocumentRequestType } from '../customRequests'
10- import { createLanguageClientManager , LanguageClientId , LanguageClientManager , getLanguageClientOptions } from '..'
12+ import { GetTextDocumentParams , getTextDocumentRequestType , GetTextDocumentResult , saveTextDocumentRequestType } from '../customRequests'
13+ import { createLanguageClientManager , LanguageClientManager , getLanguageClientOptions , StaticLanguageClientId } from '..'
1114
1215async function initializeLanguageClientAndGetConnection (
13- languageClientId : LanguageClientId ,
16+ languageClientId : StaticLanguageClientId ,
1417 capabilities : ServerCapabilities < unknown > ,
1518 automaticTextDocumentUpdate : boolean = false ,
1619 useMutualizedProxy : boolean = false
@@ -73,16 +76,26 @@ async function testLanguageClient (
7376 await initializedNotifPromise
7477
7578 // Creating a java model which will be open in the language client
76- const model = monaco . editor . createModel ( 'public class Toto {}' , 'java' , monaco . Uri . file ( '/tmp/project/src/main/Toto.java' ) )
79+ const mainFileUri = monaco . Uri . file ( '/tmp/project/src/main/Toto.java' )
80+ const fs = new RegisteredFileSystemProvider ( false )
81+ const fileContent = 'public class Toto {}'
82+
83+ fs . registerFile ( new RegisteredMemoryFile ( mainFileUri , fileContent ) )
84+ const fileSystemDisposable = registerFileSystemOverlay ( 1 , fs )
7785
78- const editor = createEditor ( document . createElement ( 'div' ) , {
86+ const modelRef = await createModelReference ( mainFileUri )
87+ const model = modelRef . object . textEditorModel !
88+
89+ const el = document . createElement ( 'div' )
90+ document . body . append ( el )
91+ const editor = createEditor ( el , {
7992 model
8093 } )
8194
8295 // Expect the model to be open
8396 expect ( await waitClientNotification ( connection . onDidOpenTextDocument ) ) . toEqual ( {
8497 textDocument : {
85- uri : 'file:///tmp/project/src/main/Toto.java' ,
98+ uri : mainFileUri . toString ( ) ,
8699 languageId : 'java' ,
87100 version : 1 ,
88101 text : 'public class Toto {}'
@@ -103,7 +116,7 @@ async function testLanguageClient (
103116 // ... and expect the changed to be sent to the server
104117 expect ( await waitClientNotification ( connection . onDidChangeTextDocument ) ) . toEqual ( {
105118 textDocument : {
106- uri : 'file:///tmp/project/src/main/Toto.java' ,
119+ uri : mainFileUri . toString ( ) ,
107120 version : 2
108121 } ,
109122 contentChanges : [ {
@@ -116,29 +129,18 @@ async function testLanguageClient (
116129 } ]
117130 } )
118131
119- if ( ! automaticTextDocumentUpdate ) {
120- // expect the document to being saved after 500ms
121- await Promise . all ( [
122- waitClientNotification ( connection . onWillSaveTextDocument ) ,
123- waitClientRequest < SaveTextDocumentParams , void , never > ( handler => connection . onRequest ( saveTextDocumentRequestType , handler ) ) . then ( ( [ params , sendResponse ] ) => {
124- sendResponse ( )
125- return params
126- } ) ,
127- waitClientNotification ( connection . onDidSaveTextDocument )
128- ] )
129- } else {
130- // wait 1sec to be sure no request is sent during this interval
131- await new Promise ( resolve => setTimeout ( resolve , 1000 ) )
132- }
132+ // wait 1sec to be sure no request is sent during this interval
133+ await new Promise ( resolve => setTimeout ( resolve , 1000 ) )
133134
134135 // Test a completion request
135136 const completionRequestPromise = waitClientRequest ( connection . onCompletion )
136137 editor . setPosition ( new monaco . Position ( 1 , 20 ) )
137138 editor . trigger ( 'me' , 'editor.action.triggerSuggest' , { } )
139+ editor . focus ( )
138140
139141 const [ completionRequest , sendCompletionRequestResponse ] = await completionRequestPromise
140142 expect ( completionRequest ) . toEqual ( {
141- textDocument : { uri : 'file:///tmp/project/src/main/Toto.java' } ,
143+ textDocument : { uri : mainFileUri . toString ( ) } ,
142144 position : { line : 0 , character : 19 } ,
143145 context : {
144146 triggerKind : CompletionTriggerKind . Invoked ,
@@ -149,13 +151,14 @@ async function testLanguageClient (
149151
150152 // Test a hover request
151153 const hoverRequestPromise = waitClientRequest ( connection . onHover )
152- await editor . getAction ( 'editor.action.showHover' ) . run ( )
154+ await editor . getAction ( 'editor.action.showHover' ) ! . run ( )
153155 const [ , sendHoverRequestResponse ] = await hoverRequestPromise
154156 sendHoverRequestResponse ( null )
155157
156158 // Test go to declaration + getTextDocument
157159 const definitionRequestPromise = waitClientRequest ( connection . onDefinition )
158- editor . getAction ( 'editor.action.revealDefinition' ) . run ( ) . catch ( console . error )
160+
161+ void vscode . commands . executeCommand ( 'editor.action.revealDefinition' )
159162
160163 const [ , sendDefinitionRequestResponse ] = await definitionRequestPromise
161164 sendDefinitionRequestResponse ( {
@@ -164,13 +167,13 @@ async function testLanguageClient (
164167 } )
165168
166169 const editorOpenDeferred = pDefer < monaco . editor . IStandaloneCodeEditor > ( )
167- const editorHandlerDisposable = registerEditorOpenHandler ( async ( model ) => {
170+ const editorHandlerDisposable = registerEditorOpenHandler ( async ( modelRef ) => {
168171 // do nothing
169172 const editor = createEditor ( document . createElement ( 'div' ) , {
170- model
173+ model : modelRef . object . textEditorModel
171174 } )
172175 editor . onDidDispose ( ( ) => {
173- model . dispose ( )
176+ modelRef . dispose ( )
174177 } )
175178 setTimeout ( ( ) => {
176179 editorOpenDeferred . resolve ( editor )
@@ -185,12 +188,15 @@ async function testLanguageClient (
185188 uri : 'file:///tmp/project/src/main/Otherfile.java'
186189 }
187190 } )
191+
192+ const openNotificationPromise = waitClientNotification ( connection . onDidOpenTextDocument )
193+
188194 sendGetDocumentRequestResponse ( {
189195 text : 'other file content'
190196 } )
191197
192198 // Expect the model to be open
193- expect ( await waitClientNotification ( connection . onDidOpenTextDocument ) ) . toEqual ( {
199+ expect ( await openNotificationPromise ) . toEqual ( {
194200 textDocument : {
195201 uri : 'file:///tmp/project/src/main/Otherfile.java' ,
196202 languageId : 'java' ,
@@ -209,16 +215,48 @@ async function testLanguageClient (
209215 }
210216 } )
211217
218+ const savePromise = modelRef . object . save ( )
219+
220+ // Expect the model to be saved
221+ const willSavePromise = waitClientNotification ( connection . onWillSaveTextDocument )
222+ const saveRequestPromise = waitClientRequest ( handler => connection . onRequest ( saveTextDocumentRequestType , handler ) )
223+ const didSavePromise = waitClientNotification ( connection . onDidSaveTextDocument )
224+
225+ expect ( await willSavePromise ) . toEqual ( {
226+ textDocument : {
227+ uri : mainFileUri . toString ( )
228+ } ,
229+ reason : vscode . TextDocumentSaveReason . Manual
230+ } )
231+ const [ saveRequest , sendSaveRequestResponse ] = await saveRequestPromise
232+ expect ( await saveRequest ) . toEqual ( {
233+ textDocument : {
234+ uri : mainFileUri . toString ( ) ,
235+ text : modelRef . object . textEditorModel ! . getValue ( )
236+ }
237+ } )
238+ sendSaveRequestResponse ( null )
239+
240+ expect ( await didSavePromise ) . toEqual ( {
241+ textDocument : {
242+ uri : mainFileUri . toString ( )
243+ }
244+ } )
245+
246+ await savePromise
247+
212248 editor . dispose ( )
213- model . dispose ( )
249+ modelRef . dispose ( )
214250
215251 // Expect the model to be closed
216252 expect ( await waitClientNotification ( connection . onDidCloseTextDocument ) ) . toEqual ( {
217253 textDocument : {
218- uri : 'file:///tmp/project/src/main/Toto.java'
254+ uri : mainFileUri . toString ( )
219255 }
220256 } )
221257
258+ fileSystemDisposable . dispose ( )
259+
222260 const disposePromise = languageClient . dispose ( )
223261
224262 const [ , sendShutdownResponse ] = await waitClientRequest < void , void , void > ( ( handler ) => connection . onShutdown ( ( token ) => handler ( undefined , token ) ) )
@@ -232,6 +270,31 @@ async function testLanguageClient (
232270 expect ( onRemainingNotification ) . not . toHaveBeenCalled ( )
233271}
234272
273+ beforeAll ( async ( ) => {
274+ await initializePromise
275+
276+ // wait for java vscode extension to be ready as we use it to test the configuration update
277+ const { getApi } = registerExtension ( {
278+ name : 'test' ,
279+ publisher : 'codingame' ,
280+ version : '1.0.0' ,
281+ engines : {
282+ vscode : '*'
283+ } ,
284+ enabledApiProposals : [ 'extensionsAny' ]
285+ } , ExtensionHostKind . LocalProcess )
286+ const api = await getApi ( )
287+
288+ await new Promise < void > ( ( resolve ) => {
289+ const disposable = vscode . extensions . onDidChange ( ( ) => {
290+ if ( api . extensions . allAcrossExtensionHosts . some ( ext => ext . id === 'redhat.java' ) ) {
291+ disposable . dispose ( )
292+ resolve ( )
293+ }
294+ } )
295+ } )
296+ } )
297+
235298describe ( 'Infrastructure' , ( ) => {
236299 test ( 'Codingame behavior without mutualization' , async ( ) => {
237300 await testLanguageClient ( false , false )
0 commit comments