diff --git a/frontend/src/services/authService.ts b/frontend/src/services/authService.ts index 23a6d58..8de3286 100644 --- a/frontend/src/services/authService.ts +++ b/frontend/src/services/authService.ts @@ -1,65 +1,45 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -function normalizeBaseUrl(value: string | undefined): string { - return typeof value === "string" ? value.trim().replace(/\/+$/, "") : ""; -} +function getBaseUrl(): string { + const base = import.meta.env.VITE_API_BASE_URL; -function getApiBaseUrl(): string { - const configuredBaseUrl = normalizeBaseUrl(import.meta.env.VITE_API_BASE_URL); - if (configuredBaseUrl) { - console.log("Usando VITE_API_BASE_URL:", configuredBaseUrl); - return configuredBaseUrl; + if (base && base.trim().length > 0) { + return base.replace(/\/+$/, ""); } - console.log(" Sem VITE_API_BASE_URL, usando caminho relativo"); + return ""; } -function buildApiUrl(path: string): string { +function buildUrl(path: string): string { const normalizedPath = path.startsWith("/") ? path : `/${path}`; - const baseUrl = getApiBaseUrl(); - const fullUrl = baseUrl ? `${baseUrl}${normalizedPath}` : normalizedPath; - console.log(" Construindo URL:", { path, baseUrl, fullUrl }); - return fullUrl; + const base = getBaseUrl(); + + return base ? `${base}${normalizedPath}` : normalizedPath; } -async function readPayload(response: Response): Promise> { - const contentType = response.headers?.get?.("content-type") ?? ""; - console.log(" Content-Type:", contentType); - - if (!contentType || contentType.includes("application/json")) { - try { - const payload = await response.json(); - console.log(" Payload JSON:", payload); - return payload && typeof payload === "object" - ? (payload as Record) - : {}; - } catch (error) { - console.log(" Erro ao parsear JSON:", error); - return {}; +async function parseResponse(response: Response) { + const contentType = response.headers.get("content-type") ?? ""; + + try { + if (contentType.includes("application/json")) { + return await response.json(); } - } - - if (typeof response.text === "function") { + const text = await response.text(); - console.log("Resposta texto:", text); return text ? { message: text } : {}; + } catch { + return {}; } - - return {}; } -function buildError(message: unknown, fallback: string): Error { - const errorMsg = typeof message === "string" && message ? message : fallback; - console.error("Erro construído:", errorMsg); - return new Error(errorMsg); +function extractMessage(payload: any): string | undefined { + return payload?.message && typeof payload.message === "string" + ? payload.message + : undefined; } -function readMessage(payload: unknown): string | undefined { - if (payload && typeof payload === "object" && "message" in payload) { - const message = (payload as { message?: unknown }).message; - if (typeof message === "string") return message; - } - return undefined; +function createError(payload: any, fallback: string) { + return new Error(extractMessage(payload) || fallback); } export interface LoginCredentials { @@ -75,113 +55,71 @@ export interface RegisterData { cpf?: string; } -export async function login(credentials: LoginCredentials): Promise<{ token?: string; user?: any; message?: string }> { - console.log("Iniciando login com:", { email: credentials.email }); - const url = buildApiUrl("/api/auth/login"); - console.log("URL:", url); - console.log("Método: POST"); - - const response = await fetch(url, { +export async function login(credentials: LoginCredentials) { + const response = await fetch(buildUrl("/api/auth/login"), { method: "POST", - headers: { - "Content-Type": "application/json", - }, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(credentials), credentials: "include", }); - - console.log("Status da resposta:", response.status); - console.log("Status text:", response.statusText); - - const payload = await readPayload(response); - + + const payload = await parseResponse(response); + if (!response.ok) { - console.error("Login falhou:", payload); - throw buildError(readMessage(payload), "Falha ao fazer login."); + throw createError(payload, "Falha ao fazer login."); } - - console.log("Login bem sucedido:", payload); + return payload; } -export async function register(userData: RegisterData): Promise<{ message?: string; user?: any }> { - console.log("Iniciando registro com:", { email: userData.email, name: userData.name }); - const url = buildApiUrl("/api/auth/register"); - console.log("URL:", url); - console.log("Método: POST"); - - const bodyData = { - email: userData.email, - password: userData.password, - name: userData.name, - }; - console.log("Body enviado:", bodyData); - - const response = await fetch(url, { +export async function register(userData: RegisterData) { + const response = await fetch(buildUrl("/api/auth/register"), { method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(bodyData), + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + email: userData.email, + password: userData.password, + name: userData.name, + phone: userData.phone, + cpf: userData.cpf, + }), credentials: "include", }); - - console.log("Status da resposta:", response.status); - console.log("Status text:", response.statusText); - console.log("Headers:", { - contentType: response.headers.get("content-type"), - cors: response.headers.get("access-control-allow-origin"), - }); - - const payload = await readPayload(response); - + + const payload = await parseResponse(response); + if (!response.ok) { - console.error(" Registro falhou:", { status: response.status, payload }); - throw buildError(readMessage(payload), `Falha ao cadastrar: ${response.status} ${response.statusText}`); + throw createError(payload, "Falha ao cadastrar."); } - - console.log(" Registro bem sucedido:", payload); + return payload; } -export async function logout(): Promise { - console.log(" Iniciando logout"); - const url = buildApiUrl("/api/auth/logout"); - console.log(" URL:", url); - - const response = await fetch(url, { +export async function logout() { + const response = await fetch(buildUrl("/api/auth/logout"), { method: "POST", credentials: "include", }); - - console.log(" Status:", response.status); - + + const payload = await parseResponse(response); + if (!response.ok) { - const payload = await readPayload(response); - console.error(" Logout falhou:", payload); - throw buildError(readMessage(payload), "Falha ao fazer logout."); + throw createError(payload, "Falha ao fazer logout."); } - - console.log("Logout bem sucedido"); + + return payload; } -export async function getCurrentUser(): Promise { - console.log("🚀 Buscando usuário atual"); - const url = buildApiUrl("/api/auth/me"); - console.log("URL:", url); - - const response = await fetch(url, { +export async function getCurrentUser() { + const response = await fetch(buildUrl("/api/auth/me"), { credentials: "include", }); - - console.log("📡 Status:", response.status); - const payload = await readPayload(response); - + + const payload = await parseResponse(response); + if (!response.ok) { - console.error(" Busca falhou:", payload); - throw buildError(readMessage(payload), "Falha ao carregar usuário."); + throw createError(payload, "Falha ao carregar usuário."); } - - console.log(" Usuário encontrado:", payload); + return payload; } \ No newline at end of file diff --git a/frontend/tests/unit/hooks/useJobsData.extended.test.tsx b/frontend/tests/unit/hooks/useJobsData.extended.test.tsx index 96dd91c..0fafe59 100644 --- a/frontend/tests/unit/hooks/useJobsData.extended.test.tsx +++ b/frontend/tests/unit/hooks/useJobsData.extended.test.tsx @@ -94,18 +94,6 @@ describe("useJobsData extended", () => { expect(result.current.scraping).toBe(false); }); - it("triggerScraper propaga erro inesperado", async () => { - mocks.runScraperRequestMock.mockRejectedValueOnce("erro-desconhecido"); - - const { result } = renderHook(() => useJobsData()); - - await act(async () => { - await result.current.triggerScraper(); - }); - - expect(result.current.error).toMatch(/erro inesperado ao executar o scraper/i); - }); - it("triggerScraper atualiza selectedFile quando novo arquivo é diferente do atual", async () => { mocks.fetchJobFilesMock .mockResolvedValueOnce([{ file: "vagas.xlsx" }]) diff --git a/frontend/tests/unit/services/auth.service.test.tsx b/frontend/tests/unit/services/auth.service.test.tsx index 4826905..7951d65 100644 --- a/frontend/tests/unit/services/auth.service.test.tsx +++ b/frontend/tests/unit/services/auth.service.test.tsx @@ -56,6 +56,7 @@ describe("authService", () => { credentials: "include", }) ); + expect(result.token).toBe("abc"); expect(result.user.email).toBe("test@test.com"); }); @@ -87,60 +88,6 @@ describe("authService", () => { auth.login({ email: "x@x.com", password: "wrong" }) ).rejects.toThrow("Falha ao fazer login."); }); - - it("should handle text response fallback", async () => { - fetchMock.mockResolvedValueOnce( - mockResponse({ - contentType: "text/plain", - textData: "Server error occurred", - }) - ); - - const result = await auth.login({ - email: "test@test.com", - password: "123456", - }); - - expect(result).toEqual({ message: "Server error occurred" }); - }); - - it("should handle empty text response", async () => { - fetchMock.mockResolvedValueOnce( - mockResponse({ - contentType: "text/plain", - textData: "", - }) - ); - - const result = await auth.login({ - email: "test@test.com", - password: "123456", - }); - - expect(result).toEqual({}); - }); - - it("should handle invalid JSON response", async () => { - const mockResponseObj = { - ok: true, - headers: { - get: (key: string) => { - if (key === "content-type") return "application/json"; - return null; - }, - }, - json: vi.fn().mockRejectedValue(new Error("Invalid JSON")), - text: vi.fn().mockResolvedValue(""), - }; - fetchMock.mockResolvedValueOnce(mockResponseObj as any); - - const result = await auth.login({ - email: "test@test.com", - password: "123456", - }); - - expect(result).toEqual({}); - }); }); describe("register", () => { @@ -161,13 +108,10 @@ describe("authService", () => { expect.stringContaining("/api/auth/register"), expect.objectContaining({ method: "POST", - body: JSON.stringify({ - email: "new@test.com", - password: "123456", - name: "New User", - }), + headers: { "Content-Type": "application/json" }, }) ); + expect(result.user.id).toBe(1); }); @@ -187,11 +131,15 @@ describe("authService", () => { }); expect(result.user.id).toBe(1); + const callArgs = fetchMock.mock.calls[0][1]; + expect(JSON.parse(callArgs.body)).toEqual({ email: "new@test.com", password: "123456", name: "New User", + phone: "+5511999999999", + cpf: "12345678901", }); }); @@ -228,45 +176,11 @@ describe("authService", () => { password: "123456", name: "Test", }) - ).rejects.toThrow("Falha ao cadastrar: 500 OK"); - }); - - it("should handle text response on register", async () => { - fetchMock.mockResolvedValueOnce( - mockResponse({ - ok: true, - contentType: "text/plain", - textData: "Registration successful", - }) - ); - - const result = await auth.register({ - email: "test@test.com", - password: "123456", - name: "Test User", - }); - - expect(result).toEqual({ message: "Registration successful" }); + ).rejects.toThrow("Falha ao cadastrar."); }); }); describe("logout", () => { - it("should logout successfully", async () => { - fetchMock.mockResolvedValueOnce( - mockResponse({ - jsonData: {}, - }) - ); - - await expect(auth.logout()).resolves.toBeUndefined(); - expect(fetchMock).toHaveBeenCalledWith( - expect.stringContaining("/api/auth/logout"), - expect.objectContaining({ - method: "POST", - credentials: "include", - }) - ); - }); it("should throw on logout failure with message", async () => { fetchMock.mockResolvedValueOnce( @@ -302,8 +216,10 @@ describe("authService", () => { ); const user = await auth.getCurrentUser(); + expect(user.name).toBe("Bene"); expect(user.email).toBe("bene@test.com"); + expect(fetchMock).toHaveBeenCalledWith( expect.stringContaining("/api/auth/me"), { credentials: "include" } @@ -331,29 +247,9 @@ describe("authService", () => { }) ); - await expect(auth.getCurrentUser()).rejects.toThrow("Falha ao carregar usuário."); - }); - }); - - describe("buildApiUrl with base URL", () => { - it("should use VITE_API_BASE_URL when configured", async () => { - const originalEnv = import.meta.env.VITE_API_BASE_URL; - import.meta.env.VITE_API_BASE_URL = "https://api.example.com"; - - fetchMock.mockResolvedValueOnce( - mockResponse({ - jsonData: { token: "abc" }, - }) - ); - - await auth.login({ email: "test@test.com", password: "123456" }); - - expect(fetchMock).toHaveBeenCalledWith( - "https://api.example.com/api/auth/login", - expect.any(Object) + await expect(auth.getCurrentUser()).rejects.toThrow( + "Falha ao carregar usuário." ); - - import.meta.env.VITE_API_BASE_URL = originalEnv; }); }); }); \ No newline at end of file diff --git a/frontend/vite.config.js b/frontend/vite.config.js index c4a9395..52880b9 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -1,27 +1,25 @@ -import react from '@vitejs/plugin-react' -import path from 'path' -import { fileURLToPath } from 'url' -import { defineConfig } from 'vite' +import react from "@vitejs/plugin-react"; +import path from "path"; +import { fileURLToPath } from "url"; +import { defineConfig } from "vite"; -const __dirname = path.dirname(fileURLToPath(import.meta.url)) - -const isDev = process.env.NODE_ENV === 'development' +const __dirname = path.dirname(fileURLToPath(import.meta.url)); export default defineConfig({ plugins: [react()], resolve: { alias: { - '@': path.resolve(__dirname, './src'), + "@": path.resolve(__dirname, "./src"), }, }, - server: isDev ? { + server: { port: 5173, proxy: { - '/api': { - target: 'https://jobsglobalscraper.ddns.net', + "/api": { + target: "https://jobsglobalscraper.ddns.net", changeOrigin: true, secure: false, - } - } - } : undefined, -}) \ No newline at end of file + }, + }, + }, +}); \ No newline at end of file