Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created ChapterDetails Component #544

Merged
merged 12 commits into from
Jan 24, 2025
55 changes: 55 additions & 0 deletions frontend/__tests__/src/data/mockChapterDetailsData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
export const mockChaterDetailsData = {
name: 'OWASP Test Chapter',
suggested_location: 'Test City, Test Country',
region: 'Test Region',
is_active: true,
tags: 'test-tag',
updated_at: 1652129718,
url: 'https://owasp.org/test-chapter',
related_urls: [
'https://discord.com/test',
'https://www.instagram.com/test',
'https://www.linkedin.com/test',
'https://www.youtube.com/test',
'https://twitter.com/test',
'https://meetup.com/test',
],
summary: 'This is a test chapter summary.',
top_contributors: [
{
avatar_url: 'https://example.com/avatar1.jpg',
name: 'Contributor 1',
contributions_count: 10,
},
{
avatar_url: 'https://example.com/avatar2.jpg',
name: 'Contributor 2',
contributions_count: 8,
},
{
avatar_url: 'https://example.com/avatar3.jpg',
name: 'Contributor 3',
contributions_count: 6,
},
{
avatar_url: 'https://example.com/avatar4.jpg',
name: 'Contributor 4',
contributions_count: 4,
},
{
avatar_url: 'https://example.com/avatar5.jpg',
name: 'Contributor 5',
contributions_count: 2,
},
{
avatar_url: 'https://example.com/avatar6.jpg',
name: 'Contributor 6',
contributions_count: 1,
},
{
avatar_url: 'https://example.com/avatar7.jpg',
name: 'Contributor 7',
contributions_count: 1,
},
],
}
77 changes: 60 additions & 17 deletions frontend/__tests__/src/pages/ChapterDetails.test.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
import { screen, waitFor } from '@testing-library/react'

import { fetchAlgoliaData } from 'api/fetchAlgoliaData'
import { ChapterDetailsPage } from 'pages'
import { render } from 'wrappers/testUtil'
import { mockChaterDetailsData } from '@tests/data/mockChapterDetailsData'
jest.mock('api/fetchAlgoliaData')

import { mockChapterData } from '@tests/data/mockChapterData'

jest.mock('api/fetchAlgoliaData', () => ({
fetchAlgoliaData: jest.fn(),
}))
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: jest.fn(),
useParams: () => ({
chapterKey: 'test-chapter',
}),
}))

describe('ChapterDetailsPage Component', () => {
describe('chapterDetailsPage Component', () => {
beforeEach(() => {
;(fetchAlgoliaData as jest.Mock).mockResolvedValue({
hits: mockChapterData.chapters,
totalPages: 2,
})
;(fetchAlgoliaData as jest.Mock).mockImplementation(() =>
Promise.resolve({
hits: [mockChaterDetailsData],
})
)
})

afterEach(() => {
Expand All @@ -37,18 +36,62 @@ describe('ChapterDetailsPage Component', () => {
test('renders chapter data correctly', async () => {
render(<ChapterDetailsPage />)
await waitFor(() => {
expect(screen.getByText('Chapter 1')).toBeInTheDocument()
expect(screen.getByText('Test City, Test Country')).toBeInTheDocument()
})
expect(screen.getByText('This is a summary of Chapter 1.')).toBeInTheDocument()
const viewButton = screen.getByText('Join')
expect(viewButton).toBeInTheDocument()
expect(screen.getByText('Test Region')).toBeInTheDocument()
expect(screen.getByText('Test-tag')).toBeInTheDocument()
expect(screen.getByText('https://owasp.org/test-chapter')).toBeInTheDocument()
expect(screen.getByText('This is a test chapter summary.')).toBeInTheDocument()
})

test('displays "Chapter not found" when there are no chapters', async () => {
test('displays "No chapters found" when there are no chapters', async () => {
;(fetchAlgoliaData as jest.Mock).mockResolvedValue({ hits: [], totalPages: 0 })
render(<ChapterDetailsPage />)
await waitFor(() => {
expect(screen.getByText('Chapter not found')).toBeInTheDocument()
})
})

test('contributors visibility check', async () => {
render(<ChapterDetailsPage />)
await waitFor(() => {
expect(screen.getByText('Contributor 1')).toBeInTheDocument()
})
expect(screen.queryByText('Contributor 7')).not.toBeInTheDocument()
})

test('renders chapter URL as clickable link', async () => {
render(<ChapterDetailsPage />)

await waitFor(() => {
const link = screen.getByText('https://owasp.org/test-chapter')
expect(link.tagName).toBe('A')
expect(link).toHaveAttribute('href', 'https://owasp.org/test-chapter')
})
})

test('handles contributors with missing names gracefully', async () => {
const chapterDataWithIncompleteContributors = {
...mockChaterDetailsData,
top_contributors: [
{
name: 'user1',
avatar_url: 'https://example.com/avatar1.jpg',
contributions_count: 30,
},
],
}

;(fetchAlgoliaData as jest.Mock).mockImplementation(() =>
Promise.resolve({
hits: [chapterDataWithIncompleteContributors],
})
)

render(<ChapterDetailsPage />)

await waitFor(() => {
expect(screen.getByText('user1')).toBeInTheDocument()
})
})
})
21 changes: 20 additions & 1 deletion frontend/__tests__/src/pages/ProjectDetails.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { within } from '@testing-library/dom'
import { screen, waitFor, fireEvent } from '@testing-library/react'
import { fetchAlgoliaData } from 'api/fetchAlgoliaData'
import { useNavigate } from 'react-router-dom'
import { formatDate } from 'utils/dateFormatter'
import { render } from 'wrappers/testUtil'
import ProjectDetailsPage, { formatDate } from 'pages/ProjectDetails'
import ProjectDetailsPage from 'pages/ProjectDetails'
import { mockProjectDetailsData } from '@tests/data/mockProjectDetailsData'
jest.mock('api/fetchAlgoliaData')

Expand All @@ -27,6 +28,24 @@ describe('ProjectDetailsPage', () => {
afterEach(() => {
jest.clearAllMocks()
})
test('renders loading spinner initially', async () => {
render(<ProjectDetailsPage />)
const loadingSpinner = screen.getAllByAltText('Loading indicator')
await waitFor(() => {
expect(loadingSpinner.length).toBeGreaterThan(0)
})
})

test('renders project data correctly', async () => {
render(<ProjectDetailsPage />)
await waitFor(() => {
expect(screen.getByText('Test Project')).toBeInTheDocument()
})
expect(screen.getByText('This is a test project description')).toBeInTheDocument()
expect(screen.getByText('Tool')).toBeInTheDocument()
expect(screen.getByText('Flagship')).toBeInTheDocument()
expect(screen.getByText('OWASP')).toBeInTheDocument()
})

test('displays error when project is not found', async () => {
;(fetchAlgoliaData as jest.Mock).mockImplementationOnce(() => Promise.resolve({ hits: [] }))
Expand Down
Loading
Loading