Skip to content

Commit

Permalink
feat: support vscode Testing API (#629)
Browse files Browse the repository at this point in the history
Closes #487
  • Loading branch information
kitsonk committed Mar 30, 2022
1 parent 2c74c58 commit 7a43c87
Show file tree
Hide file tree
Showing 24 changed files with 1,163 additions and 60 deletions.
28 changes: 14 additions & 14 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
"vscode-languageclient": "^7.0.0"
},
"devDependencies": {
"@types/semver": "7.3.8",
"@types/vscode": "1.60.0",
"@types/semver": "7.3.9",
"@types/vscode": "1.64.0",
"vscode-test": "^1.6.1"
}
}
11 changes: 10 additions & 1 deletion client/src/commands.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.

/** Contains handlers for commands that are enabled in Visual Studio Code for
* the extension. */
Expand All @@ -16,6 +16,7 @@ import {
reloadImportRegistries as reloadImportRegistriesReq,
} from "./lsp_extensions";
import * as tasks from "./tasks";
import { DenoTestController, TestingFeature } from "./testing";
import type { DenoExtensionContext, TestCommandOptions } from "./types";
import { WelcomePanel } from "./welcome";
import { assert, getDenoCommand } from "./util";
Expand Down Expand Up @@ -105,6 +106,8 @@ export function startLanguageServer(
if (extensionContext.client) {
const client = extensionContext.client;
extensionContext.client = undefined;
extensionContext.testController?.dispose();
extensionContext.testController = undefined;
extensionContext.statusBar.refresh(extensionContext);
vscode.commands.executeCommand("setContext", ENABLEMENT_FLAG, false);
await client.stop();
Expand Down Expand Up @@ -134,6 +137,8 @@ export function startLanguageServer(
serverOptions,
extensionContext.clientOptions,
);
const testingFeature = new TestingFeature();
client.registerFeature(testingFeature);
context.subscriptions.push(client.start());
await client.onReady();

Expand All @@ -147,6 +152,10 @@ export function startLanguageServer(
extensionContext.serverCapabilities = client.initializeResult?.capabilities;
extensionContext.statusBar.refresh(extensionContext);

if (testingFeature.enabled) {
context.subscriptions.push(new DenoTestController(extensionContext));
}

context.subscriptions.push(
client.onNotification(
registryState,
Expand Down
2 changes: 1 addition & 1 deletion client/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.

export const ENABLE = "enable";
export const ENABLE_PATHS = "enablePaths";
Expand Down
2 changes: 1 addition & 1 deletion client/src/content_provider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.

import { virtualTextDocument } from "./lsp_extensions";
import type { DenoExtensionContext } from "./types";
Expand Down
2 changes: 1 addition & 1 deletion client/src/debug_config_provider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.

import type { Settings } from "./types";
import { getDenoCommand } from "./util";
Expand Down
8 changes: 6 additions & 2 deletions client/src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.

import * as commands from "./commands";
import { ENABLE_PATHS, ENABLEMENT_FLAG, EXTENSION_NS } from "./constants";
Expand Down Expand Up @@ -35,6 +35,7 @@ const workspaceSettingsKeys: Array<keyof Settings> = [
"lint",
"path",
"suggest",
"testing",
"tlsCertificate",
"unsafelyIgnoreCertificateErrors",
"unstable",
Expand Down Expand Up @@ -186,7 +187,10 @@ export async function activate(
{ scheme: "file", language: "markdown" },
],
diagnosticCollectionName: "deno",
initializationOptions: getWorkspaceSettings(),
initializationOptions: getWorkspaceSettings,
markdown: {
isTrusted: true,
},
};

// When a workspace folder is opened, the updates or changes to the workspace
Expand Down
2 changes: 1 addition & 1 deletion client/src/initialize_project.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.

import { MultiStepInput } from "./multi_step_input";

Expand Down
208 changes: 206 additions & 2 deletions client/src/lsp_extensions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.

/** Contains extensions to the Language Server Protocol that are supported by
* the Deno Language Server.
Expand All @@ -12,7 +12,12 @@ import {
RequestType,
RequestType0,
} from "vscode-languageclient";
import type { TextDocumentIdentifier } from "vscode-languageclient";
import type {
Location,
MarkupContent,
Range,
TextDocumentIdentifier,
} from "vscode-languageclient";

export interface CacheParams {
referrer: TextDocumentIdentifier;
Expand Down Expand Up @@ -53,6 +58,205 @@ export const task = new RequestType<
"deno/task",
);

export interface TestData {
/** The unique ID for this test/step. */
id: string;

/** The display label for the test/step. */
label: string;

/** Any test steps that are associated with this test/step */
steps?: TestData[];

/** The range of the owning text document that applies to the test. */
range?: Range;
}

export interface TestModuleParams {
/** The text document identifier that the tests are related to. */
textDocument: TextDocumentIdentifier;

/** A indication if tests described are _newly_ discovered and should be
* _inserted_ or if the tests associated are a replacement for any existing
* tests. */
kind: "insert" | "replace";

/** The text label for the test module. */
label: string;

/** An array of tests that are owned by this test module. */
tests: TestData[];
}

/** Notification of a discovery of a test module. The notification parameters
* include */
export const testModule = new NotificationType<TestModuleParams>(
"deno/testModule",
);

export interface TestModuleDeleteParams {
/** The text document identifier that has been removed. */
textDocument: TextDocumentIdentifier;
}

export const testModuleDelete = new NotificationType<TestModuleDeleteParams>(
"deno/testModuleDelete",
);

export interface TestRunRequestParams {
/** The id of the test run to be used for future messages. */
id: number;

/** The run kind. Currently Deno only supports `"run"` */
kind: "run" | "coverage" | "debug";

/** Test modules or tests to exclude from the test run. */
exclude?: TestIdentifier[];

/** Test modules or tests to include in the test run. */
include?: TestIdentifier[];
}

interface EnqueuedTestModule {
/** The test module the enqueued test IDs relate to */
textDocument: TextDocumentIdentifier;

/** The test IDs which are now enqueued for testing */
ids: string[];
}

export interface TestRunResponseParams {
/** Test modules and test IDs that are now enqueued for testing. */
enqueued: EnqueuedTestModule[];
}

export const testRun = new RequestType<
TestRunRequestParams,
TestRunResponseParams,
void
>("deno/testRun");

export interface TestIdentifier {
/** The test module the message is related to. */
textDocument: TextDocumentIdentifier;

/** The optional ID of the test. If not present, then the message applies to
* all tests in the test module. */
id?: string;

/** The optional ID of the step. If not present, then the message only applies
* to the test. */
stepId?: string;
}

export interface TestMessage {
/** The content of the message. */
message: MarkupContent;

/** An optional string which represents the expected output. */
expectedOutput?: string;

/** An optional string which represents the actual output. */
actualOutput?: string;

/** An optional location related to the message. */
location?: Location;
}

interface TestEnqueuedStartedSkipped {
/** The state change that has occurred to a specific test or test step.
*
* - `"enqueued"` - the test is now enqueued to be tested
* - `"started"` - the test has started
* - `"skipped"` - the test was skipped
*/
type: "enqueued" | "started" | "skipped";

/** The test or test step relating to the state change. */
test: TestIdentifier;
}

interface TestFailedErrored {
/** The state change that has occurred to a specific test or test step.
*
* - `"failed"` - The test failed to run properly, versus the test erroring.
* currently the Deno language server does not support this.
* - `"errored"` - The test errored.
*/
type: "failed" | "errored";

/** The test or test step relating to the state change. */
test: TestIdentifier;

/** Messages related to the state change. */
messages: TestMessage[];

/** An optional duration, in milliseconds from the start to the current
* state. */
duration?: number;
}

interface TestPassed {
/** The state change that has occurred to a specific test or test step. */
type: "passed";

/** The test or test step relating to the state change. */
test: TestIdentifier;

/** An optional duration, in milliseconds from the start to the current
* state. */
duration?: number;
}

interface TestOutput {
/** The test or test step has output information / logged information. */
type: "output";

/** The value of the output. */
value: string;

/** The associated test or test step if there was one. */
test?: TestIdentifier;

/** An optional location associated with the output. */
location?: Location;
}

interface TestEnd {
/** The test run has ended. */
type: "end";
}

type TestRunProgressMessage =
| TestEnqueuedStartedSkipped
| TestFailedErrored
| TestPassed
| TestOutput
| TestEnd;

export interface TestRunProgressParams {
/** The test run ID that the progress message applies to. */
id: number;

/** The message*/
message: TestRunProgressMessage;
}

export const testRunProgress = new NotificationType<TestRunProgressParams>(
"deno/testRunProgress",
);

export interface TestRunCancelParams {
/** The test id to be cancelled. */
id: number;
}

export const testRunCancel = new RequestType<
TestRunCancelParams,
boolean,
void
>("deno/testRunCancel");

export interface VirtualTextDocumentParams {
textDocument: TextDocumentIdentifier;
}
Expand Down
2 changes: 1 addition & 1 deletion client/src/notification_handlers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.

import { RegistryStateParams } from "./lsp_extensions";
import { NotificationHandler } from "vscode-languageclient";
Expand Down
2 changes: 1 addition & 1 deletion client/src/server_info.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.

import { InitializeResult } from "vscode-languageclient";

Expand Down
Loading

0 comments on commit 7a43c87

Please sign in to comment.