feat: add Tencent WeChat channel plugin and update related configurations

- Added the Tencent WeChat channel plugin (`@tencent-weixin/openclaw-weixin`) to the project dependencies.
- Updated the `pnpm-lock.yaml` to include the new plugin version.
- Enhanced the README files to document the WeChat integration process.
- Implemented QR code login functionality for WeChat in the channel management system.
- Updated UI components to support WeChat channel configuration and display.
- Added localization support for WeChat connection messages in English, Japanese, and Chinese.
This commit is contained in:
Haze
2026-03-22 16:20:41 +08:00
parent f16e8062e1
commit 2ab0e7c386
31 changed files with 1602 additions and 152 deletions

View File

@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { act, render, waitFor } from '@testing-library/react';
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
import { Channels } from '@/pages/Channels/index';
const hostApiFetchMock = vi.fn();
@@ -126,4 +126,58 @@ describe('Channels page status refresh', () => {
expect(agentFetchCalls).toHaveLength(2);
});
});
it('treats WeChat accounts as plugin-managed QR accounts', async () => {
subscribeHostEventMock.mockImplementation(() => vi.fn());
hostApiFetchMock.mockImplementation(async (path: string) => {
if (path === '/api/channels/accounts') {
return {
success: true,
channels: [
{
channelType: 'wechat',
defaultAccountId: 'wx-bot-im-bot',
status: 'connected',
accounts: [
{
accountId: 'wx-bot-im-bot',
name: 'WeChat ClawBot',
configured: true,
status: 'connected',
isDefault: true,
},
],
},
],
};
}
if (path === '/api/agents') {
return {
success: true,
agents: [],
};
}
if (path === '/api/channels/wechat/cancel') {
return { success: true };
}
throw new Error(`Unexpected host API path: ${path}`);
});
render(<Channels />);
await waitFor(() => {
expect(screen.getByText('WeChat')).toBeInTheDocument();
});
fireEvent.click(screen.getByRole('button', { name: 'account.add' }));
await waitFor(() => {
expect(screen.getByText('dialog.configureTitle')).toBeInTheDocument();
});
expect(screen.queryByLabelText('account.customIdLabel')).not.toBeInTheDocument();
});
});