import { screen, waitFor } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { useTranslation } from "react-i18next" import { describe, expect, it, vi } from "vitest" import { renderWithBrowser } from "@/test/test-utils" import { StyleTemplatePreview } from "../style-template-preview" // Mock dependencies const mockAddStyleTemplate = vi.fn() const mockIsStyleTemplateAdded = vi.fn() vi.mock("@/features/user-settings/hooks/use-user-settings", () => ({ useUserSettings: () => ({ settings: {}, updateSettings: vi.fn(), }), })) vi.mock("@/features/resources", () => ({ useResources: () => ({ addStyleTemplate: mockAddStyleTemplate, isStyleTemplateAdded: mockIsStyleTemplateAdded, }), ResourcesProvider: ({ children }: { children: React.ReactNode }) => children, })) vi.mock("@/features", () => ({ ApplyButton: vi.fn(({ resource, size, type }) => (
Apply
)), })) vi.mock("@/features/browser/components/layout/add-media-button", () => ({ AddMediaButton: vi.fn(({ resource, size, type }) => (
Add
)), })) vi.mock("@/features/browser/components/layout/favorite-button", () => ({ FavoriteButton: vi.fn(({ file, size, type }) => (
Favorite
)), })) const mockTemplate = { id: "test-template-1", name: { ru: "Тестовый шаблон", en: "Test Template" }, category: "intro" as const, style: "modern" as const, aspectRatio: "16:9" as const, duration: 3, hasText: true, hasAnimation: true, thumbnail: "test-thumbnail.jpg", previewVideo: "test-preview.mp4", tags: { ru: ["тест"], en: ["test"] }, elements: [], } describe("StyleTemplatePreview", () => { const defaultProps = { template: mockTemplate, size: 200, onSelect: vi.fn(), previewWidth: 200, previewHeight: 112, } beforeEach(() => { vi.clearAllMocks() mockIsStyleTemplateAdded.mockReturnValue(false) }) it("should render template preview with thumbnail", () => { renderWithBrowser() const thumbnail = screen.getByAltText("Тестовый шаблон") expect(thumbnail).toBeInTheDocument() expect(thumbnail).toHaveAttribute("src", "test-thumbnail.jpg") expect(thumbnail).toHaveStyle({ width: "200px", height: "112px", objectFit: "cover", }) }) it("should render placeholder when no thumbnail", () => { const templateWithoutThumbnail = { ...mockTemplate, thumbnail: undefined } renderWithBrowser() expect(screen.getByText(/styleTemplates.categories.intro/)).toBeInTheDocument() }) it("should show template name", () => { renderWithBrowser() expect(screen.getByText("Тестовый шаблон")).toBeInTheDocument() }) it("should show play button on hover when preview video exists", async () => { const user = userEvent.setup() renderWithBrowser() const previewContainer = screen.getByAltText("Тестовый шаблон").parentElement // Initially no play button expect(screen.queryByTestId("play-icon")).not.toBeInTheDocument() // Hover to show play button await user.hover(previewContainer!) await waitFor(() => { const playIcon = screen.getByTestId("play-icon") expect(playIcon).toHaveClass("h-6 w-6") }) }) it("should not show play button when no preview video", async () => { const user = userEvent.setup() const templateWithoutVideo = { ...mockTemplate, previewVideo: undefined } renderWithBrowser() const previewContainer = screen.getByAltText("Тестовый шаблон").parentElement await user.hover(previewContainer!) // No play button should appear expect(screen.queryByTestId("play-icon")).not.toBeInTheDocument() }) it("should show style indicator", () => { renderWithBrowser() // Style indicator shows first 3 letters uppercase // There are two indicators with "STY" - both style and category const indicators = screen.getAllByText("STY") expect(indicators).toHaveLength(2) expect(indicators[0]).toBeInTheDocument() // Style indicator (top) }) it("should show category indicator", () => { renderWithBrowser() // Category indicator shows first 3 letters uppercase // There should be two indicators - style (top) and category (bottom) const indicators = screen.getAllByText("STY") expect(indicators).toHaveLength(2) // One for style, one for category }) it("should render favorite button", () => { renderWithBrowser() const favoriteButton = screen.getByTestId("favorite-button") expect(favoriteButton).toBeInTheDocument() expect(favoriteButton).toHaveAttribute("data-file-id", "test-template-1") expect(favoriteButton).toHaveAttribute("data-type", "styleTemplate") }) it("should render apply button", () => { renderWithBrowser() const applyButton = screen.getByTestId("apply-button") expect(applyButton).toBeInTheDocument() expect(applyButton).toHaveAttribute("data-resource-id", "test-template-1") expect(applyButton).toHaveAttribute("data-type", "styleTemplate") }) it("should render add media button", () => { renderWithBrowser() const addButton = screen.getByTestId("add-media-button") expect(addButton).toBeInTheDocument() expect(addButton).toHaveAttribute("data-resource-id", "test-template-1") expect(addButton).toHaveAttribute("data-type", "styleTemplate") }) it("should show add button with opacity when not added", () => { renderWithBrowser() const addButtonContainer = screen.getByTestId("add-media-button").parentElement expect(addButtonContainer).toHaveClass("opacity-0") }) it("should show add button with full opacity when added", () => { mockIsStyleTemplateAdded.mockReturnValue(true) renderWithBrowser() const addButtonContainer = screen.getByTestId("add-media-button").parentElement expect(addButtonContainer).toHaveClass("opacity-100") }) it("should handle template click", async () => { const user = userEvent.setup() const onSelectMock = vi.fn() renderWithBrowser() const previewContainer = screen.getByAltText("Тестовый шаблон").parentElement await user.click(previewContainer!) // Clicking the container should only trigger preview, not add to resources expect(mockAddStyleTemplate).not.toHaveBeenCalled() expect(onSelectMock).toHaveBeenCalledWith("test-template-1") }) it("should only trigger preview on template click regardless of added state", async () => { const user = userEvent.setup() const onSelectMock = vi.fn() mockIsStyleTemplateAdded.mockReturnValue(true) renderWithBrowser() const previewContainer = screen.getByAltText("Тестовый шаблон").parentElement await user.click(previewContainer!) // Should never add template on container click expect(mockAddStyleTemplate).not.toHaveBeenCalled() expect(onSelectMock).toHaveBeenCalledWith("test-template-1") }) it("should show preview button on hover but not add to resources on any click", async () => { const user = userEvent.setup() const onSelectMock = vi.fn() renderWithBrowser() const previewContainer = screen.getByAltText("Тестовый шаблон").parentElement // Hover to show preview button await user.hover(previewContainer!) // Wait for the play button to appear await waitFor(() => { const playButton = screen.queryByTestId("play-button") expect(playButton).toBeInTheDocument() }) // Click anywhere on the container await user.click(previewContainer!) // Should only trigger preview, not add to resources expect(mockAddStyleTemplate).not.toHaveBeenCalled() expect(onSelectMock).toHaveBeenCalledWith("test-template-1") }) it("should use custom preview dimensions", () => { renderWithBrowser() const thumbnail = screen.getByAltText("Тестовый шаблон") expect(thumbnail).toHaveStyle({ width: "300px", height: "169px", }) }) it("should handle mouse enter and leave", async () => { const user = userEvent.setup() renderWithBrowser() const previewContainer = screen.getByAltText("Тестовый шаблон").parentElement // Mouse enter await user.hover(previewContainer!) // Should show play button (if preview video exists) await waitFor(() => { const playIcon = previewContainer?.querySelector(".h-6.w-6") expect(playIcon).toBeInTheDocument() }) // Mouse leave await user.unhover(previewContainer!) // Play button should be hidden await waitFor(() => { const playIcon = previewContainer?.querySelector(".h-6.w-6") expect(playIcon).not.toBeInTheDocument() }) }) it("should show correct category names for different categories", () => { const categories = ["intro", "outro", "lower-third", "title", "transition", "overlay"] as const categories.forEach((category) => { const { unmount } = renderWithBrowser( , ) // Category indicator should show "STY" as translation key prefix const indicators = screen.getAllByText("STY") expect(indicators.length).toBeGreaterThanOrEqual(2) // At least style and category unmount() }) }) it("should show correct style names for different styles", () => { const styles = ["modern", "vintage", "minimal", "corporate", "creative", "cinematic"] as const styles.forEach((style) => { const { unmount } = renderWithBrowser( , ) // Style indicator should show "STY" as translation key prefix const indicators = screen.getAllByText("STY") expect(indicators.length).toBeGreaterThanOrEqual(2) // At least style and category unmount() }) }) it("should handle English language", () => { // Mock the translation hook to return English language vi.mocked(useTranslation).mockReturnValue({ t: (key: string) => key, i18n: { language: "en" }, ready: true, } as any) renderWithBrowser() // Should show English name expect(screen.getByText("Test Template")).toBeInTheDocument() }) })