import type { ReactNode } from 'react';
import { afterEach, describe, expect, test } from 'bun:test';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { MemoryRouter, useLocation } from 'react-router';
import { render, screen, waitFor } from '@testing-library/react';
import { ServersView } from './ServersView';
import { offscaleRegisterPath } from './shared';
/**
* Whether "Register a server" opens the form — from every place that offers it.
*
* The bug this pins was reported as "I click register a server and nothing happens", and nothing was
* broken: three controls carry that label and the one in the server picker was a plain link to the Servers
* section. `/offscale` and `/offscale/servers` render the same view, so from the section you were already
* on it changed the URL and nothing else — a control that looks like the primary action and is a no-op.
*
* So the test is about the link's DESTINATION doing something, which is why it renders the view at that
* destination rather than clicking the picker: the picker lives in another panel, and what has to be true
* is that arriving there opens the form.
*
* `fetch` is stubbed rather than `mock.module('hooks/useClient')` — Bun has one module registry per run, so
* that mock is process-wide and permanent, and other files already own it.
*/
const realFetch = globalThis.fetch;
afterEach(() => {
globalThis.fetch = realFetch;
});
const stubServers = (servers: unknown[] = []) => {
globalThis.fetch = (async () =>
new Response(JSON.stringify({ servers }), {
status: 200,
headers: { 'content-type': 'application/json' },
})) as unknown as typeof fetch;
};
/** Reports the live URL, so "the flag was consumed" is an assertion rather than an inference. */
const Search = () => {useLocation().search};
const Wrap = ({ at, children }: { at: string; children: ReactNode }) => (
{children}
);
const mountAt = (at: string) =>
render(
,
);
const formHeading = () => screen.queryByText('Register a Headscale server');
const search = () => screen.getByTestId('search').textContent;
describe('ServersView registration form', () => {
test('the picker link lands with the form already open', async () => {
stubServers([]);
mountAt(offscaleRegisterPath());
await waitFor(() => expect(formHeading()).not.toBeNull());
});
test('the flag is consumed, so clicking the picker link again still works', async () => {
stubServers([]);
mountAt(offscaleRegisterPath());
// Left in the URL, a second click on the picker would be a navigation to the URL already showing —
// which is the original bug, restored.
await waitFor(() => expect(search()).toBe(''));
});
test('without the flag the form stays closed', async () => {
stubServers([]);
mountAt('/offscale/servers');
// The empty state has to have rendered before "no form" means anything.
await waitFor(() => expect(screen.queryByText('No Headscale servers yet')).not.toBeNull());
expect(formHeading()).toBeNull();
});
});