mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-16 01:26:07 +00:00
ebfaad1499
The outbounds table hides balancer-loopback outbounds (`_bl_*`) but keeps each visible row's original index in `key`, then passed antd's positional row index to edit/delete/move and to the per-row probe (onTest) and its result lookup — all of which address the full, unfiltered outbounds array. Once a hidden loopback outbound precedes a visible one, the positional index diverges from the array index, so deleting or editing an outbound hit the wrong one (its deletion-impact plan and removal targeting the wrong entry), and the test button probed / showed results against the wrong outbound. Add originalOutboundIndex and route the mutating handlers through it; key the probe trigger and test-result columns by record.key. With no loopback rows hidden the mapping is the identity, so ordinary configs are unaffected.
57 lines
1.9 KiB
TypeScript
57 lines
1.9 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
import { fireEvent } from '@testing-library/react';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
|
|
import OutboundsTab from '@/pages/xray/outbounds/OutboundsTab';
|
|
import type { XraySettingsValue } from '@/hooks/useXraySetting';
|
|
|
|
import { renderWithProviders } from './test-utils';
|
|
|
|
function settingsWithHiddenLoopback(): XraySettingsValue {
|
|
return {
|
|
outbounds: [
|
|
{ tag: 'proxy-a', protocol: 'vmess' },
|
|
{ tag: '_bl_bal1', protocol: 'loopback' },
|
|
{ tag: 'proxy-b', protocol: 'vmess' },
|
|
],
|
|
} as unknown as XraySettingsValue;
|
|
}
|
|
|
|
describe('OutboundsTab hidden-loopback index mapping', () => {
|
|
it('probes the outbound at its real array index, not the positional row index', () => {
|
|
const onTest = vi.fn();
|
|
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
|
|
|
renderWithProviders(
|
|
<QueryClientProvider client={queryClient}>
|
|
<OutboundsTab
|
|
templateSettings={settingsWithHiddenLoopback()}
|
|
setTemplateSettings={vi.fn()}
|
|
outboundsTraffic={[]}
|
|
outboundTestStates={{}}
|
|
subscriptionTestStates={{}}
|
|
testingAll={false}
|
|
inboundTags={[]}
|
|
isMobile={false}
|
|
onResetTraffic={vi.fn()}
|
|
onTest={onTest}
|
|
onTestSubscription={vi.fn()}
|
|
onTestAll={vi.fn()}
|
|
onShowWarp={vi.fn()}
|
|
onShowNord={vi.fn()}
|
|
/>
|
|
</QueryClientProvider>,
|
|
);
|
|
|
|
const tbody = document.querySelector('.ant-table-tbody');
|
|
const tableRows = tbody?.querySelectorAll('tr.ant-table-row') ?? [];
|
|
expect(tableRows.length).toBe(2);
|
|
|
|
const checkButton = tableRows[1].querySelector('button[aria-label="Check"]') as HTMLButtonElement;
|
|
fireEvent.click(checkButton);
|
|
|
|
expect(onTest).toHaveBeenCalledTimes(1);
|
|
expect(onTest.mock.calls[0][0]).toBe(2);
|
|
});
|
|
});
|