diff --git a/src/web/components/section/Section.tsx b/src/web/components/section/Section.tsx index 5a4baad749..cbadddb522 100644 --- a/src/web/components/section/Section.tsx +++ b/src/web/components/section/Section.tsx @@ -13,7 +13,7 @@ import { } from 'web/components/folding/Folding'; import FoldStateIcon from 'web/components/icon/FoldStateIcon'; import Layout from 'web/components/layout/Layout'; -import SectionHeader from 'web/components/section/Header'; +import SectionHeader from 'web/components/section/SectionHeader'; interface SectionProps extends FoldToggleComponentProps { children?: React.ReactNode; diff --git a/src/web/components/section/Header.tsx b/src/web/components/section/SectionHeader.tsx similarity index 100% rename from src/web/components/section/Header.tsx rename to src/web/components/section/SectionHeader.tsx diff --git a/src/web/components/section/__tests__/Section.test.tsx b/src/web/components/section/__tests__/Section.test.tsx new file mode 100644 index 0000000000..b89fda31bc --- /dev/null +++ b/src/web/components/section/__tests__/Section.test.tsx @@ -0,0 +1,82 @@ +/* SPDX-FileCopyrightText: 2026 Greenbone AG + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import {describe, expect, test} from '@gsa/testing'; +import {fireEvent, render, screen} from 'web/testing'; +import {FoldState} from 'web/components/folding/Folding'; +import Section from 'web/components/section/Section'; + +describe('Section tests', () => { + test('should render children without a header or folding controls', () => { + render( +
+ Section content +
, + ); + + const section = screen.getByTestId('section'); + + expect(section).toHaveTextContent('Section content'); + expect(section.querySelector('.section-header')).not.toBeNull(); + expect(section.querySelector('.section-fold-icon')).toBeNull(); + }); + + test('should render the default header with title, image, and extra content', () => { + render( +
Extra content} + img={Section image} + title="Section title" + > + Section content +
, + ); + + const section = screen.getByTestId('section'); + + expect(section.querySelector('.section-header')).not.toBeNull(); + expect(section).toHaveTextContent('Section title'); + expect(section).toHaveTextContent('Section image'); + expect(section).toHaveTextContent('Extra content'); + expect(section).toHaveTextContent('Section content'); + expect(screen.getByTestId('fold-state-icon-fold')).toBeInTheDocument(); + }); + + test('should use a supplied header instead of creating the default header', () => { + render( +
Custom header}> + Section content +
, + ); + + const section = screen.getByTestId('section'); + + expect(section).toHaveTextContent('Custom header'); + expect(section).toHaveTextContent('Section content'); + expect(section.querySelector('.section-header')).toBeNull(); + }); + + test('should start folded when requested and toggle from the fold icon', () => { + render( +
+ Section content +
, + ); + + expect(screen.getByTestId('fold-state-icon-unfold')).toBeInTheDocument(); + expect(screen.getByText('Section content')).not.toBeVisible(); + + fireEvent.click(screen.getByTestId('fold-state-icon-unfold')); + + expect(screen.getByTestId('fold-state-icon-fold')).toBeInTheDocument(); + expect(screen.getByText('Section content')).toBeVisible(); + }); +}); diff --git a/src/web/components/section/__tests__/SectionHeader.test.tsx b/src/web/components/section/__tests__/SectionHeader.test.tsx new file mode 100644 index 0000000000..0cf0162f41 --- /dev/null +++ b/src/web/components/section/__tests__/SectionHeader.test.tsx @@ -0,0 +1,41 @@ +/* SPDX-FileCopyrightText: 2026 Greenbone AG + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import {describe, expect, test} from '@gsa/testing'; +import {render, screen} from 'web/testing'; +import SectionHeader from 'web/components/section/SectionHeader'; + +describe('SectionHeader tests', () => { + test('should render the section header layout', () => { + const {element} = render(); + + expect(element).toHaveClass('section-header'); + expect(element.tagName).toBe('DIV'); + expect(element.querySelector('h2')).toBeInTheDocument(); + }); + + test('should render the title, image, and children', () => { + render( + Header image} + title="Section title" + > + Header actions + , + ); + + expect(screen.getByText('Section title')).toBeInTheDocument(); + expect(screen.getByTestId('header-image')).toBeInTheDocument(); + expect(screen.getByText('Header actions')).toBeInTheDocument(); + }); + + test('should omit optional title and image when they are not provided', () => { + render(Header actions); + + expect(screen.getByText('Header actions')).toBeInTheDocument(); + expect(screen.queryByTestId('header-image')).not.toBeInTheDocument(); + expect(screen.getByRole('heading')).toBeEmptyDOMElement(); + }); +}); diff --git a/src/web/pages/reports/AuditReportDetailsContent.tsx b/src/web/pages/reports/AuditReportDetailsContent.tsx index ec533f082e..7de1efd9ca 100644 --- a/src/web/pages/reports/AuditReportDetailsContent.tsx +++ b/src/web/pages/reports/AuditReportDetailsContent.tsx @@ -23,8 +23,8 @@ import Divider from 'web/components/layout/Divider'; import Layout from 'web/components/layout/Layout'; import Loading from 'web/components/loading/Loading'; import Powerfilter from 'web/components/powerfilter/PowerFilter'; -import SectionHeader from 'web/components/section/Header'; import Section from 'web/components/section/Section'; +import SectionHeader from 'web/components/section/SectionHeader'; import Tab from 'web/components/tab/Tab'; import TabLayout from 'web/components/tab/TabLayout'; import TabList from 'web/components/tab/TabList'; diff --git a/src/web/pages/reports/DeltaReportDetailsContent.tsx b/src/web/pages/reports/DeltaReportDetailsContent.tsx index 853338f223..6ae0edc9be 100644 --- a/src/web/pages/reports/DeltaReportDetailsContent.tsx +++ b/src/web/pages/reports/DeltaReportDetailsContent.tsx @@ -25,8 +25,8 @@ import Divider from 'web/components/layout/Divider'; import Layout from 'web/components/layout/Layout'; import Loading from 'web/components/loading/Loading'; import Powerfilter from 'web/components/powerfilter/PowerFilter'; -import SectionHeader from 'web/components/section/Header'; import Section from 'web/components/section/Section'; +import SectionHeader from 'web/components/section/SectionHeader'; import Tab from 'web/components/tab/Tab'; import TabLayout from 'web/components/tab/TabLayout'; import TabList from 'web/components/tab/TabList'; diff --git a/src/web/pages/reports/ReportDetailsContent.tsx b/src/web/pages/reports/ReportDetailsContent.tsx index cb3f65eee1..5bfe13e5c8 100644 --- a/src/web/pages/reports/ReportDetailsContent.tsx +++ b/src/web/pages/reports/ReportDetailsContent.tsx @@ -21,8 +21,8 @@ import { NO_RELOAD, USE_DEFAULT_RELOAD_INTERVAL_ACTIVE, } from 'web/components/loading/Reload'; -import SectionHeader from 'web/components/section/Header'; import Section from 'web/components/section/Section'; +import SectionHeader from 'web/components/section/SectionHeader'; import Tab from 'web/components/tab/Tab'; import TabLayout from 'web/components/tab/TabLayout'; import TabList from 'web/components/tab/TabList';