Skip to content

The file page's Tests tab says no test reaches a file when the request for that answer failed #2624

Description

@RaghavChamadiya

Summary

TestsReachingList turns a rejected fetch into null and then renders null exactly like a real "nothing reaches this file" answer. A 500, a network error, or a server that is down all show the sentence "No test in the repository calls into this file, and none imports it."

packages/ui/src/health/tests-reaching-list.tsx:47-58:

  const { data, isLoading } = useSWR<TestsReachingFile | null>(
    fetcher ? `tests-reaching:${cacheKey}:${filePath}` : null,
    () => fetcher!(filePath).catch(() => null),
    { revalidateOnFocus: false },
  );
  ...
  if (!data || !data.reached || data.tests.length === 0) {

Mechanism

The .catch(() => null) swallows the error before SWR sees it, so error is never set and data is null. The empty-state branch tests !data together with !data.reached, so "we could not ask" and "we asked and nothing reaches it" take the same path. The comment above that branch explains why the second case is shown this way ("A file nothing reaches is the honest answer, not an error"). The first case is the error that comment separates it from.

The web host (packages/web/src/components/files/file-tests-panel.tsx) passes getTestsReaching, which rejects on any non-2xx response from /api/repos/{repo_id}/health/tests-reaching.

A related server-side note: the endpoint also returns its basis: "none" empty answer when the graph walk raises (packages/server/src/repowise/server/routers/code_health/coverage_routes.py:359). Its docstring says basis: "none" exists so "no test reaches this" stays distinguishable from "the graph had nothing to say". That path is worth looking at in the same change, but the UI conflation holds regardless of it.

Repro

A vitest render against origin/main:

render(
  <TestsReachingList filePath="src/a.py" cacheKey="zz"
    fetcher={async () => { throw new Error("HTTP 500"); }} />,
);
await waitFor(() =>
  expect(screen.getByText(/No test in the repository calls into this file/)).toBeInTheDocument(),
);

This passes. The rendered text is:

Tests reaching this fileNo test in the repository calls into this file, and none imports it. That is a static reading of the dependency graph, ...

Impact

A transient failure tells the reader the file is untested. The Tests tab exists to answer that question, and "no test reaches this" is the answer most likely to be acted on (write tests, or treat the file as risky to change). Nothing on the page says the answer is missing.

Done looks like

  • A rejected fetch renders a short "could not load which tests reach this file" state that is visibly different from the empty answer. Let SWR carry the error, or keep a distinct sentinel. Do not map it to null.
  • reached: false still renders the existing sentence and its static-reading caveat unchanged.
  • No fetcher still renders nothing.

Tests

In packages/ui/__tests__/health/inferred-tests.test.tsx:

  • A fetcher that rejects does not render "No test in the repository calls into this file", and does render the error state.
  • The existing "names the static limits when nothing reaches the file" test keeps passing.

Activity

  1. drakeo338 commented on Sep 28, 2026

    @drakeo338

    I'd like to take this one. I have the UI fix ready (let the fetch failure set an error state instead of folding into the empty-graph answer) plus a test for the rejected-fetch case, and will open the PR right after this comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood first issueGood for newcomers

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions