Files
stack/apps/web/src/components/auth/OAuthButton.test.tsx
Jason Woltje 81b5204258
All checks were successful
ci/woodpecker/push/orchestrator Pipeline was successful
ci/woodpecker/push/web Pipeline was successful
ci/woodpecker/push/api Pipeline was successful
feat(#415): theme fix, AuthDivider, SessionExpiryWarning components
- AUTH-014: Fix theme storage key (jarvis-theme -> mosaic-theme)
- AUTH-016: Create AuthDivider component with customizable text
- AUTH-019: Create SessionExpiryWarning floating banner (PDA-friendly, blue)
- Fix lint errors in LoginForm, OAuthButton from parallel agents
- Sync pnpm-lock.yaml for recharts dependency

Refs #415

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 11:37:31 -06:00

90 lines
3.2 KiB
TypeScript

import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { OAuthButton } from "./OAuthButton";
describe("OAuthButton", (): void => {
const defaultProps = {
providerName: "Authentik",
providerId: "authentik",
onClick: vi.fn(),
};
it("should render with provider name", (): void => {
render(<OAuthButton {...defaultProps} />);
expect(screen.getByText("Continue with Authentik")).toBeInTheDocument();
});
it("should have full width styling", (): void => {
render(<OAuthButton {...defaultProps} />);
const button = screen.getByRole("button");
expect(button.className).toContain("w-full");
});
it("should call onClick when clicked", async (): Promise<void> => {
const user = userEvent.setup();
const onClick = vi.fn();
render(<OAuthButton {...defaultProps} onClick={onClick} />);
const button = screen.getByRole("button");
await user.click(button);
expect(onClick).toHaveBeenCalledTimes(1);
});
it("should show loading state with spinner and Connecting text", (): void => {
render(<OAuthButton {...defaultProps} isLoading={true} />);
expect(screen.getByText("Connecting...")).toBeInTheDocument();
expect(screen.queryByText("Continue with Authentik")).not.toBeInTheDocument();
});
it("should be disabled when isLoading is true", (): void => {
render(<OAuthButton {...defaultProps} isLoading={true} />);
const button = screen.getByRole("button");
expect(button).toBeDisabled();
});
it("should be disabled when disabled prop is true", (): void => {
render(<OAuthButton {...defaultProps} disabled={true} />);
const button = screen.getByRole("button");
expect(button).toBeDisabled();
});
it("should have reduced opacity when disabled", (): void => {
render(<OAuthButton {...defaultProps} disabled={true} />);
const button = screen.getByRole("button");
expect(button.className).toContain("opacity-50");
expect(button.className).toContain("pointer-events-none");
});
it("should have aria-label with provider name", (): void => {
render(<OAuthButton {...defaultProps} />);
const button = screen.getByRole("button");
expect(button).toHaveAttribute("aria-label", "Continue with Authentik");
});
it("should have aria-label Connecting when loading", (): void => {
render(<OAuthButton {...defaultProps} isLoading={true} />);
const button = screen.getByRole("button");
expect(button).toHaveAttribute("aria-label", "Connecting");
});
it("should render a spinner SVG when loading", (): void => {
const { container } = render(<OAuthButton {...defaultProps} isLoading={true} />);
const spinner = container.querySelector("svg");
expect(spinner).toBeInTheDocument();
expect(spinner?.getAttribute("class")).toContain("animate-spin");
});
it("should not call onClick when disabled", async (): Promise<void> => {
const user = userEvent.setup();
const onClick = vi.fn();
render(<OAuthButton {...defaultProps} onClick={onClick} disabled={true} />);
const button = screen.getByRole("button");
await user.click(button);
expect(onClick).not.toHaveBeenCalled();
});
});