refactor(extensions): reuse shared helper primitives
This commit is contained in:
@@ -317,20 +317,11 @@ describe("createSynologyChatPlugin", () => {
|
||||
});
|
||||
|
||||
describe("gateway", () => {
|
||||
it("startAccount returns pending promise for disabled account", async () => {
|
||||
const plugin = createSynologyChatPlugin();
|
||||
const abortController = new AbortController();
|
||||
const ctx = {
|
||||
cfg: {
|
||||
channels: { "synology-chat": { enabled: false } },
|
||||
},
|
||||
accountId: "default",
|
||||
log: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
||||
abortSignal: abortController.signal,
|
||||
};
|
||||
const result = plugin.gateway.startAccount(ctx);
|
||||
async function expectPendingStartAccountPromise(
|
||||
result: Promise<unknown>,
|
||||
abortController: AbortController,
|
||||
) {
|
||||
expect(result).toBeInstanceOf(Promise);
|
||||
// Promise should stay pending (never resolve) to prevent restart loop
|
||||
const resolved = await Promise.race([
|
||||
result,
|
||||
new Promise((r) => setTimeout(() => r("pending"), 50)),
|
||||
@@ -338,29 +329,29 @@ describe("createSynologyChatPlugin", () => {
|
||||
expect(resolved).toBe("pending");
|
||||
abortController.abort();
|
||||
await result;
|
||||
}
|
||||
|
||||
async function expectPendingStartAccount(accountConfig: Record<string, unknown>) {
|
||||
const plugin = createSynologyChatPlugin();
|
||||
const abortController = new AbortController();
|
||||
const ctx = {
|
||||
cfg: {
|
||||
channels: { "synology-chat": accountConfig },
|
||||
},
|
||||
accountId: "default",
|
||||
log: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
||||
abortSignal: abortController.signal,
|
||||
};
|
||||
const result = plugin.gateway.startAccount(ctx);
|
||||
await expectPendingStartAccountPromise(result, abortController);
|
||||
}
|
||||
|
||||
it("startAccount returns pending promise for disabled account", async () => {
|
||||
await expectPendingStartAccount({ enabled: false });
|
||||
});
|
||||
|
||||
it("startAccount returns pending promise for account without token", async () => {
|
||||
const plugin = createSynologyChatPlugin();
|
||||
const abortController = new AbortController();
|
||||
const ctx = {
|
||||
cfg: {
|
||||
channels: { "synology-chat": { enabled: true } },
|
||||
},
|
||||
accountId: "default",
|
||||
log: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
||||
abortSignal: abortController.signal,
|
||||
};
|
||||
const result = plugin.gateway.startAccount(ctx);
|
||||
expect(result).toBeInstanceOf(Promise);
|
||||
// Promise should stay pending (never resolve) to prevent restart loop
|
||||
const resolved = await Promise.race([
|
||||
result,
|
||||
new Promise((r) => setTimeout(() => r("pending"), 50)),
|
||||
]);
|
||||
expect(resolved).toBe("pending");
|
||||
abortController.abort();
|
||||
await result;
|
||||
await expectPendingStartAccount({ enabled: true });
|
||||
});
|
||||
|
||||
it("startAccount refuses allowlist accounts with empty allowedUserIds", async () => {
|
||||
@@ -387,16 +378,9 @@ describe("createSynologyChatPlugin", () => {
|
||||
};
|
||||
|
||||
const result = plugin.gateway.startAccount(ctx);
|
||||
expect(result).toBeInstanceOf(Promise);
|
||||
const resolved = await Promise.race([
|
||||
result,
|
||||
new Promise((r) => setTimeout(() => r("pending"), 50)),
|
||||
]);
|
||||
expect(resolved).toBe("pending");
|
||||
await expectPendingStartAccountPromise(result, abortController);
|
||||
expect(ctx.log.warn).toHaveBeenCalledWith(expect.stringContaining("empty allowedUserIds"));
|
||||
expect(registerMock).not.toHaveBeenCalled();
|
||||
abortController.abort();
|
||||
await result;
|
||||
});
|
||||
|
||||
it("deregisters stale route before re-registering same account/path", async () => {
|
||||
|
||||
@@ -118,26 +118,21 @@ describe("sendFileUrl", () => {
|
||||
function mockUserListResponse(
|
||||
users: Array<{ user_id: number; username: string; nickname: string }>,
|
||||
) {
|
||||
const httpsGet = vi.mocked((https as any).get);
|
||||
httpsGet.mockImplementation((_url: any, _opts: any, callback: any) => {
|
||||
const res = new EventEmitter() as any;
|
||||
res.statusCode = 200;
|
||||
process.nextTick(() => {
|
||||
callback(res);
|
||||
res.emit("data", Buffer.from(JSON.stringify({ success: true, data: { users } })));
|
||||
res.emit("end");
|
||||
});
|
||||
const req = new EventEmitter() as any;
|
||||
req.destroy = vi.fn();
|
||||
return req;
|
||||
});
|
||||
mockUserListResponseImpl(users, false);
|
||||
}
|
||||
|
||||
function mockUserListResponseOnce(
|
||||
users: Array<{ user_id: number; username: string; nickname: string }>,
|
||||
) {
|
||||
mockUserListResponseImpl(users, true);
|
||||
}
|
||||
|
||||
function mockUserListResponseImpl(
|
||||
users: Array<{ user_id: number; username: string; nickname: string }>,
|
||||
once: boolean,
|
||||
) {
|
||||
const httpsGet = vi.mocked((https as any).get);
|
||||
httpsGet.mockImplementationOnce((_url: any, _opts: any, callback: any) => {
|
||||
const impl = (_url: any, _opts: any, callback: any) => {
|
||||
const res = new EventEmitter() as any;
|
||||
res.statusCode = 200;
|
||||
process.nextTick(() => {
|
||||
@@ -148,7 +143,12 @@ function mockUserListResponseOnce(
|
||||
const req = new EventEmitter() as any;
|
||||
req.destroy = vi.fn();
|
||||
return req;
|
||||
});
|
||||
};
|
||||
if (once) {
|
||||
httpsGet.mockImplementationOnce(impl);
|
||||
return;
|
||||
}
|
||||
httpsGet.mockImplementation(impl);
|
||||
}
|
||||
|
||||
describe("resolveChatUserId", () => {
|
||||
|
||||
Reference in New Issue
Block a user