completions.test.ts 5.4 KB
Newer Older
M
Matt Bierner 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import * as assert from 'assert';
import 'mocha';
import * as vscode from 'vscode';
import { disposeAll } from '../utils/dispose';

const testDocumentUri = vscode.Uri.parse('untitled:test.ts');

suite('TypeScript Completions', () => {
14
	const _disposables: vscode.Disposable[] = [];
M
Matt Bierner 已提交
15 16 17 18 19 20

	teardown(() => {
		disposeAll(_disposables);
		return vscode.commands.executeCommand('workbench.action.closeAllEditors');
	});

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
	test('Basic var completion', async () => {
		await wait(100);

		await createTestEditor(testDocumentUri,
			`const abcdef = 123;`,
			`ab$0;`
		);

		const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
		assert.strictEqual(
			document.getText(),
			joinLines(
				`const abcdef = 123;`,
				`abcdef;`
			));
	});

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
	test('Should treat period as commit character for var completions', async () => {
		await wait(100);

		await createTestEditor(testDocumentUri,
			`const abcdef = 123;`,
			`ab$0;`
		);

		const document = await typeCommitCharacter(testDocumentUri, '.', _disposables);
		assert.strictEqual(
			document.getText(),
			joinLines(
				`const abcdef = 123;`,
				`abcdef.;`
			));
	});

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
	test('Should insert backets when completing dot properties with spaces in name', async () => {
		await wait(100);

		await createTestEditor(testDocumentUri,
			'const x = { "hello world": 1 };',
			'x.$0'
		);

		const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
		assert.strictEqual(
			document.getText(),
			joinLines(
				'const x = { "hello world": 1 };',
				'x["hello world"]'
			));
	});

M
Matt Bierner 已提交
72 73 74 75
	test('Should not prioritize bracket accessor completions. #63100', async () => {
		await wait(100);

		// 'a' should be first entry in completion list
76
		await createTestEditor(testDocumentUri,
M
Matt Bierner 已提交
77
			'const x = { "z-z": 1, a: 1 };',
78 79
			'x.$0'
		);
M
Matt Bierner 已提交
80

81
		const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
M
Matt Bierner 已提交
82 83 84
		assert.strictEqual(
			document.getText(),
			joinLines(
85
				'const x = { "z-z": 1, a: 1 };',
M
Matt Bierner 已提交
86 87 88
				'x.a'
			));
	});
M
Matt Bierner 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

	test('Accepting a string completion should replace the entire string. #53962', async () => {
		await wait(100);

		await createTestEditor(testDocumentUri,
			'interface TFunction {',
			`  (_: 'abc.abc2', __ ?: {}): string;`,
			`  (_: 'abc.abc', __?: {}): string;`,
			`}`,
			'const f: TFunction = (() => { }) as any;',
			`f('abc.abc$0')`
		);

		const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
		assert.strictEqual(
			document.getText(),
			joinLines(
				'interface TFunction {',
				`  (_: 'abc.abc2', __ ?: {}): string;`,
				`  (_: 'abc.abc', __?: {}): string;`,
				`}`,
				'const f: TFunction = (() => { }) as any;',
				`f('abc.abc')`
			));
	});

M
Matt Bierner 已提交
115 116 117 118 119 120
});

const joinLines = (...args: string[]) => args.join('\n');

const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

121 122 123 124 125 126 127 128 129
async function acceptFirstSuggestion(uri: vscode.Uri, _disposables: vscode.Disposable[]) {
	const didChangeDocument = onChangedDocument(uri, _disposables);
	const didSuggest = onDidSuggest(_disposables);
	await vscode.commands.executeCommand('editor.action.triggerSuggest');
	await didSuggest;
	await vscode.commands.executeCommand('acceptSelectedSuggestion');
	return await didChangeDocument;
}

130 131 132 133 134 135 136 137 138
async function typeCommitCharacter(uri: vscode.Uri, character: string, _disposables: vscode.Disposable[]) {
	const didChangeDocument = onChangedDocument(uri, _disposables);
	const didSuggest = onDidSuggest(_disposables);
	await vscode.commands.executeCommand('editor.action.triggerSuggest');
	await didSuggest;
	await vscode.commands.executeCommand('type', {text: character});
	return await didChangeDocument;
}

M
Matt Bierner 已提交
139 140 141 142 143 144 145 146
function onChangedDocument(documentUri: vscode.Uri, disposables: vscode.Disposable[]) {
	return new Promise<vscode.TextDocument>(resolve => vscode.workspace.onDidChangeTextDocument(e => {
		if (e.document.uri.toString() === documentUri.toString()) {
			resolve(e.document);
		}
	}, undefined, disposables));
}

147 148
async function createTestEditor(uri: vscode.Uri, ...lines: string[]) {
	const document = await vscode.workspace.openTextDocument(uri);
M
Matt Bierner 已提交
149 150 151 152 153 154
	await vscode.window.showTextDocument(document);
	const activeEditor = vscode.window.activeTextEditor;
	if (!activeEditor) {
		throw new Error('no active editor');
	}

155
	await activeEditor.insertSnippet(new vscode.SnippetString(joinLines(...lines)));
M
Matt Bierner 已提交
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
}

function onDidSuggest(disposables: vscode.Disposable[]) {
	return new Promise(resolve =>
		disposables.push(vscode.languages.registerCompletionItemProvider('typescript', new class implements vscode.CompletionItemProvider {
			provideCompletionItems(doc: vscode.TextDocument, position: vscode.Position): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
				// Return a fake item that will come first
				const range = new vscode.Range(new vscode.Position(position.line, 0), position);
				return [{
					label: doc.getText(range),
					sortText: '\0',
					range: range
				}];
			}
			async resolveCompletionItem(item: vscode.CompletionItem) {
171
				await vscode.commands.executeCommand('selectNextSuggestion');
M
Matt Bierner 已提交
172 173 174 175 176
				resolve();
				return item;
			}
		})));
}