跳至主要内容

测试 API

Deno 语言服务器支持一组自定义 API 来启用测试。这些 API 是围绕为 vscode 的测试 API 提供信息而构建的,但也可以由其他语言服务器客户端使用来提供类似的接口。

功能

客户端和服务器都应该支持实验性的 testingApi 功能

interface ClientCapabilities {
experimental?: {
testingApi: boolean;
};
}
interface ServerCapabilities {
experimental?: {
testingApi: boolean;
};
}

当支持测试 API 的 Deno 版本遇到支持该功能的客户端时,它将初始化处理测试检测的代码,并开始提供启用它的通知。

还应注意,当启用测试 API 功能时,测试代码透镜将不再发送到客户端。

设置

有一些特定设置会改变语言服务器的行为

  • deno.testing.args - 一个字符串数组,将在执行测试时作为参数提供。这与 deno test 子命令的工作方式相同。
  • deno.testing.enable - 一个二进制标志,用于启用或禁用测试服务器

通知

服务器将在特定条件下向客户端发送通知。

deno/testModule

当服务器发现包含测试的模块时,它将通过发送包含 TestModuleParams 负载的 deno/testModule 通知来通知客户端。

Deno 以这种方式构建

  • 一个模块可以包含 *n* 个测试。
  • 一个测试可以包含 *n* 个步骤。
  • 一个步骤可以包含 *n* 个步骤。

当 Deno 对测试模块进行静态分析时,它会尝试识别任何测试和测试步骤。由于测试在 Deno 中的声明方式是动态的,因此它们不能总是被静态识别,只能在模块执行时识别。通知旨在处理这两种情况,以便在更新客户端时进行处理。当静态发现测试时,通知 kind 将为 "replace",当在执行时发现测试或步骤时,通知 kind 将为 "insert"

当测试文档在编辑器中被编辑,并且从客户端收到 textDocument/didChange 通知时,服务器端将执行这些更改的静态分析,如果测试已更改,客户端将收到通知。

当客户端收到 "replace" 通知时,它可以安全地“替换”测试模块表示,而当收到 "insert" 时,它应该递归地尝试添加到现有表示中。

对于测试模块,textDocument.uri 应该用作任何表示的唯一 ID(因为它是对唯一模块的字符串 URL)。TestData 项目包含唯一的 id 字符串。此 id 字符串是服务器跟踪测试的识别信息的 SHA-256 哈希。

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;
}

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[];
}

deno/testModuleDelete

当服务器正在观察的测试模块被删除时,服务器将发出 deno/testModuleDelete 通知。收到通知时,客户端应删除测试模块及其所有子测试和测试步骤的表示。

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

deno/testRunProgress

当客户端请求 deno/testRun 时,服务器将通过 deno/testRunProgress 通知支持该测试运行的进度。

客户端应该处理这些消息并更新任何 UI 表示。

状态更改在 TestRunProgressParams.message.kind 属性中表示。状态如下:

  • "enqueued" - 测试或测试步骤已排队等待测试。
  • "skipped" - 测试或测试步骤已跳过。当 Deno 测试的 ignore 选项设置为 true 时,就会发生这种情况。
  • "started" - 测试或测试步骤已开始。
  • "passed" - 测试或测试步骤已通过。
  • "failed" - 测试或测试步骤已失败。这旨在指示测试运行程序本身的错误,而不是测试本身的错误,但 Deno 目前不支持这种区分。
  • "errored" - 测试或测试步骤已出错。有关错误的更多信息将在 .message.messages 属性中。
  • "end" - 测试运行已结束。
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;
}

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;

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

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

请求

服务器处理两种不同的请求

deno/testRun

为了请求语言服务器执行一组测试,客户端发送一个 deno/testRun 请求,其中包括将在未来响应中用于客户端的测试运行 ID、测试运行的类型以及要包含或排除的任何测试模块或测试。

目前 Deno 只支持 "run" 类型的测试运行。"debug""coverage" 都计划在未来得到支持。

当没有包含的测试模块或测试时,这意味着应该执行所有发现的测试模块和测试。当包含一个测试模块,但没有包含任何测试 ID 时,这意味着该测试模块中的所有测试都应该被包含。一旦所有测试都被识别,任何被排除的测试都会被移除,并且解析后的测试集将在响应中作为 "enqueued" 返回。

由于测试步骤声明和运行方式的动态性,无法通过此 API 包含或排除测试步骤。

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[];
}

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

deno/testRunCancel

如果客户端希望取消当前正在运行的测试运行,它会发送一个包含测试 ID 的 deno/testRunCancel 请求来取消。响应将是一个布尔值,如果测试被取消,则为 true,如果无法取消,则为 false。在测试被取消时,仍然会发送适当的测试进度通知。

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