Add unit tests for channel utilities and configure testing environment
- Created a new test file `channels.test.ts` to cover utilities related to channel configurations and targets. - Implemented tests for normalizing and grouping selected channels by type, as well as building channel targets from account data and cron history. - Mocked necessary dependencies to isolate tests and ensure accurate results. - Updated `vite.config.ts` to set up the testing environment with jsdom and enable global variables for tests.
This commit is contained in:
@@ -2,6 +2,11 @@ import { CONFIG_KEYS } from '@runtime/lib/constants';
|
||||
import { normalizeAgentId, type AgentsSnapshot } from '@runtime/lib/models';
|
||||
import configManager from '@electron/service/config-service';
|
||||
import { listCronJobs } from './cron-store';
|
||||
import { listStoredChannelAccountRecords } from './channel-config';
|
||||
import {
|
||||
buildChannelStatusSummary,
|
||||
inferChannelConnectionStatus,
|
||||
} from './channel-status';
|
||||
import type {
|
||||
ChannelAccountCatalogGroup,
|
||||
ChannelConnectionStatus,
|
||||
@@ -23,6 +28,12 @@ export interface LocalChannelAccount {
|
||||
channelName: string;
|
||||
channelUrl: string;
|
||||
label: string;
|
||||
configured: boolean;
|
||||
enabled: boolean;
|
||||
channelEnabled: boolean;
|
||||
status: ChannelConnectionStatus;
|
||||
isDefault: boolean;
|
||||
lastError?: string;
|
||||
ownerAgentId: string | null;
|
||||
ownerAgentName: string | null;
|
||||
bindingScope: 'account' | 'channel' | null;
|
||||
@@ -280,32 +291,93 @@ export function getSelectedChannelsConfig(): SelectedChannelConfigItem[] {
|
||||
}
|
||||
|
||||
export function listSelectedChannelAccounts(snapshot?: Pick<AgentsSnapshot, 'agents' | 'channelOwners' | 'channelAccountOwners'>): LocalChannelAccount[] {
|
||||
const channels = getSelectedChannelsConfig();
|
||||
const agentNameById = new Map<string, string>(
|
||||
Array.isArray(snapshot?.agents)
|
||||
? snapshot.agents.map((agent) => [normalizeAgentId(agent.id), agent.name || normalizeAgentId(agent.id)])
|
||||
: [],
|
||||
);
|
||||
const accounts = new Map<string, LocalChannelAccount>();
|
||||
|
||||
return channels.map((item) => {
|
||||
for (const record of listStoredChannelAccountRecords()) {
|
||||
const accountOwnerKey = `${record.channelType}:${record.accountId}`;
|
||||
const accountOwnerId = snapshot?.channelAccountOwners?.[accountOwnerKey];
|
||||
const channelOwnerId = snapshot?.channelOwners?.[record.channelType];
|
||||
const ownerAgentId = accountOwnerId || channelOwnerId || null;
|
||||
const normalizedOwnerId = ownerAgentId ? normalizeAgentId(ownerAgentId) : null;
|
||||
const key = `${record.channelType}:${record.accountId}`;
|
||||
const status = inferChannelConnectionStatus({
|
||||
configured: true,
|
||||
channelUrl: record.channelUrl ?? '',
|
||||
status: record.channelEnabled && record.accountEnabled ? 'connected' : 'disconnected',
|
||||
hasBinding: Boolean(accountOwnerId || channelOwnerId),
|
||||
degraded: !record.channelEnabled || !record.accountEnabled,
|
||||
});
|
||||
|
||||
accounts.set(key, {
|
||||
id: record.accountId,
|
||||
accountId: record.accountId,
|
||||
channelType: record.channelType,
|
||||
channelName: record.channelLabel,
|
||||
channelUrl: record.channelUrl ?? '',
|
||||
label: record.accountName || record.accountId,
|
||||
configured: true,
|
||||
enabled: record.channelEnabled && record.accountEnabled,
|
||||
channelEnabled: record.channelEnabled,
|
||||
status,
|
||||
isDefault: record.accountId === record.defaultAccountId,
|
||||
lastError: status === 'error'
|
||||
? '渠道链接格式无效'
|
||||
: undefined,
|
||||
ownerAgentId: normalizedOwnerId,
|
||||
ownerAgentName: normalizedOwnerId ? agentNameById.get(normalizedOwnerId) ?? null : null,
|
||||
bindingScope: accountOwnerId ? 'account' : channelOwnerId ? 'channel' : null,
|
||||
});
|
||||
}
|
||||
|
||||
const legacyChannels = getSelectedChannelsConfig();
|
||||
for (const item of legacyChannels) {
|
||||
const channelType = inferChannelType(item);
|
||||
const key = `${channelType}:${item.id}`;
|
||||
if (accounts.has(key)) continue;
|
||||
|
||||
const accountOwnerKey = `${channelType}:${item.id}`;
|
||||
const accountOwnerId = snapshot?.channelAccountOwners?.[accountOwnerKey];
|
||||
const channelOwnerId = snapshot?.channelOwners?.[channelType];
|
||||
const ownerAgentId = accountOwnerId || channelOwnerId || null;
|
||||
const normalizedOwnerId = ownerAgentId ? normalizeAgentId(ownerAgentId) : null;
|
||||
const status = inferChannelConnectionStatus({
|
||||
configured: true,
|
||||
channelUrl: item.channelUrl,
|
||||
status: ownerAgentId ? 'connected' : undefined,
|
||||
hasBinding: Boolean(accountOwnerId || channelOwnerId),
|
||||
});
|
||||
|
||||
return {
|
||||
accounts.set(key, {
|
||||
id: item.id,
|
||||
accountId: item.id,
|
||||
channelType,
|
||||
channelName: item.channelName,
|
||||
channelUrl: item.channelUrl,
|
||||
label: item.channelName,
|
||||
configured: true,
|
||||
enabled: true,
|
||||
channelEnabled: true,
|
||||
status,
|
||||
isDefault: false,
|
||||
lastError: status === 'error'
|
||||
? '渠道链接格式无效'
|
||||
: undefined,
|
||||
ownerAgentId: normalizedOwnerId,
|
||||
ownerAgentName: normalizedOwnerId ? agentNameById.get(normalizedOwnerId) ?? null : null,
|
||||
bindingScope: accountOwnerId ? 'account' : channelOwnerId ? 'channel' : null,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return Array.from(accounts.values()).sort((left, right) => {
|
||||
if (left.channelName !== right.channelName) {
|
||||
return left.channelName.localeCompare(right.channelName, 'zh-CN');
|
||||
}
|
||||
return left.label.localeCompare(right.label, 'zh-CN');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -319,22 +391,38 @@ export function listSelectedChannelAccountGroups(
|
||||
const existing = groups.get(account.channelType) ?? {
|
||||
channelType: account.channelType,
|
||||
channelLabel: account.channelName || formatChannelLabel(account.channelType),
|
||||
defaultAccountId: account.accountId,
|
||||
status: 'connected' as ChannelConnectionStatus,
|
||||
defaultAccountId: account.isDefault ? account.accountId : '',
|
||||
enabled: account.channelEnabled,
|
||||
status: account.status,
|
||||
accounts: [],
|
||||
};
|
||||
|
||||
existing.enabled = existing.enabled !== false && account.channelEnabled;
|
||||
existing.accounts.push({
|
||||
accountId: account.accountId,
|
||||
name: account.label || account.channelName || account.accountId,
|
||||
configured: true,
|
||||
status: 'connected',
|
||||
isDefault: false,
|
||||
configured: account.configured,
|
||||
enabled: account.enabled,
|
||||
status: account.status,
|
||||
lastError: account.lastError,
|
||||
isDefault: account.isDefault,
|
||||
agentId: account.ownerAgentId ?? undefined,
|
||||
bindingScope: account.bindingScope ?? undefined,
|
||||
channelUrl: account.channelUrl,
|
||||
});
|
||||
|
||||
if (!existing.defaultAccountId && account.isDefault) {
|
||||
existing.defaultAccountId = account.accountId;
|
||||
}
|
||||
|
||||
if (existing.status !== 'error' && account.status === 'error') {
|
||||
existing.status = 'error';
|
||||
} else if (existing.status === 'disconnected' && account.status !== 'disconnected') {
|
||||
existing.status = account.status;
|
||||
} else if (existing.status !== 'connected' && account.status === 'connected') {
|
||||
existing.status = 'connected';
|
||||
}
|
||||
|
||||
groups.set(account.channelType, existing);
|
||||
}
|
||||
|
||||
@@ -342,13 +430,20 @@ export function listSelectedChannelAccountGroups(
|
||||
.map((group) => {
|
||||
const sortedAccounts = [...group.accounts].sort((left, right) => left.name.localeCompare(right.name));
|
||||
const defaultAccountId = group.defaultAccountId || sortedAccounts[0]?.accountId || 'default';
|
||||
const status = buildChannelStatusSummary([
|
||||
{
|
||||
...group,
|
||||
accounts: sortedAccounts,
|
||||
},
|
||||
]).status;
|
||||
|
||||
return {
|
||||
...group,
|
||||
defaultAccountId,
|
||||
status,
|
||||
accounts: sortedAccounts.map((account) => ({
|
||||
...account,
|
||||
isDefault: account.accountId === defaultAccountId,
|
||||
isDefault: account.isDefault || account.accountId === defaultAccountId,
|
||||
})),
|
||||
};
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user