166 lines
6.6 KiB
TypeScript
166 lines
6.6 KiB
TypeScript
import { render, screen, waitFor } from "@testing-library/react"
|
|
import userEvent from "@testing-library/user-event"
|
|
import { ApplicationsPage } from "../pages/ApplicationsPage"
|
|
import { renderWithProviders } from "./test-utils"
|
|
import { SHARED_APP_STATUSES } from "@/testing/constants"
|
|
import { mockOnboardingService, createGlobalMockApplication } from "@/testing/mocks"
|
|
|
|
describe("ApplicationsPage - Robust Feature Verification", () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
})
|
|
|
|
const renderPage = (apps = []) => {
|
|
;(mockOnboardingService.getApplications as jest.Mock).mockResolvedValue({
|
|
success: true,
|
|
data: apps
|
|
})
|
|
return renderWithProviders(<ApplicationsPage onViewDetails={jest.fn()} />, {
|
|
preloadedState: {
|
|
auth: {
|
|
user: { id: "admin-1", role: "DD Admin" } as any,
|
|
token: "tok",
|
|
isAuthenticated: true,
|
|
loading: false,
|
|
error: null
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
it("should correctly filter Dealership Requests based on business rules", async () => {
|
|
// Business Rules:
|
|
// 1. Must be shortlisted (ddLeadShortlisted: true)
|
|
// 2. Must NOT be in initial Questionnaire/Submitted states
|
|
// 3. Must NOT be an excluded ID (5, 6, 7, 8)
|
|
const mockApps = [
|
|
createGlobalMockApplication({
|
|
id: "valid-1",
|
|
applicantName: "Visible Application",
|
|
overallStatus: SHARED_APP_STATUSES.FDD,
|
|
ddLeadShortlisted: true
|
|
}),
|
|
createGlobalMockApplication({
|
|
id: "invalid-status",
|
|
applicantName: "Hidden By Status",
|
|
overallStatus: SHARED_APP_STATUSES.SUBMITTED,
|
|
ddLeadShortlisted: true
|
|
}),
|
|
createGlobalMockApplication({
|
|
id: "not-shortlisted",
|
|
applicantName: "Hidden By Shortlist",
|
|
overallStatus: SHARED_APP_STATUSES.ARCH,
|
|
ddLeadShortlisted: false,
|
|
isShortlisted: false,
|
|
}),
|
|
createGlobalMockApplication({
|
|
id: "5", // Excluded ID
|
|
applicantName: "Hidden By Excluded ID",
|
|
overallStatus: SHARED_APP_STATUSES.LOI,
|
|
ddLeadShortlisted: true
|
|
})
|
|
]
|
|
|
|
renderPage(mockApps)
|
|
|
|
// Verify positive visibility
|
|
expect(await screen.findByText("Visible Application")).toBeInTheDocument()
|
|
|
|
// Verify negative visibility (proving the filter logic is actually working, not bypassed)
|
|
expect(screen.queryByText("Hidden By Status")).not.toBeInTheDocument()
|
|
expect(screen.queryByText("Hidden By Shortlist")).not.toBeInTheDocument()
|
|
expect(screen.queryByText("Hidden By Excluded ID")).not.toBeInTheDocument()
|
|
})
|
|
|
|
it("should search across name, ID, and email with case-insensitivity", async () => {
|
|
const user = userEvent.setup()
|
|
const mockApps = [
|
|
createGlobalMockApplication({
|
|
id: "app-search",
|
|
applicationId: "REG-SEARCH-001",
|
|
applicantName: "Specific Dealer Name",
|
|
overallStatus: SHARED_APP_STATUSES.LOI,
|
|
ddLeadShortlisted: true
|
|
})
|
|
]
|
|
renderPage(mockApps)
|
|
|
|
const searchInput = await screen.findByTestId("onboarding-applications-search-input")
|
|
|
|
// 1. Search by name (case-insensitive)
|
|
await user.type(searchInput, "specific")
|
|
expect(await screen.findByText("Specific Dealer Name")).toBeInTheDocument()
|
|
|
|
// 2. Search by Registration ID
|
|
await user.clear(searchInput)
|
|
await user.type(searchInput, "REG-SEARCH")
|
|
expect(await screen.findByText("Specific Dealer Name")).toBeInTheDocument()
|
|
})
|
|
|
|
it("should hide applications still in questionnaire stages (including Questionnaire Completed)", async () => {
|
|
const mockApps = [
|
|
createGlobalMockApplication({
|
|
id: "qc-1",
|
|
applicantName: "Hidden Questionnaire Completed",
|
|
overallStatus: "Questionnaire Completed",
|
|
ddLeadShortlisted: true,
|
|
}),
|
|
createGlobalMockApplication({
|
|
id: "show-1",
|
|
applicantName: "Visible Post Questionnaire",
|
|
overallStatus: SHARED_APP_STATUSES.LOI,
|
|
ddLeadShortlisted: true,
|
|
}),
|
|
]
|
|
renderPage(mockApps)
|
|
|
|
expect(await screen.findByText("Visible Post Questionnaire")).toBeInTheDocument()
|
|
expect(screen.queryByText("Hidden Questionnaire Completed")).not.toBeInTheDocument()
|
|
})
|
|
|
|
it("should filter by My Assignments when checkbox is enabled", async () => {
|
|
const user = userEvent.setup()
|
|
const mockApps = [
|
|
createGlobalMockApplication({
|
|
id: "mine-1",
|
|
applicantName: "Assigned To Me",
|
|
overallStatus: SHARED_APP_STATUSES.LOI,
|
|
ddLeadShortlisted: true,
|
|
assignedTo: "admin-1",
|
|
}),
|
|
createGlobalMockApplication({
|
|
id: "other-1",
|
|
applicantName: "Assigned To Someone Else",
|
|
overallStatus: SHARED_APP_STATUSES.LOI,
|
|
ddLeadShortlisted: true,
|
|
assignedTo: "other-user",
|
|
}),
|
|
]
|
|
renderPage(mockApps)
|
|
|
|
expect(await screen.findByText("Assigned To Me")).toBeInTheDocument()
|
|
expect(screen.getByText("Assigned To Someone Else")).toBeInTheDocument()
|
|
|
|
await user.click(screen.getByTestId("onboarding-applications-assignments-checkbox"))
|
|
|
|
expect(screen.getByText("Assigned To Me")).toBeInTheDocument()
|
|
expect(screen.queryByText("Assigned To Someone Else")).not.toBeInTheDocument()
|
|
})
|
|
|
|
it("should handle API failures gracefully without crashing the dashboard", async () => {
|
|
// Mock a 500 or Network error
|
|
;(mockOnboardingService.getApplications as jest.Mock).mockRejectedValue(new Error("Network Error"))
|
|
|
|
// Suppress console.error for this test to keep logs clean
|
|
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
|
|
renderPage([])
|
|
|
|
// The dashboard should still render its UI shell and empty table, not crash
|
|
expect(await screen.findByTestId("onboarding-applications-search-input")).toBeInTheDocument()
|
|
expect(screen.getByTestId("onboarding-applications-count-text")).toHaveTextContent("0 applications")
|
|
|
|
consoleSpy.mockRestore()
|
|
})
|
|
})
|