refactor(decnet_web/AttackerDetail): extract AttackerHeader section
Lift the header (IP, country tag, traversal badge, identity badge) into its own section component. Tag helper moves to a shared AttackerDetail/ui.tsx so future sections can reuse it without re-importing through AttackerDetail.tsx. - New AttackerDetail/sections/AttackerHeader.tsx (~50 LOC) - New AttackerDetail/ui.tsx for shared presentational helpers - AttackerDetail.tsx imports both; local Tag definition deleted - AttackerHeader.test.tsx covers country present/absent, TRAVERSAL badge, IDENTITY click-through, identity null path
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { renderWithRouter } from '../../../test/renderWithRouter';
|
||||
import { makeAttacker } from '../../../test/fixtures';
|
||||
import { AttackerHeader } from './AttackerHeader';
|
||||
|
||||
describe('AttackerHeader', () => {
|
||||
it('renders the IP and a country tag when country_code is present', () => {
|
||||
renderWithRouter(<AttackerHeader attacker={makeAttacker({ country_code: 'BR' })} />);
|
||||
expect(screen.getByText('198.51.100.10')).toBeInTheDocument();
|
||||
expect(screen.getByText('BR')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('omits the country tag when country_code is null', () => {
|
||||
renderWithRouter(
|
||||
<AttackerHeader attacker={makeAttacker({ country_code: null })} />,
|
||||
);
|
||||
expect(screen.queryByText('BR')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('US')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the TRAVERSAL badge when is_traversal is true', () => {
|
||||
renderWithRouter(
|
||||
<AttackerHeader attacker={makeAttacker({ is_traversal: true })} />,
|
||||
);
|
||||
expect(screen.getByText('TRAVERSAL')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the IDENTITY badge with first 8 chars and navigates on click', async () => {
|
||||
const user = userEvent.setup();
|
||||
const identity = 'aaaabbbb-cccc-dddd-eeee-ffffffffffff';
|
||||
renderWithRouter(
|
||||
<AttackerHeader attacker={makeAttacker({ identity_id: identity })} />,
|
||||
);
|
||||
const badge = screen.getByText(/IDENTITY · aaaabbbb/);
|
||||
expect(badge).toBeInTheDocument();
|
||||
// No assertion on navigation target; we just verify the click
|
||||
// handler doesn't throw (router is present via renderWithRouter).
|
||||
await user.click(badge);
|
||||
});
|
||||
|
||||
it('omits the IDENTITY badge when identity_id is null', () => {
|
||||
renderWithRouter(
|
||||
<AttackerHeader attacker={makeAttacker({ identity_id: null })} />,
|
||||
);
|
||||
expect(screen.queryByText(/IDENTITY/)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user