From da309c16e9f1fbde626385e73d1fb7137b3b5a16 Mon Sep 17 00:00:00 2001 From: Peter Burns Date: Fri, 4 Feb 2022 13:57:12 -0600 Subject: [PATCH] Add an integration test of completions. (#232) * Add an integration test of completions. * Clarify the completions fixture file Also put the completion locations in a single, easier-to-update place in the code. * Also open our test vscode to the fixtures dir This way we can, in the future, add settings and such to a .vscode directory there. Also makes debugging a bit nicer. * Use path join more Hoping to fix windows test * Don't throw when failing to write to log file. --- packages/ts-lit-plugin/src/logger.ts | 6 ++- .../src/test/fixtures/completions.ts | 31 ++++++++++++ .../src/test/scripts/test-runner.ts | 5 +- .../vscode-lit-plugin/src/test/simple-test.ts | 47 +++++++++++++++++++ 4 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 packages/vscode-lit-plugin/src/test/fixtures/completions.ts diff --git a/packages/ts-lit-plugin/src/logger.ts b/packages/ts-lit-plugin/src/logger.ts index 7a8ad0bb..af077e3c 100644 --- a/packages/ts-lit-plugin/src/logger.ts +++ b/packages/ts-lit-plugin/src/logger.ts @@ -86,7 +86,11 @@ export class Logger extends DefaultLitAnalyzerLogger { breakLength: 50, maxArrayLength: 10 }); - appendFileSync(this.logPath, `${prefix}${message}\n`); + try { + appendFileSync(this.logPath, `${prefix}${message}\n`); + } catch { + // ignore + } this.tsLogger?.msg(`[ts-lit-plugin] ${message}`, level === LitAnalyzerLoggerLevel.ERROR ? tsServer.server.Msg.Err : tsServer.server.Msg.Info); } } diff --git a/packages/vscode-lit-plugin/src/test/fixtures/completions.ts b/packages/vscode-lit-plugin/src/test/fixtures/completions.ts new file mode 100644 index 00000000..83266d58 --- /dev/null +++ b/packages/vscode-lit-plugin/src/test/fixtures/completions.ts @@ -0,0 +1,31 @@ +// Pretending this is the Lit html function +// eslint-disable-next-line @typescript-eslint/no-explicit-any +declare const html: any; + +/** An element to test autocomplete with. */ +class CompleteMe extends HTMLElement { + /** Docs for prop 1. */ + prop1 = ""; + /** Docs for prop 2. */ + prop2 = ""; + /** Docs for prop 3. */ + prop3 = ""; +} +customElements.define("complete-me", CompleteMe); +declare global { + interface HTMLElementTagNameMap { + "complete-me": CompleteMe; + } +} + +// These lines are used as a basis for testing completions, with hardcoded +// line and character offsets in the test file. So if you change this file, +// you'll likely need to update those offsets in ../simple-test.ts +html` + + { ["'my-element' has not been registered on HTMLElementTagNameMap"] ); }); + + test("We generate completions", async () => { + const doc = await vscode.workspace.openTextDocument(vscode.Uri.file(path.join(__dirname, "../../src/test/fixtures/completions.ts"))); + const editor = await vscode.window.showTextDocument(doc); + + const tagCompletionPosition = new vscode.Position(27, 8); + const propertyCompletionPosition = new vscode.Position(25, 6); + + editor.selection = new vscode.Selection(tagCompletionPosition, tagCompletionPosition); + + async function getCompletions(expected: string) { + for (let i = 0; i < 100; i++) { + const completions = await vscode.commands.executeCommand( + "vscode.executeCompletionItemProvider", + doc.uri, + editor.selection.active + ); + if (completions && completions.items.length > 0) { + for (const completion of completions.items) { + if (completion.label === expected) { + return completions.items; + } + } + } + // Is there a better way to wait for the ts server to be ready? + // Maybe we can listen for the event that displays and hides the "initializing TS/JS language features" message? + await new Promise(resolve => setTimeout(resolve, 100)); + } + throw new Error("No completions found"); + } + + const elemCompletions = await getCompletions("complete-me"); + const elemLabels = elemCompletions.map(c => c.label); + assert.ok(elemLabels.includes("complete-me"), `Expected to find completion 'complete-me' in completions: ${JSON.stringify(elemLabels)}`); + + editor.selection = new vscode.Selection(propertyCompletionPosition, propertyCompletionPosition); + // type a '.' character + await editor.edit(editBuilder => { + editBuilder.insert(editor.selection.active, "."); + }); + + const propCompletions = await getCompletions(".prop1"); + const propLabels = propCompletions.map(c => c.label); + assert.ok(propLabels.includes(".prop1"), `Expected to find completion '.prop1' in completions: ${JSON.stringify(propLabels)}`); + assert.ok(propLabels.includes(".prop2"), `Expected to find completion '.prop2' in completions: ${JSON.stringify(propLabels)}`); + assert.ok(propLabels.includes(".prop3"), `Expected to find completion '.prop3' in completions: ${JSON.stringify(propLabels)}`); + }); });