Skip to content

Commit de61a73

Browse files
authored
Merge pull request #225 from harystyleseze/fix/discover-vehicles-live-inventory-196
fix(dashboard): source discover vehicles from live inventory API
2 parents 33ca845 + 03e8736 commit de61a73

2 files changed

Lines changed: 525 additions & 451 deletions

File tree

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import { render, screen, waitFor } from "@testing-library/react"
2+
import { beforeEach, describe, expect, it, vi } from "vitest"
3+
4+
import { DiscoverVehicles } from "@/components/dashboard/discover-vehicles"
5+
6+
function buildVehicle(overrides: Record<string, unknown> = {}) {
7+
return {
8+
_id: "vehicle-1",
9+
name: "Toyota Hiace Mini Bus 2023",
10+
type: "Mini Bus",
11+
year: 2023,
12+
price: 35000,
13+
roi: 18.5,
14+
status: "Available",
15+
fundingStatus: "Open",
16+
totalFundedAmount: 17500,
17+
complianceStatus: "compliant",
18+
...overrides,
19+
}
20+
}
21+
22+
function mockFetchSuccess(data: unknown[]) {
23+
global.fetch = vi.fn().mockResolvedValue({
24+
ok: true,
25+
json: async () => ({ success: true, data }),
26+
})
27+
}
28+
29+
function mockFetchFailure(message: string, status = 500) {
30+
global.fetch = vi.fn().mockResolvedValue({
31+
ok: false,
32+
status,
33+
json: async () => ({ success: false, message }),
34+
})
35+
}
36+
37+
describe("DiscoverVehicles", () => {
38+
beforeEach(() => {
39+
vi.clearAllMocks()
40+
// @ts-expect-error clearing global fetch between tests
41+
global.fetch = undefined
42+
})
43+
44+
it("fetches vehicles from the live inventory API rather than a fixture", async () => {
45+
mockFetchSuccess([buildVehicle()])
46+
47+
render(<DiscoverVehicles />)
48+
49+
await waitFor(() => {
50+
expect(screen.getByText("Toyota Hiace Mini Bus 2023")).toBeInTheDocument()
51+
})
52+
53+
expect(global.fetch).toHaveBeenCalledWith("/api/vehicles")
54+
})
55+
56+
it("shows a loading state while the request is in flight", () => {
57+
global.fetch = vi.fn().mockReturnValue(new Promise(() => {}))
58+
59+
render(<DiscoverVehicles />)
60+
61+
expect(screen.getByTestId("vehicles-loading")).toBeInTheDocument()
62+
})
63+
64+
it("shows an empty inventory state when the API returns no vehicles", async () => {
65+
mockFetchSuccess([])
66+
67+
render(<DiscoverVehicles />)
68+
69+
await waitFor(() => {
70+
expect(screen.getByTestId("vehicles-empty")).toBeInTheDocument()
71+
})
72+
73+
expect(screen.getByText(/No vehicles available/i)).toBeInTheDocument()
74+
})
75+
76+
it("shows an error state with retry when the API request fails", async () => {
77+
mockFetchFailure("Server Error")
78+
79+
render(<DiscoverVehicles />)
80+
81+
await waitFor(() => {
82+
expect(screen.getByTestId("vehicles-error")).toBeInTheDocument()
83+
})
84+
85+
expect(screen.getByRole("button", { name: /Retry/i })).toBeInTheDocument()
86+
})
87+
88+
it("shows an error state when fetch itself throws", async () => {
89+
global.fetch = vi.fn().mockRejectedValue(new Error("Network failure"))
90+
91+
render(<DiscoverVehicles />)
92+
93+
await waitFor(() => {
94+
expect(screen.getByTestId("vehicles-error")).toBeInTheDocument()
95+
})
96+
97+
expect(screen.getByText(/Network failure/i)).toBeInTheDocument()
98+
})
99+
100+
it("excludes delisted (retired) vehicles from the opportunities list", async () => {
101+
mockFetchSuccess([
102+
buildVehicle({ _id: "v-active", name: "Active Vehicle" }),
103+
buildVehicle({ _id: "v-retired", name: "Retired Vehicle", status: "Retired" }),
104+
])
105+
106+
render(<DiscoverVehicles />)
107+
108+
await waitFor(() => {
109+
expect(screen.getByText("Active Vehicle")).toBeInTheDocument()
110+
})
111+
112+
expect(screen.queryByText("Retired Vehicle")).not.toBeInTheDocument()
113+
})
114+
115+
it("disables funding on a vehicle that is already fully funded", async () => {
116+
mockFetchSuccess([
117+
buildVehicle({ name: "Funded Vehicle", fundingStatus: "Funded", totalFundedAmount: 35000 }),
118+
])
119+
120+
render(<DiscoverVehicles />)
121+
122+
await waitFor(() => {
123+
expect(screen.getByText("Funded Vehicle")).toBeInTheDocument()
124+
})
125+
126+
expect(screen.getByRole("button", { name: /Not Available/i })).toBeDisabled()
127+
})
128+
129+
it("renders vehicles with partial/missing optional fields without crashing", async () => {
130+
mockFetchSuccess([
131+
buildVehicle({
132+
name: "Partial Vehicle",
133+
image: undefined,
134+
complianceStatus: undefined,
135+
specifications: undefined,
136+
driverId: undefined,
137+
}),
138+
])
139+
140+
render(<DiscoverVehicles />)
141+
142+
await waitFor(() => {
143+
expect(screen.getByText("Partial Vehicle")).toBeInTheDocument()
144+
})
145+
146+
expect(screen.getByText("Uninspected")).toBeInTheDocument()
147+
expect(screen.getByText("Unassigned")).toBeInTheDocument()
148+
})
149+
})

0 commit comments

Comments
 (0)