Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/emmet/src/test/wrapWithAbbreviation.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, workspace, ConfigurationTarget } from 'vscode';
9
import { withRandomFileEditor, closeAllEditors } from './testUtils';
10
import { wrapWithAbbreviation } from '../abbreviationActions';
11
12
const htmlContentsForBlockWrapTests = `
13
<ul class="nav main">
14
<li class="item1">img</li>
15
<li class="item2">$hithere</li>
16
<li class="item3">\${hithere}</li>
17
</ul>
18
`;
19
20
const htmlContentsForInlineWrapTests = `
21
<ul class="nav main">
22
<em class="item1">img</em>
23
<em class="item2">$hithere</em>
24
<em class="item3">\${hithere}</em>
25
</ul>
26
`;
27
28
const wrapBlockElementExpected = `
29
<ul class="nav main">
30
<div>
31
<li class="item1">img</li>
32
</div>
33
<div>
34
<li class="item2">$hithere</li>
35
</div>
36
<div>
37
<li class="item3">\${hithere}</li>
38
</div>
39
</ul>
40
`;
41
42
const wrapInlineElementExpected = `
43
<ul class="nav main">
44
<span><em class="item1">img</em></span>
45
<span><em class="item2">$hithere</em></span>
46
<span><em class="item3">\${hithere}</em></span>
47
</ul>
48
`;
49
50
const wrapSnippetExpected = `
51
<ul class="nav main">
52
<a href="">
53
<li class="item1">img</li>
54
</a>
55
<a href="">
56
<li class="item2">$hithere</li>
57
</a>
58
<a href="">
59
<li class="item3">\${hithere}</li>
60
</a>
61
</ul>
62
`;
63
64
const wrapMultiLineAbbrExpected = `
65
<ul class="nav main">
66
<ul>
67
<li>
68
<li class="item1">img</li>
69
</li>
70
</ul>
71
<ul>
72
<li>
73
<li class="item2">$hithere</li>
74
</li>
75
</ul>
76
<ul>
77
<li>
78
<li class="item3">\${hithere}</li>
79
</li>
80
</ul>
81
</ul>
82
`;
83
84
// technically a bug, but also a feature (requested behaviour)
85
// https://github.com/microsoft/vscode/issues/78015
86
const wrapInlineElementExpectedFormatFalse = `
87
<ul class="nav main">
88
<h1>
89
<li class="item1">img</li>
90
</h1>
91
<h1>
92
<li class="item2">$hithere</li>
93
</h1>
94
<h1>
95
<li class="item3">\${hithere}</li>
96
</h1>
97
</ul>
98
`;
99
100
suite('Tests for Wrap with Abbreviations', () => {
101
teardown(closeAllEditors);
102
103
const multiCursors = [new Selection(2, 6, 2, 6), new Selection(3, 6, 3, 6), new Selection(4, 6, 4, 6)];
104
const multiCursorsWithSelection = [new Selection(2, 2, 2, 28), new Selection(3, 2, 3, 33), new Selection(4, 6, 4, 36)];
105
const multiCursorsWithFullLineSelection = [new Selection(2, 0, 2, 28), new Selection(3, 0, 3, 33), new Selection(4, 0, 4, 36)];
106
107
const oldValueForSyntaxProfiles = workspace.getConfiguration('emmet').inspect('syntaxProfiles');
108
109
test('Wrap with block element using multi cursor', () => {
110
return testWrapWithAbbreviation(multiCursors, 'div', wrapBlockElementExpected, htmlContentsForBlockWrapTests);
111
});
112
113
test('Wrap with inline element using multi cursor', () => {
114
return testWrapWithAbbreviation(multiCursors, 'span', wrapInlineElementExpected, htmlContentsForInlineWrapTests);
115
});
116
117
test('Wrap with snippet using multi cursor', () => {
118
return testWrapWithAbbreviation(multiCursors, 'a', wrapSnippetExpected, htmlContentsForBlockWrapTests);
119
});
120
121
test('Wrap with multi line abbreviation using multi cursor', () => {
122
return testWrapWithAbbreviation(multiCursors, 'ul>li', wrapMultiLineAbbrExpected, htmlContentsForBlockWrapTests);
123
});
124
125
test('Wrap with block element using multi cursor selection', () => {
126
return testWrapWithAbbreviation(multiCursorsWithSelection, 'div', wrapBlockElementExpected, htmlContentsForBlockWrapTests);
127
});
128
129
test('Wrap with inline element using multi cursor selection', () => {
130
return testWrapWithAbbreviation(multiCursorsWithSelection, 'span', wrapInlineElementExpected, htmlContentsForInlineWrapTests);
131
});
132
133
test('Wrap with snippet using multi cursor selection', () => {
134
return testWrapWithAbbreviation(multiCursorsWithSelection, 'a', wrapSnippetExpected, htmlContentsForBlockWrapTests);
135
});
136
137
test('Wrap with multi line abbreviation using multi cursor selection', () => {
138
return testWrapWithAbbreviation(multiCursorsWithSelection, 'ul>li', wrapMultiLineAbbrExpected, htmlContentsForBlockWrapTests);
139
});
140
141
test('Wrap with block element using multi cursor full line selection', () => {
142
return testWrapWithAbbreviation(multiCursorsWithFullLineSelection, 'div', wrapBlockElementExpected, htmlContentsForBlockWrapTests);
143
});
144
145
test('Wrap with inline element using multi cursor full line selection', () => {
146
return testWrapWithAbbreviation(multiCursorsWithFullLineSelection, 'span', wrapInlineElementExpected, htmlContentsForInlineWrapTests);
147
});
148
149
test('Wrap with snippet using multi cursor full line selection', () => {
150
return testWrapWithAbbreviation(multiCursorsWithFullLineSelection, 'a', wrapSnippetExpected, htmlContentsForBlockWrapTests);
151
});
152
153
test('Wrap with multi line abbreviation using multi cursor full line selection', () => {
154
return testWrapWithAbbreviation(multiCursorsWithFullLineSelection, 'ul>li', wrapMultiLineAbbrExpected, htmlContentsForBlockWrapTests);
155
});
156
157
test('Wrap with abbreviation and comment filter', () => {
158
const contents = `
159
<ul class="nav main">
160
line
161
</ul>
162
`;
163
const expectedContents = `
164
<ul class="nav main">
165
<li class="hello">line</li>
166
<!-- /.hello -->
167
</ul>
168
`;
169
return testWrapWithAbbreviation([new Selection(2, 0, 2, 0)], 'li.hello|c', expectedContents, contents);
170
});
171
172
test('Wrap with abbreviation link', () => {
173
const contents = `
174
<ul class="nav main">
175
line
176
</ul>
177
`;
178
const expectedContents = `
179
<a href="https://example.com">
180
<div>
181
<ul class="nav main">
182
line
183
</ul>
184
</div>
185
</a>
186
`;
187
return testWrapWithAbbreviation([new Selection(1, 2, 1, 2)], 'a[href="https://example.com"]>div', expectedContents, contents);
188
});
189
190
test('Wrap with abbreviation entire node when cursor is on opening tag', () => {
191
const contents = `
192
<div class="nav main">
193
hello
194
</div>
195
`;
196
const expectedContents = `
197
<div>
198
<div class="nav main">
199
hello
200
</div>
201
</div>
202
`;
203
return testWrapWithAbbreviation([new Selection(1, 2, 1, 2)], 'div', expectedContents, contents);
204
});
205
206
test('Wrap with abbreviation entire node when cursor is on closing tag', () => {
207
const contents = `
208
<div class="nav main">
209
hello
210
</div>
211
`;
212
const expectedContents = `
213
<div>
214
<div class="nav main">
215
hello
216
</div>
217
</div>
218
`;
219
return testWrapWithAbbreviation([new Selection(3, 2, 3, 2)], 'div', expectedContents, contents);
220
});
221
222
test('Wrap with abbreviation inner node in cdata', () => {
223
const contents = `
224
<div class="nav main">
225
<![CDATA[
226
<div>
227
<p>Test 1</p>
228
</div>
229
<p>Test 2</p>
230
]]>
231
hello
232
</div>
233
`;
234
const expectedContents = `
235
<div class="nav main">
236
<![CDATA[
237
<div>
238
<p>Test 1</p>
239
</div>
240
<div>
241
<p>Test 2</p>
242
</div>
243
]]>
244
hello
245
</div>
246
`;
247
return testWrapWithAbbreviation([new Selection(6, 5, 6, 5)], 'div', expectedContents, contents);
248
});
249
250
test('Wrap with abbreviation inner node in script in cdata', () => {
251
const contents = `
252
<div class="nav main">
253
<![CDATA[
254
<script type="text/plain">
255
<p>Test 1</p>
256
</script>
257
<p>Test 2</p>
258
]]>
259
hello
260
</div>
261
`;
262
const expectedContents = `
263
<div class="nav main">
264
<![CDATA[
265
<script type="text/plain">
266
<div>
267
<p>Test 1</p>
268
</div>
269
</script>
270
<p>Test 2</p>
271
]]>
272
hello
273
</div>
274
`;
275
return testWrapWithAbbreviation([new Selection(4, 10, 4, 10)], 'div', expectedContents, contents);
276
});
277
278
test('Wrap with abbreviation inner node in cdata one-liner', () => {
279
const contents = `
280
<div class="nav main">
281
<![CDATA[<p>Test here</p>]]>
282
hello
283
</div>
284
`;
285
// this result occurs because no selection on the open/close p tag was given
286
const expectedContents = `
287
<div class="nav main">
288
<div><![CDATA[<p>Test here</p>]]></div>
289
hello
290
</div>
291
`;
292
return testWrapWithAbbreviation([new Selection(2, 15, 2, 15)], 'div', expectedContents, contents);
293
});
294
295
test('Wrap with multiline abbreviation doesnt add extra spaces', () => {
296
// Issue #29898
297
const contents = `
298
hello
299
`;
300
const expectedContents = `
301
<ul>
302
<li><a href="">hello</a></li>
303
</ul>
304
`;
305
return testWrapWithAbbreviation([new Selection(1, 2, 1, 2)], 'ul>li>a', expectedContents, contents);
306
});
307
308
test('Wrap individual lines with abbreviation', () => {
309
const contents = `
310
<ul class="nav main">
311
<li class="item1">This $10 is not a tabstop</li>
312
<li class="item2">hi.there</li>
313
</ul>
314
`;
315
const wrapIndividualLinesExpected = `
316
<ul class="nav main">
317
<ul>
318
<li class="hello1">
319
<li class="item1">This $10 is not a tabstop</li>
320
</li>
321
<li class="hello2">
322
<li class="item2">hi.there</li>
323
</li>
324
</ul>
325
</ul>
326
`;
327
return testWrapIndividualLinesWithAbbreviation([new Selection(2, 2, 3, 33)], 'ul>li.hello$*', wrapIndividualLinesExpected, contents);
328
});
329
330
test('Wrap individual lines with abbreviation with extra space selected', () => {
331
const contents = `
332
<ul class="nav main">
333
<li class="item1">img</li>
334
<li class="item2">hi.there</li>
335
</ul>
336
`;
337
const wrapIndividualLinesExpected = `
338
<ul class="nav main">
339
<ul>
340
<li class="hello1">
341
<li class="item1">img</li>
342
</li>
343
<li class="hello2">
344
<li class="item2">hi.there</li>
345
</li>
346
</ul>
347
</ul>
348
`;
349
return testWrapIndividualLinesWithAbbreviation([new Selection(2, 1, 4, 0)], 'ul>li.hello$*', wrapIndividualLinesExpected, contents);
350
});
351
352
test('Wrap individual lines with abbreviation with comment filter', () => {
353
const contents = `
354
<ul class="nav main">
355
<li class="item1">img</li>
356
<li class="item2">hi.there</li>
357
</ul>
358
`;
359
const wrapIndividualLinesExpected = `
360
<ul class="nav main">
361
<ul>
362
<li class="hello">
363
<li class="item1">img</li>
364
</li>
365
<!-- /.hello -->
366
<li class="hello">
367
<li class="item2">hi.there</li>
368
</li>
369
<!-- /.hello -->
370
</ul>
371
</ul>
372
`;
373
return testWrapIndividualLinesWithAbbreviation([new Selection(2, 2, 3, 33)], 'ul>li.hello*|c', wrapIndividualLinesExpected, contents);
374
});
375
376
test('Wrap individual lines with abbreviation and trim', () => {
377
const contents = `
378
<ul class="nav main">
379
• lorem ipsum
380
• lorem ipsum
381
</ul>
382
`;
383
const wrapIndividualLinesExpected = `
384
<ul class="nav main">
385
<ul>
386
<li class="hello1">lorem ipsum</li>
387
<li class="hello2">lorem ipsum</li>
388
</ul>
389
</ul>
390
`;
391
return testWrapIndividualLinesWithAbbreviation([new Selection(2, 3, 3, 16)], 'ul>li.hello$*|t', wrapIndividualLinesExpected, contents);
392
});
393
394
test('Wrap with abbreviation and format set to false', () => {
395
return workspace.getConfiguration('emmet').update('syntaxProfiles', { 'html': { 'format': false } }, ConfigurationTarget.Global).then(() => {
396
return testWrapWithAbbreviation(multiCursors, 'h1', wrapInlineElementExpectedFormatFalse, htmlContentsForBlockWrapTests).then(() => {
397
return workspace.getConfiguration('emmet').update('syntaxProfiles', oldValueForSyntaxProfiles ? oldValueForSyntaxProfiles.globalValue : undefined, ConfigurationTarget.Global);
398
});
399
});
400
});
401
402
test('Wrap multi line selections with abbreviation', () => {
403
const htmlContentsForWrapMultiLineTests = `
404
<ul class="nav main">
405
line1
406
line2
407
408
line3
409
line4
410
</ul>
411
`;
412
413
const wrapMultiLineExpected = `
414
<ul class="nav main">
415
<div>
416
line1
417
line2
418
</div>
419
420
<div>
421
line3
422
line4
423
</div>
424
</ul>
425
`;
426
427
return testWrapWithAbbreviation([new Selection(2, 4, 3, 9), new Selection(5, 4, 6, 9)], 'div', wrapMultiLineExpected, htmlContentsForWrapMultiLineTests);
428
});
429
430
test('Wrap multiline with abbreviation uses className for jsx files', () => {
431
const wrapMultiLineJsxExpected = `
432
<ul class="nav main">
433
<div className="hello">
434
<li class="item1">img</li>
435
<li class="item2">$hithere</li>
436
<li class="item3">\${hithere}</li>
437
</div>
438
</ul>
439
`;
440
441
return testWrapWithAbbreviation([new Selection(2, 2, 4, 36)], '.hello', wrapMultiLineJsxExpected, htmlContentsForBlockWrapTests, 'jsx');
442
});
443
444
test('Wrap individual line with abbreviation uses className for jsx files', () => {
445
const wrapIndividualLinesJsxExpected = `
446
<ul class="nav main">
447
<div className="hello1">
448
<li class="item1">img</li>
449
</div>
450
<div className="hello2">
451
<li class="item2">$hithere</li>
452
</div>
453
<div className="hello3">
454
<li class="item3">\${hithere}</li>
455
</div>
456
</ul>
457
`;
458
459
return testWrapIndividualLinesWithAbbreviation([new Selection(2, 2, 4, 36)], '.hello$*', wrapIndividualLinesJsxExpected, htmlContentsForBlockWrapTests, 'jsx');
460
});
461
462
test('Wrap with abbreviation merge overlapping computed ranges', () => {
463
const contents = `
464
<div class="nav main">
465
hello
466
</div>
467
`;
468
const expectedContents = `
469
<div>
470
<div class="nav main">
471
hello
472
</div>
473
</div>
474
`;
475
return testWrapWithAbbreviation([new Selection(1, 2, 1, 2), new Selection(1, 10, 1, 10)], 'div', expectedContents, contents);
476
});
477
478
test('Wrap with abbreviation ignore invalid abbreviation', () => {
479
const contents = `
480
<div class="nav main">
481
hello
482
</div>
483
`;
484
return testWrapWithAbbreviation([new Selection(1, 2, 1, 2)], 'div]', contents, contents);
485
});
486
487
});
488
489
490
function testWrapWithAbbreviation(selections: Selection[], abbreviation: string, expectedContents: string, input: string, fileExtension: string = 'html'): Thenable<any> {
491
return withRandomFileEditor(input, fileExtension, (editor, _) => {
492
editor.selections = selections;
493
const promise = wrapWithAbbreviation({ abbreviation });
494
if (!promise) {
495
assert.strictEqual(1, 2, 'Wrap with Abbreviation returned undefined.');
496
return Promise.resolve();
497
}
498
499
return promise.then(() => {
500
assert.strictEqual(editor.document.getText(), expectedContents);
501
return Promise.resolve();
502
});
503
});
504
}
505
506
function testWrapIndividualLinesWithAbbreviation(selections: Selection[], abbreviation: string, expectedContents: string, input: string, fileExtension: string = 'html'): Thenable<any> {
507
return withRandomFileEditor(input, fileExtension, (editor, _) => {
508
editor.selections = selections;
509
const promise = wrapWithAbbreviation({ abbreviation });
510
if (!promise) {
511
assert.strictEqual(1, 2, 'Wrap individual lines with Abbreviation returned undefined.');
512
return Promise.resolve();
513
}
514
515
return promise.then(() => {
516
assert.strictEqual(editor.document.getText(), expectedContents);
517
return Promise.resolve();
518
});
519
});
520
}
521
522