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) =>
,
-}));
-
-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) =>
,
@@ -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) =>
,
-}));
-
-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) =>
,
@@ -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