Skip to content
Closed
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
72 changes: 72 additions & 0 deletions frontend/__tests__/testUtils/sharedAssertions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { screen, waitFor, fireEvent } from '@testing-library/react'

export const assertRepoDetails = async ({
heading,
license,
stars,
forks,
commits,
contributors,
issues,
}: {
heading: string
license: string
stars: string
forks: string
commits?: string
contributors?: string
issues: string
}) => {
await waitFor(() => {
const title = screen.getByRole('heading', { name: heading })
expect(title).toBeInTheDocument()
expect(screen.getByText(license)).toBeInTheDocument()
})
expect(screen.getByText(stars)).toBeInTheDocument()
expect(screen.getByText(forks)).toBeInTheDocument()
if (commits) expect(screen.getByText(commits)).toBeInTheDocument()
if (contributors) expect(screen.getByText(contributors)).toBeInTheDocument()
expect(screen.getByText(issues)).toBeInTheDocument()
}

export const assertHeadingsAndTexts = async ({
headingText,
texts,
}: {
headingText?: string
texts: string[]
}) => {
if (headingText) {
await waitFor(() => {
const heading = screen.getByRole('heading', { name: headingText })
expect(heading).toBeInTheDocument()
})
}

texts.forEach((text) => {
expect(screen.getByText(text)).toBeInTheDocument()
})
}

export const assertContributorToggle = async (initial: string, others: string[]) => {
await waitFor(() => {
expect(screen.getByText(initial)).toBeInTheDocument()
expect(screen.queryByText('Contributor 10')).not.toBeInTheDocument()
})

const showMoreButton = screen.getByRole('button', { name: /Show more/i })
fireEvent.click(showMoreButton)

await waitFor(() => {
others.forEach((name) => {
expect(screen.getByText(name)).toBeInTheDocument()
})
})

const showLessButton = screen.getByRole('button', { name: /Show less/i })
fireEvent.click(showLessButton)

await waitFor(() => {
expect(screen.queryByText('Contributor 10')).not.toBeInTheDocument()
})
}
76 changes: 34 additions & 42 deletions frontend/__tests__/unit/components/BreadCrumbs.test.tsx
Original file line number Diff line number Diff line change
@@ -1,68 +1,60 @@
import { render, screen } from '@testing-library/react'
import { usePathname } from 'next/navigation'
import BreadCrumbs from 'components/BreadCrumbs'
import '@testing-library/jest-dom'

jest.mock('next/navigation', () => ({
usePathname: jest.fn(),
}))
const renderBreadCrumbs = (items = []) => render(<BreadCrumbs breadcrumbItems={items} />)

describe('BreadCrumb', () => {
afterEach(() => {
jest.clearAllMocks()
})

test('does not render on root path "/"', () => {
;(usePathname as jest.Mock).mockReturnValue('/')
const sampleItems = [
{ title: 'Dashboard', path: '/dashboard' },
{ title: 'Users', path: '/dashboard/users' },
{ title: 'Profile', path: '/dashboard/users/profile' },
]

render(<BreadCrumbs />)
describe('BreadCrumbs', () => {
test('does not render when breadcrumb item is empty', () => {
renderBreadCrumbs()
expect(screen.queryByText('Home')).not.toBeInTheDocument()
})

test('renders breadcrumb with multiple segments', () => {
;(usePathname as jest.Mock).mockReturnValue('/dashboard/users/profile')

render(<BreadCrumbs />)

renderBreadCrumbs(sampleItems)
expect(screen.getByText('Home')).toBeInTheDocument()
expect(screen.getByText('Dashboard')).toBeInTheDocument()
expect(screen.getByText('Users')).toBeInTheDocument()
expect(screen.getByText('Profile')).toBeInTheDocument()
})

test('disables the last segment (non-clickable)', () => {
;(usePathname as jest.Mock).mockReturnValue('/settings/account')

render(<BreadCrumbs />)

const items = [
{ title: 'Settings', path: '/settings' },
{ title: 'Account', path: '/settings/account' },
]
renderBreadCrumbs(items)
const lastSegment = screen.getByText('Account')
expect(lastSegment).toBeInTheDocument()
expect(lastSegment).not.toHaveAttribute('href')
expect(lastSegment.closest('a')).toBeNull()
})

test('links have correct href attributes', () => {
;(usePathname as jest.Mock).mockReturnValue('/dashboard/users/profile')

render(<BreadCrumbs />)

const homeLink = screen.getByText('Home').closest('a')
const dashboardLink = screen.getByText('Dashboard').closest('a')
const usersLink = screen.getByText('Users').closest('a')

expect(homeLink).toHaveAttribute('href', '/')
expect(dashboardLink).toHaveAttribute('href', '/dashboard')
expect(usersLink).toHaveAttribute('href', '/dashboard/users')
test('links have correct path attributes', () => {
renderBreadCrumbs(sampleItems)
expect(screen.getByText('Home').closest('a')).toHaveAttribute('href', '/')
expect(screen.getByText('Dashboard').closest('a')).toHaveAttribute('href', '/dashboard')
expect(screen.getByText('Users').closest('a')).toHaveAttribute('href', '/dashboard/users')
})

test('links have hover styles', () => {
;(usePathname as jest.Mock).mockReturnValue('/dashboard/users')

render(<BreadCrumbs />)

const homeLink = screen.getByText('Home').closest('a')
const dashboardLink = screen.getByText('Dashboard').closest('a')

expect(homeLink).toHaveClass('hover:text-blue-700', 'hover:underline')
expect(dashboardLink).toHaveClass('hover:text-blue-700', 'hover:underline')
const items = [
{ title: 'Dashboard', path: '/dashboard' },
{ title: 'Users', path: '/dashboard/users' },
]
renderBreadCrumbs(items)
expect(screen.getByText('Home').closest('a')).toHaveClass(
'hover:text-blue-700',
'hover:underline'
)
expect(screen.getByText('Dashboard').closest('a')).toHaveClass(
'hover:text-blue-700',
'hover:underline'
)
})
})
22 changes: 3 additions & 19 deletions frontend/__tests__/unit/pages/About.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useQuery } from '@apollo/client'
import { addToast } from '@heroui/toast'
import { fireEvent, screen, waitFor, within } from '@testing-library/react'
import { assertContributorToggle } from '@testUtils/sharedAssertions'
import { mockAboutData } from '@unit/data/mockAboutData'
import { useRouter } from 'next/navigation'
import { act } from 'react'
Expand Down Expand Up @@ -207,29 +208,12 @@ describe('About Component', () => {
})
})

// eslint-disable-next-line jest/expect-expect
test('toggles contributors list when show more/less is clicked', async () => {
await act(async () => {
render(<About />)
})
await waitFor(() => {
expect(screen.getByText('Contributor 6')).toBeInTheDocument()
expect(screen.queryByText('Contributor 10')).not.toBeInTheDocument()
})

const showMoreButton = screen.getByRole('button', { name: /Show more/i })
fireEvent.click(showMoreButton)

await waitFor(() => {
expect(screen.getByText('Contributor 7')).toBeInTheDocument()
expect(screen.getByText('Contributor 8')).toBeInTheDocument()
})

const showLessButton = screen.getByRole('button', { name: /Show less/i })
fireEvent.click(showLessButton)

await waitFor(() => {
expect(screen.queryByText('Contributor 10')).not.toBeInTheDocument()
})
await assertContributorToggle('Contributor 6', ['Contributor 7', 'Contributor 8'])
})

test('renders technologies section correctly', async () => {
Expand Down
16 changes: 10 additions & 6 deletions frontend/__tests__/unit/pages/CommitteeDetails.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQuery } from '@apollo/client'
import { screen, waitFor } from '@testing-library/react'
import { assertHeadingsAndTexts } from '@testUtils/sharedAssertions'
import { mockCommitteeDetailsData } from '@unit/data/mockCommitteeDetailsData'
import { render } from 'wrappers/testUtil'
import CommitteeDetailsPage from 'app/committees/[committeeKey]/page'
Expand Down Expand Up @@ -48,15 +49,18 @@ describe('CommitteeDetailsPage Component', () => {
})
})

// eslint-disable-next-line jest/expect-expect
test('renders committee data correctly', async () => {
render(<CommitteeDetailsPage />)
await waitFor(() => {
expect(screen.getByText('Test Committee')).toBeInTheDocument()
await assertHeadingsAndTexts({
headingText: 'Test Committee',
texts: [
'This is a test committee summary.',
'Leader 1',
'Leader 2',
'https://owasp.org/test-committee',
],
})
expect(screen.getByText('This is a test committee summary.')).toBeInTheDocument()
expect(screen.getByText('Leader 1')).toBeInTheDocument()
expect(screen.getByText('Leader 2')).toBeInTheDocument()
expect(screen.getByText('https://owasp.org/test-committee')).toBeInTheDocument()
})

test('displays "Committee not found" when there is no committee', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ describe('OrganizationDetailsPage', () => {
render(<OrganizationDetailsPage />)

await waitFor(() => {
expect(screen.getByText('Test Organization')).toBeInTheDocument()
const title = screen.getByRole('heading', { name: 'Test Organization' })
expect(title).toBeInTheDocument()
})

expect(screen.getByText('@test-org')).toBeInTheDocument()
Expand Down
37 changes: 11 additions & 26 deletions frontend/__tests__/unit/pages/ProjectDetails.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useQuery } from '@apollo/client'
import { addToast } from '@heroui/toast'
import { act, fireEvent, screen, waitFor, within } from '@testing-library/react'
import { act, screen, waitFor, within } from '@testing-library/react'
import { assertContributorToggle, assertRepoDetails } from '@testUtils/sharedAssertions'
import { mockProjectDetailsData } from '@unit/data/mockProjectDetailsData'
import { render } from 'wrappers/testUtil'
import ProjectDetailsPage from 'app/projects/[projectKey]/page'
Expand Down Expand Up @@ -68,6 +69,7 @@ describe('ProjectDetailsPage', () => {
})
})

// eslint-disable-next-line jest/expect-expect
test('renders project details when data is available', async () => {
;(useQuery as jest.Mock).mockReturnValue({
data: mockProjectDetailsData,
Expand All @@ -76,13 +78,13 @@ describe('ProjectDetailsPage', () => {

render(<ProjectDetailsPage />)

await waitFor(() => {
expect(screen.getByText('Test Project')).toBeInTheDocument()
expect(screen.getByText('Lab')).toBeInTheDocument()
await assertRepoDetails({
heading: 'Test Project',
license: 'Lab',
stars: '2.2K Stars',
forks: '10 Forks',
issues: '10 Issues',
})
expect(screen.getByText('2.2K Stars')).toBeInTheDocument()
expect(screen.getByText('10 Forks')).toBeInTheDocument()
expect(screen.getByText('10 Issues')).toBeInTheDocument()
})

test('renders error message when GraphQL request fails', async () => {
Expand All @@ -105,27 +107,10 @@ describe('ProjectDetailsPage', () => {
})
})

// eslint-disable-next-line jest/expect-expect
test('toggles contributors list when show more/less is clicked', async () => {
render(<ProjectDetailsPage />)
await waitFor(() => {
expect(screen.getByText('Contributor 9')).toBeInTheDocument()
expect(screen.queryByText('Contributor 10')).not.toBeInTheDocument()
})

const showMoreButton = screen.getByRole('button', { name: /Show more/i })
fireEvent.click(showMoreButton)

await waitFor(() => {
expect(screen.getByText('Contributor 7')).toBeInTheDocument()
expect(screen.getByText('Contributor 8')).toBeInTheDocument()
})

const showLessButton = screen.getByRole('button', { name: /Show less/i })
fireEvent.click(showLessButton)

await waitFor(() => {
expect(screen.queryByText('Contributor 10')).not.toBeInTheDocument()
})
await assertContributorToggle('Contributor 9', ['Contributor 7', 'Contributor 8'])
})

test('navigates to user page when contributor is clicked', async () => {
Expand Down
43 changes: 14 additions & 29 deletions frontend/__tests__/unit/pages/RepositoryDetails.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useQuery } from '@apollo/client'
import { addToast } from '@heroui/toast'
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
import { act, screen, waitFor } from '@testing-library/react'
import { assertContributorToggle, assertRepoDetails } from '@testUtils/sharedAssertions'
import { mockRepositoryData } from '@unit/data/mockRepositoryData'
import { render } from 'wrappers/testUtil'
import RepositoryDetailsPage from 'app/organizations/[organizationKey]/repositories/[repositoryKey]/page'
Expand Down Expand Up @@ -59,6 +60,7 @@ describe('RepositoryDetailsPage', () => {
})
})

// eslint-disable-next-line jest/expect-expect
test('renders repository details when data is available', async () => {
;(useQuery as jest.Mock).mockReturnValue({
data: mockRepositoryData,
Expand All @@ -67,15 +69,15 @@ describe('RepositoryDetailsPage', () => {

render(<RepositoryDetailsPage />)

await waitFor(() => {
expect(screen.getByText('Test Repo')).toBeInTheDocument()
expect(screen.getByText('MIT')).toBeInTheDocument()
})
expect(screen.getByText('50K Stars')).toBeInTheDocument()
expect(screen.getByText('3K Forks')).toBeInTheDocument()
expect(screen.getByText('10 Commits')).toBeInTheDocument()
expect(screen.getByText('5 Contributors')).toBeInTheDocument()
expect(screen.getByText('2 Issues')).toBeInTheDocument()
await assertRepoDetails({
heading: 'Test Repo',
license: 'MIT',
stars: '50K Stars',
forks: '3K Forks',
commits: '10 Commits',
contributors: '5 Contributors',
issues: '2 Issues',
})
})

test('renders error message when GraphQL request fails', async () => {
Expand All @@ -98,27 +100,10 @@ describe('RepositoryDetailsPage', () => {
})
})

// eslint-disable-next-line jest/expect-expect
test('toggles contributors list when show more/less is clicked', async () => {
render(<RepositoryDetailsPage />)
await waitFor(() => {
expect(screen.getByText('Contributor 9')).toBeInTheDocument()
expect(screen.queryByText('Contributor 10')).not.toBeInTheDocument()
})

const showMoreButton = screen.getByRole('button', { name: /Show more/i })
fireEvent.click(showMoreButton)

await waitFor(() => {
expect(screen.getByText('Contributor 7')).toBeInTheDocument()
expect(screen.getByText('Contributor 8')).toBeInTheDocument()
})

const showLessButton = screen.getByRole('button', { name: /Show less/i })
fireEvent.click(showLessButton)

await waitFor(() => {
expect(screen.queryByText('Contributor 10')).not.toBeInTheDocument()
})
await assertContributorToggle('Contributor 9', ['Contributor 7', 'Contributor 8'])
})

test('navigates to user page when contributor is clicked', async () => {
Expand Down
Loading