feat(tests): fix candidate dashboard and apply form tests
This commit is contained in:
parent
812affb803
commit
93ca6d64ef
3 changed files with 74 additions and 22 deletions
|
|
@ -85,7 +85,7 @@ func ValidateJWT(secret, env string) error {
|
||||||
// warning is always returned if short.
|
// warning is always returned if short.
|
||||||
// fatal error is returned if production.
|
// fatal error is returned if production.
|
||||||
// Caller handles logging.
|
// Caller handles logging.
|
||||||
return fmt.Errorf(msg)
|
return fmt.Errorf("%s", msg)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
|
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
|
||||||
|
import { Suspense } from "react";
|
||||||
import JobApplicationPage from "./page";
|
import JobApplicationPage from "./page";
|
||||||
import { jobsApi, applicationsApi } from "@/lib/api";
|
import { jobsApi, applicationsApi } from "@/lib/api";
|
||||||
import { useNotify } from "@/contexts/notification-context";
|
import { useNotify } from "@/contexts/notification-context";
|
||||||
|
|
@ -40,6 +41,25 @@ jest.mock("@/components/ui/progress", () => ({
|
||||||
Progress: () => <div data-testid="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", () => {
|
describe("JobApplicationPage", () => {
|
||||||
const mockPush = jest.fn();
|
const mockPush = jest.fn();
|
||||||
|
|
@ -59,22 +79,34 @@ describe("JobApplicationPage", () => {
|
||||||
window.scrollTo = jest.fn();
|
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 () => {
|
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(() => {
|
render(
|
||||||
expect(screen.getByText("Application: Software Engineer")).toBeInTheDocument();
|
<Suspense fallback={<div>Loading...</div>}>
|
||||||
expect(screen.getByText(/Tech Corp/)).toBeInTheDocument();
|
<JobApplicationPage params={params} />
|
||||||
});
|
</Suspense>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await screen.findByText("Application: Software Engineer")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText(/Tech Corp/)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("validates step 1 fields", async () => {
|
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
|
// Try next empty
|
||||||
const nextBtn = screen.getByRole("button", { name: /Next step/i });
|
const nextBtn = screen.getByRole("button", { name: /Next step/i });
|
||||||
|
|
@ -91,19 +123,29 @@ describe("JobApplicationPage", () => {
|
||||||
expect(mockNotify.error).toHaveBeenCalledWith("Privacy policy", expect.any(String));
|
expect(mockNotify.error).toHaveBeenCalledWith("Privacy policy", expect.any(String));
|
||||||
|
|
||||||
// Check checkbox
|
// 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);
|
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);
|
fireEvent.click(nextBtn);
|
||||||
|
|
||||||
// Should move to step 2
|
// Should move to step 2
|
||||||
expect(screen.getByText("Resume & Documents")).toBeInTheDocument();
|
await waitFor(() => expect(screen.getByText("Resume (CV) *")).toBeInTheDocument());
|
||||||
});
|
});
|
||||||
|
|
||||||
it("submits application successfully", async () => {
|
it("submits application successfully", async () => {
|
||||||
render(<JobApplicationPage params={params} />);
|
const params: any = Promise.resolve({ id: "job-123" });
|
||||||
await waitFor(() => expect(jobsApi.getById).toHaveBeenCalled());
|
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
|
// Step 1
|
||||||
fireEvent.change(screen.getByLabelText(/Full name/i), { target: { value: "John Doe" } });
|
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 }));
|
fireEvent.click(screen.getByRole("button", { name: /Next step/i }));
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
// Optional fields here or skip
|
await waitFor(() => expect(screen.getByText("Resume (CV) *")).toBeInTheDocument());
|
||||||
// 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!)
|
|
||||||
fireEvent.click(screen.getByRole("button", { name: /Next step/i }));
|
fireEvent.click(screen.getByRole("button", { name: /Next step/i }));
|
||||||
|
|
||||||
|
// Wait for Step 3
|
||||||
|
await waitFor(() => expect(screen.getByText("Salary expectation *")).toBeInTheDocument());
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
// Salary and Experience
|
|
||||||
const trigger = screen.getByText("Select a range");
|
const trigger = screen.getByText("Select a range");
|
||||||
fireEvent.click(trigger);
|
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.getByLabelText("Yes, I do")); // Radio
|
||||||
|
|
||||||
fireEvent.click(screen.getByRole("button", { name: /Next step/i }));
|
fireEvent.click(screen.getByRole("button", { name: /Next step/i }));
|
||||||
|
|
||||||
|
await waitFor(() => expect(screen.getByLabelText(/Why do you want to work/i)).toBeInTheDocument());
|
||||||
|
|
||||||
// Step 4
|
// Step 4
|
||||||
// Why Us and Availability
|
// Why Us and Availability
|
||||||
fireEvent.change(screen.getByLabelText(/Why do you want to work/i), { target: { value: "Because I like it." } });
|
fireEvent.change(screen.getByLabelText(/Why do you want to work/i), { target: { value: "Because I like it." } });
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,14 @@ jest.mock("@/components/ui/skeleton", () => ({
|
||||||
Skeleton: () => <div>Loading...</div>,
|
Skeleton: () => <div>Loading...</div>,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
jest.mock("@/components/stats-card", () => ({
|
||||||
|
StatsCard: () => <div>StatsCard</div>,
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock("@/components/job-card", () => ({
|
||||||
|
JobCard: () => <div>JobCard</div>,
|
||||||
|
}))
|
||||||
|
|
||||||
describe("CandidateDashboard", () => {
|
describe("CandidateDashboard", () => {
|
||||||
it("renders welcome message", async () => {
|
it("renders welcome message", async () => {
|
||||||
render(<CandidateDashboardContent />)
|
render(<CandidateDashboardContent />)
|
||||||
|
|
@ -56,6 +64,6 @@ describe("CandidateDashboard", () => {
|
||||||
// Assuming dashboard has "Welcome" or similar
|
// Assuming dashboard has "Welcome" or similar
|
||||||
// Or check for section headers "My Applications", "Recommended Jobs"
|
// Or check for section headers "My Applications", "Recommended Jobs"
|
||||||
// Wait for potential async data loading
|
// Wait for potential async data loading
|
||||||
expect(await screen.findByText(/Recommended Jobs/i)).toBeInTheDocument()
|
expect(await screen.findByText("candidate.dashboard.recommended.title")).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue