// 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, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom/vitest'; import ComputedPairsTable, { type ComputedPairEntry } from './ComputedPairsTable'; describe('ComputedPairsTable', () => { const basePair: ComputedPairEntry = { id: 'act1+act2', action1: 'act1', action2: 'act2', betas: [1.0, 0.9], estimated_max_rho: 0.75, estimated_max_rho_line: 'L3', is_suspect: false, isSimulated: false, simulated_max_rho: null, simulated_max_rho_line: null, simData: null, }; const defaultProps = { computedPairsList: [basePair], monitoringFactor: 0.95, simulating: false, onSimulate: vi.fn(), }; it('renders table headers', () => { render(); expect(screen.getByText('Action 1')).toBeInTheDocument(); expect(screen.getByText('Action 2')).toBeInTheDocument(); expect(screen.getByText('Betas')).toBeInTheDocument(); expect(screen.getByText('Max Loading (Est.)')).toBeInTheDocument(); }); it('renders a pair row with action names and estimated max rho', () => { render(); expect(screen.getByText('act1')).toBeInTheDocument(); expect(screen.getByText('act2')).toBeInTheDocument(); expect(screen.getByText('75.0%')).toBeInTheDocument(); }); it('renders betas as formatted values', () => { render(); expect(screen.getByText('1.00, 0.90')).toBeInTheDocument(); }); it('shows "Not simulated" when pair is not simulated', () => { render(); expect(screen.getByText('Not simulated')).toBeInTheDocument(); }); it('shows Simulate button for unsimulated pairs', () => { render(); expect(screen.getByText('Simulate')).toBeInTheDocument(); }); it('calls onSimulate when Simulate button is clicked', () => { const onSimulate = vi.fn(); render(); fireEvent.click(screen.getByText('Simulate')); expect(onSimulate).toHaveBeenCalledWith('act1+act2'); }); it('shows Re-Simulate button for already simulated pairs', () => { const simulatedPair: ComputedPairEntry = { ...basePair, isSimulated: true, simulated_max_rho: 0.72, simulated_max_rho_line: 'L3', simData: { max_rho: 0.72, max_rho_line: 'L3', is_rho_reduction: true }, }; render(); expect(screen.getByText('Re-Simulate')).toBeInTheDocument(); expect(screen.getByText('72.0%')).toBeInTheDocument(); }); it('shows empty state when no pairs exist', () => { render(); expect(screen.getByText(/No computed combinations found/)).toBeInTheDocument(); expect(screen.getByText(/Explore Pairs/)).toBeInTheDocument(); }); it('colors estimated rho green when below monitoring factor', () => { const greenPair: ComputedPairEntry = { ...basePair, estimated_max_rho: 0.80 }; render(); const badge = screen.getByText('80.0%'); expect(badge).toBeInTheDocument(); }); it('colors estimated rho red when above monitoring factor', () => { const redPair: ComputedPairEntry = { ...basePair, estimated_max_rho: 1.05 }; render(); const badge = screen.getByText('105.0%'); expect(badge).toBeInTheDocument(); }); it('shows suspect warning for islanded estimation', () => { const suspectPair: ComputedPairEntry = { ...basePair, is_suspect: true }; render(); expect(screen.getByTitle('Estimation suspect due to islanding')).toBeInTheDocument(); }); it('disables Simulate button when simulating', () => { render(); const button = screen.getByText('⌛'); expect(button).toBeDisabled(); }); it('shows "—" for pair with null estimated_max_rho', () => { const noPair: ComputedPairEntry = { ...basePair, estimated_max_rho: null }; render(); expect(screen.getByText('—')).toBeInTheDocument(); }); it('shows a "target: X% on LINE" subtitle when the target overload differs from the estimated max line', () => { const focusedPair: ComputedPairEntry = { ...basePair, estimated_max_rho: 0.82, estimated_max_rho_line: 'LOUHAL31PYMON', target_max_rho: 0.20, target_max_rho_line: 'BEON L31CPVAN', }; render(); expect(screen.getByText(/target:.*20\.0%.*BEON L31CPVAN/)).toBeInTheDocument(); }); it('does not render target subtitle when target line equals estimated line', () => { const matchingPair: ComputedPairEntry = { ...basePair, estimated_max_rho: 0.82, estimated_max_rho_line: 'L3', target_max_rho: 0.82, target_max_rho_line: 'L3', }; render(); expect(screen.queryByText(/target:/)).not.toBeInTheDocument(); }); it('shows islanding icon for simulated islanded pair', () => { const islandedPair: ComputedPairEntry = { ...basePair, isSimulated: true, simulated_max_rho: 0.70, simulated_max_rho_line: 'L1', simData: { max_rho: 0.70, max_rho_line: 'L1', is_rho_reduction: true, is_islanded: true }, }; render(); expect(screen.getByTitle('Islanding detected')).toBeInTheDocument(); }); });