import { screen } from '@testing-library/react' ; import userEvent from '@testing-library/user-event' ; import { findVisSelectorTabs , mockConsoleMethod , renderApp , selectExplorerNode , } from '../test-utils' ; import { NexusVis } from '../vis-packs/nexus/visualizations' ; test ( 'visualize NXdata group with "spectrum" interpretation' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_entry/spectrum' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxSpectrum ) ; await expect ( screen . findByRole ( 'figure' , { name : 'twoD_spectrum (arb. units)' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'visualize NXdata group with "image" interpretation' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_entry/image' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxImage ) ; await expect ( screen . findByRole ( 'figure' , { name : 'Interference fringes' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'visualize NXdata group with 2D signal' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_entry/nx_process/nx_data' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxImage ) ; await expect ( screen . findByRole ( 'figure' , { name : 'NeXus 2D' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'visualize NXentry group with relative path to 2D default signal' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_entry' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxImage ) ; await expect ( screen . findByRole ( 'figure' , { name : 'NeXus 2D' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'visualize NXentry group with absolute path to 2D default signal' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_entry/nx_process/absolute_default_path' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxImage ) ; await expect ( screen . findByRole ( 'figure' , { name : 'NeXus 2D' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'visualize NXroot group with 2D default signal' , async ( ) => { await renderApp ( ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxImage ) ; await expect ( screen . findByRole ( 'figure' , { name : 'NeXus 2D' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'visualize NXdata group with 2D complex signal' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_entry/complex_image' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxImage ) ; await expect ( screen . findByRole ( 'figure' , { name : 'twoD_complex (amplitude)' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'visualize NXdata group with 1D complex signal' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_entry/complex_spectrum' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxSpectrum ) ; await expect ( screen . findByRole ( 'figure' , { name : 'twoD_complex' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'visualize NXdata group with "rgb-image" interpretation' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_entry/rgb-image' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxRGB ) ; await expect ( screen . findByRole ( 'figure' , { name : 'RGB CMY DGW' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'follow SILX styles when visualizing NXdata group' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_entry/log_spectrum' ) ; const logSelectors = await screen . findAllByRole ( 'button' , { name : 'Log' } ) ; expect ( logSelectors ) . toHaveLength ( 2 ) ; } ) ; test ( 'visualize NXentry group with implicit default child NXdata group' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_no_default' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxSpectrum ) ; await expect ( screen . findByRole ( 'figure' , { name : 'oneD' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'show error when `default` entity is not found' , async ( ) => { await renderApp ( ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; await selectExplorerNode ( 'nexus_malformed/default_not_found' ) ; await expect ( screen . findByText ( 'No entity found at /test' ) ) . resolves . toBeVisible ( ) ; expect ( errorSpy ) . toHaveBeenCalledTimes ( 2 ) ; } ) ; test ( 'show error when `signal` entity is not found' , async ( ) => { await renderApp ( ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; await selectExplorerNode ( 'nexus_malformed/signal_not_found' ) ; await expect ( screen . findByText ( 'Expected "unknown" signal entity to exist' ) ) . resolves . toBeVisible ( ) ; expect ( errorSpy ) . toHaveBeenCalledTimes ( 2 ) ; } ) ; test ( 'show error when `signal` entity is not a dataset' , async ( ) => { await renderApp ( ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; await selectExplorerNode ( 'nexus_malformed/signal_not_dataset' ) ; await expect ( screen . findByText ( 'Expected "some_group" signal to be a dataset' ) ) . resolves . toBeVisible ( ) ; expect ( errorSpy ) . toHaveBeenCalledTimes ( 2 ) ; } ) ; test ( 'show error when `signal` dataset is not array' , async ( ) => { await renderApp ( ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; await selectExplorerNode ( 'nexus_malformed/signal_not_array' ) ; await expect ( screen . findByText ( 'Expected dataset to have array shape' ) ) . resolves . toBeVisible ( ) ; expect ( errorSpy ) . toHaveBeenCalledTimes ( 2 ) ; } ) ; test ( 'show error when `signal` dataset is not numeric' , async ( ) => { await renderApp ( ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; await selectExplorerNode ( 'nexus_malformed/signal_not_numeric' ) ; await expect ( screen . findByText ( 'Expected dataset to have numeric or complex type' ) ) . resolves . toBeVisible ( ) ; expect ( errorSpy ) . toHaveBeenCalledTimes ( 2 ) ; } ) ; test ( 'show fallback message when NXdata group has no `signal` attribute' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_malformed/no_signal' ) ; await expect ( screen . findByText ( 'No visualization available for this entity.' ) ) . resolves . toBeInTheDocument ( ) ; } ) ; test ( 'visualize NXdata group with unknown interpretation' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_malformed/interpretation_unknown' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxImage ) ; await expect ( screen . findByRole ( 'figure' , { name : 'fourD' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'visualize NXdata group with "rgb-image" interpretation but incompatible signal' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_malformed/rgb-image_incompatible' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxSpectrum ) ; await expect ( screen . findByRole ( 'figure' , { name : 'oneD' } ) ) . resolves . toBeVisible ( ) ; } ) ; test ( 'ignore unknown `SILX_style` options and invalid values' , async ( ) => { await renderApp ( ) ; await selectExplorerNode ( 'nexus_malformed/silx_style_unknown' ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxSpectrum ) ; const scaleSelectors = await screen . findAllByRole ( 'button' , { name : 'Linear' , } ) ; expect ( scaleSelectors ) . toHaveLength ( 2 ) ; expect ( errorSpy ) . not . toHaveBeenCalled ( ) ; errorSpy . mockRestore ( ) ; } ) ; test ( 'warn in console when `SILX_style` attribute is not valid JSON' , async ( ) => { await renderApp ( ) ; const warningSpy = mockConsoleMethod ( 'warn' ) ; await selectExplorerNode ( 'nexus_malformed/silx_style_malformed' ) ; const tabs = await findVisSelectorTabs ( ) ; expect ( tabs ) . toHaveLength ( 1 ) ; expect ( tabs [ 0 ] ) . toHaveTextContent ( NexusVis . NxSpectrum ) ; expect ( warningSpy ) . toHaveBeenCalledWith ( "Malformed 'SILX_style' attribute: {" ) ; warningSpy . mockRestore ( ) ; } ) ; test ( 'cancel and retry slow fetch of NxSpectrum' , async ( ) => { jest . useFakeTimers ( 'modern' ) ; await renderApp ( ) ; await selectExplorerNode ( 'resilience/slow_nx_spectrum' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; userEvent . click ( await screen . findByRole ( 'button' , { name : /Cancel/ } ) ) ; await expect ( screen . findByText ( 'Request cancelled' ) ) . resolves . toBeVisible ( ) ; expect ( errorSpy ) . toHaveBeenCalledTimes ( 2 ) ; errorSpy . mockRestore ( ) ; userEvent . click ( await screen . findByRole ( 'button' , { name : /Retry/ } ) ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; jest . runAllTimers ( ) ; await expect ( screen . findByRole ( 'figure' ) ) . resolves . toBeVisible ( ) ; jest . runOnlyPendingTimers ( ) ; jest . useRealTimers ( ) ; } ) ; test ( 'cancel and retry slow fetch of NxImage' , async ( ) => { jest . useFakeTimers ( 'modern' ) ; await renderApp ( ) ; await selectExplorerNode ( 'resilience/slow_nx_image' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; userEvent . click ( await screen . findByRole ( 'button' , { name : /Cancel/ } ) ) ; await expect ( screen . findByText ( 'Request cancelled' ) ) . resolves . toBeVisible ( ) ; expect ( errorSpy ) . toHaveBeenCalledTimes ( 2 ) ; errorSpy . mockRestore ( ) ; userEvent . click ( await screen . findByRole ( 'button' , { name : /Retry/ } ) ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; jest . runAllTimers ( ) ; await expect ( screen . findByRole ( 'figure' ) ) . resolves . toBeVisible ( ) ; jest . runOnlyPendingTimers ( ) ; jest . useRealTimers ( ) ; } ) ; test ( 'retry fetching automatically when re-selecting NxSpectrum' , async ( ) => { jest . useFakeTimers ( 'modern' ) ; await renderApp ( ) ; await selectExplorerNode ( 'resilience/slow_nx_spectrum' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; userEvent . click ( await screen . findByRole ( 'button' , { name : /Cancel/ } ) ) ; await expect ( screen . findByText ( 'Request cancelled' ) ) . resolves . toBeVisible ( ) ; expect ( errorSpy ) . toHaveBeenCalledTimes ( 2 ) ; errorSpy . mockRestore ( ) ; await selectExplorerNode ( 'entities' ) ; await expect ( screen . findByText ( /No visualization/ ) ) . resolves . toBeVisible ( ) ; await selectExplorerNode ( 'slow_nx_spectrum' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; jest . runAllTimers ( ) ; await expect ( screen . findByRole ( 'figure' ) ) . resolves . toBeVisible ( ) ; jest . runOnlyPendingTimers ( ) ; jest . useRealTimers ( ) ; } ) ; test ( 'retry fetching automatically when re-selecting NxImage' , async ( ) => { jest . useFakeTimers ( 'modern' ) ; await renderApp ( ) ; await selectExplorerNode ( 'resilience/slow_nx_image' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; userEvent . click ( await screen . findByRole ( 'button' , { name : /Cancel/ } ) ) ; await expect ( screen . findByText ( 'Request cancelled' ) ) . resolves . toBeVisible ( ) ; expect ( errorSpy ) . toHaveBeenCalledTimes ( 2 ) ; errorSpy . mockRestore ( ) ; await selectExplorerNode ( 'entities' ) ; await expect ( screen . findByText ( /No visualization/ ) ) . resolves . toBeVisible ( ) ; await selectExplorerNode ( 'slow_nx_image' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; jest . runAllTimers ( ) ; await expect ( screen . findByRole ( 'figure' ) ) . resolves . toBeVisible ( ) ; jest . runOnlyPendingTimers ( ) ; jest . useRealTimers ( ) ; } ) ; test ( 'retry fetching automatically when selecting other NxSpectrum slice' , async ( ) => { jest . useFakeTimers ( 'modern' ) ; await renderApp ( ) ; await selectExplorerNode ( 'resilience/slow_nx_spectrum' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; userEvent . click ( await screen . findByRole ( 'button' , { name : /Cancel/ } ) ) ; await expect ( screen . findByText ( 'Request cancelled' ) ) . resolves . toBeVisible ( ) ; expect ( errorSpy ) . toHaveBeenCalledTimes ( 2 ) ; errorSpy . mockRestore ( ) ; const d0Slider = screen . getByRole ( 'slider' , { name : 'Dimension slider' } ) ; d0Slider . focus ( ) ; userEvent . keyboard ( '{PageUp}' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; jest . runAllTimers ( ) ; await expect ( screen . findByRole ( 'figure' ) ) . resolves . toBeVisible ( ) ; userEvent . keyboard ( '{PageDown}' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; jest . runAllTimers ( ) ; await expect ( screen . findByRole ( 'figure' ) ) . resolves . toBeVisible ( ) ; d0Slider . blur ( ) ; jest . runOnlyPendingTimers ( ) ; jest . useRealTimers ( ) ; } ) ; test ( 'retry fetching supporting datasets automatically when selecting other NxImage slice' , async ( ) => { jest . useFakeTimers ( 'modern' ) ; await renderApp ( ) ; await selectExplorerNode ( 'resilience/slow_nx_image' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; const errorSpy = mockConsoleMethod ( 'error' ) ; userEvent . click ( await screen . findByRole ( 'button' , { name : /Cancel/ } ) ) ; await expect ( screen . findByText ( 'Request cancelled' ) ) . resolves . toBeVisible ( ) ; expect ( errorSpy ) . toHaveBeenCalledTimes ( 2 ) ; errorSpy . mockRestore ( ) ; const d0Slider = screen . getByRole ( 'slider' , { name : 'Dimension slider' } ) ; d0Slider . focus ( ) ; userEvent . keyboard ( '{PageUp}' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; jest . runAllTimers ( ) ; await expect ( screen . findByRole ( 'figure' ) ) . resolves . toBeVisible ( ) ; userEvent . keyboard ( '{PageDown}' ) ; await expect ( screen . findByText ( /Loading data/ ) ) . resolves . toBeVisible ( ) ; jest . runAllTimers ( ) ; await expect ( screen . findByRole ( 'figure' ) ) . resolves . toBeVisible ( ) ; d0Slider . blur ( ) ; jest . runOnlyPendingTimers ( ) ; jest . useRealTimers ( ) ; } ) ;