diff --git a/frontend/tests/unit/components/login/RegisterSide.extended.test.tsx b/frontend/tests/unit/components/login/RegisterSide.extended.test.tsx deleted file mode 100644 index 1b2ba37..0000000 --- a/frontend/tests/unit/components/login/RegisterSide.extended.test.tsx +++ /dev/null @@ -1,241 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; -import { beforeEach, describe, expect, it, vi } from "vitest"; -import "@testing-library/jest-dom/vitest"; - -vi.mock("@unpic/react", () => ({ - Image: (props: any) => {props.alt}, -})); - -vi.mock("framer-motion", () => ({ - motion: { - div: ({ children, whileHover, whileTap, animate, transition, ...props }: any) => -
{children}
, - button: ({ children, whileHover, whileTap, animate, transition, ...props }: any) => - , - }, -})); - -vi.mock("react-phone-number-input", () => ({ - default: ({ value, onChange, placeholder }: any) => ( - onChange(event.target.value)} - /> - ), -})); - -const mockNavigate = vi.fn(); -vi.mock("react-router-dom", () => ({ - useNavigate: () => mockNavigate, -})); - -const mockApiPost = vi.fn(); -const mockApiGet = vi.fn(); -vi.mock("@/services/api", () => ({ - api: { - post: (...args: any[]) => mockApiPost(...args), - get: (...args: any[]) => mockApiGet(...args), - }, -})); - -import RegisterSide from "@/components/login/RegisterSide"; - -// ─── helpers ──────────────────────────────────────────────────────────────── -function fillValidForm() { - fireEvent.change(screen.getByLabelText(/nome/i), { target: { value: "Bene" } }); - fireEvent.change(screen.getByLabelText(/email/i), { target: { value: "bene@teste.com" } }); - fireEvent.change(screen.getByLabelText(/^telefone$/i), { target: { value: "+5534999999999" } }); - fireEvent.change(screen.getByLabelText(/senha/i), { target: { value: "123456" } }); - fireEvent.change(screen.getByLabelText(/cpf/i), { target: { value: "12345678901" } }); -} - -describe("RegisterSide — branches extras", () => { - beforeEach(() => { - mockApiPost.mockReset(); - mockApiGet.mockReset(); - mockNavigate.mockReset(); - }); - - // ── Branch: submit com sucesso → navega para /app ──────────────────────── - it("navega para /app após cadastro bem-sucedido", async () => { - mockApiPost.mockResolvedValueOnce({ data: {} }); - render(); - fillValidForm(); - fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); - await waitFor(() => expect(mockNavigate).toHaveBeenCalledWith("/app")); - }); - - // ── Branch: API retorna erro de validação por campo (data.error é objeto) ─ - it("exibe erros de campo quando API retorna objeto de validação", async () => { - mockApiPost.mockRejectedValueOnce({ - response: { - data: { - error: { - name: { _errors: ["Nome já existe"] }, - email: { _errors: ["E-mail já cadastrado"] }, - phone: { _errors: ["Telefone inválido"] }, - password: { _errors: ["Senha fraca"] }, - cpf: { _errors: ["CPF já cadastrado"] }, - }, - }, - }, - }); - - render(); - fillValidForm(); - fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); - - await waitFor(() => expect(screen.getByText("Nome já existe")).toBeInTheDocument()); - expect(screen.getByText("E-mail já cadastrado")).toBeInTheDocument(); - expect(screen.getByText("Telefone inválido")).toBeInTheDocument(); - expect(screen.getByText("Senha fraca")).toBeInTheDocument(); - expect(screen.getByText("CPF já cadastrado")).toBeInTheDocument(); - }); - - // ── Branch: API retorna mensagem de e-mail duplicado (fallback string) ──── - it("exibe erro de e-mail duplicado quando mensagem contém 'email'", async () => { - mockApiPost.mockRejectedValueOnce({ - response: { data: { message: "email already in use" } }, - }); - - render(); - fillValidForm(); - fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); - - await waitFor(() => - expect(screen.getByText(/endereço de e-mail já está em uso/i)).toBeInTheDocument() - ); - }); - - // ── Branch: API retorna mensagem genérica (fallback string, sem 'email') ── - it("exibe globalError quando API retorna mensagem genérica", async () => { - mockApiPost.mockRejectedValueOnce({ - response: { data: { message: "Servidor indisponível" } }, - }); - - render(); - fillValidForm(); - fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); - - await waitFor(() => - expect(screen.getByText("Servidor indisponível")).toBeInTheDocument() - ); - }); - - // ── Branch: API retorna data.error como string (sem 'email') ───────────── - it("exibe globalError quando data.error é uma string genérica", async () => { - mockApiPost.mockRejectedValueOnce({ - response: { data: { error: "Erro interno" } }, - }); - - render(); - fillValidForm(); - fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); - - await waitFor(() => - expect(screen.getByText("Erro interno")).toBeInTheDocument() - ); - }); - - // ── Branch: erro sem response (ex: rede) → globalError genérico ────────── - it("exibe erro de conexão quando não há response (erro de rede)", async () => { - mockApiPost.mockRejectedValueOnce(new Error("Network Error")); - - render(); - fillValidForm(); - fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); - - await waitFor(() => - expect(screen.getByText(/erro inesperado de conexão/i)).toBeInTheDocument() - ); - }); - - // ── Branch: OAuth Google — sucesso com URL ──────────────────────────────── - it("redireciona para URL do Google OAuth quando API retorna url", async () => { - const locationSpy = vi.spyOn(window, "location", "get").mockReturnValue({ - ...window.location, - href: "", - } as Location); - const hrefSetter = vi.fn(); - Object.defineProperty(window.location, "href", { set: hrefSetter, configurable: true }); - - mockApiGet.mockResolvedValueOnce({ data: { url: "https://google.com/oauth" } }); - render(); - fireEvent.click(screen.getByAltText(/google/i).closest("button")!); - - await waitFor(() => - expect(hrefSetter).toHaveBeenCalledWith("https://google.com/oauth") - ); - - locationSpy.mockRestore(); - }); - - // ── Branch: OAuth GitHub — API não retorna URL → throw + globalError ────── - it("exibe globalError quando OAuth não retorna URL", async () => { - mockApiGet.mockResolvedValueOnce({ data: {} }); // sem url - - render(); - // Botões OAuth são os que contêm apenas SVG (sem texto) - const oauthButtons = screen.getAllByRole("button").filter( - (btn) => btn.querySelector("svg") && !btn.textContent?.trim() - ); - fireEvent.click(oauthButtons[oauthButtons.length - 1]); // GitHub é o último - - await waitFor(() => - expect(screen.getByText(/não foi possível conectar/i)).toBeInTheDocument() - ); - }); - - // ── Branch: OAuth — erro Axios com response.data.error string ───────────── - it("exibe mensagem de erro do Axios no OAuth", async () => { - mockApiGet.mockRejectedValueOnce({ - response: { data: { error: "Provedor desativado" } }, - }); - - render(); - // Clica no Google pelo alt text da imagem - fireEvent.click(screen.getByAltText(/google/i).closest("button")!); - - await waitFor(() => - expect(screen.getByText("Provedor desativado")).toBeInTheDocument() - ); - }); - - // ── Branch: alterna visibilidade da senha ──────────────────────────────── - it("alterna tipo do input de senha ao clicar no botão de revelar", () => { - render(); - const senhaInput = screen.getByLabelText(/senha/i) as HTMLInputElement; - expect(senhaInput.type).toBe("password"); - - const toggleBtn = screen.getAllByRole("button").find( - (btn) => btn.querySelector("svg") && !btn.textContent?.match(/cadastrar/i) - )!; - fireEvent.click(toggleBtn); - expect(senhaInput.type).toBe("text"); - - fireEvent.click(toggleBtn); - expect(senhaInput.type).toBe("password"); - }); - - // ── Branch: formatCpf — cobre os 4 ramos de formatação ─────────────────── - it("formata CPF progressivamente nos 4 estágios", () => { - render(); - const cpfInput = screen.getByLabelText(/cpf/i); - - fireEvent.change(cpfInput, { target: { value: "12" } }); - expect(cpfInput).toHaveValue("12"); - - fireEvent.change(cpfInput, { target: { value: "12345" } }); - expect(cpfInput).toHaveValue("123.45"); - - fireEvent.change(cpfInput, { target: { value: "12345678" } }); - expect(cpfInput).toHaveValue("123.456.78"); - - fireEvent.change(cpfInput, { target: { value: "12345678901" } }); - expect(cpfInput).toHaveValue("123.456.789-01"); - }); -}); diff --git a/frontend/tests/unit/components/login/RegisterSide.test.tsx b/frontend/tests/unit/components/login/RegisterSide.test.tsx index 81a23a6..184be00 100644 --- a/frontend/tests/unit/components/login/RegisterSide.test.tsx +++ b/frontend/tests/unit/components/login/RegisterSide.test.tsx @@ -1,20 +1,11 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ - import { fireEvent, render, screen, waitFor } from "@testing-library/react"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it, vi } from "vitest"; -// ===================== -// MOCKS -// ===================== const mockRegister = vi.fn(); - vi.mock("@/services/authService", () => ({ register: (...args: any[]) => mockRegister(...args), })); -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; -import { beforeEach, describe, expect, it, vi } from "vitest"; -import "@testing-library/jest-dom/vitest"; vi.mock("@unpic/react", () => ({ Image: (props: any) => {props.alt}, @@ -23,13 +14,7 @@ vi.mock("@unpic/react", () => ({ vi.mock("framer-motion", () => ({ motion: { div: ({ children, ...props }: any) =>
{children}
, - button: ({ children, ...props }: any) => ( - - ), - div: ({ children, whileHover, whileTap, animate, transition, ...props }: any) => -
{children}
, - button: ({ children, whileHover, whileTap, animate, transition, ...props }: any) => - , + button: ({ children, ...props }: any) => , }, })); @@ -45,30 +30,13 @@ vi.mock("react-phone-number-input", () => ({ ), })); -vi.mock("react-router-dom", () => ({ - useNavigate: () => vi.fn(), -})); - -const mockApiPost = vi.fn(); -const mockApiGet = vi.fn(); -vi.mock("@/services/api", () => ({ - api: { - post: (...args: any[]) => mockApiPost(...args), - get: (...args: any[]) => mockApiGet(...args), - }, -})); - import RegisterSide from "@/components/login/RegisterSide"; -// ===================== -// TEST SUITE -// ===================== describe("RegisterSide", () => { const originalLocation = window.location; beforeEach(() => { mockRegister.mockReset(); - Object.defineProperty(window, "location", { configurable: true, value: { href: "" }, @@ -80,203 +48,104 @@ describe("RegisterSide", () => { configurable: true, value: originalLocation, }); - - beforeEach(() => { - mockApiPost.mockClear(); - mockApiGet.mockClear(); }); it("renderiza formulário e alterna visibilidade da senha", () => { render(); - const passwordInput = screen.getByLabelText(/senha/i) as HTMLInputElement; expect(passwordInput.type).toBe("password"); - const toggleButtons = screen.getAllByRole("button"); - fireEvent.click(toggleButtons[0]); - + const revealButton = screen.getAllByRole("button", { name: "" })[0]; + fireEvent.click(revealButton); expect(screen.getByLabelText(/senha/i)).toHaveAttribute("type", "text"); }); - it("mostra erros obrigatórios quando submit vazio", async () => { + it("mostra erros obrigatórios ao submeter vazio", async () => { render(); - fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); - - expect( - await screen.findByText(/campo de nome.*obrigatório/i) - ).toBeInTheDocument(); - expect( - await screen.findByText(/campo de e-mail.*obrigatório/i) - ).toBeInTheDocument(); - expect( - await screen.findByText(/campo de telefone.*obrigatório/i) - ).toBeInTheDocument(); - expect( - await screen.findByText(/campo de senha.*obrigatório/i) - ).toBeInTheDocument(); - // CPF é campo opcional — não dispara erro de obrigatório + expect(await screen.findByText(/campo de nome é obrigatório/i)).toBeInTheDocument(); + expect(await screen.findByText(/campo de e-mail é obrigatório/i)).toBeInTheDocument(); + expect(await screen.findByText(/campo de telefone é obrigatório/i)).toBeInTheDocument(); + expect(await screen.findByText(/campo de senha é obrigatório/i)).toBeInTheDocument(); }); - - it("valida CPF quando preenchido incorretamente", async () => { + it("valida CPF inválido quando preenchido", async () => { render(); - - fireEvent.change(screen.getByLabelText(/nome/i), { - target: { value: "Usuário Teste" }, - }); - - fireEvent.change(screen.getByLabelText(/email/i), { - target: { value: "teste@email.com" }, - }); - - fireEvent.change(screen.getByPlaceholderText(/\(34\)/i), { - target: { value: "+5534999999999" }, - }); - - fireEvent.change(screen.getByLabelText(/senha/i), { - target: { value: "123456" }, - }); - - fireEvent.change(screen.getByLabelText(/cpf/i), { - target: { value: "123" }, - }); - + fireEvent.change(screen.getByLabelText(/nome/i), { target: { value: "Usuário" } }); + fireEvent.change(screen.getByLabelText(/email/i), { target: { value: "teste@email.com" } }); + fireEvent.change(screen.getByPlaceholderText(/\(34\)/i), { target: { value: "+5534999999999" } }); + fireEvent.change(screen.getByLabelText(/senha/i), { target: { value: "123456" } }); + fireEvent.change(screen.getByLabelText(/cpf/i), { target: { value: "123" } }); fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); - - // Componente exibe: "CPF inválido. Deve conter 11 dígitos." - expect(await screen.findByText(/cpf inv[aá]lido/i)).toBeInTheDocument(); + expect(await screen.findByText(/cpf inválido/i)).toBeInTheDocument(); }); - it("envia formulário válido com CPF opcional", async () => { - mockRegister.mockResolvedValueOnce({ - message: "Usuário criado", - user: { id: 1 }, - }); - + it("envia formulário válido sem CPF", async () => { + mockRegister.mockResolvedValueOnce({ message: "Usuário criado" }); render(); - - fireEvent.change(screen.getByLabelText(/nome/i), { - target: { value: "Usuário Teste" }, - }); - - fireEvent.change(screen.getByLabelText(/email/i), { - target: { value: "teste@email.com" }, - }); - - fireEvent.change(screen.getByPlaceholderText(/\(34\)/i), { - target: { value: "+5534999999999" }, - }); - - fireEvent.change(screen.getByLabelText(/senha/i), { - target: { value: "123456" }, - }); - + fireEvent.change(screen.getByLabelText(/nome/i), { target: { value: "Bene" } }); + fireEvent.change(screen.getByLabelText(/email/i), { target: { value: "bene@teste.com" } }); + fireEvent.change(screen.getByPlaceholderText(/\(34\)/i), { target: { value: "+5534999999999" } }); + fireEvent.change(screen.getByLabelText(/senha/i), { target: { value: "123456" } }); fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); - await waitFor(() => { - expect(mockRegister).toHaveBeenCalled(); + expect(mockRegister).toHaveBeenCalledWith({ + email: "bene@teste.com", + password: "123456", + name: "Bene", + }); }); + expect(window.location.href).toBe("/login?registered=true"); }); - it("exibe erro quando API falha", async () => { + it("exibe erro da API", async () => { mockRegister.mockRejectedValueOnce(new Error("Email já cadastrado")); - render(); - - fireEvent.change(screen.getByLabelText(/nome/i), { - target: { value: "Bene" }, - }); - - fireEvent.change(screen.getByLabelText(/email/i), { - target: { value: "bene@teste.com" }, - }); - - fireEvent.change(screen.getByPlaceholderText(/\(34\)/i), { - target: { value: "+5534999999999" }, - }); - - fireEvent.change(screen.getByLabelText(/senha/i), { - target: { value: "123456" }, - }); - + fireEvent.change(screen.getByLabelText(/nome/i), { target: { value: "Bene" } }); + fireEvent.change(screen.getByLabelText(/email/i), { target: { value: "bene@teste.com" } }); + fireEvent.change(screen.getByPlaceholderText(/\(34\)/i), { target: { value: "+5534999999999" } }); + fireEvent.change(screen.getByLabelText(/senha/i), { target: { value: "123456" } }); fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); - - expect( - await screen.findByText(/email já cadastrado/i) - ).toBeInTheDocument(); + expect(await screen.findByText(/Email já cadastrado/i)).toBeInTheDocument(); }); it("mostra loading durante requisição", async () => { - mockRegister.mockImplementation( - () => new Promise((resolve) => setTimeout(resolve, 200)) - ); - - render(); - - fireEvent.change(screen.getByLabelText(/nome/i), { - target: { value: "Bene" }, - }); - it("formata cpf e envia submit válido", async () => { - mockApiPost.mockResolvedValueOnce({ data: {} }); - + mockRegister.mockImplementation(() => new Promise(() => {})); render(); fireEvent.change(screen.getByLabelText(/nome/i), { target: { value: "Bene" } }); fireEvent.change(screen.getByLabelText(/email/i), { target: { value: "bene@teste.com" } }); - fireEvent.change(screen.getByLabelText(/^telefone$/i), { target: { value: "+5534999999999" } }); + fireEvent.change(screen.getByPlaceholderText(/\(34\)/i), { target: { value: "+5534999999999" } }); fireEvent.change(screen.getByLabelText(/senha/i), { target: { value: "123456" } }); - fireEvent.change(screen.getByLabelText(/cpf/i), { target: { value: "12345678901" } }); - - fireEvent.change(screen.getByLabelText(/email/i), { - target: { value: "bene@teste.com" }, - }); - - fireEvent.change(screen.getByPlaceholderText(/\(34\)/i), { - target: { value: "+5534999999999" }, - }); - - fireEvent.change(screen.getByLabelText(/senha/i), { - target: { value: "123456" }, - }); - fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); + expect(await screen.findByRole("button", { name: /cadastrando\.\.\./i })).toBeDisabled(); + }); - expect( - await screen.findByRole("button", { name: /cadastrando/i }) - ).toBeDisabled(); + it("formata CPF corretamente", () => { + render(); + const cpfInput = screen.getByLabelText(/cpf/i) as HTMLInputElement; + fireEvent.change(cpfInput, { target: { value: "12345678901" } }); + expect(cpfInput.value).toBe("123.456.789-01"); + fireEvent.change(cpfInput, { target: { value: "123456789" } }); + expect(cpfInput.value).toBe("123.456.789"); }); it("desabilita inputs durante loading", async () => { - mockRegister.mockImplementation( - () => new Promise((resolve) => setTimeout(resolve, 200)) - ); - + mockRegister.mockImplementation(() => new Promise(() => {})); render(); - - const nome = screen.getByLabelText(/nome/i); - const email = screen.getByLabelText(/email/i); - const senha = screen.getByLabelText(/senha/i); - - fireEvent.change(nome, { target: { value: "Bene" } }); - fireEvent.change(email, { target: { value: "bene@teste.com" } }); - fireEvent.change(senha, { target: { value: "123456" } }); - - fireEvent.change(screen.getByPlaceholderText(/\(34\)/i), { - target: { value: "+5534999999999" }, + const nomeInput = screen.getByLabelText(/nome/i); + const emailInput = screen.getByLabelText(/email/i); + const telefoneInput = screen.getByPlaceholderText(/\(34\)/i); + const passwordInput = screen.getByLabelText(/senha/i); + fireEvent.change(nomeInput, { target: { value: "Bene" } }); + fireEvent.change(emailInput, { target: { value: "bene@teste.com" } }); + fireEvent.change(telefoneInput, { target: { value: "+5534999999999" } }); + fireEvent.change(passwordInput, { target: { value: "123456" } }); + fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); await waitFor(() => { - expect(mockApiPost).toHaveBeenCalledWith("/auth/register", { - name: "Bene", - email: "bene@teste.com", - phone: "+5534999999999", - password: "123456", - cpf: "12345678901", - }); + expect(nomeInput).toBeDisabled(); + expect(emailInput).toBeDisabled(); + expect(telefoneInput).toBeDisabled(); + expect(passwordInput).toBeDisabled(); }); - - fireEvent.click(screen.getByRole("button", { name: /cadastrar/i })); - - expect( - await screen.findByRole("button", { name: /cadastrando/i }) - ).toBeDisabled(); }); -}); +}); \ No newline at end of file diff --git a/frontend/tests/unit/components/login/RigthSide.extended.test.tsx b/frontend/tests/unit/components/login/RigthSide.extended.test.tsx deleted file mode 100644 index f59ff80..0000000 --- a/frontend/tests/unit/components/login/RigthSide.extended.test.tsx +++ /dev/null @@ -1,156 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; -import { beforeEach, describe, expect, it, vi } from "vitest"; -import "@testing-library/jest-dom/vitest"; - -vi.mock("@unpic/react", () => ({ - Image: (props: any) => {props.alt}, -})); - -vi.mock("framer-motion", () => ({ - motion: { - div: ({ children, ...props }: any) =>
{children}
, - button: ({ children, ...props }: any) => , - }, -})); - -const mockNavigate = vi.fn(); -vi.mock("react-router-dom", () => ({ - useNavigate: () => mockNavigate, -})); - -const mockLogin = vi.fn(); -vi.mock("@/context/AuthContext", () => ({ - useAuth: () => ({ login: mockLogin }), -})); - -const mockApiGet = vi.fn(); -vi.mock("@/services/api", () => ({ - api: { get: (...args: any[]) => mockApiGet(...args) }, -})); - -import RigthSide from "@/components/login/RigthSide"; - -function fillValidForm() { - fireEvent.change(screen.getByLabelText(/email/i), { target: { value: "qa@teste.com" } }); - fireEvent.change(screen.getByLabelText(/senha/i), { target: { value: "123456" } }); -} - -describe("RigthSide — branches extras", () => { - beforeEach(() => { - mockLogin.mockReset(); - mockApiGet.mockReset(); - mockNavigate.mockReset(); - }); - - // ── Branch: login com sucesso → navega para /app ───────────────────────── - it("navega para /app após login bem-sucedido", async () => { - mockLogin.mockResolvedValueOnce(undefined); - render(); - fillValidForm(); - fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - await waitFor(() => expect(mockNavigate).toHaveBeenCalledWith("/app")); - }); - - // ── Branch: login falha com Axios error (response.data.error string) ────── - it("exibe mensagem de erro do Axios quando login falha com response", async () => { - mockLogin.mockRejectedValueOnce({ - response: { data: { error: "Credenciais inválidas" } }, - }); - render(); - fillValidForm(); - fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - await waitFor(() => - expect(screen.getByText("Credenciais inválidas")).toBeInTheDocument() - ); - }); - - // ── Branch: login falha sem response (erro de rede) ─────────────────────── - it("exibe erro genérico quando login falha sem response", async () => { - mockLogin.mockRejectedValueOnce(new Error("Network Error")); - render(); - fillValidForm(); - fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - await waitFor(() => - expect(screen.getByText(/credenciais inválidas ou erro de conexão/i)).toBeInTheDocument() - ); - }); - - // ── Branch: OAuth Google — sucesso com URL ──────────────────────────────── - it("redireciona para URL do Google OAuth", async () => { - const hrefSetter = vi.fn(); - const locationSpy = vi.spyOn(window, "location", "get").mockReturnValue({ - ...window.location, - href: "", - } as Location); - Object.defineProperty(window.location, "href", { set: hrefSetter, configurable: true }); - - mockApiGet.mockResolvedValueOnce({ data: { url: "https://google.com/oauth" } }); - render(); - - // Clica no Google pelo alt text da imagem - fireEvent.click(screen.getByAltText(/google/i).closest("button")!); - - await waitFor(() => - expect(hrefSetter).toHaveBeenCalledWith("https://google.com/oauth") - ); - - locationSpy.mockRestore(); - }); - - // ── Branch: OAuth — API não retorna URL → throw → globalError ───────────── - it("exibe globalError quando OAuth não retorna URL", async () => { - mockApiGet.mockResolvedValueOnce({ data: {} }); // sem url - render(); - - fireEvent.click(screen.getByAltText(/google/i).closest("button")!); - - await waitFor(() => - expect(screen.getByText(/não foi possível conectar/i)).toBeInTheDocument() - ); - }); - - // ── Branch: OAuth — erro Axios com response.data.error ─────────────────── - it("exibe mensagem do Axios no OAuth quando há response.data.error", async () => { - mockApiGet.mockRejectedValueOnce({ - response: { data: { error: "Provedor desativado" } }, - }); - render(); - - const oauthButtons = screen.getAllByRole("button").filter( - (btn) => !btn.textContent?.match(/entrar|entrando/i) - ); - fireEvent.click(oauthButtons[1]); // LinkedIn - - await waitFor(() => - expect(screen.getByText("Provedor desativado")).toBeInTheDocument() - ); - }); - - // ── Branch: OAuth — erro sem response ──────────────────────────────────── - it("exibe erro genérico de OAuth quando erro não tem response", async () => { - mockApiGet.mockRejectedValueOnce(new Error("Network Error")); - render(); - - const oauthButtons = screen.getAllByRole("button").filter( - (btn) => !btn.textContent?.match(/entrar|entrando/i) - ); - fireEvent.click(oauthButtons[2]); // GitHub - - await waitFor(() => - expect(screen.getByText(/não foi possível conectar/i)).toBeInTheDocument() - ); - }); - - // ── Branch: isSubmitting desabilita botão de entrar ─────────────────────── - it("exibe texto 'Entrando...' e desabilita botão durante submit", async () => { - // login nunca resolve para manter isSubmitting = true - mockLogin.mockImplementation(() => new Promise(() => {})); - render(); - fillValidForm(); - fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - await waitFor(() => - expect(screen.getByRole("button", { name: /entrando/i })).toBeDisabled() - ); - }); -}); diff --git a/frontend/tests/unit/components/login/RigthSide.test.tsx b/frontend/tests/unit/components/login/RigthSide.test.tsx index 1000c48..05c3d2b 100644 --- a/frontend/tests/unit/components/login/RigthSide.test.tsx +++ b/frontend/tests/unit/components/login/RigthSide.test.tsx @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import "@testing-library/jest-dom/vitest"; import { fireEvent, render, screen, waitFor } from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; @@ -7,9 +8,6 @@ const mockLogin = vi.fn(); vi.mock("@/services/authService", () => ({ login: (...args: any[]) => mockLogin(...args), })); -import { fireEvent, render, screen } from "@testing-library/react"; -import { beforeEach, describe, expect, it, vi } from "vitest"; -import "@testing-library/jest-dom/vitest"; vi.mock("@unpic/react", () => ({ Image: (props: any) => {props.alt}, @@ -26,19 +24,6 @@ vi.mock("react-router-dom", () => ({ useNavigate: () => vi.fn(), })); -const mockLogin = vi.fn(); -vi.mock("@/context/AuthContext", () => ({ - useAuth: () => ({ - login: mockLogin, - }), -})); - -vi.mock("@/services/api", () => ({ - api: { - get: vi.fn(), - }, -})); - import RigthSide from "@/components/login/RigthSide"; describe("RigthSide", () => { @@ -62,19 +47,15 @@ describe("RigthSide", () => { it("renderiza formulário corretamente", () => { render(); - expect(screen.getByLabelText(/email/i)).toBeInTheDocument(); expect(screen.getByLabelText(/senha/i)).toBeInTheDocument(); expect(screen.getByRole("button", { name: /entrar/i })).toBeInTheDocument(); expect(screen.getByText(/cadastre-se/i)).toBeInTheDocument(); expect(screen.getByText(/ou faça login com/i)).toBeInTheDocument(); - beforeEach(() => { - mockLogin.mockClear(); }); it("alterna visibilidade da senha ao clicar no botão", () => { render(); - const passwordInput = screen.getByLabelText(/senha/i) as HTMLInputElement; expect(passwordInput.type).toBe("password"); @@ -87,94 +68,70 @@ describe("RigthSide", () => { it("mostra erro de email obrigatório ao submeter vazio", async () => { render(); - fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - expect(await screen.findByText(/campo de e-mail.*obrigatório/i)).toBeInTheDocument(); expect(screen.getByText(/campo de senha.*obrigatório/i)).toBeInTheDocument(); }); - it("valida tamanho mínimo da senha", async () => { render(); - fireEvent.change(screen.getByLabelText(/email/i), { target: { value: "teste@email.com" } }); fireEvent.change(screen.getByLabelText(/senha/i), { target: { value: "123" } }); fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - expect(await screen.findByText(/pelo menos 6 caracteres/i)).toBeInTheDocument(); }); it("envia formulário válido e redireciona após login", async () => { mockLogin.mockResolvedValueOnce({ token: "fake-token-123", user: { id: 1, email: "teste@email.com" } }); - render(); - fireEvent.change(screen.getByLabelText(/email/i), { target: { value: "teste@email.com" } }); fireEvent.change(screen.getByLabelText(/senha/i), { target: { value: "123456" } }); fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - await waitFor(() => { expect(mockLogin).toHaveBeenCalledWith({ email: "teste@email.com", password: "123456", }); }); - expect(localStorage.getItem("token")).toBe("fake-token-123"); expect(window.location.href).toBe("/dashboard"); }); it("exibe erro quando API retorna erro", async () => { mockLogin.mockRejectedValueOnce(new Error("Credenciais inválidas")); - render(); - fireEvent.change(screen.getByLabelText(/email/i), { target: { value: "teste@email.com" } }); fireEvent.change(screen.getByLabelText(/senha/i), { target: { value: "senhaerrada" } }); fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - expect(await screen.findByText(/Credenciais inválidas/i)).toBeInTheDocument(); }); it("exibe erro genérico quando API retorna erro sem mensagem", async () => { mockLogin.mockRejectedValueOnce(new Error("")); - - it("envia formulário valido", async () => { - mockLogin.mockResolvedValueOnce(undefined); render(); - fireEvent.change(screen.getByLabelText(/email/i), { target: { value: "teste@email.com" } }); fireEvent.change(screen.getByLabelText(/senha/i), { target: { value: "senhaerrada" } }); fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - expect(await screen.findByText(/Erro ao fazer login. Verifique suas credenciais./i)).toBeInTheDocument(); }); it("mostra loading durante requisição", async () => { mockLogin.mockImplementation(() => new Promise(resolve => setTimeout(resolve, 200))); - render(); - fireEvent.change(screen.getByLabelText(/email/i), { target: { value: "teste@email.com" } }); fireEvent.change(screen.getByLabelText(/senha/i), { target: { value: "123456" } }); fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - expect(await screen.findByRole("button", { name: /entrando\.\.\./i })).toBeDisabled(); }); it("desabilita inputs durante loading", async () => { mockLogin.mockImplementation(() => new Promise(resolve => setTimeout(resolve, 200))); - render(); - const emailInput = screen.getByLabelText(/email/i); const passwordInput = screen.getByLabelText(/senha/i); - fireEvent.change(emailInput, { target: { value: "teste@email.com" } }); fireEvent.change(passwordInput, { target: { value: "123456" } }); fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - await waitFor(() => { expect(emailInput).toBeDisabled(); expect(passwordInput).toBeDisabled(); @@ -183,20 +140,14 @@ describe("RigthSide", () => { it("não envia formulário quando validação falha", async () => { render(); - fireEvent.click(screen.getByRole("button", { name: /entrar/i })); - await waitFor(() => { expect(mockLogin).not.toHaveBeenCalled(); - expect(mockLogin).toHaveBeenCalledWith({ - email: "qa@teste.com", - password: "123456", }); }); it("checkbox de lembrete está presente", () => { render(); - const checkbox = screen.getByRole("checkbox"); expect(checkbox).toBeInTheDocument(); expect(checkbox).toBeChecked(); @@ -204,8 +155,6 @@ describe("RigthSide", () => { it("botão de esqueceu a senha está presente", () => { render(); - expect(screen.getByText(/esqueceu a senha/i)).toBeInTheDocument(); - }); - + }); }); \ No newline at end of file