Skip to content

Commit 95b8e69

Browse files
feat: enhance tests for useJobsData and auth service with new scenarios
1 parent e609af7 commit 95b8e69

4 files changed

Lines changed: 123 additions & 0 deletions

File tree

frontend/tests/unit/hooks/useJobsData.extended.test.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,38 @@ describe("useJobsData extended", () => {
6767
expect(result.current.error).toBe("falha jobs");
6868
});
6969

70+
it("aplica os metadados padrão quando a API retorna payload parcial", async () => {
71+
mocks.fetchJobsByAPIMock.mockResolvedValueOnce({});
72+
73+
const { result } = renderHook(() => useJobsData(3, 10));
74+
75+
await waitFor(() => {
76+
expect(result.current.loading).toBe(false);
77+
expect(result.current.meta).toEqual({
78+
total: 0,
79+
hasNext: false,
80+
hasPrev: false,
81+
page: 3,
82+
limit: 10,
83+
totalPages: 0,
84+
});
85+
});
86+
87+
expect(result.current.jobs).toEqual([]);
88+
});
89+
90+
it("usa mensagem padrão quando carregar vagas rejeita sem Error", async () => {
91+
mocks.fetchJobsByAPIMock.mockRejectedValueOnce("offline");
92+
93+
const { result } = renderHook(() => useJobsData());
94+
95+
await waitFor(() => {
96+
expect(result.current.error).toBe(
97+
"Erro inesperado ao carregar vagas.",
98+
);
99+
});
100+
});
101+
70102
it("triggerScraper carrega jobs após executar request", async () => {
71103
const { result } = renderHook(() => useJobsData());
72104

@@ -78,4 +110,23 @@ describe("useJobsData extended", () => {
78110
expect(mocks.fetchJobsByAPIMock).toHaveBeenCalled();
79111
expect(result.current.scraping).toBe(false);
80112
});
113+
114+
it("usa mensagem padrão quando o scraper rejeita sem Error", async () => {
115+
mocks.runScraperRequestMock.mockRejectedValueOnce("indisponível");
116+
117+
const { result } = renderHook(() => useJobsData());
118+
119+
await waitFor(() => {
120+
expect(result.current.loading).toBe(false);
121+
});
122+
123+
await act(async () => {
124+
await result.current.triggerScraper();
125+
});
126+
127+
expect(result.current.error).toBe(
128+
"Erro inesperado ao executar o scraper.",
129+
);
130+
expect(result.current.scraping).toBe(false);
131+
});
81132
});

frontend/tests/unit/new_dashboard/branch-coverage.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Header } from "@/domains/new_dashboard/components/layout/Header";
66
import { MessageDetailModal } from "@/domains/new_dashboard/components/layout/MessageDetailModal";
77
import { JobDetailModal } from "@/domains/new_dashboard/components/jobs/JobDetailModal";
88
import { JobRow } from "@/domains/new_dashboard/components/jobs/JobRow";
9+
import { MentoringTab } from "@/domains/new_dashboard/components/mentoring/MentoringTab";
910
import { ProfileForm } from "@/domains/new_dashboard/components/profile/ProfileForm";
1011
import { Modal } from "@/domains/new_dashboard/components/shared/Modal";
1112
import {
@@ -236,6 +237,27 @@ describe("new_dashboard branch coverage", () => {
236237
expect(onClose).toHaveBeenCalledOnce();
237238
});
238239

240+
it("abre, confirma e fecha os detalhes de uma mentoria", () => {
241+
render(<MentoringTab />);
242+
243+
fireEvent.click(screen.getAllByRole("button", { name: "Ver Mais" })[0]);
244+
245+
expect(
246+
screen.getByRole("heading", { name: "Julio Silva", level: 2 }),
247+
).toBeInTheDocument();
248+
expect(screen.queryByText(/participação confirmada/i)).not.toBeInTheDocument();
249+
250+
fireEvent.click(
251+
screen.getByRole("button", { name: /confirmar participação/i }),
252+
);
253+
expect(screen.getByText(/participação confirmada/i)).toBeInTheDocument();
254+
255+
fireEvent.click(screen.getByRole("button", { name: "Fechar" }));
256+
expect(
257+
screen.queryByRole("heading", { name: "Julio Silva", level: 2 }),
258+
).not.toBeInTheDocument();
259+
});
260+
239261
it("usa origem sistema como fallback no detalhe da mensagem", () => {
240262
render(
241263
<MessageDetailModal

frontend/tests/unit/new_dashboard/theme.toast.test.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ describe("new_dashboard theme and toast contexts", () => {
105105
expect(container).toBeEmptyDOMElement();
106106
});
107107

108+
it("renderiza toast quando recebe uma mensagem", () => {
109+
render(<Toast message="Perfil atualizado" />);
110+
111+
expect(screen.getByText("Perfil atualizado")).toBeInTheDocument();
112+
});
113+
108114
it("lança erro quando o contexto de toast é usado fora do provider", () => {
109115
expect(() => render(<ToastHookConsumer />)).toThrow(
110116
/useToastContext must be used within ToastProvider/i,

frontend/tests/unit/services/auth.service.test.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,50 @@ describe("authService", () => {
3333
beforeEach(() => {
3434
fetchMock.mockReset();
3535
vi.restoreAllMocks();
36+
vi.unstubAllEnvs();
37+
});
38+
39+
describe("response parsing and URL normalization", () => {
40+
it("uses the configured API URL without trailing slashes", async () => {
41+
vi.stubEnv("VITE_API_BASE_URL", "https://api.example.com///");
42+
fetchMock.mockResolvedValueOnce(mockResponse({ jsonData: { ok: true } }));
43+
44+
await expect(auth.logout()).resolves.toEqual({ ok: true });
45+
46+
expect(fetchMock).toHaveBeenCalledWith(
47+
"https://api.example.com/auth/logout",
48+
expect.objectContaining({ method: "POST" }),
49+
);
50+
});
51+
52+
it("parses non-JSON response bodies as messages", async () => {
53+
fetchMock.mockResolvedValueOnce(
54+
mockResponse({
55+
contentType: "text/plain",
56+
textData: "Logout concluído",
57+
}),
58+
);
59+
60+
await expect(auth.logout()).resolves.toEqual({
61+
message: "Logout concluído",
62+
});
63+
});
64+
65+
it("returns an empty payload for an empty response body", async () => {
66+
fetchMock.mockResolvedValueOnce(
67+
mockResponse({ contentType: "", textData: "" }),
68+
);
69+
70+
await expect(auth.logout()).resolves.toEqual({});
71+
});
72+
73+
it("returns an empty payload when response parsing fails", async () => {
74+
const response = mockResponse({ contentType: "application/json" });
75+
response.json.mockRejectedValueOnce(new SyntaxError("invalid JSON"));
76+
fetchMock.mockResolvedValueOnce(response);
77+
78+
await expect(auth.logout()).resolves.toEqual({});
79+
});
3680
});
3781

3882
describe("login", () => {

0 commit comments

Comments
 (0)