feat: unify cron delivery account and target selection (#642)
This commit is contained in:
committed by
GitHub
Unverified
parent
9aea3c9441
commit
9d40e1fa05
198
tests/unit/cron-routes.test.ts
Normal file
198
tests/unit/cron-routes.test.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import type { IncomingMessage, ServerResponse } from 'http';
|
||||
|
||||
const parseJsonBodyMock = vi.fn();
|
||||
const sendJsonMock = vi.fn();
|
||||
|
||||
vi.mock('@electron/api/route-utils', () => ({
|
||||
parseJsonBody: (...args: unknown[]) => parseJsonBodyMock(...args),
|
||||
sendJson: (...args: unknown[]) => sendJsonMock(...args),
|
||||
}));
|
||||
|
||||
describe('handleCronRoutes', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it('creates cron jobs with external delivery configuration', async () => {
|
||||
parseJsonBodyMock.mockResolvedValue({
|
||||
name: 'Weather delivery',
|
||||
message: 'Summarize today',
|
||||
schedule: '0 9 * * *',
|
||||
delivery: {
|
||||
mode: 'announce',
|
||||
channel: 'feishu',
|
||||
to: 'user:ou_weather',
|
||||
},
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
const rpc = vi.fn().mockResolvedValue({
|
||||
id: 'job-1',
|
||||
name: 'Weather delivery',
|
||||
enabled: true,
|
||||
createdAtMs: 1,
|
||||
updatedAtMs: 2,
|
||||
schedule: { kind: 'cron', expr: '0 9 * * *' },
|
||||
payload: { kind: 'agentTurn', message: 'Summarize today' },
|
||||
delivery: { mode: 'announce', channel: 'feishu', to: 'user:ou_weather' },
|
||||
state: {},
|
||||
});
|
||||
|
||||
const { handleCronRoutes } = await import('@electron/api/routes/cron');
|
||||
const handled = await handleCronRoutes(
|
||||
{ method: 'POST' } as IncomingMessage,
|
||||
{} as ServerResponse,
|
||||
new URL('http://127.0.0.1:3210/api/cron/jobs'),
|
||||
{
|
||||
gatewayManager: { rpc },
|
||||
} as never,
|
||||
);
|
||||
|
||||
expect(handled).toBe(true);
|
||||
expect(rpc).toHaveBeenCalledWith('cron.add', expect.objectContaining({
|
||||
delivery: { mode: 'announce', channel: 'feishu', to: 'user:ou_weather' },
|
||||
}));
|
||||
expect(sendJsonMock).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
200,
|
||||
expect.objectContaining({
|
||||
id: 'job-1',
|
||||
delivery: { mode: 'announce', channel: 'feishu', to: 'user:ou_weather' },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('updates cron jobs with transformed payload and delivery fields', async () => {
|
||||
parseJsonBodyMock.mockResolvedValue({
|
||||
message: 'Updated prompt',
|
||||
delivery: {
|
||||
mode: 'announce',
|
||||
channel: 'feishu',
|
||||
to: 'user:ou_next',
|
||||
},
|
||||
});
|
||||
|
||||
const rpc = vi.fn().mockResolvedValue({
|
||||
id: 'job-2',
|
||||
name: 'Updated job',
|
||||
enabled: true,
|
||||
createdAtMs: 1,
|
||||
updatedAtMs: 3,
|
||||
schedule: { kind: 'cron', expr: '0 9 * * *' },
|
||||
payload: { kind: 'agentTurn', message: 'Updated prompt' },
|
||||
delivery: { mode: 'announce', channel: 'feishu', to: 'user:ou_next' },
|
||||
state: {},
|
||||
});
|
||||
|
||||
const { handleCronRoutes } = await import('@electron/api/routes/cron');
|
||||
await handleCronRoutes(
|
||||
{ method: 'PUT' } as IncomingMessage,
|
||||
{} as ServerResponse,
|
||||
new URL('http://127.0.0.1:3210/api/cron/jobs/job-2'),
|
||||
{
|
||||
gatewayManager: { rpc },
|
||||
} as never,
|
||||
);
|
||||
|
||||
expect(rpc).toHaveBeenCalledWith('cron.update', {
|
||||
id: 'job-2',
|
||||
patch: {
|
||||
payload: { kind: 'agentTurn', message: 'Updated prompt' },
|
||||
delivery: { mode: 'announce', channel: 'feishu', to: 'user:ou_next' },
|
||||
},
|
||||
});
|
||||
expect(sendJsonMock).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
200,
|
||||
expect.objectContaining({
|
||||
id: 'job-2',
|
||||
message: 'Updated prompt',
|
||||
delivery: { mode: 'announce', channel: 'feishu', to: 'user:ou_next' },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('passes through delivery.accountId for multi-account cron jobs', async () => {
|
||||
parseJsonBodyMock.mockResolvedValue({
|
||||
delivery: {
|
||||
mode: 'announce',
|
||||
channel: 'feishu',
|
||||
to: 'user:ou_owner',
|
||||
accountId: 'feishu-0d009958',
|
||||
},
|
||||
});
|
||||
|
||||
const rpc = vi.fn().mockResolvedValue({
|
||||
id: 'job-account',
|
||||
name: 'Account job',
|
||||
enabled: true,
|
||||
createdAtMs: 1,
|
||||
updatedAtMs: 4,
|
||||
schedule: { kind: 'cron', expr: '0 9 * * *' },
|
||||
payload: { kind: 'agentTurn', message: 'Prompt' },
|
||||
delivery: { mode: 'announce', channel: 'feishu', accountId: 'feishu-0d009958', to: 'user:ou_owner' },
|
||||
state: {},
|
||||
});
|
||||
|
||||
const { handleCronRoutes } = await import('@electron/api/routes/cron');
|
||||
await handleCronRoutes(
|
||||
{ method: 'PUT' } as IncomingMessage,
|
||||
{} as ServerResponse,
|
||||
new URL('http://127.0.0.1:3210/api/cron/jobs/job-account'),
|
||||
{
|
||||
gatewayManager: { rpc },
|
||||
} as never,
|
||||
);
|
||||
|
||||
expect(rpc).toHaveBeenCalledWith('cron.update', {
|
||||
id: 'job-account',
|
||||
patch: {
|
||||
delivery: {
|
||||
mode: 'announce',
|
||||
channel: 'feishu',
|
||||
to: 'user:ou_owner',
|
||||
accountId: 'feishu-0d009958',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects WeChat scheduled delivery because the plugin requires a live context token', async () => {
|
||||
parseJsonBodyMock.mockResolvedValue({
|
||||
name: 'WeChat delivery',
|
||||
message: 'Send update',
|
||||
schedule: '0 10 * * *',
|
||||
delivery: {
|
||||
mode: 'announce',
|
||||
channel: 'wechat',
|
||||
to: 'wechat:wxid_target',
|
||||
accountId: 'wechat-bot',
|
||||
},
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
const rpc = vi.fn();
|
||||
|
||||
const { handleCronRoutes } = await import('@electron/api/routes/cron');
|
||||
const handled = await handleCronRoutes(
|
||||
{ method: 'POST' } as IncomingMessage,
|
||||
{} as ServerResponse,
|
||||
new URL('http://127.0.0.1:3210/api/cron/jobs'),
|
||||
{
|
||||
gatewayManager: { rpc },
|
||||
} as never,
|
||||
);
|
||||
|
||||
expect(handled).toBe(true);
|
||||
expect(rpc).not.toHaveBeenCalled();
|
||||
expect(sendJsonMock).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
400,
|
||||
expect.objectContaining({
|
||||
success: false,
|
||||
error: expect.stringContaining('WeChat scheduled delivery is not supported'),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user