import React, { act } from 'react';
import { createRoot } from 'react-dom/client';
import { afterEach, describe, expect, it, vi } from 'vitest';

import type { MemberSpawnStatusEntry, ResolvedTeamMember, TeamTaskWithKanban } from '@shared/types';

const hoisted = vi.hoisted(() => ({
  openExternal: vi.fn(),
}));

vi.mock('@renderer/api', () => ({
  api: {
    openExternal: hoisted.openExternal,
  },
}));

vi.mock('@renderer/components/ui/badge', () => ({
  Badge: ({
    children,
    className,
    title,
  }: {
    children: React.ReactNode;
    className?: string;
    title?: string;
  }) => React.createElement('span', { className, title }, children),
}));

vi.mock('@renderer/components/ui/tooltip', () => ({
  TooltipProvider: ({
    children,
    delayDuration,
    skipDelayDuration,
  }: {
    children: React.ReactNode;
    delayDuration?: number;
    skipDelayDuration?: number;
  }) =>
    React.createElement(
      'div',
      {
        'data-testid': 'tooltip-provider',
        'data-delay-duration': delayDuration,
        'data-skip-delay-duration': skipDelayDuration,
      },
      children
    ),
  Tooltip: ({
    children,
    delayDuration,
    open,
  }: {
    children: React.ReactNode;
    delayDuration?: number;
    open?: boolean;
  }) =>
    React.createElement(
      'div',
      {
        'data-testid': 'tooltip-root',
        'data-delay-duration': delayDuration,
        'data-open': open,
      },
      children
    ),
  TooltipTrigger: ({ children }: { children: React.ReactNode }) =>
    React.createElement(React.Fragment, null, children),
  TooltipContent: ({
    children,
    className,
  }: {
    children: React.ReactNode;
    className?: string;
  }) => React.createElement('div', { className, 'data-testid': 'tooltip-content' }, children),
}));

vi.mock('@renderer/hooks/useTheme', () => ({
  useTheme: () => ({ isLight: false }),
}));

vi.mock('@renderer/components/team/members/CurrentTaskIndicator', () => ({
  CurrentTaskIndicator: () => null,
}));

import { MemberCard } from '@renderer/components/team/members/MemberCard';

const member: ResolvedTeamMember = {
  name: 'alice',
  status: 'unknown',
  taskCount: 0,
  currentTaskId: null,
  lastActiveAt: null,
  messageCount: 0,
  color: 'blue',
  agentType: 'reviewer',
  role: 'Reviewer',
  providerId: 'gemini',
  removedAt: undefined,
};

const currentTask: TeamTaskWithKanban = {
  id: 'task-1',
  displayId: 'abc12345',
  subject: 'Build calculator UI',
  status: 'in_progress',
} as unknown as TeamTaskWithKanban;

const failedSpawnEntry: MemberSpawnStatusEntry = {
  status: 'error',
  launchState: 'failed_to_start',
  runtimeAlive: false,
  bootstrapConfirmed: false,
  hardFailure: true,
  hardFailureReason: 'spawn failed',
  agentToolAccepted: false,
  livenessKind: 'not_found',
  runtimeDiagnostic: 'spawn failed',
  runtimeDiagnosticSeverity: 'error',
  updatedAt: '2026-04-24T12:00:00.000Z',
};

const skippedSpawnEntry: MemberSpawnStatusEntry = {
  status: 'skipped',
  launchState: 'skipped_for_launch',
  runtimeAlive: false,
  bootstrapConfirmed: false,
  hardFailure: false,
  agentToolAccepted: false,
  skippedForLaunch: true,
  skipReason: 'Skipped by user after launch failure: spawn failed',
  skippedAt: '2026-04-24T12:01:00.000Z',
  updatedAt: '2026-04-24T12:01:00.000Z',
};

describe('MemberCard starting-state visuals', () => {
  afterEach(() => {
    document.body.innerHTML = '';
    hoisted.openExternal.mockReset();
    vi.useRealTimers();
  });

  it('shows runtime summary while keeping the starting treatment after provisioning stops', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          runtimeSummary: 'Anthropic · haiku · Medium',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'spawning',
          spawnLaunchState: 'starting',
          spawnRuntimeAlive: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('starting');
    expect(host.textContent).toContain('Anthropic · haiku · Medium');
    expect(host.querySelector('.member-waiting-shimmer')).not.toBeNull();
    expect(host.querySelectorAll('.skeleton-shimmer').length).toBe(0);

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('shows provider retry advisory instead of plain online while bootstrap contact is still pending', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            runtimeAdvisory: {
              kind: 'sdk_retrying',
              observedAt: '2026-04-07T09:00:00.000Z',
              retryUntil: '2099-04-07T09:00:45.000Z',
              retryDelayMs: 45_000,
              reasonCode: 'quota_exhausted',
            },
          },
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'online',
          spawnLaunchState: 'runtime_pending_bootstrap',
          spawnRuntimeAlive: true,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('Gemini quota retry');
    expect(host.textContent).not.toContain('online');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('shows a full loading badge for connecting teammates during provisioning', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: false,
          isTeamProvisioning: true,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('connecting');
    expect(host.querySelector('[aria-label="connecting"]')).not.toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('keeps runtime retry visible even while the teammate already has an active task', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            currentTaskId: currentTask.id,
            runtimeAdvisory: {
              kind: 'sdk_retrying',
              observedAt: '2026-04-07T09:00:00.000Z',
              retryUntil: '2099-04-07T09:00:45.000Z',
              retryDelayMs: 45_000,
              reasonCode: 'quota_exhausted',
              message: 'Gemini cli backend error: capacity exceeded.',
            },
          },
          memberColor: 'blue',
          currentTask,
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'online',
          spawnLaunchState: 'confirmed_alive',
          spawnRuntimeAlive: true,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('Gemini quota retry');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('shows timed OpenCode quota advisory with a relaunch action', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const onRestartMember = vi.fn();

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            providerId: 'opencode',
            runtimeAdvisory: {
              kind: 'api_error',
              observedAt: '2026-05-17T21:44:34.000Z',
              retryUntil: '2099-05-18T00:00:00.000Z',
              retryDelayMs: 8_000,
              reasonCode: 'quota_exhausted',
              message: 'Free usage exceeded, subscribe to Go https://opencode.ai/go',
            },
          },
          memberColor: 'blue',
          currentTask,
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'online',
          spawnLaunchState: 'confirmed_alive',
          spawnRuntimeAlive: true,
          onRestartMember,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('OpenCode quota error · retry');
    const relaunchButton = host.querySelector('button[aria-label="Relaunch OpenCode"]');
    expect(relaunchButton).not.toBeNull();
    expect(host.querySelector('button[aria-label="Copy diagnostics"]')).not.toBeNull();

    await act(async () => {
      (relaunchButton as HTMLButtonElement).click();
      await Promise.resolve();
    });

    expect(onRestartMember).toHaveBeenCalledWith('alice');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('shows the OpenCode advisory relaunch action in awaiting-reply rows', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const onRestartMember = vi.fn();

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            providerId: 'opencode',
            runtimeAdvisory: {
              kind: 'api_error',
              observedAt: '2026-05-17T21:44:34.000Z',
              retryUntil: '2099-05-18T00:00:00.000Z',
              retryDelayMs: 8_000,
              reasonCode: 'quota_exhausted',
              message: 'Free usage exceeded, subscribe to Go https://opencode.ai/go',
            },
          },
          memberColor: 'blue',
          isAwaitingReply: true,
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'online',
          spawnLaunchState: 'confirmed_alive',
          spawnRuntimeAlive: true,
          onRestartMember,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('OpenCode quota error · retry');
    const relaunchButton = host.querySelector('button[aria-label="Relaunch OpenCode"]');
    expect(relaunchButton).not.toBeNull();
    expect(host.querySelector('button[aria-label="Copy diagnostics"]')).not.toBeNull();

    await act(async () => {
      (relaunchButton as HTMLButtonElement).click();
      await Promise.resolve();
    });

    expect(onRestartMember).toHaveBeenCalledWith('alice');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('does not show the OpenCode advisory relaunch action for protocol-proof warnings', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const onRestartMember = vi.fn();

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            providerId: 'opencode',
            runtimeAdvisory: {
              kind: 'api_error',
              observedAt: '2026-05-17T21:44:34.000Z',
              reasonCode: 'protocol_proof_missing',
              message: 'non_visible_tool_without_task_progress',
            },
          },
          memberColor: 'blue',
          currentTask,
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'online',
          spawnLaunchState: 'confirmed_alive',
          spawnRuntimeAlive: true,
          onRestartMember,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('OpenCode proof missing');
    expect(host.querySelector('button[aria-label="Relaunch OpenCode"]')).toBeNull();
    expect(host.querySelector('button[aria-label="Copy diagnostics"]')).toBeNull();
    expect(onRestartMember).not.toHaveBeenCalled();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('keeps runtime-pending launch status visible even when the teammate has an active task', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            currentTaskId: currentTask.id,
          },
          memberColor: 'blue',
          currentTask,
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'online',
          spawnLaunchState: 'runtime_pending_bootstrap',
          spawnRuntimeAlive: true,
          spawnLivenessSource: 'process',
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('waiting for bootstrap');
    expect(host.textContent).not.toContain('online');
    expect(host.querySelector('[aria-label="waiting for bootstrap"]')).not.toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('keeps registered-only OpenCode status visible next to active task context', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            providerId: 'opencode',
            currentTaskId: currentTask.id,
          },
          memberColor: 'blue',
          currentTask,
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'waiting',
          spawnLaunchState: 'runtime_pending_bootstrap',
          spawnRuntimeAlive: false,
          runtimeEntry: {
            memberName: 'alice',
            alive: false,
            restartable: false,
            providerId: 'opencode',
            livenessKind: 'registered_only',
            runtimeDiagnostic: 'registered runtime metadata without live process',
            updatedAt: '2026-04-27T12:17:58.714Z',
          },
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('registered');
    expect(host.querySelector('[aria-label="registered"]')).not.toBeNull();
    expect(host.firstElementChild?.className).toContain('-mx-[calc(1rem-5px)]');
    expect(host.firstElementChild?.className).toContain('px-[calc(1rem-5px)]');
    expect(host.querySelector('[role="button"]')?.className).toContain('-mx-[calc(1rem-5px)]');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('keeps the starting treatment and runtime summary visible while a runtime is still joining', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          runtimeSummary: 'Anthropic · sonnet · Medium',
          isTeamAlive: true,
          isTeamProvisioning: false,
          isLaunchSettling: true,
          spawnStatus: 'online',
          spawnLaunchState: 'runtime_pending_bootstrap',
          spawnRuntimeAlive: true,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('starting');
    expect(host.textContent).toContain('Anthropic · sonnet · Medium');
    expect(host.textContent).not.toContain('online');
    expect(host.querySelector('.member-waiting-shimmer')).not.toBeNull();
    expect(host.querySelectorAll('.skeleton-shimmer').length).toBe(0);

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('shows an awaiting permission badge for teammates blocked on runtime permissions', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'online',
          spawnLaunchState: 'runtime_pending_permission',
          spawnRuntimeAlive: true,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('awaiting permission');
    expect(host.querySelector('[aria-label="awaiting permission"]')).not.toBeNull();
    expect(host.querySelector('.member-waiting-shimmer')).not.toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('shows a waiting-for-bootstrap badge while runtime bootstrap is still pending after the process comes online', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          runtimeSummary: 'Gemini · flash · Medium',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'online',
          spawnLaunchState: 'runtime_pending_bootstrap',
          spawnRuntimeAlive: true,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('waiting for bootstrap');
    expect(host.textContent).not.toContain('ready');
    expect(host.querySelector('[aria-label="waiting for bootstrap"]')).not.toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('shows ready instead of idle for confirmed teammates while launch is still settling', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          runtimeSummary: 'Anthropic · sonnet · Medium',
          isTeamAlive: true,
          isTeamProvisioning: false,
          isLaunchSettling: true,
          spawnStatus: 'online',
          spawnLaunchState: 'confirmed_alive',
          spawnRuntimeAlive: true,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('ready');
    expect(host.textContent).not.toContain('idle');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('shows member color on the avatar ring instead of a colored card rail', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
        })
      );
      await Promise.resolve();
    });

    const img = host.querySelector('img');
    const avatarRing = img?.parentElement;
    const clickableCard = host.querySelector('[role="button"]') as HTMLElement | null;

    expect(avatarRing).not.toBeNull();
    expect(avatarRing?.style.borderColor).toBe('#3b82f6');
    expect(clickableCard?.style.borderLeft).toBe('');
    expect(clickableCard?.style.background).toBe('');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('renders memory after the role label in the compact runtime summary row', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          runtimeSummary: '5.2 · Medium · 238.3 MB',
          isTeamAlive: true,
          isTeamProvisioning: false,
        })
      );
      await Promise.resolve();
    });

    const text = host.textContent ?? '';
    expect(text).toContain('5.2 · Medium');
    expect(text).toContain('Reviewer');
    expect(text).toContain('238.3 MB');
    expect(text.indexOf('Reviewer')).toBeLessThan(text.indexOf('238.3 MB'));

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('labels shared OpenCode host memory instead of member-owned runtime memory', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          runtimeSummary: 'minimax · via OpenCode · 183.9 MB',
          runtimeEntry: {
            memberName: 'alice',
            alive: true,
            restartable: false,
            providerId: 'opencode',
            pid: 333,
            runtimeLoadScope: 'shared-host',
            rssBytes: 183.9 * 1024 * 1024,
            updatedAt: '2026-04-24T12:00:00.000Z',
          },
          isTeamAlive: true,
          isTeamProvisioning: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.querySelector('[title="RSS source: shared OpenCode host"]')).not.toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('renders the bottom runtime telemetry strip when resource history is available', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          runtimeSummary: 'gpt-5.4-mini · Codex · 238.3 MB',
          runtimeEntry: {
            memberName: 'alice',
            alive: true,
            restartable: true,
            providerId: 'codex',
            pid: 222,
            pidSource: 'tmux_child',
            rssBytes: 238.3 * 1024 * 1024,
            cpuPercent: 14,
            primaryCpuPercent: 4,
            primaryRssBytes: 210 * 1024 * 1024,
            childCpuPercent: 10,
            childRssBytes: 28.3 * 1024 * 1024,
            processCount: 3,
            runtimeLoadScope: 'process-tree',
            resourceHistory: [
              {
                timestamp: '2026-04-24T12:00:00.000Z',
                rssBytes: 220 * 1024 * 1024,
                cpuPercent: 0,
                primaryCpuPercent: 0,
                primaryRssBytes: 210 * 1024 * 1024,
                childCpuPercent: 0,
                childRssBytes: 10 * 1024 * 1024,
                processCount: 2,
                runtimeLoadScope: 'process-tree',
                pidSource: 'tmux_child',
                pid: 222,
              },
              {
                timestamp: '2026-04-24T12:00:05.000Z',
                rssBytes: 238.3 * 1024 * 1024,
                cpuPercent: 14,
                primaryCpuPercent: 4,
                primaryRssBytes: 210 * 1024 * 1024,
                childCpuPercent: 10,
                childRssBytes: 28.3 * 1024 * 1024,
                processCount: 3,
                runtimeLoadScope: 'process-tree',
                pidSource: 'tmux_child',
                pid: 222,
              },
            ],
            updatedAt: '2026-04-24T12:00:05.000Z',
          },
          runtimeTelemetryVisible: true,
          runtimeTelemetryScale: {
            cpuCapPercent: 100,
            memoryCapBytes: 512 * 1024 * 1024,
          },
          isTeamAlive: true,
          isTeamProvisioning: false,
        })
      );
      await Promise.resolve();
    });

    const strip = host.querySelector('[data-testid="member-runtime-telemetry-strip"]');
    expect(strip).not.toBeNull();
    expect(strip?.querySelector('path[fill="#22c55e"]')).not.toBeNull();
    const cpuPath = strip?.querySelector('path[stroke="#3b82f6"]');
    expect(cpuPath).not.toBeNull();
    expect(cpuPath?.getAttribute('d')).toContain('M0 16.10');
    expect(strip?.getAttribute('title')).toBeNull();
    expect(
      host.querySelector('[data-testid="tooltip-root"][data-delay-duration="0"]')
    ).not.toBeNull();
    expect(host.querySelector('[data-testid="tooltip-root"]')?.getAttribute('data-open')).toBe(
      'false'
    );
    expect(host.textContent).toContain('Local runtime load');
    expect(host.textContent).toContain('Parent and child processes only.');
    expect(host.textContent).toContain('root PID 222');
    expect(host.textContent).toContain('3 processes');
    expect(host.textContent).toContain('CPU');
    expect(host.textContent).toContain('14%');
    expect(host.textContent).toContain('Memory');
    expect(host.textContent).toContain('238 MB');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('ignores malformed runtime telemetry history without crashing', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          runtimeSummary: 'gpt-5.4-mini · Codex · 238.3 MB',
          runtimeEntry: {
            memberName: 'alice',
            alive: true,
            restartable: true,
            providerId: 'codex',
            pid: 222,
            resourceHistory: 'not-an-array',
            updatedAt: '2026-04-24T12:00:05.000Z',
          } as any,
          runtimeTelemetryVisible: true,
          isTeamAlive: true,
          isTeamProvisioning: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.querySelector('[data-testid="member-runtime-telemetry-strip"]')).toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('ignores malformed runtime telemetry samples while rendering valid samples', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          runtimeSummary: 'gpt-5.4-mini · Codex · 238.3 MB',
          runtimeEntry: {
            memberName: 'alice',
            alive: true,
            restartable: true,
            providerId: 'codex',
            pid: 222,
            resourceHistory: [
              null,
              {
                timestamp: '2026-04-24T12:00:00.000Z',
                rssBytes: 220 * 1024 * 1024,
                cpuPercent: 0,
              },
              'bad-sample',
              {
                timestamp: '2026-04-24T12:00:05.000Z',
                rssBytes: 238 * 1024 * 1024,
                cpuPercent: 12,
              },
            ],
            updatedAt: '2026-04-24T12:00:05.000Z',
          } as any,
          runtimeTelemetryVisible: true,
          isTeamAlive: true,
          isTeamProvisioning: false,
        })
      );
      await Promise.resolve();
    });

    const strip = host.querySelector('[data-testid="member-runtime-telemetry-strip"]');
    expect(strip).not.toBeNull();
    expect(strip?.querySelector('path[stroke="#3b82f6"]')).not.toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('shows a worktree badge only for teammates configured with worktree isolation', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            providerId: 'opencode',
            isolation: 'worktree',
            cwd: '/tmp/project-alice-worktree',
          },
          memberColor: 'blue',
          runtimeSummary: 'kimi · via OpenCode',
          isTeamAlive: true,
          isTeamProvisioning: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('worktree');
    expect(host.textContent).toContain('Worktree isolation is enabled.');
    expect(host.textContent).toContain('Path: /tmp/project-alice-worktree');

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            providerId: 'opencode',
            isolation: 'worktree',
          },
          memberColor: 'blue',
          runtimeEntry: {
            memberName: 'alice',
            alive: true,
            restartable: true,
            providerId: 'opencode',
            cwd: '/tmp/project',
            updatedAt: '2026-04-24T12:00:00.000Z',
          },
          runtimeSummary: 'kimi · via OpenCode',
          isTeamAlive: true,
          isTeamProvisioning: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('worktree');
    expect(host.textContent).toContain('Path is not available yet.');
    expect(host.textContent).not.toContain('Runtime cwd: /tmp/project');

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            providerId: 'opencode',
            cwd: '/tmp/project',
          },
          memberColor: 'blue',
          runtimeSummary: 'kimi · via OpenCode',
          isTeamAlive: true,
          isTeamProvisioning: false,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).not.toContain('worktree');
    expect(host.textContent).not.toContain('shared');
    expect(host.querySelector('[title^="Shared workspace"]')).toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('copies bounded launch diagnostics only for launch errors', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const writeText = vi.fn().mockResolvedValue(undefined);
    Object.defineProperty(navigator, 'clipboard', {
      configurable: true,
      value: { writeText },
    });
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          runtimeRunId: 'run-42',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'waiting',
          spawnLaunchState: 'runtime_pending_bootstrap',
          spawnRuntimeAlive: false,
          spawnEntry: {
            status: 'waiting',
            launchState: 'runtime_pending_bootstrap',
            runtimeAlive: false,
            bootstrapConfirmed: false,
            hardFailure: false,
            agentToolAccepted: true,
            livenessKind: 'shell_only',
            runtimeDiagnostic: 'tmux pane foreground command is zsh',
            runtimeDiagnosticSeverity: 'warning',
            updatedAt: '2026-04-24T12:00:00.000Z',
          },
          runtimeEntry: {
            memberName: 'alice',
            alive: false,
            restartable: true,
            pid: 26676,
            pidSource: 'tmux_pane',
            paneCurrentCommand: 'zsh',
            processCommand: 'node runtime --token super-secret',
            updatedAt: '2026-04-24T12:00:01.000Z',
          },
        })
      );
      await Promise.resolve();
    });

    expect(host.querySelector('[aria-label="Copy diagnostics"]')).toBeNull();

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          runtimeRunId: 'run-42',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'error',
          spawnLaunchState: 'failed_to_start',
          spawnRuntimeAlive: false,
          spawnError: 'spawn failed',
          spawnEntry: {
            status: 'error',
            launchState: 'failed_to_start',
            runtimeAlive: false,
            bootstrapConfirmed: false,
            hardFailure: true,
            hardFailureReason: 'spawn failed',
            agentToolAccepted: false,
            livenessKind: 'not_found',
            runtimeDiagnostic: 'spawn failed',
            runtimeDiagnosticSeverity: 'error',
            updatedAt: '2026-04-24T12:00:00.000Z',
          },
          runtimeEntry: {
            memberName: 'alice',
            alive: false,
            restartable: true,
            pid: 26676,
            pidSource: 'tmux_pane',
            paneCurrentCommand: 'zsh',
            processCommand: 'node runtime --token super-secret',
            updatedAt: '2026-04-24T12:00:01.000Z',
          },
        })
      );
      await Promise.resolve();
    });

    const button = host.querySelector('[aria-label="Copy diagnostics"]') as HTMLButtonElement;
    expect(button).not.toBeNull();

    await act(async () => {
      button.click();
      await Promise.resolve();
    });

    expect(writeText).toHaveBeenCalledTimes(1);
    const payload = JSON.parse(writeText.mock.calls[0][0] as string) as {
      runId?: string;
      livenessKind?: string;
      processCommand?: string;
    };
    expect(payload.runId).toBe('run-42');
    expect(payload.livenessKind).toBe('not_found');
    expect(payload.processCommand).toContain('--token [redacted]');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('renders retry for failed teammate launches', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'error',
          spawnLaunchState: 'failed_to_start',
          spawnRuntimeAlive: false,
          spawnError: 'spawn failed',
          spawnEntry: failedSpawnEntry,
          onRestartMember: vi.fn(),
        })
      );
      await Promise.resolve();
    });

    expect(host.querySelector('[aria-label="Retry teammate"]')).not.toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('shows a compact failed launch reason on the member row with clickable links', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const reason =
      'Latest assistant message msg_df2d6414f0016Bn0Pc0QJbo5sU failed with APIError - Insufficient credits. Add more using https://openrouter.ai/settings/credits';

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'error',
          spawnLaunchState: 'failed_to_start',
          spawnRuntimeAlive: false,
          spawnError: reason,
          spawnEntry: {
            ...failedSpawnEntry,
            hardFailureReason: reason,
            runtimeDiagnostic: reason,
          },
          onRestartMember: vi.fn(),
        })
      );
      await Promise.resolve();
    });

    const failureReason = host.querySelector('[data-testid="member-launch-failure-reason"]');
    expect(failureReason?.textContent).toContain('Insufficient credits');
    expect(failureReason?.textContent).toContain('OpenRouter credits');
    expect(failureReason?.textContent).not.toContain('Latest assistant message');
    expect(failureReason?.textContent).not.toContain('msg_df2d6414');

    const link = failureReason?.querySelector(
      'a[href="https://openrouter.ai/settings/credits"]'
    ) as HTMLAnchorElement | null;
    expect(link).not.toBeNull();

    await act(async () => {
      link?.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
      await Promise.resolve();
    });

    expect(hoisted.openExternal).toHaveBeenCalledWith('https://openrouter.ai/settings/credits');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('does not truncate long failed launch reasons on the member row', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const reason = `APIError - ${'Codex runtime context includes missing login session. '.repeat(
      8
    )}final diagnostic marker`;

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'error',
          spawnLaunchState: 'failed_to_start',
          spawnRuntimeAlive: false,
          spawnError: reason,
          spawnEntry: {
            ...failedSpawnEntry,
            hardFailureReason: reason,
            runtimeDiagnostic: reason,
          },
          onRestartMember: vi.fn(),
        })
      );
      await Promise.resolve();
    });

    const failureReason = host.querySelector('[data-testid="member-launch-failure-reason"]');
    expect(failureReason?.textContent).toContain('final diagnostic marker');
    expect(failureReason?.querySelector('.line-clamp-2')).toBeNull();
    expect(failureReason?.textContent).not.toContain('...');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('renders Relaunch OpenCode for registered-only OpenCode teammates', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const onRestartMember = vi.fn(async () => undefined);
    const onClick = vi.fn();
    const openCodeMember: ResolvedTeamMember = {
      ...member,
      providerId: 'opencode',
    };

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: openCodeMember,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'online',
          spawnLaunchState: 'confirmed_alive',
          spawnRuntimeAlive: true,
          spawnEntry: {
            status: 'online',
            launchState: 'confirmed_alive',
            runtimeAlive: false,
            bootstrapConfirmed: false,
            livenessKind: 'registered_only',
            updatedAt: '2026-04-24T12:00:00.000Z',
          },
          runtimeEntry: {
            memberName: 'alice',
            alive: false,
            restartable: true,
            providerId: 'opencode',
            livenessKind: 'registered_only',
            runtimeDiagnostic: 'registered runtime metadata without live process',
            updatedAt: '2026-04-24T12:00:00.000Z',
          },
          onClick,
          onRestartMember,
        })
      );
      await Promise.resolve();
    });

    const button = host.querySelector('[aria-label="Relaunch OpenCode"]') as HTMLButtonElement;
    expect(button).not.toBeNull();

    await act(async () => {
      button.click();
      await Promise.resolve();
    });

    expect(onRestartMember).toHaveBeenCalledWith('alice');
    expect(onClick).not.toHaveBeenCalled();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('does not render Relaunch OpenCode for fresh runtime candidates', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    vi.useFakeTimers();
    vi.setSystemTime(new Date('2026-04-24T12:01:00.000Z'));
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            providerId: 'opencode',
          },
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'online',
          spawnLaunchState: 'runtime_pending_bootstrap',
          spawnRuntimeAlive: true,
          spawnEntry: {
            status: 'online',
            launchState: 'runtime_pending_bootstrap',
            runtimeAlive: true,
            bootstrapConfirmed: false,
            livenessKind: 'runtime_process_candidate',
            firstSpawnAcceptedAt: '2026-04-24T12:00:00.000Z',
            updatedAt: '2026-04-24T12:00:00.000Z',
          },
          runtimeEntry: {
            memberName: 'alice',
            alive: true,
            restartable: true,
            providerId: 'opencode',
            livenessKind: 'runtime_process_candidate',
            updatedAt: '2026-04-24T12:00:00.000Z',
          },
          onRestartMember: vi.fn(),
        })
      );
      await Promise.resolve();
    });

    expect(host.querySelector('[aria-label="Relaunch OpenCode"]')).toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
    vi.useRealTimers();
  });

  it('renders skip for failed teammate launches', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'error',
          spawnLaunchState: 'failed_to_start',
          spawnRuntimeAlive: false,
          spawnError: 'spawn failed',
          spawnEntry: failedSpawnEntry,
          onSkipMemberForLaunch: vi.fn(),
        })
      );
      await Promise.resolve();
    });

    expect(host.querySelector('[aria-label="Skip for this launch"]')).not.toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('retries failed teammate launches without opening the member row', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const onClick = vi.fn();
    let resolveRetry!: () => void;
    const retryPromise = new Promise<void>((resolve) => {
      resolveRetry = resolve;
    });
    const onRestartMember = vi.fn(() => retryPromise);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'error',
          spawnLaunchState: 'failed_to_start',
          spawnRuntimeAlive: false,
          spawnError: 'spawn failed',
          spawnEntry: failedSpawnEntry,
          onClick,
          onRestartMember,
        })
      );
      await Promise.resolve();
    });

    const button = host.querySelector('[aria-label="Retry teammate"]') as HTMLButtonElement;
    expect(button).not.toBeNull();

    await act(async () => {
      button.click();
      await Promise.resolve();
    });

    expect(onRestartMember).toHaveBeenCalledWith('alice');
    expect(onClick).not.toHaveBeenCalled();
    expect(host.querySelector('[aria-label="Retrying teammate"]')).not.toBeNull();

    await act(async () => {
      resolveRetry();
      await retryPromise;
      await Promise.resolve();
    });

    expect(host.querySelector('[aria-label="Retry teammate"]')).not.toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('skips failed teammate launches without opening the member row', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const onClick = vi.fn();
    let resolveSkip!: () => void;
    const skipPromise = new Promise<void>((resolve) => {
      resolveSkip = resolve;
    });
    const onSkipMemberForLaunch = vi.fn(() => skipPromise);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'error',
          spawnLaunchState: 'failed_to_start',
          spawnRuntimeAlive: false,
          spawnError: 'spawn failed',
          spawnEntry: failedSpawnEntry,
          onClick,
          onSkipMemberForLaunch,
        })
      );
      await Promise.resolve();
    });

    const button = host.querySelector('[aria-label="Skip for this launch"]') as HTMLButtonElement;
    expect(button).not.toBeNull();

    await act(async () => {
      button.click();
      await Promise.resolve();
    });

    expect(onSkipMemberForLaunch).toHaveBeenCalledWith('alice');
    expect(onClick).not.toHaveBeenCalled();
    expect(host.querySelector('[aria-label="Skipping teammate"]')).not.toBeNull();

    await act(async () => {
      resolveSkip();
      await skipPromise;
      await Promise.resolve();
    });

    expect(host.querySelector('[aria-label="Skip for this launch"]')).not.toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('keeps retry available and exposes retry errors after rejection', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const onRestartMember = vi.fn(async () => {
      throw new Error('restart failed');
    });

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'error',
          spawnLaunchState: 'failed_to_start',
          spawnRuntimeAlive: false,
          spawnError: 'spawn failed',
          spawnEntry: failedSpawnEntry,
          onRestartMember,
        })
      );
      await Promise.resolve();
    });

    const button = host.querySelector('[aria-label="Retry teammate"]') as HTMLButtonElement;
    expect(button).not.toBeNull();

    await act(async () => {
      button.click();
      await Promise.resolve();
      await Promise.resolve();
    });

    expect(onRestartMember).toHaveBeenCalledWith('alice');
    expect(host.querySelector('[aria-label="Retry teammate"]')).not.toBeNull();
    expect(host.textContent).toContain('restart failed');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('keeps skip available and exposes skip errors after rejection', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);
    const onSkipMemberForLaunch = vi.fn(async () => {
      throw new Error('skip failed');
    });

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'error',
          spawnLaunchState: 'failed_to_start',
          spawnRuntimeAlive: false,
          spawnError: 'spawn failed',
          spawnEntry: failedSpawnEntry,
          onSkipMemberForLaunch,
        })
      );
      await Promise.resolve();
    });

    const button = host.querySelector('[aria-label="Skip for this launch"]') as HTMLButtonElement;
    expect(button).not.toBeNull();

    await act(async () => {
      button.click();
      await Promise.resolve();
      await Promise.resolve();
    });

    expect(onSkipMemberForLaunch).toHaveBeenCalledWith('alice');
    expect(host.querySelector('[aria-label="Skip for this launch"]')).not.toBeNull();
    expect(host.textContent).toContain('skip failed');

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('shows skipped teammates as skipped and keeps retry available', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member,
          memberColor: 'blue',
          isTeamAlive: true,
          isTeamProvisioning: false,
          spawnStatus: 'skipped',
          spawnLaunchState: 'skipped_for_launch',
          spawnRuntimeAlive: false,
          spawnEntry: skippedSpawnEntry,
          onRestartMember: vi.fn(),
          onSkipMemberForLaunch: vi.fn(),
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('skipped');
    expect(host.textContent).toContain('Skipped by user after launch failure');
    expect(host.querySelector('[aria-label="Retry teammate"]')).not.toBeNull();
    expect(host.querySelector('[aria-label="Skip for this launch"]')).toBeNull();

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });

  it('moves worktree branch details into the worktree badge tooltip', async () => {
    vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
    const host = document.createElement('div');
    document.body.appendChild(host);
    const root = createRoot(host);

    await act(async () => {
      root.render(
        React.createElement(MemberCard, {
          member: {
            ...member,
            name: 'jack',
            isolation: 'worktree',
            cwd: '/Users/belief/.claude/team-worktrees/sol-team-proj-abc/room/jack',
            gitBranch: 'agent-teams/room/jack-abc',
          },
          memberColor: 'turquoise',
          isTeamAlive: true,
        })
      );
      await Promise.resolve();
    });

    expect(host.textContent).toContain('worktree');
    expect(host.textContent).toContain(
      'Path: /Users/belief/.claude/team-worktrees/sol-team-proj-abc/room/jack'
    );
    expect(host.textContent).toContain('Branch: agent-teams/room/jack-abc');
    expect(host.textContent?.match(/agent-teams\/room\/jack-abc/g)).toHaveLength(1);

    await act(async () => {
      root.unmount();
      await Promise.resolve();
    });
  });
});
