Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/emmet/src/test/cssAbbreviationAction.test.ts
4774 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import 'mocha';
7
import * as assert from 'assert';
8
import { Selection, CompletionList, CancellationTokenSource, Position, CompletionTriggerKind, CompletionContext } from 'vscode';
9
import { withRandomFileEditor, closeAllEditors } from './testUtils';
10
import { expandEmmetAbbreviation } from '../abbreviationActions';
11
import { DefaultCompletionItemProvider } from '../defaultCompletionProvider';
12
13
const completionProvider = new DefaultCompletionItemProvider();
14
const cssContents = `
15
.boo {
16
margin: 20px 10px;
17
pos:f
18
background-image: url('tryme.png');
19
pos:f
20
}
21
22
.boo .hoo {
23
margin: 10px;
24
ind
25
}
26
`;
27
28
const scssContents = `
29
.boo {
30
margin: 10px;
31
p10
32
.hoo {
33
p20
34
}
35
}
36
@include b(alert) {
37
38
margin: 10px;
39
p30
40
41
@include b(alert) {
42
p40
43
}
44
}
45
.foo {
46
margin: 10px;
47
margin: a
48
.hoo {
49
color: #000;
50
}
51
}
52
`;
53
54
const invokeCompletionContext: CompletionContext = {
55
triggerKind: CompletionTriggerKind.Invoke,
56
triggerCharacter: undefined,
57
};
58
59
suite('Tests for Expand Abbreviations (CSS)', () => {
60
teardown(closeAllEditors);
61
62
test('Expand abbreviation (CSS)', () => {
63
return withRandomFileEditor(cssContents, 'css', (editor, _) => {
64
editor.selections = [new Selection(3, 1, 3, 6), new Selection(5, 1, 5, 6)];
65
return expandEmmetAbbreviation(null).then(() => {
66
assert.strictEqual(editor.document.getText(), cssContents.replace(/pos:f/g, 'position: fixed;'));
67
return Promise.resolve();
68
});
69
});
70
});
71
72
test('No emmet when cursor inside comment (CSS)', () => {
73
const testContent = `
74
.foo {
75
/*margin: 10px;
76
m10
77
padding: 10px;*/
78
display: auto;
79
}
80
`;
81
82
return withRandomFileEditor(testContent, 'css', (editor, _) => {
83
editor.selection = new Selection(3, 4, 3, 4);
84
return expandEmmetAbbreviation(null).then(() => {
85
assert.strictEqual(editor.document.getText(), testContent);
86
const cancelSrc = new CancellationTokenSource();
87
const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token, invokeCompletionContext);
88
if (completionPromise) {
89
assert.strictEqual(1, 2, `Invalid completion at property value`);
90
}
91
return Promise.resolve();
92
});
93
});
94
});
95
96
test('No emmet when cursor in selector of a rule (CSS)', () => {
97
const testContent = `
98
.foo {
99
margin: 10px;
100
}
101
102
nav#
103
`;
104
105
return withRandomFileEditor(testContent, 'css', (editor, _) => {
106
editor.selection = new Selection(5, 4, 5, 4);
107
return expandEmmetAbbreviation(null).then(() => {
108
assert.strictEqual(editor.document.getText(), testContent);
109
const cancelSrc = new CancellationTokenSource();
110
const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token, invokeCompletionContext);
111
if (completionPromise) {
112
assert.strictEqual(1, 2, `Invalid completion at property value`);
113
}
114
return Promise.resolve();
115
});
116
});
117
});
118
119
test('Skip when typing property values when there is a property in the next line (CSS)', () => {
120
const testContent = `
121
.foo {
122
margin: a
123
margin: 10px;
124
}
125
`;
126
127
return withRandomFileEditor(testContent, 'css', (editor, _) => {
128
editor.selection = new Selection(2, 10, 2, 10);
129
return expandEmmetAbbreviation(null).then(() => {
130
assert.strictEqual(editor.document.getText(), testContent);
131
const cancelSrc = new CancellationTokenSource();
132
const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token, invokeCompletionContext);
133
if (completionPromise) {
134
assert.strictEqual(1, 2, `Invalid completion at property value`);
135
}
136
return Promise.resolve();
137
});
138
});
139
});
140
141
test('Skip when typing the last property value in single line rules (CSS)', () => {
142
const testContent = `.foo {padding: 10px; margin: a}`;
143
144
return withRandomFileEditor(testContent, 'css', (editor, _) => {
145
editor.selection = new Selection(0, 30, 0, 30);
146
return expandEmmetAbbreviation(null).then(() => {
147
assert.strictEqual(editor.document.getText(), testContent);
148
const cancelSrc = new CancellationTokenSource();
149
const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(0, 30), cancelSrc.token, invokeCompletionContext);
150
if (completionPromise) {
151
assert.strictEqual(1, 2, `Invalid completion at property value`);
152
}
153
return Promise.resolve();
154
});
155
});
156
});
157
158
test('Allow hex color or !important when typing property values when there is a property in the next line (CSS)', () => {
159
const testContent = `
160
.foo {
161
margin: #12 !
162
margin: 10px;
163
}
164
`;
165
166
return withRandomFileEditor(testContent, 'css', (editor, _) => {
167
const cancelSrc = new CancellationTokenSource();
168
const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(2, 12), cancelSrc.token, invokeCompletionContext);
169
const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(2, 14), cancelSrc.token, invokeCompletionContext);
170
171
if (!completionPromise1 || !completionPromise2) {
172
assert.strictEqual(1, 2, `Completion promise wasnt returned`);
173
return Promise.resolve();
174
}
175
176
const callBack = (completionList: CompletionList, expandedText: string) => {
177
if (!completionList.items || !completionList.items.length) {
178
assert.strictEqual(1, 2, `Empty Completions`);
179
return;
180
}
181
const emmetCompletionItem = completionList.items[0];
182
assert.strictEqual(emmetCompletionItem.label, expandedText, `Label of completion item doesnt match.`);
183
assert.strictEqual((<string>emmetCompletionItem.documentation || '').replace(/\|/g, ''), expandedText, `Docs of completion item doesnt match.`);
184
};
185
186
return Promise.all([completionPromise1, completionPromise2]).then(([result1, result2]) => {
187
assert.ok(result1);
188
assert.ok(result2);
189
callBack(result1, '#121212');
190
callBack(result2, '!important');
191
editor.selections = [new Selection(2, 12, 2, 12), new Selection(2, 14, 2, 14)];
192
return expandEmmetAbbreviation(null).then(() => {
193
assert.strictEqual(editor.document.getText(), testContent.replace('#12', '#121212').replace('!', '!important'));
194
});
195
});
196
});
197
});
198
199
test('Skip when typing property values when there is a property in the previous line (CSS)', () => {
200
const testContent = `
201
.foo {
202
margin: 10px;
203
margin: a
204
}
205
`;
206
207
return withRandomFileEditor(testContent, 'css', (editor, _) => {
208
editor.selection = new Selection(3, 10, 3, 10);
209
return expandEmmetAbbreviation(null).then(() => {
210
assert.strictEqual(editor.document.getText(), testContent);
211
const cancelSrc = new CancellationTokenSource();
212
const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(3, 10), cancelSrc.token, invokeCompletionContext);
213
if (completionPromise) {
214
assert.strictEqual(1, 2, `Invalid completion at property value`);
215
}
216
return Promise.resolve();
217
});
218
});
219
});
220
221
test('Allow hex color or !important when typing property values when there is a property in the previous line (CSS)', () => {
222
const testContent = `
223
.foo {
224
margin: 10px;
225
margin: #12 !
226
}
227
`;
228
229
return withRandomFileEditor(testContent, 'css', (editor, _) => {
230
const cancelSrc = new CancellationTokenSource();
231
const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 12), cancelSrc.token, invokeCompletionContext);
232
const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(3, 14), cancelSrc.token, invokeCompletionContext);
233
234
if (!completionPromise1 || !completionPromise2) {
235
assert.strictEqual(1, 2, `Completion promise wasnt returned`);
236
return Promise.resolve();
237
}
238
239
const callBack = (completionList: CompletionList, expandedText: string) => {
240
if (!completionList.items || !completionList.items.length) {
241
assert.strictEqual(1, 2, `Empty Completions`);
242
return;
243
}
244
const emmetCompletionItem = completionList.items[0];
245
assert.strictEqual(emmetCompletionItem.label, expandedText, `Label of completion item doesnt match.`);
246
assert.strictEqual((<string>emmetCompletionItem.documentation || '').replace(/\|/g, ''), expandedText, `Docs of completion item doesnt match.`);
247
};
248
249
return Promise.all([completionPromise1, completionPromise2]).then(([result1, result2]) => {
250
assert.ok(result1);
251
assert.ok(result2);
252
callBack(result1, '#121212');
253
callBack(result2, '!important');
254
editor.selections = [new Selection(3, 12, 3, 12), new Selection(3, 14, 3, 14)];
255
return expandEmmetAbbreviation(null).then(() => {
256
assert.strictEqual(editor.document.getText(), testContent.replace('#12', '#121212').replace('!', '!important'));
257
});
258
});
259
});
260
});
261
262
test('Skip when typing property values when it is the only property in the rule (CSS)', () => {
263
const testContent = `
264
.foo {
265
margin: a
266
}
267
`;
268
269
return withRandomFileEditor(testContent, 'css', (editor, _) => {
270
editor.selection = new Selection(2, 10, 2, 10);
271
return expandEmmetAbbreviation(null).then(() => {
272
assert.strictEqual(editor.document.getText(), testContent);
273
const cancelSrc = new CancellationTokenSource();
274
const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token, invokeCompletionContext);
275
if (completionPromise) {
276
assert.strictEqual(1, 2, `Invalid completion at property value`);
277
}
278
return Promise.resolve();
279
});
280
});
281
});
282
283
test('Allow hex colors or !important when typing property values when it is the only property in the rule (CSS)', () => {
284
const testContent = `
285
.foo {
286
margin: #12 !
287
}
288
`;
289
290
return withRandomFileEditor(testContent, 'css', (editor, _) => {
291
const cancelSrc = new CancellationTokenSource();
292
const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(2, 12), cancelSrc.token, invokeCompletionContext);
293
const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(2, 14), cancelSrc.token, invokeCompletionContext);
294
295
if (!completionPromise1 || !completionPromise2) {
296
assert.strictEqual(1, 2, `Completion promise wasnt returned`);
297
return Promise.resolve();
298
}
299
300
const callBack = (completionList: CompletionList, expandedText: string) => {
301
if (!completionList.items || !completionList.items.length) {
302
assert.strictEqual(1, 2, `Empty Completions`);
303
return;
304
}
305
const emmetCompletionItem = completionList.items[0];
306
assert.strictEqual(emmetCompletionItem.label, expandedText, `Label of completion item doesnt match.`);
307
assert.strictEqual((<string>emmetCompletionItem.documentation || '').replace(/\|/g, ''), expandedText, `Docs of completion item doesnt match.`);
308
};
309
310
return Promise.all([completionPromise1, completionPromise2]).then(([result1, result2]) => {
311
assert.ok(result1);
312
assert.ok(result2);
313
callBack(result1, '#121212');
314
callBack(result2, '!important');
315
editor.selections = [new Selection(2, 12, 2, 12), new Selection(2, 14, 2, 14)];
316
return expandEmmetAbbreviation(null).then(() => {
317
assert.strictEqual(editor.document.getText(), testContent.replace('#12', '#121212').replace('!', '!important'));
318
});
319
});
320
});
321
});
322
323
test('# shouldnt expand to hex color when in selector (CSS)', () => {
324
const testContent = `
325
.foo {
326
#
327
}
328
`;
329
330
return withRandomFileEditor(testContent, 'css', (editor, _) => {
331
editor.selection = new Selection(2, 2, 2, 2);
332
return expandEmmetAbbreviation(null).then(() => {
333
assert.strictEqual(editor.document.getText(), testContent);
334
const cancelSrc = new CancellationTokenSource();
335
const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 2), cancelSrc.token, invokeCompletionContext);
336
if (completionPromise) {
337
assert.strictEqual(1, 2, `Invalid completion of hex color at property name`);
338
}
339
return Promise.resolve();
340
});
341
});
342
});
343
344
345
test('Expand abbreviation in completion list (CSS)', () => {
346
const abbreviation = 'pos:f';
347
const expandedText = 'position: fixed;';
348
349
return withRandomFileEditor(cssContents, 'css', (editor, _) => {
350
editor.selection = new Selection(3, 1, 3, 6);
351
const cancelSrc = new CancellationTokenSource();
352
const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 6), cancelSrc.token, invokeCompletionContext);
353
const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(5, 6), cancelSrc.token, invokeCompletionContext);
354
if (!completionPromise1 || !completionPromise2) {
355
assert.strictEqual(1, 2, `Problem with expanding pos:f`);
356
return Promise.resolve();
357
}
358
359
const callBack = (completionList: CompletionList) => {
360
if (!completionList.items || !completionList.items.length) {
361
assert.strictEqual(1, 2, `Problem with expanding pos:f`);
362
return;
363
}
364
const emmetCompletionItem = completionList.items[0];
365
assert.strictEqual(emmetCompletionItem.label, expandedText, `Label of completion item doesnt match.`);
366
assert.strictEqual((<string>emmetCompletionItem.documentation || '').replace(/\|/g, ''), expandedText, `Docs of completion item doesnt match.`);
367
assert.strictEqual(emmetCompletionItem.filterText, abbreviation, `FilterText of completion item doesnt match.`);
368
};
369
370
return Promise.all([completionPromise1, completionPromise2]).then(([result1, result2]) => {
371
assert.ok(result1);
372
assert.ok(result2);
373
callBack(result1);
374
callBack(result2);
375
return Promise.resolve();
376
});
377
});
378
});
379
380
test('Expand abbreviation (SCSS)', () => {
381
return withRandomFileEditor(scssContents, 'scss', (editor, _) => {
382
editor.selections = [
383
new Selection(3, 4, 3, 4),
384
new Selection(5, 5, 5, 5),
385
new Selection(11, 4, 11, 4),
386
new Selection(14, 5, 14, 5)
387
];
388
return expandEmmetAbbreviation(null).then(() => {
389
assert.strictEqual(editor.document.getText(), scssContents.replace(/p(\d\d)/g, 'padding: $1px;'));
390
return Promise.resolve();
391
});
392
});
393
});
394
395
test('Expand abbreviation in completion list (SCSS)', () => {
396
397
return withRandomFileEditor(scssContents, 'scss', (editor, _) => {
398
editor.selection = new Selection(3, 4, 3, 4);
399
const cancelSrc = new CancellationTokenSource();
400
const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 4), cancelSrc.token, invokeCompletionContext);
401
const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(5, 5), cancelSrc.token, invokeCompletionContext);
402
const completionPromise3 = completionProvider.provideCompletionItems(editor.document, new Position(11, 4), cancelSrc.token, invokeCompletionContext);
403
const completionPromise4 = completionProvider.provideCompletionItems(editor.document, new Position(14, 5), cancelSrc.token, invokeCompletionContext);
404
if (!completionPromise1) {
405
assert.strictEqual(1, 2, `Problem with expanding padding abbreviations at line 3 col 4`);
406
}
407
if (!completionPromise2) {
408
assert.strictEqual(1, 2, `Problem with expanding padding abbreviations at line 5 col 5`);
409
}
410
if (!completionPromise3) {
411
assert.strictEqual(1, 2, `Problem with expanding padding abbreviations at line 11 col 4`);
412
}
413
if (!completionPromise4) {
414
assert.strictEqual(1, 2, `Problem with expanding padding abbreviations at line 14 col 5`);
415
}
416
417
if (!completionPromise1 || !completionPromise2 || !completionPromise3 || !completionPromise4) {
418
return Promise.resolve();
419
}
420
421
const callBack = (completionList: CompletionList, abbreviation: string, expandedText: string) => {
422
if (!completionList.items || !completionList.items.length) {
423
assert.strictEqual(1, 2, `Problem with expanding m10`);
424
return;
425
}
426
const emmetCompletionItem = completionList.items[0];
427
assert.strictEqual(emmetCompletionItem.label, expandedText, `Label of completion item doesnt match.`);
428
assert.strictEqual((<string>emmetCompletionItem.documentation || '').replace(/\|/g, ''), expandedText, `Docs of completion item doesnt match.`);
429
assert.strictEqual(emmetCompletionItem.filterText, abbreviation, `FilterText of completion item doesnt match.`);
430
};
431
432
return Promise.all([completionPromise1, completionPromise2, completionPromise3, completionPromise4]).then(([result1, result2, result3, result4]) => {
433
assert.ok(result1);
434
assert.ok(result2);
435
assert.ok(result3);
436
assert.ok(result4);
437
callBack(result1, 'p10', 'padding: 10px;');
438
callBack(result2, 'p20', 'padding: 20px;');
439
callBack(result3, 'p30', 'padding: 30px;');
440
callBack(result4, 'p40', 'padding: 40px;');
441
return Promise.resolve();
442
});
443
});
444
});
445
446
447
test('Invalid locations for abbreviations in scss', () => {
448
const scssContentsNoExpand = `
449
m10
450
.boo {
451
margin: 10px;
452
.hoo {
453
background:
454
}
455
}
456
`;
457
458
return withRandomFileEditor(scssContentsNoExpand, 'scss', (editor, _) => {
459
editor.selections = [
460
new Selection(1, 3, 1, 3), // outside rule
461
new Selection(5, 15, 5, 15) // in the value part of property value
462
];
463
return expandEmmetAbbreviation(null).then(() => {
464
assert.strictEqual(editor.document.getText(), scssContentsNoExpand);
465
return Promise.resolve();
466
});
467
});
468
});
469
470
test('Invalid locations for abbreviations in scss in completion list', () => {
471
const scssContentsNoExpand = `
472
m10
473
.boo {
474
margin: 10px;
475
.hoo {
476
background:
477
}
478
}
479
`;
480
481
return withRandomFileEditor(scssContentsNoExpand, 'scss', (editor, _) => {
482
editor.selection = new Selection(1, 3, 1, 3); // outside rule
483
const cancelSrc = new CancellationTokenSource();
484
let completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, invokeCompletionContext);
485
if (completionPromise) {
486
assert.strictEqual(1, 2, `m10 gets expanded in invalid location (outside rule)`);
487
}
488
489
editor.selection = new Selection(5, 15, 5, 15); // in the value part of property value
490
completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, invokeCompletionContext);
491
if (completionPromise) {
492
return completionPromise.then((completionList: CompletionList | undefined) => {
493
if (completionList && completionList.items && completionList.items.length > 0) {
494
assert.strictEqual(1, 2, `m10 gets expanded in invalid location (n the value part of property value)`);
495
}
496
return Promise.resolve();
497
});
498
}
499
return Promise.resolve();
500
});
501
});
502
503
test('Skip when typing property values when there is a nested rule in the next line (SCSS)', () => {
504
return withRandomFileEditor(scssContents, 'scss', (editor, _) => {
505
editor.selection = new Selection(19, 10, 19, 10);
506
return expandEmmetAbbreviation(null).then(() => {
507
assert.strictEqual(editor.document.getText(), scssContents);
508
const cancelSrc = new CancellationTokenSource();
509
const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(19, 10), cancelSrc.token, invokeCompletionContext);
510
if (completionPromise) {
511
assert.strictEqual(1, 2, `Invalid completion at property value`);
512
}
513
return Promise.resolve();
514
});
515
});
516
});
517
});
518
519
520