import { render, screen, waitFor } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { MemoryRouter, Routes, Route } from "react-router-dom" import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { DomainsPage } from "./DomainsPage" import { AuthProvider } from "@/auth/AuthContext" import { api } from "@/api/client" import { vi, beforeEach, test, expect } from "vitest" import type { Account, Domain, Template } from "@/api/types" const PROJECT_ID = "p1" const accounts: Account[] = [ { id: "acc1", provider: "selectel", comment: "Main" }, { id: "acc2", provider: "cloudflare", comment: "Backup" }, ] const templates: Template[] = [ { id: "t1", name: "Standard", records: [], version: 1 }, { id: "t2", name: "Minimal", records: [], version: 1 }, ] const domains: Domain[] = [ { id: "d1", providerAccountId: "acc1", zoneName: "example.com.", zoneId: "z1", templateId: null, lastCheckStatus: "drift" }, { id: "d2", providerAccountId: "acc2", zoneName: "test.org.", zoneId: "z2", templateId: "t1", lastCheckStatus: "in_sync" }, ] function renderPage() { const qc = new QueryClient() return render( } /> diff page} /> , ) } beforeEach(() => { vi.restoreAllMocks() vi.spyOn(api.auth, "me").mockResolvedValue({ user: { id: "u1", email: "a@b.com" }, project: { id: PROJECT_ID, name: "Default" }, }) vi.spyOn(api, "listDomains").mockResolvedValue(domains) vi.spyOn(api, "listAccounts").mockResolvedValue(accounts) vi.spyOn(api, "listTemplates").mockResolvedValue(templates) }) test("отрисовывает домены и ссылку на diff-страницу", async () => { renderPage() expect(await screen.findByText("example.com.")).toBeInTheDocument() expect(screen.getByText("test.org.")).toBeInTheDocument() const links = screen.getAllByRole("link", { name: /diff/i }) expect(links.length).toBe(2) expect(links[0]).toHaveAttribute("href", "/domains/d1") expect(links[1]).toHaveAttribute("href", "/domains/d2") }) test("кнопка импорта вызывает api.importZones с выбранной учёткой", async () => { const importSpy = vi.spyOn(api, "importZones").mockResolvedValue([]) const user = userEvent.setup() renderPage() await screen.findByText("example.com.") await user.click(screen.getByRole("combobox", { name: /учётн/i })) await user.click(await screen.findByRole("option", { name: /cloudflare/i })) await user.click(screen.getByRole("button", { name: /импортировать зоны/i })) await waitFor(() => expect(importSpy).toHaveBeenCalledWith(PROJECT_ID, "acc2")) }) test("привязка шаблона в строке домена вызывает api.setDomainTemplate", async () => { const setTemplateSpy = vi.spyOn(api, "setDomainTemplate").mockResolvedValue(domains[0]) const user = userEvent.setup() renderPage() await screen.findByText("example.com.") await user.click(screen.getByRole("combobox", { name: /example\.com\./i })) await user.click(await screen.findByRole("option", { name: /^standard$/i })) await waitFor(() => expect(setTemplateSpy).toHaveBeenCalledWith(PROJECT_ID, "d1", "t1")) }) test("ошибка привязки шаблона отображается пользователю", async () => { vi.spyOn(api, "setDomainTemplate").mockRejectedValue(new Error("Не удалось привязать шаблон")) const user = userEvent.setup() renderPage() await screen.findByText("example.com.") await user.click(screen.getByRole("combobox", { name: /example\.com\./i })) await user.click(await screen.findByRole("option", { name: /^standard$/i })) expect(await screen.findByRole("alert")).toHaveTextContent("Не удалось привязать шаблон") }) test("пустое состояние при отсутствии доменов", async () => { vi.spyOn(api, "listDomains").mockResolvedValue([]) renderPage() expect(await screen.findByText(/доменов пока нет/i)).toBeInTheDocument() }) test("drift-badge отражает lastCheckStatus каждого домена", async () => { renderPage() await screen.findByText("example.com.") expect(screen.getByText("drift")).toBeInTheDocument() expect(screen.getByText("in sync")).toBeInTheDocument() })