// Copyright (c) 2025-2026, RTE (https://www.rte-france.com) // This Source Code Form is subject to the terms of the Mozilla Public License, version 2.0. // If a copy of the Mozilla Public License, version 2.0 was not distributed with this file, // you can obtain one at http://mozilla.org/MPL/2.0/. // SPDX-License-Identifier: MPL-2.0 // This file is part of Co-Study4Grid a Power Grid Study tool Assistant Interface to help solve contigencies for a grid state under study. import { describe, it, expect, vi } from 'vitest'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import NoticesPanel, { type Notice } from './NoticesPanel'; describe('NoticesPanel', () => { const baseNotices: Notice[] = [ { id: 'one', title: 'First notice', body: 'Lorem ipsum.', severity: 'info' }, { id: 'two', title: 'Second notice', body: 'Dolor sit amet.', severity: 'warning' }, ]; it('renders nothing when the notices array is empty', () => { const { container } = render(); expect(container.firstChild).toBeNull(); }); it('renders the pill with a count badge when notices are present', () => { render(); const pill = screen.getByTestId('notices-pill'); expect(pill).toBeInTheDocument(); expect(pill).toHaveTextContent('2'); // Panel is collapsed by default — list should not be visible. expect(screen.queryByTestId('notices-list')).not.toBeInTheDocument(); }); it('uses a bell glyph, NOT the ⚠️ warning sign (de-conflicted from the overloads marker)', () => { render(); const pill = screen.getByTestId('notices-pill'); expect(pill).toHaveTextContent('🔔'); expect(pill).not.toHaveTextContent('⚠️'); }); it('expands the panel and shows each notice when the pill is clicked', async () => { const user = userEvent.setup(); render(); await user.click(screen.getByTestId('notices-pill')); expect(screen.getByTestId('notices-list')).toBeInTheDocument(); expect(screen.getByTestId('notice-one')).toHaveTextContent('First notice'); expect(screen.getByTestId('notice-two')).toHaveTextContent('Second notice'); }); it('invokes onDismiss when the dismiss button is clicked', async () => { const user = userEvent.setup(); const onDismiss = vi.fn(); render( , ); await user.click(screen.getByTestId('notices-pill')); await user.click(screen.getByLabelText('Dismiss Monitoring')); expect(onDismiss).toHaveBeenCalledTimes(1); }); it('renders an in-card action button and triggers it on click', async () => { const user = userEvent.setup(); const onClick = vi.fn(); render( , ); await user.click(screen.getByTestId('notices-pill')); await user.click(screen.getByText('Open settings')); expect(onClick).toHaveBeenCalledTimes(1); }); it('renders the popover via a portal so it escapes ancestor overflow:hidden clipping', async () => { const user = userEvent.setup(); render(
, ); await user.click(screen.getByTestId('notices-pill')); const list = screen.getByTestId('notices-list'); const clippingParent = screen.getByTestId('clipping-parent'); // The portal target is document.body, so the popover must NOT // be a DOM descendant of the clipping container — that's how // it escapes the sidebar's `overflow: hidden`. expect(clippingParent.contains(list)).toBe(false); expect(document.body.contains(list)).toBe(true); expect(list).toHaveStyle({ position: 'fixed' }); }); it('wraps long unbreakable strings inside the notice card so they cannot bleed out', async () => { const user = userEvent.setup(); render( feature_actions_from_REPAS.2024.12.10_withPSTs.json, severity: 'info', }]} />, ); await user.click(screen.getByTestId('notices-pill')); const card = screen.getByTestId('notice-long-path'); // overflowWrap: anywhere + wordBreak: break-word are what allow // a long filename or path to break inside the 320 px panel // instead of pushing past the card edges. expect(card).toHaveStyle({ overflow: 'hidden' }); expect(card).toHaveStyle({ overflowWrap: 'anywhere' }); expect(card).toHaveStyle({ wordBreak: 'break-word' }); }); it('hides the panel when the underlying notice list becomes empty', async () => { const user = userEvent.setup(); const { rerender } = render(); await user.click(screen.getByTestId('notices-pill')); expect(screen.getByTestId('notices-list')).toBeInTheDocument(); rerender(); // With zero notices the pill self-hides entirely. expect(screen.queryByTestId('notices-pill')).not.toBeInTheDocument(); expect(screen.queryByTestId('notices-list')).not.toBeInTheDocument(); }); });