Files
Remote-Terminal-for-MeshCore/frontend/src/test/visualizerView.test.tsx
T
Ryan Gregg 5e5ab7db4d Keep overheard packet traffic out of the chat render path
Typing in a conversation got progressively slower as its history grew.
The cause was not the input: every packet the node overhears was stored
in App state, so each one re-rendered the whole tree, including the
un-memoized MessageList. That cost scales with history length, and on a
busy mesh it saturated the main thread so keystrokes queued behind it.

Measured in Chromium with the real components, cost per overheard packet:

  history    before    after
      50      7.3ms    ~0ms
     500     48.5ms    ~0ms
    1000     97.7ms    ~0ms
    2000    228.4ms    ~0ms

The packet stream now lives in a small external store that views subscribe
to individually, so only the map, visualizer, raw feed, and cracker re-render
when a packet arrives, so the chat view is no longer along for the ride.
This also retires useRawPacketStatsSession, whose session state was App
state for the same reason.
2026-07-25 12:32:14 -07:00

51 lines
1.7 KiB
TypeScript

import { fireEvent, render, screen } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { VisualizerView } from '../components/VisualizerView';
import { resetRawPacketStore, seedRawPacketStore } from '../stores/rawPacketStore';
import type { RawPacket } from '../types';
// The 3D scene needs WebGL, which jsdom does not provide.
vi.mock('../components/PacketVisualizer3D', () => ({
PacketVisualizer3D: () => <div data-testid="packet-visualizer-3d" />,
}));
function createPacket(overrides: Partial<RawPacket> = {}): RawPacket {
return {
id: 1,
timestamp: 1700000000,
data: '000000000000',
payload_type: 'REQ',
snr: null,
rssi: null,
decrypted: false,
decrypted_info: null,
...overrides,
};
}
describe('VisualizerView packet feed', () => {
beforeEach(() => {
window.localStorage.clear();
resetRawPacketStore();
});
it('opens the packet analyzer when a feed packet is clicked', () => {
seedRawPacketStore({ packets: [createPacket({ id: 7, observation_id: 21 })] });
render(<VisualizerView contacts={[]} channels={[]} config={null} />);
expect(screen.queryByText('Packet Details')).not.toBeInTheDocument();
// Desktop split-pane and mobile tab both render the feed, so take the first.
fireEvent.click(screen.getAllByRole('button', { name: /TF/ })[0]);
expect(screen.getByText('Packet Details')).toBeInTheDocument();
});
it('does not render the analyzer until a packet is selected', () => {
render(<VisualizerView contacts={[]} channels={[]} config={null} />);
expect(screen.queryByText('Packet Details')).not.toBeInTheDocument();
});
});