gohorsejobs/frontend/src/app/post-job/page.test.tsx
2026-01-03 19:57:09 -03:00

207 lines
7.3 KiB
TypeScript

import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import PostJobPage from "./page";
import { toast } from "sonner";
import { useRouter } from "next/navigation";
// Mock dependencies
jest.mock("@/lib/i18n", () => ({
useTranslation: () => ({
t: (key: string) => key,
locale: "en",
setLocale: jest.fn(),
}),
useI18n: () => ({
t: (key: string) => key,
locale: "en",
setLocale: jest.fn(),
}),
}));
jest.mock("next/navigation", () => ({
useRouter: jest.fn(),
}));
jest.mock("sonner", () => ({
toast: {
error: jest.fn(),
success: jest.fn(),
},
}));
jest.mock("./translations", () => ({
translations: {
en: {
title: "Post a Job",
buttons: { next: "Next Step", publish: "Publish Job", publishing: "Publishing..." },
company: {
name: "Company Name",
namePlaceholder: "My Company",
email: "Email",
password: "Password",
confirmPassword: "Confirm Password",
phone: "Phone",
},
job: {
title: "Job Details",
jobTitle: "Job Title",
jobTitlePlaceholder: "e.g. Developer",
description: "Job Description",
location: "Location",
salary: "Salary",
},
steps: { data: "Data", confirm: "Confirm" },
cardTitle: { step1: "Step 1", step2: "Step 2" },
cardDesc: { step1: "Desc 1", step2: "Desc 2" },
common: { company: "Company", job: "Job", name: "Name", email: "Email", title: "Title" },
options: {
period: { hourly: "/hr" },
contract: { permanent: "Permanent" },
hours: { fullTime: "Full Time" },
mode: { remote: "Remote" }
},
errors: {
company_required: "Company required",
password_mismatch: "Password mismatch",
password_length: "Password length",
job_required: "Job required",
submit_failed: "Submit failed"
},
success: {
job_created: "Job created"
}
},
},
}));
// Mock RichTextEditor component
jest.mock("@/components/rich-text-editor", () => ({
RichTextEditor: ({ value, onChange, placeholder }: any) => (
<textarea
placeholder={placeholder}
value={value}
onChange={(e) => onChange(e.target.value)}
data-testid="rich-text-editor"
/>
),
}));
// Mock LocationPicker component
jest.mock("@/components/location-picker", () => ({
LocationPicker: ({ value, onChange }: any) => (
<input
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="Location"
data-testid="location-picker"
/>
),
}));
describe("PostJobPage", () => {
const mockPush = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
(useRouter as jest.Mock).mockReturnValue({ push: mockPush });
global.fetch = jest.fn();
// Mock scroll methods not in test env
window.scrollTo = jest.fn();
});
it("renders step 1 initially", () => {
render(<PostJobPage />);
expect(screen.getByText("Postar uma Vaga")).toBeInTheDocument();
expect(screen.getByText("Step 1")).toBeInTheDocument();
expect(screen.getByPlaceholderText("My Company")).toBeInTheDocument();
});
it("validates company fields before proceeding", () => {
render(<PostJobPage />);
// Try next without filling
fireEvent.click(screen.getByText("Next Step"));
expect(toast.error).toHaveBeenCalledWith("Preencha os dados obrigatórios da empresa");
// Fill password mismatch
fireEvent.change(screen.getByPlaceholderText("My Company"), { target: { value: "Test Co" } });
fireEvent.change(screen.getByPlaceholderText("contato@empresa.com"), { target: { value: "test@co.com" } });
const passwords = screen.getAllByPlaceholderText("••••••••");
fireEvent.change(passwords[0], { target: { value: "12345678" } });
fireEvent.change(passwords[1], { target: { value: "mismatch" } });
fireEvent.click(screen.getByText("Next Step"));
expect(toast.error).toHaveBeenCalledWith("As senhas não coincidem");
});
it("proceeds to step 2 when company info is valid", () => {
render(<PostJobPage />);
fireEvent.change(screen.getByPlaceholderText("My Company"), { target: { value: "Test Co" } });
fireEvent.change(screen.getByPlaceholderText("contato@empresa.com"), { target: { value: "test@co.com" } });
const passwords = screen.getAllByPlaceholderText("••••••••");
fireEvent.change(passwords[0], { target: { value: "password123" } });
fireEvent.change(passwords[1], { target: { value: "password123" } });
// Need to fill job description as well now
fireEvent.change(screen.getByPlaceholderText("e.g. Developer"), { target: { value: "Frontend Dev" } });
const editors = screen.getAllByTestId("rich-text-editor");
if (editors.length > 1) {
fireEvent.change(editors[1], { target: { value: "Job Desc" } });
} else {
fireEvent.change(editors[0], { target: { value: "Job Desc" } });
}
fireEvent.click(screen.getByText("Next Step"));
expect(screen.getByText("Step 2")).toBeInTheDocument();
});
it("submits the form successfully", async () => {
(global.fetch as jest.Mock)
.mockResolvedValueOnce({
ok: true,
json: async () => ({ token: "fake-token" }),
}) // Register
.mockResolvedValueOnce({
ok: true,
json: async () => ({ id: "job-123" }),
}); // Create Job
render(<PostJobPage />);
// Step 1
fireEvent.change(screen.getByPlaceholderText("My Company"), { target: { value: "Test Co" } });
fireEvent.change(screen.getByPlaceholderText("contato@empresa.com"), { target: { value: "test@co.com" } });
const passwords = screen.getAllByPlaceholderText("••••••••");
fireEvent.change(passwords[0], { target: { value: "password123" } });
fireEvent.change(passwords[1], { target: { value: "password123" } });
// Fill Job Details (Step 1)
fireEvent.change(screen.getByPlaceholderText("e.g. Developer"), { target: { value: "Frontend Dev" } });
const editors = screen.getAllByTestId("rich-text-editor");
if (editors.length > 1) {
fireEvent.change(editors[1], { target: { value: "Job Desc" } });
} else {
fireEvent.change(editors[0], { target: { value: "Job Desc" } });
}
fireEvent.click(screen.getByText("Next Step"));
// Check we are on Step 2
expect(screen.getByText("Step 2")).toBeInTheDocument();
// Submit
fireEvent.click(screen.getByText("Publish Job"));
await waitFor(() => {
expect(global.fetch).toHaveBeenCalledTimes(2);
expect(toast.success).toHaveBeenCalled();
expect(mockPush).toHaveBeenCalledWith("/dashboard/jobs");
});
});
});