Skip to content

Commit 3f86c94

Browse files
Merge branch 'main' into feature/multi-column-sorting-clean
2 parents 78511e4 + 87af04f commit 3f86c94

31 files changed

+183
-183
lines changed

frontend/__tests__/unit/components/AnchorTitle.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,13 @@ describe('AnchorTitle Component', () => {
139139

140140
const titleRegex = /^#[a-z0-9-]+$/
141141

142-
titles.forEach((title) => {
142+
for (const title of titles) {
143143
const { unmount } = render(<AnchorTitle title={title} />)
144144
const link = screen.getByRole('link')
145145
const href = link.getAttribute('href')
146146
expect(href).toMatch(titleRegex)
147147
unmount()
148-
})
148+
}
149149
})
150150
})
151151

frontend/__tests__/unit/components/Badges.test.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,15 @@ describe('Badges Component', () => {
100100
{ cssClass: 'bug_slash', expectedIcon: 'bug' }, // Backend snake_case input
101101
]
102102

103-
backendIcons.forEach(({ cssClass, expectedIcon }) => {
104-
it(`renders ${cssClass} icon correctly (transforms snake_case to camelCase)`, () => {
105-
render(<Badges name={`${cssClass} Badge`} cssClass={cssClass} />)
103+
for (const backendIcon of backendIcons) {
104+
it(`renders ${backendIcon.cssClass} icon correctly (transforms snake_case to camelCase)`, () => {
105+
render(<Badges name={`${backendIcon.cssClass} Badge`} cssClass={backendIcon.cssClass} />)
106106

107107
const icon = screen.getByTestId('badge-icon')
108108
expect(icon).toBeInTheDocument()
109-
expect(icon).toHaveAttribute('data-icon', expectedIcon)
109+
expect(icon).toHaveAttribute('data-icon', backendIcon.expectedIcon)
110110
})
111-
})
111+
}
112112

113113
it('handles camelCase input directly', () => {
114114
render(<Badges name="Bug Slash Badge" cssClass="bugSlash" />)

frontend/__tests__/unit/components/BarChart.test.tsx

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -234,32 +234,16 @@ describe('<BarChart />', () => {
234234
expect(series[0].name).toBe('Actual')
235235
expect(series[0].data).toHaveLength(3)
236236

237-
series[0].data.forEach(
238-
(
239-
dataPoint: {
240-
x: string
241-
y: number
242-
goals: Array<{
243-
name: string
244-
value: number
245-
strokeWidth: number
246-
strokeHeight: number
247-
strokeLineCap: string
248-
strokeColor: string
249-
}>
250-
},
251-
index: number
252-
) => {
253-
expect(dataPoint.x).toBe(mockProps.labels[index])
254-
expect(dataPoint.y).toBe(mockProps.days[index])
255-
expect(dataPoint.goals).toHaveLength(1)
256-
expect(dataPoint.goals[0].name).toBe('Requirement')
257-
expect(dataPoint.goals[0].value).toBe(mockProps.requirements[index])
258-
expect(dataPoint.goals[0].strokeWidth).toBe(5)
259-
expect(dataPoint.goals[0].strokeHeight).toBe(15)
260-
expect(dataPoint.goals[0].strokeLineCap).toBe('round')
261-
}
262-
)
237+
for (const [index, dataPoint] of series[0].data.entries()) {
238+
expect(dataPoint.x).toBe(mockProps.labels[index])
239+
expect(dataPoint.y).toBe(mockProps.days[index])
240+
expect(dataPoint.goals).toHaveLength(1)
241+
expect(dataPoint.goals[0].name).toBe('Requirement')
242+
expect(dataPoint.goals[0].value).toBe(mockProps.requirements[index])
243+
expect(dataPoint.goals[0].strokeWidth).toBe(5)
244+
expect(dataPoint.goals[0].strokeHeight).toBe(15)
245+
expect(dataPoint.goals[0].strokeLineCap).toBe('round')
246+
}
263247
})
264248

265249
it('configures colors array correctly', () => {

frontend/__tests__/unit/components/CardDetailsPage.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -746,10 +746,10 @@ describe('CardDetailsPage', () => {
746746
render(<CardDetailsPage {...defaultProps} type="chapter" socialLinks={socialLinks} />)
747747

748748
const links = screen.getAllByRole('link')
749-
links.forEach((link) => {
749+
for (const link of links) {
750750
expect(link).toHaveAttribute('target', '_blank')
751751
expect(link).toHaveAttribute('rel', 'noopener noreferrer')
752-
})
752+
}
753753
})
754754
})
755755

@@ -1030,10 +1030,10 @@ describe('CardDetailsPage', () => {
10301030
const links = screen.getAllByRole('link')
10311031
const externalLinks = links.filter((link) => link.getAttribute('href')?.startsWith('http'))
10321032

1033-
externalLinks.forEach((link) => {
1033+
for (const link of externalLinks) {
10341034
expect(link).toHaveAttribute('target', '_blank')
10351035
expect(link).toHaveAttribute('rel', 'noopener noreferrer')
1036-
})
1036+
}
10371037
})
10381038

10391039
it('renders with proper document structure', () => {

frontend/__tests__/unit/components/DisplayIcon.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,12 +259,12 @@ describe('DisplayIcon', () => {
259259
{ item: 'contributionCount', value: 30 },
260260
]
261261

262-
testCases.forEach(({ item, value }) => {
263-
const iconsWithItem: Icon = { [item]: value }
264-
const { container } = render(<DisplayIcon item={item} icons={iconsWithItem} />)
262+
for (const testCase of testCases) {
263+
const iconsWithItem: Icon = { [testCase.item]: testCase.value }
264+
const { container } = render(<DisplayIcon item={testCase.item} icons={iconsWithItem} />)
265265
const containerDiv = container.querySelector('div[class*="flip-container"]')
266266
expect(containerDiv).toBeInTheDocument()
267-
})
267+
}
268268
})
269269

270270
it('applies correct icon classes', () => {

frontend/__tests__/unit/components/DonutBarChart.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ describe('DonutBarChart Component Test Suite', () => {
303303
it('handles different icon types', () => {
304304
const iconTypes = ['chart-pie', 'chart-bar', 'analytics', 'dashboard', 'heart']
305305

306-
iconTypes.forEach((iconType) => {
306+
for (const iconType of iconTypes) {
307307
const { unmount } = render(
308308
<DonutBarChart
309309
icon={iconProp(iconType)}
@@ -314,7 +314,7 @@ describe('DonutBarChart Component Test Suite', () => {
314314

315315
expect(screen.getByTestId('secondary-card')).toHaveAttribute('data-icon', iconType)
316316
unmount()
317-
})
317+
}
318318
})
319319

320320
it('handles various title formats', () => {
@@ -326,14 +326,14 @@ describe('DonutBarChart Component Test Suite', () => {
326326
'',
327327
]
328328

329-
titles.forEach((title) => {
329+
for (const title of titles) {
330330
const { unmount } = render(
331331
<DonutBarChart icon="chart-pie" title={title} series={[33, 33, 34]} />
332332
)
333333

334334
expect(screen.getByTestId('anchor-title')).toHaveTextContent(title)
335335
unmount()
336-
})
336+
}
337337
})
338338

339339
it('handles large series values', () => {

frontend/__tests__/unit/components/Footer.test.tsx

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ describe('Footer', () => {
130130
test('renders all footer sections with correct titles', () => {
131131
renderFooter()
132132

133-
mockFooterSections.forEach((section) => {
133+
for (const section of mockFooterSections) {
134134
expect(screen.getByText(section.title)).toBeInTheDocument()
135-
})
135+
}
136136
})
137137

138138
test('renders all section links correctly', () => {
@@ -150,22 +150,22 @@ describe('Footer', () => {
150150
}
151151
}
152152
}
153-
regularLinks.forEach((link) => {
153+
for (const link of regularLinks) {
154154
const linkElement = screen.getByRole('link', { name: link.text })
155155
expect(linkElement).toBeInTheDocument()
156156
expect(linkElement).toHaveAttribute('href', link.href)
157157
expect(linkElement).toHaveAttribute('target', '_blank')
158-
})
158+
}
159159

160-
spanElements.forEach((link) => {
160+
for (const link of spanElements) {
161161
expect(screen.getByText(link.text)).toBeInTheDocument()
162-
})
162+
}
163163
})
164164

165165
test('renders social media icons with correct attributes', () => {
166166
renderFooter()
167167

168-
mockFooterIcons.forEach((icon) => {
168+
for (const icon of mockFooterIcons) {
169169
const link = screen.getByLabelText(`OWASP Nest ${icon.label}`)
170170
expect(link).toBeInTheDocument()
171171
expect(link).toHaveAttribute('href', icon.href)
@@ -174,7 +174,7 @@ describe('Footer', () => {
174174

175175
const iconElement = link.querySelector('[data-testid="font-awesome-icon"]')
176176
expect(iconElement).toBeInTheDocument()
177-
})
177+
}
178178
})
179179

180180
test('renders copyright information with current year', () => {
@@ -271,40 +271,40 @@ describe('Footer', () => {
271271
renderFooter()
272272

273273
const buttons = screen.getAllByRole('button')
274-
buttons.forEach((button, index) => {
274+
275+
for (const [index, button] of buttons.entries()) {
275276
const sectionTitle = mockFooterSections[index].title
276277
expect(button).toHaveAttribute('aria-controls', `footer-section-${sectionTitle}`)
277278
expect(button).toHaveAttribute('aria-expanded')
278-
})
279+
}
279280
})
280281

281282
test('has correct section IDs matching aria-controls', () => {
282283
renderFooter()
283284

284-
mockFooterSections.forEach((section) => {
285+
for (const section of mockFooterSections) {
285286
const sectionElement = document.getElementById(`footer-section-${section.title}`)
286287
expect(sectionElement).toBeInTheDocument()
287-
})
288+
}
288289
})
289290

290291
test('has proper semantic structure', () => {
291292
renderFooter()
292293

293294
expect(screen.getByRole('contentinfo')).toBeInTheDocument()
294295

295-
mockFooterSections.forEach((section) => {
296+
for (const section of mockFooterSections) {
296297
const heading = screen.getByRole('heading', { name: section.title, level: 3 })
297298
expect(heading).toBeInTheDocument()
298-
})
299+
}
299300
})
300301

301302
test('has proper aria-labels for social media links', () => {
302303
renderFooter()
303-
304-
mockFooterIcons.forEach((icon) => {
304+
for (const icon of mockFooterIcons) {
305305
const link = screen.getByLabelText(`OWASP Nest ${icon.label}`)
306306
expect(link).toBeInTheDocument()
307-
})
307+
}
308308
})
309309
})
310310

@@ -335,10 +335,10 @@ describe('Footer', () => {
335335
renderFooter()
336336

337337
const buttons = screen.getAllByRole('button')
338-
buttons.forEach((button) => {
338+
for (const button of buttons) {
339339
expect(button).toHaveClass('flex', 'w-full', 'items-center', 'justify-between')
340340
expect(button).toHaveAttribute('data-disable-animation', 'true')
341-
})
341+
}
342342
})
343343

344344
test('applies correct section content classes for collapsed/expanded states', () => {
@@ -381,9 +381,9 @@ describe('Footer', () => {
381381

382382
const buttons = screen.getAllByRole('button')
383383
expect(buttons.length).toBeGreaterThan(0)
384-
buttons.forEach((button) => {
384+
for (const button of buttons) {
385385
expect(button).toHaveAttribute('data-disable-animation', 'true')
386-
})
386+
}
387387
})
388388
})
389389
})

frontend/__tests__/unit/components/LeadersList.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,9 @@ describe('LeadersList Component', () => {
268268

269269
// Check that leader links are inside TruncatedText
270270
const links = screen.getAllByTestId('leader-link')
271-
links.forEach((link) => {
271+
for (const link of links) {
272272
expect(truncatedText).toContainElement(link)
273-
})
273+
}
274274
})
275275

276276
it('generates unique keys for each leader span', () => {

frontend/__tests__/unit/components/LogoCarousel.test.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -406,20 +406,20 @@ describe('MovingLogos (LogoCarousel)', () => {
406406
render(<MovingLogos sponsors={mockSponsors} />)
407407

408408
const links = screen.getAllByTestId('sponsor-link')
409-
links.forEach((link) => {
409+
for (const link of links) {
410410
expect(link).toHaveAttribute('target', '_blank')
411411
expect(link).toHaveAttribute('rel', 'noopener noreferrer')
412-
})
412+
}
413413
})
414414

415415
it('maintains semantic structure for screen readers', () => {
416416
render(<MovingLogos sponsors={mockSponsors} />)
417417

418418
const sponsorLinks = screen.getAllByTestId('sponsor-link')
419-
sponsorLinks.forEach((link) => {
419+
for (const link of sponsorLinks) {
420420
expect(link).toBeInTheDocument()
421421
expect(link.tagName).toBe('A')
422-
})
422+
}
423423
})
424424

425425
it('provides descriptive text for external links', () => {
@@ -454,10 +454,10 @@ describe('MovingLogos (LogoCarousel)', () => {
454454
render(<MovingLogos sponsors={mockSponsors} />)
455455

456456
const images = screen.getAllByTestId('sponsor-image')
457-
images.forEach((image) => {
457+
for (const image of images) {
458458
expect(image).toHaveAttribute('style', 'object-fit: contain;')
459459
expect(image).toHaveAttribute('data-fill', 'true')
460-
})
460+
}
461461
})
462462

463463
it('maintains proper DOM hierarchy', () => {
@@ -514,9 +514,9 @@ describe('MovingLogos (LogoCarousel)', () => {
514514
const sponsorContainers = document.querySelectorAll('[class*="min-w-[220px]"]')
515515
expect(sponsorContainers).toHaveLength(6)
516516

517-
sponsorContainers.forEach((container) => {
517+
for (const container of sponsorContainers) {
518518
expect(container).toHaveClass('min-w-[220px]')
519-
})
519+
}
520520
})
521521
})
522522
})

frontend/__tests__/unit/components/MetricsCard.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ describe('MetricsCard component', () => {
6565
[30, 'text-red-900'],
6666
]
6767

68-
cases.forEach(([score, expectedClass]) => {
68+
for (const [score, expectedClass] of cases) {
6969
const metric = makeMetric({ score })
7070
render(<MetricsCard metric={metric} />)
7171
const scoreEl = screen.getByText(score.toString()).closest('div')
7272
expect(scoreEl).toHaveClass(expectedClass)
73-
})
73+
}
7474
})
7575

7676
it('updates displayed values and link when metric props change via rerender', () => {

0 commit comments

Comments
 (0)