Ctrl K
ComunidadGuías…

components/components.test.tsx

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { User } from '@/prisma/generated/client';
import { cleanup, render, screen } from '@testing-library/react';
import type { ReactNode } from 'react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import FormField from './FormField';
import Loader from './Loader';
import NavBar from './NavBar';
import NavHeader from './NavHeader';
import OTPInputWrapper from './OTPInputWrapper';
import Page from './Page';
import PageBody from './PageBody';
import PageContainer from './PageContainer';
import PageFooter from './PageFooter';
import PageFooterSponsor from './PageFooterSponsor';
import PageHeader from './PageHeader';
import Placeholder from './Placeholder';
import TimeDiff from './TimeDiff';
import NavSidebar from './NavSidebar';
import UserAvatar from './UserAvatar';
import { renderWithIntl } from '@/utils/test/renderWithIntl';

vi.mock('next-intl/server', () => ({
  getTranslations: vi.fn(async () => {
    return (key: string) => {
      if (key === 'madeWith') return 'Made with';
      if (key === 'by') return 'by';
      if (key === 'sourceCode') return 'Source code';
      if (key === 'buyMeCoffee') return 'Buy me a Coffee';

      return key;
    };
  }),
}));

vi.mock('input-otp', () => ({
  __esModule: true,
  OTPInput: ({ onChange }: { onChange: (value: string) => void }) => (
    <input
      data-testid="mocked-input-otp"
      onChange={(e) => onChange(e.target.value)}
    />
  ),
  SlotProps: ({ char, isActive }: { char: string; isActive: boolean }) => (
    <div className={`slot ${isActive ? 'active' : ''}`}>{char}</div>
  ),
}));

vi.mock('@/app/login/lib/actions', () => ({
  getCurrentSession: () => {
    return {
      user: {
        id: 1,
        name: 'Test User',
        role: 'user',
      },
    };
  },
}));

const mockUsePathname = vi.fn(() => '/');
vi.mock('next/navigation', () => ({
  usePathname: () => mockUsePathname(),
  useSearchParams: () => new URLSearchParams(),
}));

type OTPInputRenderProps = {
  slots: [];
};

vi.mock('input-otp', () => ({
  __esModule: true,
  OTPInput: ({
    render,
  }: {
    render: (props: OTPInputRenderProps) => ReactNode;
  }) => {
    return <div>{render({ slots: [] })}</div>;
  },
  SlotProps: ({ char, isActive }: { char: string; isActive: boolean }) => (
    <div className={`slot ${isActive ? 'active' : ''}`}>{char}q</div>
  ),
}));

describe('Component Tests', () => {
  beforeEach(() => {
    cleanup();
  });

  it('renders TimeDiff component', () => {
    const { container } = render(<TimeDiff updatedAt={new Date()} />);
    expect(container).toBeInTheDocument();
  });

  it('renders Placeholder component', () => {
    const { container } = render(<Placeholder />);
    expect(container).toBeInTheDocument();
  });

  it('renders Placeholder component with only background', () => {
    const { container } = render(<Placeholder background={true} />);
    expect(container).toBeInTheDocument();
    expect(container.querySelector('.card-body')).not.toBeInTheDocument();
  });

  it('renders PageHeader component', () => {
    const { container } = render(
      <PageHeader title="Test Title" breadcrumbs={[]} />,
    );
    expect(container).toBeInTheDocument();
  });

  it('renders PageHeader component with breadcrumbs', () => {
    const { container } = render(
      <PageHeader
        title="Test Title"
        breadcrumbs={[
          { name: 'Home', href: '/' },
          { name: 'Dashboard', href: '/dashboard' },
        ]}
      />,
    );
    expect(container).toBeInTheDocument();
    expect(screen.getByText('Home')).toBeInTheDocument();
    expect(screen.getByText('Dashboard')).toBeInTheDocument();
  });

  // TODO: implement image in the new ui
  // it('renders PageHeader component with imageUrl', () => {
  //   const { container } = render(
  //     <PageHeader
  //       title="Test Title"
  //       breadcrumbs={[]}
  //       imageUrl="test-image.jpg"
  //     />
  //   );
  //   expect(container).toBeInTheDocument();
  //   expect(container.querySelector('img')).toBeInTheDocument();
  // });

  it('renders PageFooterSponsor component', async () => {
    const pageFooterSponsor = await PageFooterSponsor();
    const { container } = render(pageFooterSponsor);
    expect(container).toBeInTheDocument();
  });

  it('renders PageFooter component', async () => {
    const pageFooter = await PageFooter();
    const { container } = render(pageFooter);
    expect(container).toBeInTheDocument();
  });

  it('renders PageFooterSponsor component inside PageFooter', async () => {
    vi.stubEnv('SHOW_SPONSOR_FOOTER', 'true');
    const pageFooter = await PageFooter();
    const { container } = render(pageFooter);
    expect(container).toBeInTheDocument();
    expect(screen.getByText('Buy me a Coffee')).toBeInTheDocument();
  });

  it('does not render PageFooterSponsor component inside PageFooter when env is false', async () => {
    vi.stubEnv('SHOW_SPONSOR_FOOTER', 'false');
    const pageFooter = await PageFooter();
    const { container } = render(pageFooter);
    expect(container).toBeInTheDocument();
    expect(screen.queryByText('Buy me a Coffee')).not.toBeInTheDocument();
  });

  it('renders PageContainer component', async () => {
    const pageContainer = await PageContainer({ children: <div>Test</div> });
    const { container } = render(pageContainer);
    expect(container).toBeInTheDocument();
  });

  it('renders PageBody component', () => {
    const { container } = render(<PageBody>Test Content</PageBody>);
    expect(container).toBeInTheDocument();
  });

  it('renders Page component', async () => {
    const page = await Page({ children: <div>Test</div> });
    const { container } = render(page);
    expect(container).toBeInTheDocument();
  });

  it('renders OTPInputWrapper component', () => {
    const { container } = render(<OTPInputWrapper onChange={() => {}} />);
    expect(container).toBeInTheDocument();
  });

  it('renders OTPInputWrapper component with slots', () => {
    const { container } = render(<OTPInputWrapper onChange={() => {}} />);
    expect(container).toBeInTheDocument();
    expect(screen.getByText('-')).toBeInTheDocument();
  });

  it('renders NavHeader component', async () => {
    const { container } = renderWithIntl(
      <NavHeader user={{ id: 1, name: 'Test User', role: 'user' } as User} />,
    );
    expect(container).toBeInTheDocument();
  });

  it('renders up to two user initials', () => {
    render(<UserAvatar name="Alexis Quinn" />);
    expect(screen.getByText('AQ')).toBeInTheDocument();
  });

  it('renders NavBar component', () => {
    const { container } = renderWithIntl(
      <NavBar user={{ id: 1, role: 'user' } as User} />,
    );
    expect(container).toBeInTheDocument();
  });

  it('renders NavBar component with admin role', () => {
    const { container } = renderWithIntl(
      <NavBar user={{ id: 1, role: 'admin' } as User} />,
    );
    expect(container).toBeInTheDocument();
    expect(screen.getByText('Admin')).toBeInTheDocument();
  });

  it('not shows admin nav for non-admin users', () => {
    const { container } = renderWithIntl(
      <NavBar user={{ id: 1, role: 'user' } as User} />,
    );
    expect(container).toBeInTheDocument();
    expect(screen.queryByText('Admin')).not.toBeInTheDocument();
  });

  it('shows favorites and recent nav icons only when collapsed', () => {
    const user = { id: 1, role: 'user' } as User;
    const { rerender } = renderWithIntl(<NavBar user={user} />);
    expect(document.querySelector('a[href="/favorites"]')).toBeNull();

    rerender(<NavBar user={user} isCollapsed />);
    expect(document.querySelector('a[href="/favorites"]')).not.toBeNull();
    expect(document.querySelector('a[href="/recent"]')).not.toBeNull();
  });

  it('renders expanded quick links with see more in NavBar', () => {
    renderWithIntl(
      <NavBar
        user={{ id: 1, role: 'user' } as User}
        quickLinks={{
          favorites: [{ type: 'note', title: 'My fav note', url: '/boards/1/notes/2' }],
          recent: [{ type: 'board', title: 'My recent board', url: '/boards/3/notes' }],
        }}
      />,
    );
    expect(screen.getByText('My fav note').closest('a')).toHaveAttribute(
      'href',
      '/boards/1/notes/2',
    );
    expect(screen.getByText('My recent board')).toBeInTheDocument();
    const seeMore = screen.getAllByText('See more').map((a) => a.getAttribute('href'));
    expect(seeMore).toEqual(['/favorites', '/recent']);
  });

  it('renders Loader component', () => {
    const { container } = render(<Loader caption="Loading..." />);
    expect(container).toBeInTheDocument();
  });

  it('renders FormField component', () => {
    const { container } = render(<FormField label="Test Label" name="test" />);
    expect(container).toBeInTheDocument();
  });

  it('renders NavSidebar component', () => {
    const { container } = renderWithIntl(
      <NavSidebar user={{ id: 1, role: 'user' } as User} />,
    );
    expect(container).toBeInTheDocument();
  });

  it('renders Loader component', () => {
    const { container } = render(<Loader caption="Loading..." />);
    expect(container).toBeInTheDocument();
  });
});