import { render, screen, waitFor } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { MemoryRouter } from "react-router-dom" import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { ChannelsPage } from "./ChannelsPage" import { AuthProvider } from "@/auth/AuthContext" import { api } from "@/api/client" import { vi, beforeEach, test, expect } from "vitest" import type { Channel } from "@/api/types" const PROJECT_ID = "p1" const channels: Channel[] = [ { id: "c1", type: "telegram", config: { chat_id: "123456" }, enabled: true }, { id: "c2", type: "webhook", config: { url: "https://hooks.example.com/x" }, enabled: false }, ] function renderPage() { const qc = new QueryClient() return render( , ) } 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, "listChannels").mockResolvedValue(channels) }) test("отрисовывает список каналов без секрета", async () => { renderPage() expect(await screen.findByText("telegram")).toBeInTheDocument() expect(screen.getByText("webhook")).toBeInTheDocument() expect(screen.getByText(/123456/)).toBeInTheDocument() expect(screen.getByText(/hooks\.example\.com/)).toBeInTheDocument() expect(document.body.textContent).not.toMatch(/bot_token/i) expect(screen.queryByDisplayValue(/123456/)).not.toBeInTheDocument() }) test("создание telegram-канала собирает config.chat_id + secret=bot_token", async () => { const createSpy = vi.spyOn(api, "createChannel").mockResolvedValue({ id: "c3", type: "telegram", config: { chat_id: "999" }, enabled: true, }) const user = userEvent.setup() renderPage() await screen.findByText("telegram") await user.click(screen.getByRole("combobox", { name: /тип канала/i })) await user.click(await screen.findByRole("option", { name: /telegram/i })) await user.type(screen.getByLabelText(/chat id/i), "999") await user.type(screen.getByLabelText(/bot token/i), "SECRET_TOKEN") await user.click(screen.getByRole("button", { name: /добавить канал/i })) await waitFor(() => expect(createSpy).toHaveBeenCalledWith(PROJECT_ID, { type: "telegram", config: { chat_id: "999" }, secret: "SECRET_TOKEN", }), ) expect(document.body.textContent).not.toMatch(/SECRET_TOKEN/) }) test("создание webhook-канала собирает config.url без секрета", async () => { const createSpy = vi.spyOn(api, "createChannel").mockResolvedValue({ id: "c4", type: "webhook", config: { url: "https://hooks.example.com/y" }, enabled: true, }) const user = userEvent.setup() renderPage() await screen.findByText("telegram") await user.click(screen.getByRole("combobox", { name: /тип канала/i })) await user.click(await screen.findByRole("option", { name: /webhook/i })) await user.type(screen.getByLabelText(/url/i), "https://hooks.example.com/y") await user.click(screen.getByRole("button", { name: /добавить канал/i })) await waitFor(() => expect(createSpy).toHaveBeenCalledWith(PROJECT_ID, { type: "webhook", config: { url: "https://hooks.example.com/y" }, secret: "", }), ) }) test("удаление канала вызывает api.deleteChannel", async () => { const deleteSpy = vi.spyOn(api, "deleteChannel").mockResolvedValue(undefined) vi.spyOn(window, "confirm").mockReturnValue(true) const user = userEvent.setup() renderPage() await screen.findByText("telegram") await user.click(screen.getByRole("button", { name: /удалить канал telegram/i })) await waitFor(() => expect(deleteSpy).toHaveBeenCalledWith(PROJECT_ID, "c1")) }) test("кнопка «Тест» вызывает api.testChannel", async () => { const testSpy = vi.spyOn(api, "testChannel").mockResolvedValue({ status: "ok" }) const user = userEvent.setup() renderPage() await screen.findByText("telegram") const testButtons = screen.getAllByRole("button", { name: /тест/i }) await user.click(testButtons[0]) await waitFor(() => expect(testSpy).toHaveBeenCalledWith(PROJECT_ID, "c1")) }) test("ошибка тест-отправки отображается как alert", async () => { vi.spyOn(api, "testChannel").mockRejectedValue(new Error("Канал не отвечает")) const user = userEvent.setup() renderPage() await screen.findByText("telegram") const testButtons = screen.getAllByRole("button", { name: /тест/i }) await user.click(testButtons[0]) expect(await screen.findByRole("alert")).toHaveTextContent("Канал не отвечает") }) test("пустое состояние при отсутствии каналов", async () => { vi.spyOn(api, "listChannels").mockResolvedValue([]) renderPage() expect(await screen.findByText(/каналов пока нет/i)).toBeInTheDocument() })