Files
EJClaw/src/index.test.ts
Eyejoker c89242b6dd fix: harden stripToolCallLeaks regex for CJK/non-ASCII garbage tokens
The previous regex used \w+ for descriptor tokens between the function
name and JSON body, which only matches ASCII word characters. Model
hallucinations often inject CJK/non-ASCII text (e.g. 彩神争霸) in this
position. Switch to (?:\s+[^\s{}]+)+ to match any whitespace-separated
non-brace tokens regardless of character set.

Also removes stale backward-compat re-exports from index.ts and updates
the test import for composeDashboardContent.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 18:06:31 +09:00

103 lines
2.9 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest';
import {
editFormattedTrackedChannelMessage,
sendFormattedChannelMessage,
sendFormattedTrackedChannelMessage,
} from './index.js';
import { composeDashboardContent } from './dashboard-render.js';
import { Channel } from './types.js';
function makeChannel(overrides: Partial<Channel> = {}): Channel {
return {
name: 'test',
connect: async () => {},
sendMessage: async () => {},
isConnected: () => true,
ownsJid: (jid: string) => jid === 'dc:test',
disconnect: async () => {},
...overrides,
};
}
describe('index scheduler messaging helpers', () => {
it('sends formatted tracked messages through sendAndTrack', async () => {
const sendAndTrack = vi.fn(async () => 'msg-123');
const channel = makeChannel({ sendAndTrack });
const messageId = await sendFormattedTrackedChannelMessage(
[channel],
'dc:test',
'<internal>hidden</internal>watching ci',
);
expect(messageId).toBe('msg-123');
expect(sendAndTrack).toHaveBeenCalledWith('dc:test', 'watching ci');
});
it('edits formatted tracked messages through editMessage', async () => {
const editMessage = vi.fn(async () => {});
const channel = makeChannel({ editMessage });
await editFormattedTrackedChannelMessage(
[channel],
'dc:test',
'msg-123',
'<internal>hidden</internal>still watching',
);
expect(editMessage).toHaveBeenCalledWith(
'dc:test',
'msg-123',
'still watching',
);
});
it('skips empty messages after formatting', async () => {
const sendMessage = vi.fn(async () => {});
const sendAndTrack = vi.fn(async () => 'msg-123');
const editMessage = vi.fn(async () => {});
const channel = makeChannel({ sendMessage, sendAndTrack, editMessage });
const trackedResult = await sendFormattedTrackedChannelMessage(
[channel],
'dc:test',
'<internal>only hidden</internal>',
);
await editFormattedTrackedChannelMessage(
[channel],
'dc:test',
'msg-123',
'<internal>only hidden</internal>',
);
await sendFormattedChannelMessage(
[channel],
'dc:test',
'<internal>only hidden</internal>',
);
expect(trackedResult).toBeNull();
expect(sendAndTrack).not.toHaveBeenCalled();
expect(editMessage).not.toHaveBeenCalled();
expect(sendMessage).not.toHaveBeenCalled();
});
});
describe('composeDashboardContent', () => {
it('returns an empty string when all dashboard sections are disabled', () => {
expect(
composeDashboardContent([], new Date('2026-03-23T04:00:00+09:00')),
).toBe('');
});
it('keeps non-status sections when room status is hidden', () => {
const content = composeDashboardContent(
['**사용량**\nCodex OK'],
new Date('2026-03-23T04:00:00+09:00'),
);
expect(content).toContain('**사용량**');
expect(content).not.toContain('**📊 에이전트 상태**');
});
});