feat(tests): fix candidate dashboard and apply form tests

This commit is contained in:
Tiago Yamamoto 2026-01-01 11:56:00 -03:00
parent 812affb803
commit 93ca6d64ef
3 changed files with 74 additions and 22 deletions

View file

@ -85,7 +85,7 @@ func ValidateJWT(secret, env string) error {
// warning is always returned if short.
// fatal error is returned if production.
// Caller handles logging.
return fmt.Errorf(msg)
return fmt.Errorf("%s", msg)
}
return nil
}

View file

@ -1,5 +1,6 @@
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { Suspense } from "react";
import JobApplicationPage from "./page";
import { jobsApi, applicationsApi } from "@/lib/api";
import { useNotify } from "@/contexts/notification-context";
@ -40,6 +41,25 @@ jest.mock("@/components/ui/progress", () => ({
Progress: () => <div data-testid="progress" />,
}));
jest.mock("framer-motion", () => ({
motion: { div: ({ children }: any) => <div>{children}</div> },
AnimatePresence: ({ children }: any) => <>{children}</>,
}));
jest.mock("@/components/ui/select", () => ({
Select: ({ onValueChange, children }: any) => (
<div data-testid="select">
<button data-testid="select-option-3k" onClick={() => onValueChange("up-to-3k")}>
Select 3k
</button>
{children}
</div>
),
SelectTrigger: ({ children }: any) => <button>{children}</button>,
SelectValue: ({ placeholder }: any) => <span>{placeholder}</span>,
SelectContent: ({ children }: any) => <div>{children}</div>,
SelectItem: ({ children }: any) => <div>{children}</div>,
}));
describe("JobApplicationPage", () => {
const mockPush = jest.fn();
@ -59,22 +79,34 @@ describe("JobApplicationPage", () => {
window.scrollTo = jest.fn();
});
// Since component uses `use(params)`, we need to wrap or pass a promise
const params = Promise.resolve({ id: "job-123" });
it("renders job title and company info", async () => {
render(<JobApplicationPage params={params} />);
const params: any = Promise.resolve({ id: "job-123" });
params.status = "fulfilled";
params.value = { id: "job-123" };
await waitFor(() => {
expect(screen.getByText("Application: Software Engineer")).toBeInTheDocument();
expect(screen.getByText(/Tech Corp/)).toBeInTheDocument();
});
render(
<Suspense fallback={<div>Loading...</div>}>
<JobApplicationPage params={params} />
</Suspense>
);
expect(await screen.findByText("Application: Software Engineer")).toBeInTheDocument();
expect(screen.getByText(/Tech Corp/)).toBeInTheDocument();
});
it("validates step 1 fields", async () => {
render(<JobApplicationPage params={params} />);
const params: any = Promise.resolve({ id: "job-123" });
params.status = "fulfilled";
params.value = { id: "job-123" };
await waitFor(() => expect(screen.getByText("Application: Software Engineer")).toBeInTheDocument());
render(
<Suspense fallback={<div>Loading...</div>}>
<JobApplicationPage params={params} />
</Suspense>
);
// Wait for load
expect(await screen.findByText("Application: Software Engineer")).toBeInTheDocument();
// Try next empty
const nextBtn = screen.getByRole("button", { name: /Next step/i });
@ -91,19 +123,29 @@ describe("JobApplicationPage", () => {
expect(mockNotify.error).toHaveBeenCalledWith("Privacy policy", expect.any(String));
// Check checkbox
// Finding checkbox by ID might be easiest or by label text click
const policyLabel = screen.getByText(/I have read and agree to the/i);
fireEvent.click(policyLabel); // Should toggle checkbox associated with label
fireEvent.click(policyLabel);
fireEvent.click(nextBtn);
// Should move to step 2
expect(screen.getByText("Resume & Documents")).toBeInTheDocument();
await waitFor(() => expect(screen.getByText("Resume (CV) *")).toBeInTheDocument());
});
it("submits application successfully", async () => {
render(<JobApplicationPage params={params} />);
await waitFor(() => expect(jobsApi.getById).toHaveBeenCalled());
const params: any = Promise.resolve({ id: "job-123" });
params.status = "fulfilled";
params.value = { id: "job-123" };
render(
<Suspense fallback={<div>Loading...</div>}>
<JobApplicationPage params={params} />
</Suspense>
);
// Wait for load
expect(await screen.findByText("Application: Software Engineer")).toBeInTheDocument();
await waitFor(() => expect(screen.getByLabelText(/Full name/i)).toBeInTheDocument());
// Step 1
fireEvent.change(screen.getByLabelText(/Full name/i), { target: { value: "John Doe" } });
@ -113,21 +155,23 @@ describe("JobApplicationPage", () => {
fireEvent.click(screen.getByRole("button", { name: /Next step/i }));
// Step 2
// Optional fields here or skip
// Resume is technically required (Step 2 logic: case 2 returns true currently in the simplified code?
// Looking at source: case 2: return true; (lines 122). So no validation on Step 2!)
await waitFor(() => expect(screen.getByText("Resume (CV) *")).toBeInTheDocument());
fireEvent.click(screen.getByRole("button", { name: /Next step/i }));
// Wait for Step 3
await waitFor(() => expect(screen.getByText("Salary expectation *")).toBeInTheDocument());
// Step 3
// Salary and Experience
const trigger = screen.getByText("Select a range");
fireEvent.click(trigger);
fireEvent.click(screen.getByText("Up to R$ 3,000")); // SelectOption
fireEvent.click(screen.getByTestId("select-option-3k"));
fireEvent.click(screen.getByLabelText("Yes, I do")); // Radio
fireEvent.click(screen.getByRole("button", { name: /Next step/i }));
await waitFor(() => expect(screen.getByLabelText(/Why do you want to work/i)).toBeInTheDocument());
// Step 4
// Why Us and Availability
fireEvent.change(screen.getByLabelText(/Why do you want to work/i), { target: { value: "Because I like it." } });

View file

@ -49,6 +49,14 @@ jest.mock("@/components/ui/skeleton", () => ({
Skeleton: () => <div>Loading...</div>,
}))
jest.mock("@/components/stats-card", () => ({
StatsCard: () => <div>StatsCard</div>,
}))
jest.mock("@/components/job-card", () => ({
JobCard: () => <div>JobCard</div>,
}))
describe("CandidateDashboard", () => {
it("renders welcome message", async () => {
render(<CandidateDashboardContent />)
@ -56,6 +64,6 @@ describe("CandidateDashboard", () => {
// Assuming dashboard has "Welcome" or similar
// Or check for section headers "My Applications", "Recommended Jobs"
// Wait for potential async data loading
expect(await screen.findByText(/Recommended Jobs/i)).toBeInTheDocument()
expect(await screen.findByText("candidate.dashboard.recommended.title")).toBeInTheDocument()
})
})