124 lines
4.0 KiB
TypeScript
124 lines
4.0 KiB
TypeScript
import { afterEach, describe, expect, test, vi } from 'vitest';
|
|
import { NapCatCore } from '../napcat-core/index';
|
|
import type { SelfStatusInfo, SelfInfo } from '../napcat-core/types';
|
|
|
|
interface FakeProfileListener {
|
|
onSelfStatusChanged: (info: SelfStatusInfo) => void;
|
|
}
|
|
|
|
interface FakeMessageListener {
|
|
onKickedOffLine: (info: { tipsTitle: string; tipsDesc: string; }) => void;
|
|
}
|
|
|
|
function status (value: number): SelfStatusInfo {
|
|
return {
|
|
uid: 'self-uid',
|
|
status: value,
|
|
extStatus: 0,
|
|
termType: 0,
|
|
netType: 0,
|
|
iconType: 0,
|
|
customStatus: undefined,
|
|
setTime: '0',
|
|
};
|
|
}
|
|
|
|
function createCore (online: boolean | undefined) {
|
|
let profileListener: FakeProfileListener | undefined;
|
|
let messageListener: FakeMessageListener | undefined;
|
|
const session = {
|
|
getMsgService: () => ({
|
|
addKernelMsgListener: vi.fn((listener: FakeMessageListener) => {
|
|
messageListener = listener;
|
|
}),
|
|
}),
|
|
getProfileService: () => ({
|
|
addKernelProfileListener: vi.fn((listener: FakeProfileListener) => {
|
|
profileListener = listener;
|
|
}),
|
|
}),
|
|
};
|
|
const logger = {
|
|
log: vi.fn(),
|
|
logError: vi.fn(),
|
|
logWarn: vi.fn(),
|
|
logDebug: vi.fn(),
|
|
};
|
|
const emit = vi.fn();
|
|
// NapCatCore's constructor loads the native wrapper, which is unavailable in tests.
|
|
// Only the listener wiring is under test, so the instance is built field-by-field.
|
|
const core = Object.create(NapCatCore.prototype) as NapCatCore;
|
|
Object.assign(core, {
|
|
context: { logger, session },
|
|
selfInfo: { uid: 'self-uid', uin: '1', online } as SelfInfo,
|
|
event: { emit },
|
|
});
|
|
return {
|
|
core,
|
|
emit,
|
|
profileListener: () => profileListener,
|
|
messageListener: () => messageListener,
|
|
};
|
|
}
|
|
|
|
describe('silent offline (SelfOffline) event', () => {
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
test('emits SelfOffline when the account transitions online -> offline', async () => {
|
|
const { core, emit, profileListener } = createCore(true);
|
|
await core.initNapCatCoreListeners();
|
|
|
|
profileListener()!.onSelfStatusChanged(status(20));
|
|
|
|
expect(emit).toHaveBeenCalledTimes(1);
|
|
expect(emit).toHaveBeenCalledWith('SelfOffline', expect.stringContaining('账号状态变更为离线'));
|
|
expect(core.selfInfo.online).toBe(false);
|
|
});
|
|
|
|
test('does not emit again while the account stays offline', async () => {
|
|
const { core, emit, profileListener } = createCore(true);
|
|
await core.initNapCatCoreListeners();
|
|
|
|
profileListener()!.onSelfStatusChanged(status(20));
|
|
profileListener()!.onSelfStatusChanged(status(20));
|
|
profileListener()!.onSelfStatusChanged(status(20));
|
|
|
|
expect(emit).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
test('emits again after the account recovered and went offline once more', async () => {
|
|
const { core, emit, profileListener } = createCore(true);
|
|
await core.initNapCatCoreListeners();
|
|
|
|
profileListener()!.onSelfStatusChanged(status(20));
|
|
profileListener()!.onSelfStatusChanged(status(10));
|
|
profileListener()!.onSelfStatusChanged(status(20));
|
|
|
|
expect(emit).toHaveBeenCalledTimes(2);
|
|
expect(core.selfInfo.online).toBe(false);
|
|
});
|
|
|
|
test('does not emit during startup when the account was never online', async () => {
|
|
const { core, emit, profileListener } = createCore(undefined);
|
|
await core.initNapCatCoreListeners();
|
|
|
|
profileListener()!.onSelfStatusChanged(status(20));
|
|
|
|
expect(emit).not.toHaveBeenCalled();
|
|
expect(core.selfInfo.online).toBe(false);
|
|
});
|
|
|
|
test('keeps emitting KickedOffLine as before', async () => {
|
|
const { core, emit, messageListener } = createCore(true);
|
|
await core.initNapCatCoreListeners();
|
|
|
|
messageListener()!.onKickedOffLine({ tipsTitle: '下线通知', tipsDesc: '当前账号已在其它设备登录' });
|
|
|
|
expect(emit).toHaveBeenCalledTimes(1);
|
|
expect(emit).toHaveBeenCalledWith('KickedOffLine', expect.stringContaining('当前账号已在其它设备登录'));
|
|
expect(core.selfInfo.online).toBe(false);
|
|
});
|
|
});
|