Skip to content

Commit 752111d

Browse files
author
Loïc Mangeonjean
committed
fix: fix tests
1 parent 1b257c3 commit 752111d

File tree

6 files changed

+140
-42
lines changed

6 files changed

+140
-42
lines changed

FixJSDOMEnvironment.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const JSDOMEnvironment = require('jest-environment-jsdom').default
2+
3+
4+
class FixJSDOMEnvironment extends JSDOMEnvironment {
5+
constructor(...args) {
6+
super(...args);
7+
8+
// FIXME https://github.com/jsdom/jsdom/issues/3363
9+
this.global.structuredClone = structuredClone;
10+
}
11+
}
12+
13+
// https://github.com/facebook/jest/blob/v29.4.3/website/versioned_docs/version-29.4/Configuration.md#testenvironment-string
14+
module.exports = FixJSDOMEnvironment

babel.test.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ module.exports = {
22
plugins: [
33
["@babel/plugin-transform-modules-commonjs", {
44
importInterop: 'babel'
5-
}]
5+
}],
6+
"babel-plugin-transform-import-meta"
67
],
78
presets: [
89
"@babel/preset-env",

browserMock.js

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
const fs = require('fs/promises')
2+
const { performance } = require('perf_hooks')
3+
const path = require('path')
24

35
Object.defineProperty(document, 'queryCommandSupported', {
46
value: jest.fn().mockImplementation(() => true),
@@ -19,20 +21,19 @@ Object.defineProperty(window, 'matchMedia', {
1921
});
2022

2123
Object.defineProperty(window, 'fetch', {
22-
value: jest.fn(async (path) => {
23-
24-
const content = await fs.readFile(path)
24+
value: jest.fn(async (url) => {
25+
const content = await fs.readFile(new URL(url).pathname)
2526
return {
2627
json: async () => JSON.stringify(JSON.parse(content.toString())),
27-
arrayBuffer: async () => content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength)
28+
arrayBuffer: async () => content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength),
29+
status: 200
2830
}
2931
})
3032
})
3133

3234
Object.defineProperty(URL, 'createObjectURL', {
3335
value: jest.fn((blob) => {
34-
35-
return null
36+
return 'blob:not-working'
3637
})
3738
})
3839

@@ -90,6 +91,9 @@ Object.defineProperty(window, 'TextEncoder', {
9091
Object.defineProperty(window, 'TextDecoder', {
9192
value: class TextDecoder {
9293
decode (octets) {
94+
if (octets == null) {
95+
return ''
96+
}
9397
var string = "";
9498
var i = 0;
9599
while (i < octets.length) {
@@ -130,4 +134,19 @@ Object.defineProperty(window, 'TextDecoder', {
130134

131135
Object.defineProperty(window, 'Buffer', {
132136
value: undefined
133-
})
137+
})
138+
139+
// Force override performance, for some reason the implementation is empty otherwise
140+
let _performance = performance
141+
Object.defineProperty(global, 'performance', {
142+
get () { return _performance },
143+
set (v) {
144+
// ignore
145+
}
146+
})
147+
148+
global.CSS = {
149+
escape: v => v
150+
}
151+
152+
Element.prototype.scrollIntoView = jest.fn();

jest/onig.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = "vscode-oniguruma/release/onig.wasm"
1+
module.exports = "node_modules/vscode-oniguruma/release/onig.wasm"

src/tests/infrastructure.test.ts

Lines changed: 95 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
2-
import { createEditor, monaco, registerEditorOpenHandler } from '@codingame/monaco-editor-wrapper'
1+
import { createEditor, initializePromise, monaco, registerEditorOpenHandler } from '@codingame/monaco-editor-wrapper'
32
import { CompletionTriggerKind, ServerCapabilities, TextDocumentSyncKind, Range } from 'vscode-languageserver-protocol'
43
import {
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'
811
import 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

1215
async 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+
235298
describe('Infrastructure', () => {
236299
test('Codingame behavior without mutualization', async () => {
237300
await testLanguageClient(false, false)

src/tests/lifecycle.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
1+
import { whenReady } from '@codingame/monaco-vscode-java-default-extension'
22
import { TestInfrastructure } from './tools'
33
import { createLanguageClientManager, getLanguageClientOptions } from '..'
44

55
describe('Lifecycle', () => {
66
test('Can dispose the language client manager immediately', async () => {
77
const infrastructure = new TestInfrastructure(false, false, 2000)
8+
await whenReady()
89

910
const languageClient = createLanguageClientManager('java', infrastructure, {
1011
...getLanguageClientOptions('java'),

0 commit comments

Comments
 (0)