Skip to content

Commit

Permalink
Rewrite completions tests
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Aug 24, 2024
1 parent 653651a commit 705cd4b
Show file tree
Hide file tree
Showing 41 changed files with 519 additions and 315 deletions.
8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@
},
"pnpm": {
"overrides": {
"@volar/kit": "https://pkg.pr.new/volarjs/volar.js/@volar/kit@01441c3",
"@volar/language-core": "https://pkg.pr.new/volarjs/volar.js/@volar/language-core@01441c3",
"@volar/language-server": "https://pkg.pr.new/volarjs/volar.js/@volar/language-server@01441c3",
"@volar/language-service": "https://pkg.pr.new/volarjs/volar.js/@volar/language-service@01441c3",
"@volar/source-map": "https://pkg.pr.new/volarjs/volar.js/@volar/source-map@01441c3",
"@volar/typescript": "https://pkg.pr.new/volarjs/volar.js/@volar/typescript@01441c3",
"@volar/vscode": "https://pkg.pr.new/volarjs/volar.js/@volar/vscode@01441c3",
"volar-service-typescript": "https://pkg.pr.new/volarjs/services/volar-service-typescript@177b9ed",
"inquirer": "9.2.23"
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/language-server/lib/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function initialize(
};
}
),
getFullLanguageServicePlugins(ts)
getFullLanguageServicePlugins(ts, { disableAutoImportCache: params.initializationOptions.typescript.disableAutoImportCache })
);

function updateFileWatcher(vueCompilerOptions: VueCompilerOptions) {
Expand Down
1 change: 1 addition & 0 deletions packages/language-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"dependencies": {
"@volar/language-core": "~2.4.0",
"@volar/language-server": "~2.4.0",
"@volar/test-utils": "~2.4.0",
"@vue/language-core": "2.0.28",
"@vue/language-service": "2.0.28",
"@vue/typescript-plugin": "2.0.28",
Expand Down
124 changes: 124 additions & 0 deletions packages/language-server/tests/__snapshots__/completions.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Completions > #2454 1`] = `
"
<script setup lang="ts">
let vLoading: any;
</script>
<template>
<div v-loading="vLoading"></div>
</template>
"
`;

exports[`Completions > #2511 1`] = `
"
<script setup lang="ts">
import componentForAutoImport$1 from './component-for-auto-import.vue';
</script>
"
`;

exports[`Completions > #3658 1`] = `
"
<template>
<Comp>
<template #foo="foo">
{{ foo }}
</template>
</Comp>
</template>
"
`;
exports[`Completions > #4639 1`] = `
"
<template>
<div @click.capture />
</template>
"
`;
exports[`Completions > $event argument 1`] = `"<template><div @click="console.log($event)"></div></template>"`;
exports[`Completions > <script setup> 1`] = `
"
<template>{{ foo }}</template>
<script lang="ts" setup>
const foo = 1;
</script>
"
`;
exports[`Completions > Alias path 1`] = `
"
<script setup lang="ts">
import Component from '@/empty.vue';
</script>
"
`;
exports[`Completions > Component auto import 1`] = `
"
<script setup lang="ts">
import ComponentForAutoImport from './ComponentForAutoImport.vue';
</script>
<template>
<ComponentForAutoImport />
</template>
"
`;
exports[`Completions > Directives 1`] = `"<template><div v-html="$1"></div></template>"`;
exports[`Completions > Directives 2`] = `"<template><div v-cloak></div></template>"`;
exports[`Completions > Directives 3`] = `"<template><div v-else></div></template>"`;
exports[`Completions > Directives 4`] = `"<template><div v-pre></div></template>"`;
exports[`Completions > Relative path 1`] = `
"
<script setup lang="ts">
import Component from './empty.vue';
</script>
"
`;
exports[`Completions > Slot name 1`] = `
"
<template>
<Foo>
<template #default></template>
</Foo>
</template>
<script lang="ts" setup>
let Foo: new () => {
$slots: {
default: any;
};
};
</script>
"
`;
exports[`Completions > core#8811 1`] = `
"
<script setup lang="ts">
declare const Foo: new () => {
$props: {
FooBar: string;
};
};
</script>
<template>
<Foo :-foo-bar="$1" ></Foo>
</template>
"
`;
210 changes: 210 additions & 0 deletions packages/language-server/tests/completions.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import { InsertReplaceEdit, TextDocument, TextEdit } from '@volar/language-server';
import { afterEach, describe, expect, it } from 'vitest';
import { URI } from 'vscode-uri';
import { getLanguageServer, testWorkspacePath } from './server.js';

describe('Completions', async () => {

it('Directives', async () => {
await assertCompletion('fixture.vue', 'vue', `<template><div v-ht|></div></template>`, 'v-html');
await assertCompletion('fixture.vue', 'vue', `<template><div v-cl|></div></template>`, 'v-cloak');
await assertCompletion('fixture.vue', 'vue', `<template><div v-el|></div></template>`, 'v-else');
await assertCompletion('fixture.vue', 'vue', `<template><div v-p|></div></template>`, 'v-pre');
});

it('$event argument', async () => {
await assertCompletion('fixture.vue', 'vue', `<template><div @click="console.log($eve|)"></div></template>`, '$event');
});

it('<script setup>', async () => {
await assertCompletion('fixture.vue', 'vue', `
<template>{{ f| }}</template>
<script lang="ts" setup>
const foo = 1;
</script>
`, 'foo');
});

it('Slot name', async () => {
await assertCompletion('fixture.vue', 'vue', `
<template>
<Foo>
<template #|></template>
</Foo>
</template>
<script lang="ts" setup>
let Foo: new () => {
$slots: {
default: any;
};
};
</script>
`, 'default');
});

it('#2454', async () => {
await assertCompletion('fixture.vue', 'vue', `
<script setup lang="ts">
let vLoading: any;
</script>
<template>
<div v-load|="vLoading"></div>
</template>
`, 'v-loading');
});

it('#2511', async () => {
await ensureGlobalTypesHolder('tsconfigProject');
await openDocument('tsconfigProject/component-for-auto-import.vue', 'vue', `<script setup lang="ts"></script>`);
await assertCompletion('tsconfigProject/fixture.vue', 'vue', `
<script setup lang="ts">
import componentFor|
</script>
`, 'ComponentForAutoImport');
});

it('#3658', async () => {
await assertCompletion('fixture.vue', 'vue', `
<template>
<Comp>
<template #foo="foo">
{{ fo| }}
</template>
</Comp>
</template>
`, 'foo');
});

it('#4639', async () => {
await assertCompletion('fixture.vue', 'vue', `
<template>
<div @click.| />
</template>
`, 'capture');
});

it('Alias path', async () => {
await ensureGlobalTypesHolder('tsconfigProject');
await assertCompletion('tsconfigProject/fixture.vue', 'vue', `
<script setup lang="ts">
import Component from '@/|';
</script>
`, 'empty.vue');
});

it('Relative path', async () => {
await ensureGlobalTypesHolder('tsconfigProject');
await assertCompletion('tsconfigProject/fixture.vue', 'vue', `
<script setup lang="ts">
import Component from './|';
</script>
`, 'empty.vue');
});

it('Component auto import', async () => {
await ensureGlobalTypesHolder('tsconfigProject');
await openDocument('tsconfigProject/ComponentForAutoImport.vue', 'vue', `<script setup lang="ts"></script>`);
await assertCompletion('tsconfigProject/fixture.vue', 'vue', `
<script setup lang="ts">
</script>
<template>
<ComponentForA| />
</template>
`, 'ComponentForAutoImport');
});

it('core#8811', async () => {
await ensureGlobalTypesHolder('tsconfigProject');
await assertCompletion('tsconfigProject/fixture.vue', 'vue', `
<script setup lang="ts">
declare const Foo: new () => {
$props: {
FooBar: string;
};
};
</script>
<template>
<Foo :-| ></Foo>
</template>
`, ':-foo-bar');
});

const openedDocuments: TextDocument[] = [];

afterEach(async () => {
const server = await getLanguageServer();
for (const document of openedDocuments) {
await server.closeTextDocument(document.uri);
}
openedDocuments.length = 0;
});

/**
* @deprecated Remove this when #4717 fixed.
*/
async function ensureGlobalTypesHolder(folderName: string) {
const document = await openDocument(`${folderName}/globalTypesHolder.vue`, 'vue', '');
const server = await getLanguageServer();
await server.sendDocumentDiagnosticRequest(document.uri);
}

async function assertCompletion(fileName: string, languageId: string, content: string, itemLabel: string) {
const offset = content.indexOf('|');
content = content.slice(0, offset) + content.slice(offset + 1);

const server = await getLanguageServer();
let document = await openDocument(fileName, languageId, content);

const position = document.positionAt(offset);
const completions = await server.sendCompletionRequest(document.uri, position);

let completion = completions?.items.find(item => item.label === itemLabel);
expect(completion).toBeDefined();

completion = await server.sendCompletionResolveRequest(completion!);
expect(completion).toBeDefined();

const edits: TextEdit[] = [];

if (completion.textEdit) {
if (InsertReplaceEdit.is(completion.textEdit)) {
edits.push({ newText: completion.textEdit.newText, range: completion.textEdit.replace });
}
else {
edits.push(completion.textEdit);
}
}
else {
edits.push({
newText: completion.insertText ?? completion.label,
range: { start: position, end: position },
});
}
if (completion.additionalTextEdits) {
edits.push(...completion.additionalTextEdits);
}
if (edits.length === 0) {
console.log(completion);
}
expect(edits.length).toBeGreaterThan(0);

document = await server.updateTextDocument(document.uri, edits);

expect(document.getText()).toMatchSnapshot();
}

async function openDocument(fileName: string, languageId: string, content: string) {
const server = await getLanguageServer();
const uri = URI.file(`${testWorkspacePath}/${fileName}`);
const document = await server.openInMemoryDocument(uri.toString(), languageId, content);
if (openedDocuments.every(d => d.uri !== document.uri)) {
openedDocuments.push(document);
}
return document;
}
});
29 changes: 29 additions & 0 deletions packages/language-server/tests/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as path from 'path';
import type { LanguageServerHandle } from '@volar/test-utils';
import { startLanguageServer } from '@volar/test-utils';
import { URI } from 'vscode-uri';

let serverHandle: LanguageServerHandle | undefined;

export const testWorkspacePath = path.resolve(__dirname, '../../../test-workspace');

export async function getLanguageServer() {
if (!serverHandle) {
serverHandle = startLanguageServer(require.resolve('../bin/vue-language-server.js'), testWorkspacePath);
serverHandle.connection.onNotification('textDocument/publishDiagnostics', () => { });

await serverHandle.initialize(
URI.file(testWorkspacePath).toString(),
{
typescript: {
tsdk: path.dirname(require.resolve('typescript/lib/typescript.js')),
disableAutoImportCache: true,
},
vue: {
hybridMode: false,
},
}
);
}
return serverHandle;
}
Loading

0 comments on commit 705cd4b

Please sign in to comment.