Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions frontends/main/src/app-pages/HomePage/NewsEventsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,11 @@ const Story: React.FC<{ item: NewsFeedItem; mobile: boolean }> = ({
mobile,
}) => {
return (
<StoryCard mobile={mobile} href={item.url} forwardClicksToLink>
<StoryCard mobile={mobile} forwardClicksToLink>
{item.image.url ? (
<Card.Image src={item.image.url} alt={item.image.alt || ""} />
) : null}
<Card.Title lines={2} style={{ marginBottom: -13 }}>
<Card.Title href={item.url} lines={2} style={{ marginBottom: -13 }}>
{item.title}
</Card.Title>
<Card.Footer>
Expand Down Expand Up @@ -222,7 +222,7 @@ const NewsEventsSection: React.FC = () => {
const stories = news.results.slice(0, 6)

const EventCards = events.results.map((item) => (
<EventCard key={item.id} href={item.url} forwardClicksToLink>
<EventCard key={item.id} forwardClicksToLink>
<Card.Content>
<EventDate>
<EventDay>
Expand All @@ -238,7 +238,7 @@ const NewsEventsSection: React.FC = () => {
)}
</EventMonth>
</EventDate>
<Link href={item.url}>
<Link href={item.url} data-card-link>
<EventTitle>{item.title}</EventTitle>
</Link>
<Chevron />
Expand Down
33 changes: 11 additions & 22 deletions frontends/main/src/app-pages/UnitsListingPage/UnitCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
UnitLogo,
} from "ol-components"
import { useChannelDetail } from "api/hooks/channels"
import Link from "next/link"

const CardStyled = styled(Card)({
height: "100%",
Expand Down Expand Up @@ -77,23 +78,10 @@ const LoadingContent = styled.div({
padding: "24px",
})

const HeadingText = styled(Typography)(({ theme }) => ({
const HeadingText = styled.span(({ theme }) => ({
alignSelf: "stretch",
color: theme.custom.colors.darkGray2,
...theme.typography.body2,
[theme.breakpoints.down("md")]: {
display: "none",
},
}))

const SubHeadingText = styled(HeadingText)(({ theme }) => ({
alignSelf: "stretch",
color: theme.custom.colors.darkGray2,
...theme.typography.body2,
display: "none",
[theme.breakpoints.down("md")]: {
display: "block",
},
}))

const CountsTextContainer = styled.div({
Expand Down Expand Up @@ -131,24 +119,24 @@ const UnitCard: React.FC<UnitCardProps> = (props) => {
const channelDetail = channelDetailQuery.data
const unitUrl = channelDetail?.channel_url

return channelDetailQuery.isLoading ? (
<UnitCardLoading />
) : (
<CardStyled href={unitUrl && new URL(unitUrl!).pathname}>
if (!unitUrl) return null
const href = unitUrl && new URL(unitUrl).pathname

return (
<CardStyled forwardClicksToLink data-testid={`unit-card-${unit.code}`}>
<Card.Content>
<UnitCardContainer>
<UnitCardContent>
<LogoContainer>
<UnitLogo unitCode={unit.code as OfferedByEnum} height={50} />
<Link href={href} data-card-link>
<UnitLogo unitCode={unit.code as OfferedByEnum} height={50} />
</Link>
</LogoContainer>
<CardBottom>
<ValuePropContainer>
<HeadingText>
{channelDetail?.configuration?.heading}
</HeadingText>
<SubHeadingText>
{channelDetail?.configuration?.sub_heading}
</SubHeadingText>
</ValuePropContainer>
<CountsTextContainer>
<CountsText data-testid={`course-count-${unit.code}`}>
Expand Down Expand Up @@ -192,6 +180,7 @@ export const UnitCards: React.FC<UnitCardsProps> = (props) => {
{units?.map((unit) => {
const courseCount = courseCounts[unit.code] || 0
const programCount = programCounts[unit.code] || 0

return unit.value_prop ? (
<UnitCard
key={unit.code}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,9 @@
import React from "react"
import { renderWithProviders, screen, waitFor, within } from "@/test-utils"
import type { LearningResourcesSearchResponse } from "api"
import UnitsListingPage from "./UnitsListingPage"
import { factories, setMockResponse, urls } from "api/test-utils"
import { assertHeadings } from "ol-test-utilities"

const makeSearchResponse = (
aggregations: Record<string, number>,
): LearningResourcesSearchResponse => {
return {
metadata: {
suggestions: [],
aggregations: {
topic: Object.entries(aggregations).map(([key, docCount]) => ({
key,
doc_count: docCount,
})),
},
},
count: 0,
results: [],
next: null,
previous: null,
}
}

describe("DepartmentListingPage", () => {
const setupApis = () => {
const make = factories.learningResources
Expand Down Expand Up @@ -59,67 +38,49 @@ describe("DepartmentListingPage", () => {
value_prop: "Professional Unit 2 value prop",
professional: true,
})
const professionalUnit3 = make.offeror({
code: "professionalUnit3",
name: "Professional Unit 3",
value_prop: "Professional Unit 3 value prop",
professional: true,
})

const units = [
academicUnit1,
academicUnit2,
academicUnit3,
professionalUnit1,
professionalUnit2,
professionalUnit3,
]
const courseCounts = {
const courseCounts: Record<string, number> = {
academicUnit1: 10,
academicUnit2: 20,
academicUnit3: 1,
professionalUnit1: 40,
professionalUnit2: 50,
professionalUnit3: 0,
professionalUnit2: 0,
}
const programCounts = {
const programCounts: Record<string, number> = {
academicUnit1: 1,
academicUnit2: 2,
academicUnit3: 0,
professionalUnit1: 4,
professionalUnit2: 5,
professionalUnit3: 6,
}

setMockResponse.get(urls.channels.counts("unit"), [
{
name: academicUnit1,
counts: {
programs: 7,
courses: 10,
},
},
])
setMockResponse.get(urls.offerors.list(), units)

setMockResponse.get(
urls.search.resources({
resource_type: ["course"],
aggregations: ["offered_by"],
}),
makeSearchResponse(courseCounts),
)
setMockResponse.get(
urls.search.resources({
resource_type: ["program"],
aggregations: ["offered_by"],
urls.channels.counts("unit"),
units.map((unit) => {
return {
name: unit.code,
counts: {
courses: courseCounts[unit.code],
programs: programCounts[unit.code],
},
}
}),
makeSearchResponse(programCounts),
)
setMockResponse.get(urls.offerors.list(), {
count: units.length,
results: units,
})

units.forEach((unit) => {
setMockResponse.get(urls.channels.details("unit", unit.code), {
channel_url: `/units/${unit.code}`,
channel_url: `${window.location.origin}/units/${unit.code}`,
})
})

Expand All @@ -138,49 +99,43 @@ describe("DepartmentListingPage", () => {

it("Shows unit properties within the proper section", async () => {
const { units, courseCounts, programCounts } = setupApis()

renderWithProviders(<UnitsListingPage />)

const academicSection = screen.getByTestId("UnitSection-academic")
const professionalSection = screen.getByTestId("UnitSection-professional")

await waitFor(() => {
const academicSection = screen.getByTestId("UnitSection-academic")
const professionalSection = screen.getByTestId("UnitSection-professional")
units.forEach(async (unit) => {
Comment on lines 108 to -145
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is fixing a bug where /units page links were broken. This test should have caught that, except it wasn't actually doing anything because forEach can't be awaited (it always returns undefined) So the test effectively ended on line 144.

const section = unit.professional
? professionalSection
: academicSection
const channelLink = await within(section).findByRole("link", {
name: unit.name,
})
const logoImage = await within(section).findByAltText(unit.name)
const valuePropText = await within(section).findByText(
unit.value_prop ? unit.value_prop : "",
)
expect(channelLink).toHaveAttribute("href", `/units/${unit.code}`)
expect(logoImage).toHaveAttribute(
"src",
`/images/units/${unit.code}.svg`,
)
expect(valuePropText).toBeInTheDocument()
const courseCount = courseCounts[unit.code as keyof typeof courseCounts]
const programCount =
programCounts[unit.code as keyof typeof programCounts]
const courseCountText = await within(section).findByTestId(
`course-count-${unit.code}`,
)
const programCountText = await within(section).findByTestId(
`program-count-${unit.code}`,
)
if (courseCount > 0) {
expect(courseCountText).toHaveTextContent(`Courses: ${courseCount}`)
} else {
expect(courseCountText).toHaveTextContent("")
}
if (programCount > 0) {
expect(programCountText).toHaveTextContent(
`Programs: ${programCount}`,
)
} else {
expect(programCountText).toHaveTextContent("")
}
})
const links = within(academicSection).getAllByRole("link")
expect(links).toHaveLength(3)
return links
})
await waitFor(() => {
const links = within(professionalSection).getAllByRole("link")
expect(links).toHaveLength(2)
return links
})

units.forEach((unit) => {
const section = unit.professional ? professionalSection : academicSection
const card = within(section).getByTestId(`unit-card-${unit.code}`)
const link = within(card).getByRole("link")
expect(link).toHaveAttribute("href", `/units/${unit.code}`)

const courseCount = courseCounts[unit.code]
const programCount = programCounts[unit.code]
const courseCountEl = within(card).getByTestId(
`course-count-${unit.code}`,
)
const programCountEl = within(card).getByTestId(
`program-count-${unit.code}`,
)
expect(courseCountEl).toHaveTextContent(
courseCount > 0 ? `Courses: ${courseCount}` : "",
)
expect(programCountEl).toHaveTextContent(
programCount > 0 ? `Programs: ${programCount}` : "",
)
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ const UnitSection: React.FC<UnitSectionProps> = (props) => {
programCounts,
isLoading,
} = props

return (
<UnitContainer data-testid={`UnitSection-${id}`}>
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { screen } from "@testing-library/react"
import UserListCardCondensed from "./UserListCardCondensed"
import * as factories from "api/test-utils/factories"
import { userListView } from "@/common/urls"
import { renderWithProviders } from "@/test-utils"
import { renderWithProviders, user } from "@/test-utils"
import invariant from "tiny-invariant"

const userListFactory = factories.userLists

Expand All @@ -18,4 +19,16 @@ describe("UserListCard", () => {
)
screen.getByText(userList.title)
})

test("Clicking card navigates to href", async () => {
const userList = userListFactory.userList()
renderWithProviders(
<UserListCardCondensed href="#test" userList={userList} />,
)
const link = screen.getByRole("link", { name: userList.title })
expect(link).toHaveAttribute("href", "#test")
invariant(link.parentElement)
await user.click(link.parentElement)
expect(window.location.hash).toBe("#test")
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ const UserListCardCondensed = ({
className,
}: UserListCardCondensedProps) => {
return (
<StyledCard href={href} className={className}>
<StyledCard forwardClicksToLink className={className}>
<ListCardCondensed.Content>
<TextContainer>
<Link href={href}>
<Link href={href} data-card-link>
<Typography
variant="subtitle1"
color={theme.custom.colors.darkGray2}
Expand Down
7 changes: 4 additions & 3 deletions frontends/ol-components/src/components/Card/Card.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from "react"
import type { Meta, StoryObj } from "@storybook/react"
import { Card } from "./Card"
import type { CardProps } from "./Card"
import { ActionButton } from "../Button/Button"
import { RiMenuAddLine, RiBookmarkLine } from "@remixicon/react"

const meta: Meta<typeof Card> = {
const meta: Meta<CardProps & { href?: string }> = {
title: "smoot-design/Cards/Card",
argTypes: {
size: {
Expand All @@ -19,7 +20,7 @@ const meta: Meta<typeof Card> = {
alt="Provide a meaningful description or leave this blank."
/>
<Card.Info>Info</Card.Info>
<Card.Title>
<Card.Title href={args.href}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit
</Card.Title>
<Card.Actions>
Expand Down Expand Up @@ -51,7 +52,7 @@ const meta: Meta<typeof Card> = {

export default meta

type Story = StoryObj<typeof Card>
type Story = StoryObj<CardProps & { href?: string }>

export const Medium: Story = {
args: {
Expand Down
Loading
Loading