Add tests for centered modal adoption, search modal results, and accounts batch actions

- Implement tests for the CenteredModal component to ensure it follows the shared modal shell pattern.
- Add comprehensive tests for the SearchModal results, including API interactions and UI behavior.
- Create tests for accounts batch actions, verifying the functionality of refreshing balances and selecting accounts via row clicks.
- Introduce tests for the accounts centered modal to confirm the use of CenteredModal for add/edit/rebind flows.
- Add tests for the accounts edit panel to ensure proper rendering and functionality when opening the edit modal.
- Implement tests for the accounts tokens header to verify the reuse of the accounts page header in the tokens segment.
- Create tests for the system proxy settings, ensuring the correct saving of the proxy URL.
- Add tests for the tokens actions layout to confirm the proper layout and styling of token row actions.
- Implement tests for the tokens batch actions, including deletion of selected tokens and row selection behavior.
- Introduce tests for the tokens focus navigation to ensure the correct highlighting of focused token rows.
This commit is contained in:
cita
2026-03-07 18:04:05 +08:00
parent c31bbcbb51
commit c437d93715
65 changed files with 3984 additions and 486 deletions
+18 -1
View File
@@ -1,5 +1,6 @@
const FOCUS_SITE_ID_KEY = 'focusSiteId';
const FOCUS_ACCOUNT_ID_KEY = 'focusAccountId';
const FOCUS_TOKEN_ID_KEY = 'focusTokenId';
const OPEN_REBIND_KEY = 'openRebind';
function normalizePositiveId(input: unknown): number | null {
@@ -22,16 +23,26 @@ export function buildSiteFocusPath(siteId: number): string {
export function buildAccountFocusPath(
accountId: number,
options?: { openRebind?: boolean },
options?: { openRebind?: boolean; segment?: 'session' | 'apikey' | 'tokens' },
): string {
const normalizedId = normalizePositiveId(accountId);
if (!normalizedId) return '/accounts';
const params = new URLSearchParams();
if (options?.segment && options.segment !== 'session') params.set('segment', options.segment);
params.set(FOCUS_ACCOUNT_ID_KEY, String(normalizedId));
if (options?.openRebind) params.set(OPEN_REBIND_KEY, '1');
return `/accounts?${params.toString()}`;
}
export function buildTokenFocusPath(tokenId: number): string {
const normalizedId = normalizePositiveId(tokenId);
if (!normalizedId) return '/accounts?segment=tokens';
const params = new URLSearchParams();
params.set('segment', 'tokens');
params.set(FOCUS_TOKEN_ID_KEY, String(normalizedId));
return `/accounts?${params.toString()}`;
}
export function readFocusSiteId(search: string): number | null {
const params = new URLSearchParams(search);
return normalizePositiveId(params.get(FOCUS_SITE_ID_KEY));
@@ -45,10 +56,16 @@ export function readFocusAccountIntent(search: string): { accountId: number | nu
};
}
export function readFocusTokenId(search: string): number | null {
const params = new URLSearchParams(search);
return normalizePositiveId(params.get(FOCUS_TOKEN_ID_KEY));
}
export function clearFocusParams(search: string): string {
const params = new URLSearchParams(search);
params.delete(FOCUS_SITE_ID_KEY);
params.delete(FOCUS_ACCOUNT_ID_KEY);
params.delete(FOCUS_TOKEN_ID_KEY);
params.delete(OPEN_REBIND_KEY);
const next = params.toString();
return next ? `?${next}` : '';
+4
View File
@@ -0,0 +1,4 @@
export function shouldIgnoreRowSelectionClick(target: EventTarget | null): boolean {
const element = target as { closest?: (selector: string) => unknown } | null;
return !!element?.closest?.('button, a, input, textarea, select, label, [role="button"]');
}
+4 -4
View File
@@ -3,7 +3,7 @@ export type SiteForm = {
url: string;
externalCheckinUrl: string;
platform: string;
proxyUrl: string;
useSystemProxy: boolean;
globalWeight: string;
};
@@ -16,12 +16,12 @@ type SiteSaveAction =
| { kind: 'update'; id: number; payload: SiteForm };
export function emptySiteForm(): SiteForm {
return { name: '', url: '', externalCheckinUrl: '', platform: '', proxyUrl: '', globalWeight: '1' };
return { name: '', url: '', externalCheckinUrl: '', platform: '', useSystemProxy: false, globalWeight: '1' };
}
export function siteFormFromSite(site: Partial<SiteForm> & {
proxyUrl?: string | null;
externalCheckinUrl?: string | null;
useSystemProxy?: boolean | null;
globalWeight?: number | string | null;
}): SiteForm {
const globalWeightRaw = Number(site.globalWeight);
@@ -31,7 +31,7 @@ export function siteFormFromSite(site: Partial<SiteForm> & {
url: site.url ?? '',
externalCheckinUrl: site.externalCheckinUrl ?? '',
platform: site.platform ?? '',
proxyUrl: site.proxyUrl ?? '',
useSystemProxy: !!site.useSystemProxy,
globalWeight,
};
}