// @vitest-environment jsdom
import { render, screen, cleanup } from "@testing-library/react";
import { describe, test, expect, vi, afterEach } from "vitest";
import "vitest-dom/extend-expect";
import TableCard from "../TableCard";
describe("TableCard", () => {
afterEach(() => {
cleanup();
});
const defaultProps = {
countByProperty: [
["example.com", "100"],
["test.com", "50"],
] as [string, string, string?][],
columnHeaders: ["Site", "Views"],
};
test("renders basic table structure", () => {
render();
expect(screen.getByText("Site")).toBeInTheDocument();
expect(screen.getByText("Views")).toBeInTheDocument();
expect(screen.getByText("example.com")).toBeInTheDocument();
expect(screen.getByText("test.com")).toBeInTheDocument();
expect(screen.getByText("100")).toBeInTheDocument();
expect(screen.getByText("50")).toBeInTheDocument();
});
test("renders external link icon for URLs", () => {
const propsWithUrls = {
countByProperty: [
["https://example.com", "100"],
["http://test.com", "50"],
["not-a-url", "25"],
] as [string, string, string?][],
columnHeaders: ["Site", "Views"],
};
const { container } = render();
// Should render external link icons for URLs - query specifically within this component
const externalLinks = container.querySelectorAll('a[href^="http"]');
expect(externalLinks).toHaveLength(2);
// Check that the links have correct attributes
expect(externalLinks[0]).toHaveAttribute("href", "https://example.com");
expect(externalLinks[0]).toHaveAttribute("target", "_blank");
expect(externalLinks[0]).toHaveAttribute("rel", "noreferrer");
expect(externalLinks[0]).toHaveAttribute("aria-hidden", "true");
expect(externalLinks[1]).toHaveAttribute("href", "http://test.com");
expect(externalLinks[1]).toHaveAttribute("target", "_blank");
expect(externalLinks[1]).toHaveAttribute("rel", "noreferrer");
expect(externalLinks[1]).toHaveAttribute("aria-hidden", "true");
// Non-URL should not have an external link
expect(screen.getByText("not-a-url")).toBeInTheDocument();
});
test("does not render external link icon for non-URLs", () => {
const propsWithoutUrls = {
countByProperty: [
["example.com", "100"],
["some-path", "50"],
["", "25"],
] as [string, string, string?][],
columnHeaders: ["Site", "Views"],
};
const { container } = render();
// Should not render any external link icons
const externalLinks = container.querySelectorAll('a[href^="http"]');
expect(externalLinks).toHaveLength(0);
});
test("works with onClick handler and external links", () => {
const mockOnClick = vi.fn();
const propsWithOnClick = {
countByProperty: [
["https://example.com", "100"],
["not-a-url", "50"],
] as [string, string, string?][],
columnHeaders: ["Site", "Views"],
onClick: mockOnClick,
};
const { container } = render();
// Should have both clickable buttons and external links
const buttons = screen.getAllByRole("button");
expect(buttons).toHaveLength(2);
const externalLinks = container.querySelectorAll('a[href^="http"]');
expect(externalLinks).toHaveLength(1);
expect(externalLinks[0]).toHaveAttribute("href", "https://example.com");
});
test("applies labelFormatter to URLs before checking for external links", () => {
const labelFormatter = (label: string) => label.toUpperCase();
const propsWithFormatter = {
countByProperty: [
["https://example.com", "100"],
] as [string, string, string?][],
columnHeaders: ["Site", "Views"],
labelFormatter,
};
const { container } = render();
// Should still detect the original URL for external link
const externalLinks = container.querySelectorAll('a[href^="http"]');
expect(externalLinks).toHaveLength(1);
expect(externalLinks[0]).toHaveAttribute("href", "https://example.com");
// But display the formatted label
expect(screen.getByText("HTTPS://EXAMPLE.COM")).toBeInTheDocument();
});
test("handles edge cases for URL detection", () => {
const edgeCaseProps = {
countByProperty: [
["https://", "10"],
["http://", "20"],
["ftp://example.com", "30"],
["https://example.com/path?query=1", "40"],
] as [string, string, string?][],
columnHeaders: ["Site", "Views"],
};
const { container } = render();
const externalLinks = container.querySelectorAll('a[href^="http"]');
// Should only match http:// and https:// protocols
expect(externalLinks).toHaveLength(3);
expect(externalLinks[0]).toHaveAttribute("href", "https://");
expect(externalLinks[1]).toHaveAttribute("href", "http://");
expect(externalLinks[2]).toHaveAttribute("href", "https://example.com/path?query=1");
// ftp:// should not have an external link
expect(screen.getByText("ftp://example.com")).toBeInTheDocument();
});
});