@@ -15,10 +15,12 @@ import {
15
15
} from 'vscode-languageserver-protocol'
16
16
import type { ClientCapabilities , ProtocolConnection } from 'vscode-languageclient'
17
17
import type { Feature } from '@tailwindcss/language-service/src/features'
18
+ import { CacheMap } from '../src/cache-map'
18
19
19
20
type Settings = any
20
21
21
- interface FixtureContext extends Pick < ProtocolConnection , 'sendRequest' | 'onNotification' > {
22
+ interface FixtureContext
23
+ extends Pick < ProtocolConnection , 'sendRequest' | 'sendNotification' | 'onNotification' > {
22
24
client : ProtocolConnection
23
25
openDocument : ( params : {
24
26
text : string
@@ -28,6 +30,7 @@ interface FixtureContext extends Pick<ProtocolConnection, 'sendRequest' | 'onNot
28
30
} ) => Promise < { uri : string ; updateSettings : ( settings : Settings ) => Promise < void > } >
29
31
updateSettings : ( settings : Settings ) => Promise < void >
30
32
updateFile : ( file : string , text : string ) => Promise < void >
33
+ fixtureUri ( fixture : string ) : string
31
34
32
35
readonly project : {
33
36
config : string
@@ -39,7 +42,7 @@ interface FixtureContext extends Pick<ProtocolConnection, 'sendRequest' | 'onNot
39
42
}
40
43
}
41
44
42
- async function init ( fixture : string ) : Promise < FixtureContext > {
45
+ async function init ( fixture : string | string [ ] ) : Promise < FixtureContext > {
43
46
let settings = { }
44
47
let docSettings = new Map < string , Settings > ( )
45
48
@@ -125,13 +128,34 @@ async function init(fixture: string): Promise<FixtureContext> {
125
128
} ,
126
129
}
127
130
131
+ const fixtures = Array . isArray ( fixture ) ? fixture : [ fixture ]
132
+
133
+ function fixtureUri ( fixture : string ) {
134
+ return `file://${ path . resolve ( './tests/fixtures' , fixture ) } `
135
+ }
136
+
137
+ function resolveUri ( ...parts : string [ ] ) {
138
+ const filepath =
139
+ fixtures . length > 1
140
+ ? path . resolve ( './tests/fixtures' , ...parts )
141
+ : path . resolve ( './tests/fixtures' , fixtures [ 0 ] , ...parts )
142
+
143
+ return `file://${ filepath } `
144
+ }
145
+
146
+ const workspaceFolders = fixtures . map ( ( fixture ) => ( {
147
+ name : `Fixture ${ fixture } ` ,
148
+ uri : fixtureUri ( fixture ) ,
149
+ } ) )
150
+
151
+ const rootUri = fixtures . length > 1 ? null : workspaceFolders [ 0 ] . uri
152
+
128
153
await client . sendRequest ( InitializeRequest . type , {
129
154
processId : - 1 ,
130
- // rootPath: '.',
131
- rootUri : `file://${ path . resolve ( './tests/fixtures/' , fixture ) } ` ,
155
+ rootUri,
132
156
capabilities,
133
157
trace : 'off' ,
134
- workspaceFolders : [ ] ,
158
+ workspaceFolders,
135
159
initializationOptions : {
136
160
testMode : true ,
137
161
} ,
@@ -158,23 +182,38 @@ async function init(fixture: string): Promise<FixtureContext> {
158
182
} )
159
183
} )
160
184
185
+ interface PromiseWithResolvers < T > extends Promise < T > {
186
+ resolve : ( value ?: T | PromiseLike < T > ) => void
187
+ reject : ( reason ?: any ) => void
188
+ }
189
+
190
+ let openingDocuments = new CacheMap < string , PromiseWithResolvers < void > > ( )
161
191
let projectDetails : any = null
162
192
163
- client . onNotification ( 'tailwind /projectDetails' , ( params ) => {
193
+ client . onNotification ( '@/tailwindCSS /projectDetails' , ( params ) => {
164
194
console . log ( '[TEST] Project detailed changed' )
165
195
projectDetails = params
166
196
} )
167
197
198
+ client . onNotification ( '@/tailwindCSS/documentReady' , ( params ) => {
199
+ console . log ( '[TEST] Document ready' , params . uri )
200
+ openingDocuments . get ( params . uri ) ?. resolve ( )
201
+ } )
202
+
168
203
let counter = 0
169
204
170
205
return {
171
206
client,
207
+ fixtureUri,
172
208
get project ( ) {
173
209
return projectDetails
174
210
} ,
175
211
sendRequest ( type : any , params : any ) {
176
212
return client . sendRequest ( type , params )
177
213
} ,
214
+ sendNotification ( type : any , params ?: any ) {
215
+ return client . sendNotification ( type , params )
216
+ } ,
178
217
onNotification ( type : any , callback : any ) {
179
218
return client . onNotification ( type , callback )
180
219
} ,
@@ -189,9 +228,24 @@ async function init(fixture: string): Promise<FixtureContext> {
189
228
dir ?: string
190
229
settings ?: Settings
191
230
} ) {
192
- let uri = `file:// ${ path . resolve ( './tests/fixtures' , fixture , dir , `file-${ counter ++ } ` ) } `
231
+ let uri = resolveUri ( dir , `file-${ counter ++ } ` )
193
232
docSettings . set ( uri , settings )
194
233
234
+ let openPromise = openingDocuments . remember ( uri , ( ) => {
235
+ let resolve = ( ) => { }
236
+ let reject = ( ) => { }
237
+
238
+ let p = new Promise < void > ( ( _resolve , _reject ) => {
239
+ resolve = _resolve
240
+ reject = _reject
241
+ } )
242
+
243
+ return Object . assign ( p , {
244
+ resolve,
245
+ reject,
246
+ } )
247
+ } )
248
+
195
249
await client . sendNotification ( DidOpenTextDocumentNotification . type , {
196
250
textDocument : {
197
251
uri,
@@ -204,6 +258,7 @@ async function init(fixture: string): Promise<FixtureContext> {
204
258
// If opening a document stalls then it's probably because this promise is not being resolved
205
259
// This can happen if a document is not covered by one of the selectors because of it's URI
206
260
await initPromise
261
+ await openPromise
207
262
208
263
return {
209
264
uri,
@@ -220,7 +275,7 @@ async function init(fixture: string): Promise<FixtureContext> {
220
275
} ,
221
276
222
277
async updateFile ( file : string , text : string ) {
223
- let uri = `file:// ${ path . resolve ( './tests/fixtures' , fixture , file ) } `
278
+ let uri = resolveUri ( file )
224
279
225
280
await client . sendNotification ( DidChangeTextDocumentNotification . type , {
226
281
textDocument : { uri, version : counter ++ } ,
@@ -230,7 +285,7 @@ async function init(fixture: string): Promise<FixtureContext> {
230
285
}
231
286
}
232
287
233
- export function withFixture ( fixture , callback : ( c : FixtureContext ) => void ) {
288
+ export function withFixture ( fixture : string , callback : ( c : FixtureContext ) => void ) {
234
289
describe ( fixture , ( ) => {
235
290
let c : FixtureContext = { } as any
236
291
@@ -246,3 +301,26 @@ export function withFixture(fixture, callback: (c: FixtureContext) => void) {
246
301
callback ( c )
247
302
} )
248
303
}
304
+
305
+ export function withWorkspace ( {
306
+ fixtures,
307
+ run,
308
+ } : {
309
+ fixtures : string [ ]
310
+ run : ( c : FixtureContext ) => void
311
+ } ) {
312
+ describe ( `workspace: ${ fixtures . join ( ', ' ) } ` , ( ) => {
313
+ let c : FixtureContext = { } as any
314
+
315
+ beforeAll ( async ( ) => {
316
+ // Using the connection object as the prototype lets us access the connection
317
+ // without defining getters for all the methods and also lets us add helpers
318
+ // to the connection object without having to resort to using a Proxy
319
+ Object . setPrototypeOf ( c , await init ( fixtures ) )
320
+
321
+ return ( ) => c . client . dispose ( )
322
+ } )
323
+
324
+ run ( c )
325
+ } )
326
+ }
0 commit comments