在本页

测试 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 跳转到标题

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

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