Skip to content

[Feature]: Expose changed and related test selection through the programmatic API #1596

Description

@jesusgalhub

What problem does this feature solve?

Rstest supports affected-test selection from its CLI through --changed, --related, and the Jest-compatible --findRelatedTests alias. However, this behavior is not available to tools that embed Rstest through its programmatic APIs.

createRstest accepts test-file filters that have already been resolved, while runRstest accepts exact test files. Neither API can:

  • Discover changed source files from the Git working tree or a commit/branch.
  • Resolve the test files related to source files through Rstest's build module graph.
  • Apply forceRerunTriggers consistently.
  • Preserve the CLI behavior for changed coverage, empty selections, exact filtering, validation, and reporter context.

The implementation used by the CLI, including resolveRelatedTestFiles and the effective-filter resolution, is internal and is not exported by @rstest/core or @rstest/core/api.

This affects frameworks and test orchestration tools that build an Rstest configuration and projects in memory. They cannot delegate to the Rstest CLI without serializing that configuration to a temporary file. Their remaining options are to copy Rstest's Git and Rspack graph logic or import private implementation files, both of which are fragile and can diverge from Rstest behavior.

A public programmatic API would let wrappers expose the same affected-test workflows as the Rstest CLI while keeping selection semantics owned by Rstest.

What does the proposed API look like?

One possible API is an experimental async factory in @rstest/core/api that creates an instance after resolving the requested selection:

import { createRstestWithSelection } from "@rstest/core/api";

const rstest = await createRstestWithSelection(
  {
    config,
    projects,
  },
  {
    command: "run",
    selection: {
      type: "changed",
      since: "origin/main",
    },
  },
);

await rstest.runTests();

Related source files could use the same API:

const rstest = await createRstestWithSelection(
  {
    config,
    projects,
  },
  {
    command: "list",
    selection: {
      type: "related",
      files: ["src/button.ts", "src/theme.ts"],
    },
  },
);

await rstest.listTests({ filesOnly: true });

A possible type definition:

type RstestSelection =
  | {
      type: "filters";
      files: string[];
    }
  | {
      type: "related";
      files: string[];
    }
  | {
      type: "changed";
      since?: string;
    };

type CreateRstestWithSelectionOptions = {
  command: "run" | "watch" | "list";
  selection?: RstestSelection;
};

The exact shape is flexible. The important part is that the API should share the implementation used by the CLI and return an Rstest instance configured with:

  • Resolved exact test-file filters for related and changed selection.
  • The same validation and error messages as the CLI.
  • forceRerunTriggers behavior.
  • Changed-coverage filters.
  • Related-selection context used by reporters and empty-selection handling.

--findRelatedTests would remain a CLI alias and map to the same programmatic related selection rather than requiring a separate API concept.

Ideally, the Rstest CLI would also consume this API internally so CLI and embedded integrations cannot drift apart.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions