All files / web/src/routes/__tests__ route-test-utils.tsx

100% Statements 60/60
100% Branches 11/11
100% Functions 5/5
100% Lines 60/60

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 991x         1x 1x 1x                     1x 1x 1x 1x 1x 32x 32x 32x 32x 32x 1x 32x 31x 31x 31x 32x   32x 8x 8x 8x 31x 31x 8x 32x   1x 1x         1x 1x 1x 1x         1x 27x 27x 27x   27x 27x 27x 27x 27x 27x   27x 27x                     1x 28x 28x 28x 28x 28x 28x   28x 28x 28x 28x   28x 28x 28x  
import {
  createMemoryHistory,
  createRouter,
  RouterProvider,
} from '@tanstack/react-router';
import { render } from '@testing-library/react';
import { vi } from 'vitest';
import { routeTree } from '../../routeTree.gen';
 
/**
 * Recursively walk the route tree and collect all route IDs.
 * Each route stores its relative ID segment in `options.id`.
 * Full IDs are built by concatenating parent segments.
 * The root route has no `options.id` — we emit `__root__` for it.
 *
 * Accepts `typeof routeTree` which is a complex generic — we use
 * structural access via `as` casts on the untyped shape.
 */
export function collectRouteIds(
  route: typeof routeTree,
  ids: Set<string> = new Set(),
): Set<string> {
  function walk(
    node: { isRoot?: boolean; options?: { id?: string }; children?: object },
    parentId: string,
  ) {
    let fullId: string;
    if (node.isRoot) {
      fullId = '__root__';
    } else {
      const segment = node.options?.id as string;
      fullId = parentId + segment;
    }
    ids.add(fullId);
 
    if (node.children) {
      for (const child of Object.values(
        node.children as Record<string, typeof node>,
      )) {
        walk(child, node.isRoot ? '' : fullId);
      }
    }
  }
 
  walk(
    route as unknown as {
      isRoot?: boolean;
      options?: { id?: string };
      children?: object;
    },
    '',
  );
  return ids;
}
 
/**
 * Render a route by navigating to the given path using the real route tree.
 */
export function renderRoute(path: string) {
  const memoryHistory = createMemoryHistory({
    initialEntries: [path],
  });
 
  const router = createRouter({
    routeTree,
    history: memoryHistory,
    defaultPendingMinMs: 0,
    defaultPreload: false,
  });
 
  return render(<RouterProvider router={router} />);
}
 
/**
 * Configure a global `fetch` mock that responds to `/auth/status` requests.
 *
 * Both `__root.tsx` (beforeLoad) and `login.tsx` (beforeLoad) call
 * `fetch('/v1/super-agents/auth/status')` to decide whether to render
 * the page or redirect.
 *
 * Returns the mock so callers can add further assertions.
 */
export function setupAuthMocks(
  options: { authRequired?: boolean; authenticated?: boolean } = {
    authRequired: false,
    authenticated: true,
  },
) {
  const { authRequired = false, authenticated = true } = options;
 
  const mockFetch = vi.fn().mockResolvedValue({
    ok: true,
    json: async () => ({ authRequired, authenticated }),
  });
 
  vi.stubGlobal('fetch', mockFetch);
  return mockFetch;
}