Skip to content

Commit 2b44bac

Browse files
authored
added hover message and new statuses for the site listing page (#2407)
1 parent 2b3a6ec commit 2b44bac

File tree

7 files changed

+385
-8
lines changed

7 files changed

+385
-8
lines changed

static/js/components/PublishStatusIndicator.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as React from "react"
22

33
import { PublishStatus } from "../constants"
44

5-
const publishStatusMessage = (status: PublishStatus): string => {
5+
export const publishStatusMessage = (status: PublishStatus | null): string => {
66
switch (status) {
77
case PublishStatus.NotStarted:
88
return "Not started"

static/js/pages/SitesDashboard.test.tsx

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import IntegrationTestHelper, {
1111
import { Website } from "../types/websites"
1212
import PaginationControls from "../components/PaginationControls"
1313
import * as searchHooks from "../hooks/search"
14+
import React from "react"
15+
import { render, fireEvent } from "@testing-library/react"
16+
import { StatusWithDateHover, formatDateTime } from "./SitesDashboard"
17+
import { PublishStatus } from "../constants"
1418

1519
jest.mock("../hooks/search", () => {
1620
return {
@@ -169,3 +173,188 @@ describe("SitesDashboard", () => {
169173
expect(paginationControls.prop("previous")).toBe(previous)
170174
})
171175
})
176+
177+
describe("StatusWithDateHover component", () => {
178+
it("displays status text by default", () => {
179+
const { getByText } = render(
180+
<StatusWithDateHover
181+
statusText="Published"
182+
dateTime="2023-01-15T12:30:45Z"
183+
className="text-success"
184+
/>,
185+
)
186+
187+
expect(getByText("Published")).toBeInTheDocument()
188+
})
189+
190+
it("shows formatted date on hover", () => {
191+
const { getByText, container } = render(
192+
<StatusWithDateHover
193+
statusText="Published"
194+
dateTime="2023-01-15T12:30:45Z"
195+
className="text-success"
196+
/>,
197+
)
198+
199+
const element = container.firstChild as HTMLElement
200+
fireEvent.mouseEnter(element)
201+
202+
expect(getByText(/Published on Jan 15, 2023/)).toBeInTheDocument()
203+
})
204+
205+
it("reverts to status text when mouse leaves", () => {
206+
const { getByText, container } = render(
207+
<StatusWithDateHover
208+
statusText="Published"
209+
dateTime="2023-01-15T12:30:45Z"
210+
className="text-success"
211+
/>,
212+
)
213+
214+
const element = container.firstChild as HTMLElement
215+
216+
// Hover
217+
fireEvent.mouseEnter(element)
218+
expect(getByText(/Published on Jan 15, 2023/)).toBeInTheDocument()
219+
220+
// Un-hover
221+
fireEvent.mouseLeave(element)
222+
expect(getByText("Published")).toBeInTheDocument()
223+
})
224+
225+
it("applies the provided className", () => {
226+
const { container } = render(
227+
<StatusWithDateHover
228+
statusText="Published"
229+
dateTime="2023-01-15T12:30:45Z"
230+
className="text-success"
231+
/>,
232+
)
233+
234+
expect(container.firstChild).toHaveClass("text-success")
235+
})
236+
})
237+
238+
describe("formatDateTime function", () => {
239+
it("formats date strings", () => {
240+
const result = formatDateTime("2023-01-15T12:30:45Z")
241+
242+
expect(result).toContain("2023")
243+
expect(result).toContain("Jan")
244+
expect(result).toContain("15")
245+
})
246+
})
247+
248+
describe("Site status indicators", () => {
249+
it("shows status for different site states", async () => {
250+
const testHelper = new IntegrationTestHelper()
251+
const testWebsites = makeWebsites(5)
252+
253+
// Never published site - no publish dates or statuses
254+
const neverPublishedSite = {
255+
...testWebsites[0],
256+
name: "never-published-site",
257+
uuid: "test-uuid-1",
258+
publish_date: null,
259+
draft_publish_date: null,
260+
live_publish_status: null,
261+
unpublished: false,
262+
},
263+
// Unpublished site - has publish_date but marked as unpublished
264+
unpublishedSite = {
265+
...testWebsites[1],
266+
name: "unpublished-site",
267+
uuid: "test-uuid-2",
268+
publish_date: "2023-01-01T12:00:00Z",
269+
unpublished: true,
270+
unpublish_status: PublishStatus.Success,
271+
unpublish_status_updated_on: "2023-01-15T12:30:45Z",
272+
updated_on: "2023-01-15T12:30:45Z",
273+
},
274+
// Draft site - has draft_publish_status and draft_publish_date
275+
// but no publish_date and unpublished is false
276+
draftSite = {
277+
...testWebsites[2],
278+
name: "draft-site",
279+
uuid: "test-uuid-3",
280+
draft_publish_date: "2023-01-15T12:30:45Z",
281+
draft_publish_status: PublishStatus.Success,
282+
publish_date: null,
283+
live_publish_status: null,
284+
unpublished: false,
285+
updated_on: "2023-01-15T12:30:45Z",
286+
},
287+
// Published site - has publish_date and live_publish_status
288+
publishedSite = {
289+
...testWebsites[3],
290+
name: "published-site",
291+
uuid: "test-uuid-4",
292+
publish_date: "2023-01-01T12:00:00Z",
293+
live_publish_status: PublishStatus.Success,
294+
unpublished: false,
295+
updated_on: "2023-01-15T12:30:45Z",
296+
},
297+
// Failed site - has live_publish_status marked as errored
298+
failedSite = {
299+
...testWebsites[4],
300+
name: "failed-site",
301+
uuid: "test-uuid-5",
302+
publish_date: "2023-01-01T12:00:00Z",
303+
live_publish_status: PublishStatus.Errored,
304+
unpublished: false,
305+
updated_on: "2023-01-15T12:30:45Z",
306+
}
307+
308+
const statusSites = [
309+
neverPublishedSite,
310+
unpublishedSite,
311+
draftSite,
312+
publishedSite,
313+
failedSite,
314+
]
315+
const testResponse = {
316+
results: statusSites,
317+
next: "https://example.com",
318+
previous: null,
319+
count: statusSites.length,
320+
}
321+
322+
testHelper.mockGetRequest(
323+
siteApiListingUrl.param({ offset: 0 }).toString(),
324+
testResponse,
325+
)
326+
327+
const websitesLookup: Record<string, Website> = {}
328+
for (const site of statusSites) {
329+
websitesLookup[site.name] = site
330+
}
331+
332+
const testRender = testHelper.configureRenderer(
333+
SitesDashboard,
334+
{},
335+
{
336+
entities: {
337+
websitesListing: {
338+
["0"]: {
339+
...testResponse,
340+
results: statusSites.map((site) => site.name),
341+
},
342+
},
343+
websiteDetails: websitesLookup,
344+
},
345+
queries: {},
346+
},
347+
)
348+
349+
const { wrapper } = await testRender()
350+
351+
// Check for status text
352+
expect(wrapper.text()).toContain("Never Published")
353+
expect(wrapper.text()).toContain("Unpublished from Production")
354+
expect(wrapper.text()).toContain("Draft")
355+
expect(wrapper.text()).toContain("Published")
356+
357+
// Cleanup
358+
testHelper.cleanup()
359+
})
360+
})

0 commit comments

Comments
 (0)