Files
SnowLuma/packages/sdk/tests/guards.test.ts
T
TanTan fa9c73363d
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
SnowLuma v2.4.2 source snapshot
2026-11-13 09:02:00 +08:00

496 lines
14 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
isBotStatusEvent,
isGroupMessageEvent,
isMessageEvent,
isMetaEvent,
isNoticeEvent,
isPrivateMessageEvent,
isRequestEvent,
noticeType,
requestType,
type OneBotGroupMessageEvent,
type OneBotMetaEvent,
type OneBotNoticeEvent,
type OneBotPrivateMessageEvent,
type OneBotRequestEvent,
type SnowLumaEvent,
} from '../src';
const PRIVATE_MESSAGE: OneBotPrivateMessageEvent = {
time: 1_700_000_001,
self_id: 10000,
post_type: 'message',
message_type: 'private',
sub_type: 'friend',
message_id: 11,
message_seq: 12,
user_id: 20001,
message: [{ type: 'text', data: { text: 'hi' } }],
raw_message: 'hi',
font: 0,
sender: { user_id: 20001, nickname: 'alice' },
};
const PRIVATE_SENT: OneBotPrivateMessageEvent = {
time: 1_700_000_002,
self_id: 10000,
post_type: 'message_sent',
message_type: 'private',
sub_type: 'friend',
message_id: 13,
user_id: 20002,
message: 'echo',
raw_message: 'echo',
font: 0,
sender: { user_id: 10000, nickname: 'bot' },
};
const GROUP_MESSAGE: OneBotGroupMessageEvent = {
time: 1_700_000_003,
self_id: 10000,
post_type: 'message',
message_type: 'group',
sub_type: 'normal',
message_id: 21,
message_seq: 22,
group_id: 30001,
user_id: 20003,
message: [{ type: 'text', data: { text: 'hey' } }],
raw_message: 'hey',
font: 0,
sender: { user_id: 20003, nickname: 'bob', card: 'Bobby', role: 'member' },
};
const GROUP_SENT: OneBotGroupMessageEvent = {
time: 1_700_000_004,
self_id: 10000,
post_type: 'message_sent',
message_type: 'group',
sub_type: 'normal',
message_id: 23,
group_id: 30002,
user_id: 10000,
message: 'sent',
raw_message: 'sent',
font: 0,
sender: { user_id: 10000, nickname: 'bot' },
};
const NOTICE: OneBotNoticeEvent = {
time: 1_700_000_005,
self_id: 10000,
post_type: 'notice',
notice_type: 'group_increase',
};
const REQUEST: OneBotRequestEvent = {
time: 1_700_000_006,
self_id: 10000,
post_type: 'request',
request_type: 'friend',
flag: 'flag-friend-1',
user_id: 20004,
comment: 'please',
};
const META: OneBotMetaEvent = {
time: 1_700_000_007,
self_id: 10000,
post_type: 'meta_event',
meta_event_type: 'heartbeat',
};
const UNKNOWN: SnowLumaEvent = {
time: 1_700_000_008,
self_id: 10000,
post_type: 'unknown',
};
describe('isMessageEvent', () => {
it('accepts inbound private and group messages', () => {
expect(isMessageEvent(PRIVATE_MESSAGE)).toBe(true);
expect(isMessageEvent(GROUP_MESSAGE)).toBe(true);
});
it('accepts message_sent private and group events', () => {
expect(isMessageEvent(PRIVATE_SENT)).toBe(true);
expect(isMessageEvent(GROUP_SENT)).toBe(true);
});
it('rejects message post types whose message_type is not private or group', () => {
const guild: SnowLumaEvent = {
time: 9,
self_id: 10000,
post_type: 'message',
message_type: 'guild',
};
const sentChannel: SnowLumaEvent = {
time: 10,
self_id: 10000,
post_type: 'message_sent',
message_type: 'channel',
};
const missingType: SnowLumaEvent = {
time: 11,
self_id: 10000,
post_type: 'message',
};
expect(isMessageEvent(guild)).toBe(false);
expect(isMessageEvent(sentChannel)).toBe(false);
expect(isMessageEvent(missingType)).toBe(false);
});
it('rejects non-message events even when message_type is present', () => {
const noticeShaped: SnowLumaEvent = {
time: 12,
self_id: 10000,
post_type: 'notice',
notice_type: 'notify',
message_type: 'private',
};
expect(isMessageEvent(NOTICE)).toBe(false);
expect(isMessageEvent(REQUEST)).toBe(false);
expect(isMessageEvent(META)).toBe(false);
expect(isMessageEvent(UNKNOWN)).toBe(false);
expect(isMessageEvent(noticeShaped)).toBe(false);
});
});
describe('isPrivateMessageEvent', () => {
it('accepts private inbound and sent messages', () => {
expect(isPrivateMessageEvent(PRIVATE_MESSAGE)).toBe(true);
expect(isPrivateMessageEvent(PRIVATE_SENT)).toBe(true);
});
it('rejects group messages and non-message events', () => {
expect(isPrivateMessageEvent(GROUP_MESSAGE)).toBe(false);
expect(isPrivateMessageEvent(GROUP_SENT)).toBe(false);
expect(isPrivateMessageEvent(NOTICE)).toBe(false);
expect(isPrivateMessageEvent(REQUEST)).toBe(false);
expect(isPrivateMessageEvent(META)).toBe(false);
});
it('rejects private message_type when post_type is not a message kind', () => {
const leftover: SnowLumaEvent = {
time: 13,
self_id: 10000,
post_type: 'notice',
notice_type: 'friend_add',
message_type: 'private',
};
expect(isPrivateMessageEvent(leftover)).toBe(false);
});
});
describe('isGroupMessageEvent', () => {
it('accepts group inbound and sent messages', () => {
expect(isGroupMessageEvent(GROUP_MESSAGE)).toBe(true);
expect(isGroupMessageEvent(GROUP_SENT)).toBe(true);
});
it('rejects private messages and non-message events', () => {
expect(isGroupMessageEvent(PRIVATE_MESSAGE)).toBe(false);
expect(isGroupMessageEvent(PRIVATE_SENT)).toBe(false);
expect(isGroupMessageEvent(NOTICE)).toBe(false);
expect(isGroupMessageEvent(REQUEST)).toBe(false);
expect(isGroupMessageEvent(META)).toBe(false);
});
it('rejects group message_type when post_type is not a message kind', () => {
const leftover: SnowLumaEvent = {
time: 14,
self_id: 10000,
post_type: 'request',
request_type: 'group',
flag: 'flag-x',
message_type: 'group',
};
expect(isGroupMessageEvent(leftover)).toBe(false);
});
});
describe('isNoticeEvent', () => {
it('accepts notice events with a string notice_type', () => {
expect(isNoticeEvent(NOTICE)).toBe(true);
expect(
isNoticeEvent({
time: 15,
self_id: 10000,
post_type: 'notice',
notice_type: '',
}),
).toBe(true);
});
it('rejects notice post_type when notice_type is not a string', () => {
const missing: SnowLumaEvent = {
time: 16,
self_id: 10000,
post_type: 'notice',
};
const numeric: SnowLumaEvent = {
time: 17,
self_id: 10000,
post_type: 'notice',
notice_type: 7,
};
const nulled: SnowLumaEvent = {
time: 18,
self_id: 10000,
post_type: 'notice',
notice_type: null,
};
expect(isNoticeEvent(missing)).toBe(false);
expect(isNoticeEvent(numeric)).toBe(false);
expect(isNoticeEvent(nulled)).toBe(false);
});
it('accepts bot_status notices and rejects incomplete ones', () => {
expect(
isBotStatusEvent({
time: 19,
self_id: 10000,
post_type: 'notice',
notice_type: 'bot_status',
sub_type: 'online',
user_id: 10000,
}),
).toBe(true);
expect(
isBotStatusEvent({
time: 20,
self_id: 10000,
post_type: 'notice',
notice_type: 'bot_status',
sub_type: 'offline',
user_id: 10000,
}),
).toBe(true);
expect(isBotStatusEvent(NOTICE)).toBe(false);
expect(
isBotStatusEvent({
time: 21,
self_id: 10000,
post_type: 'notice',
notice_type: 'bot_status',
sub_type: 'flap',
user_id: 10000,
}),
).toBe(false);
});
it('rejects other post types', () => {
expect(isNoticeEvent(PRIVATE_MESSAGE)).toBe(false);
expect(isNoticeEvent(REQUEST)).toBe(false);
expect(isNoticeEvent(META)).toBe(false);
expect(isNoticeEvent(UNKNOWN)).toBe(false);
});
});
describe('isRequestEvent', () => {
it('accepts request events with string request_type and flag', () => {
expect(isRequestEvent(REQUEST)).toBe(true);
expect(
isRequestEvent({
time: 19,
self_id: 10000,
post_type: 'request',
request_type: 'group',
sub_type: 'add',
flag: '',
group_id: 30003,
}),
).toBe(true);
});
it('rejects request post_type when request_type or flag is not a string', () => {
const missingFlag: SnowLumaEvent = {
time: 20,
self_id: 10000,
post_type: 'request',
request_type: 'friend',
};
const numericFlag: SnowLumaEvent = {
time: 21,
self_id: 10000,
post_type: 'request',
request_type: 'friend',
flag: 99,
};
const missingType: SnowLumaEvent = {
time: 22,
self_id: 10000,
post_type: 'request',
flag: 'flag-2',
};
const numericType: SnowLumaEvent = {
time: 23,
self_id: 10000,
post_type: 'request',
request_type: 1,
flag: 'flag-3',
};
const nullFlag: SnowLumaEvent = {
time: 24,
self_id: 10000,
post_type: 'request',
request_type: 'friend',
flag: null,
};
expect(isRequestEvent(missingFlag)).toBe(false);
expect(isRequestEvent(numericFlag)).toBe(false);
expect(isRequestEvent(missingType)).toBe(false);
expect(isRequestEvent(numericType)).toBe(false);
expect(isRequestEvent(nullFlag)).toBe(false);
});
it('rejects other post types even when request fields are present', () => {
const leftover: SnowLumaEvent = {
time: 25,
self_id: 10000,
post_type: 'notice',
notice_type: 'group_ban',
request_type: 'group',
flag: 'flag-4',
};
expect(isRequestEvent(PRIVATE_MESSAGE)).toBe(false);
expect(isRequestEvent(NOTICE)).toBe(false);
expect(isRequestEvent(META)).toBe(false);
expect(isRequestEvent(leftover)).toBe(false);
});
});
describe('isMetaEvent', () => {
it('accepts meta_event events with a string meta_event_type', () => {
expect(isMetaEvent(META)).toBe(true);
expect(
isMetaEvent({
time: 26,
self_id: 10000,
post_type: 'meta_event',
meta_event_type: 'lifecycle',
}),
).toBe(true);
});
it('rejects meta_event post_type when meta_event_type is not a string', () => {
const missing: SnowLumaEvent = {
time: 27,
self_id: 10000,
post_type: 'meta_event',
};
const numeric: SnowLumaEvent = {
time: 28,
self_id: 10000,
post_type: 'meta_event',
meta_event_type: 0,
};
const nulled: SnowLumaEvent = {
time: 29,
self_id: 10000,
post_type: 'meta_event',
meta_event_type: null,
};
expect(isMetaEvent(missing)).toBe(false);
expect(isMetaEvent(numeric)).toBe(false);
expect(isMetaEvent(nulled)).toBe(false);
});
it('rejects other post types', () => {
expect(isMetaEvent(PRIVATE_MESSAGE)).toBe(false);
expect(isMetaEvent(NOTICE)).toBe(false);
expect(isMetaEvent(REQUEST)).toBe(false);
expect(isMetaEvent(UNKNOWN)).toBe(false);
});
});
describe('noticeType', () => {
it('matches notice events by notice_type', () => {
const isIncrease = noticeType('group_increase');
const isDecrease = noticeType('group_decrease');
expect(isIncrease(NOTICE)).toBe(true);
expect(isDecrease(NOTICE)).toBe(false);
expect(
isIncrease({
time: 30,
self_id: 10000,
post_type: 'notice',
notice_type: 'group_decrease',
}),
).toBe(false);
});
it('rejects events that fail isNoticeEvent', () => {
const isIncrease = noticeType('group_increase');
const missingType: SnowLumaEvent = {
time: 31,
self_id: 10000,
post_type: 'notice',
};
const leftover: SnowLumaEvent = {
time: 32,
self_id: 10000,
post_type: 'message',
message_type: 'private',
notice_type: 'group_increase',
};
expect(isIncrease(missingType)).toBe(false);
expect(isIncrease(leftover)).toBe(false);
expect(isIncrease(REQUEST)).toBe(false);
expect(isIncrease(PRIVATE_MESSAGE)).toBe(false);
});
});
describe('requestType', () => {
it('matches request events by request_type', () => {
const isFriend = requestType('friend');
const isGroup = requestType('group');
expect(isFriend(REQUEST)).toBe(true);
expect(isGroup(REQUEST)).toBe(false);
expect(
isFriend({
time: 33,
self_id: 10000,
post_type: 'request',
request_type: 'group',
flag: 'flag-group-1',
}),
).toBe(false);
});
it('rejects events that fail isRequestEvent', () => {
const isFriend = requestType('friend');
const missingFlag: SnowLumaEvent = {
time: 34,
self_id: 10000,
post_type: 'request',
request_type: 'friend',
};
const leftover: SnowLumaEvent = {
time: 35,
self_id: 10000,
post_type: 'notice',
notice_type: 'friend_add',
request_type: 'friend',
flag: 'flag-5',
};
expect(isFriend(missingFlag)).toBe(false);
expect(isFriend(leftover)).toBe(false);
expect(isFriend(NOTICE)).toBe(false);
expect(isFriend(META)).toBe(false);
});
});