diff --git a/src/components/admin/__tests__/api-token-overview-responsive.test.tsx b/src/components/admin/__tests__/api-token-overview-responsive.test.tsx
new file mode 100644
index 000000000..f9c2ef6e6
--- /dev/null
+++ b/src/components/admin/__tests__/api-token-overview-responsive.test.tsx
@@ -0,0 +1,115 @@
+import { describe, expect, it, vi } from "vitest";
+import { renderToStaticMarkup } from "react-dom/server";
+
+/**
+ * v1.4.15 phase A2 — `/admin/api-tokens` table responsive guard.
+ *
+ * The token table previously rendered six full-width columns at every
+ * breakpoint. On Pixel-5-class viewports (360 CSS px) the row exceeded
+ * the card and forced the document itself to scroll horizontally. The
+ * fix hides three lower-priority columns (user, last-used, created)
+ * until `sm:`/`md:` and surfaces the user inline under the token name
+ * on mobile so no data is lost.
+ *
+ * This test asserts the responsive classes are present in the rendered
+ * markup so a future refactor can't silently drop them.
+ */
+
+vi.mock("next/navigation", () => ({
+ useRouter: () => ({ push: vi.fn(), replace: vi.fn() }),
+ usePathname: () => "/admin/api-tokens",
+}));
+
+const sampleTokens = [
+ {
+ id: "tok1",
+ name: "iOS app",
+ permissions: ["*"],
+ lastUsedAt: "2026-05-08T12:00:00Z",
+ expiresAt: null,
+ createdAt: "2026-05-01T08:00:00Z",
+ revoked: false,
+ user: { id: "u1", username: "marc" },
+ },
+];
+
+vi.mock("@tanstack/react-query", () => ({
+ useQuery: () => ({
+ data: sampleTokens,
+ isLoading: false,
+ isError: false,
+ refetch: vi.fn(),
+ }),
+ useQueryClient: () => ({ invalidateQueries: vi.fn() }),
+ useMutation: () => ({
+ mutate: vi.fn(),
+ isPending: false,
+ isError: false,
+ error: null,
+ }),
+}));
+
+vi.mock("@/hooks/use-auth", () => ({
+ useAuth: () => ({
+ user: {
+ id: "u1",
+ username: "marc",
+ email: "marc@example.com",
+ role: "ADMIN",
+ },
+ isAuthenticated: true,
+ isLoading: false,
+ refetch: vi.fn(),
+ }),
+}));
+
+import { I18nProvider } from "@/lib/i18n/context";
+import { ApiTokenOverviewSection } from "../api-token-overview-section";
+
+function render() {
+ return renderToStaticMarkup(
+
| + | {t("admin.tokenUser")} | @@ -73,10 +79,10 @@ export function ApiTokenOverviewSection() { | {t("admin.tokenStatus")} | -+ | {t("admin.tokenLastUsed")} | -+ | {t("admin.tokenCreated")} | + | {token.user.username} | -{token.name} | +
+
+ {token.name}
+ {/* On mobile the user column is hidden, so
+ surface the username inline under the
+ token name instead of dropping it. */}
+
+ {token.user.username}
+
+
+ |
{token.permissions.map((p) => (
@@ -122,12 +138,12 @@ export function ApiTokenOverviewSection() {
)}
|
- + | {token.lastUsedAt ? formatDateTime(token.lastUsedAt) : t("admin.tokenNeverUsed")} | -+ | {formatDate(token.createdAt)} |
|---|