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 }) => (
onChange(e.target.value)}
/>
),
SlotProps: ({ char, isActive }: { char: string; isActive: boolean }) => (
{char}
),
}));
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 {render({ slots: [] })}
;
},
SlotProps: ({ char, isActive }: { char: string; isActive: boolean }) => (
{char}q
),
}));
describe('Component Tests', () => {
beforeEach(() => {
cleanup();
});
it('renders TimeDiff component', () => {
const { container } = render();
expect(container).toBeInTheDocument();
});
it('renders Placeholder component', () => {
const { container } = render();
expect(container).toBeInTheDocument();
});
it('renders Placeholder component with only background', () => {
const { container } = render();
expect(container).toBeInTheDocument();
expect(container.querySelector('.card-body')).not.toBeInTheDocument();
});
it('renders PageHeader component', () => {
const { container } = render(
,
);
expect(container).toBeInTheDocument();
});
it('renders PageHeader component with breadcrumbs', () => {
const { container } = render(
,
);
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(
//
// );
// 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: Test
});
const { container } = render(pageContainer);
expect(container).toBeInTheDocument();
});
it('renders PageBody component', () => {
const { container } = render(Test Content);
expect(container).toBeInTheDocument();
});
it('renders Page component', async () => {
const page = await Page({ children: Test
});
const { container } = render(page);
expect(container).toBeInTheDocument();
});
it('renders OTPInputWrapper component', () => {
const { container } = render( {}} />);
expect(container).toBeInTheDocument();
});
it('renders OTPInputWrapper component with slots', () => {
const { container } = render( {}} />);
expect(container).toBeInTheDocument();
expect(screen.getByText('-')).toBeInTheDocument();
});
it('renders NavHeader component', async () => {
const { container } = renderWithIntl(
,
);
expect(container).toBeInTheDocument();
});
it('renders up to two user initials', () => {
render();
expect(screen.getByText('AQ')).toBeInTheDocument();
});
it('renders NavBar component', () => {
const { container } = renderWithIntl(
,
);
expect(container).toBeInTheDocument();
});
it('renders NavBar component with admin role', () => {
const { container } = renderWithIntl(
,
);
expect(container).toBeInTheDocument();
expect(screen.getByText('Admin')).toBeInTheDocument();
});
it('not shows admin nav for non-admin users', () => {
const { container } = renderWithIntl(
,
);
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();
expect(document.querySelector('a[href="/favorites"]')).toBeNull();
rerender();
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(
,
);
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();
expect(container).toBeInTheDocument();
});
it('renders FormField component', () => {
const { container } = render();
expect(container).toBeInTheDocument();
});
it('renders NavSidebar component', () => {
const { container } = renderWithIntl(
,
);
expect(container).toBeInTheDocument();
});
it('renders Loader component', () => {
const { container } = render();
expect(container).toBeInTheDocument();
});
});