fix tests
This commit is contained in:
parent
fecc028709
commit
d9093572ac
@ -1,9 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(pnpm build:*)",
|
||||
"Bash(pnpm test:*)",
|
||||
"Bash(pnpm -w run test:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -3,13 +3,50 @@ import { probeTwitch } from "./probe.js";
|
||||
import type { TwitchAccountConfig } from "./types.js";
|
||||
|
||||
// Mock Twurple modules - Vitest v4 compatible mocking
|
||||
const mockConnect = vi.fn().mockResolvedValue(undefined);
|
||||
const mockUnbind = vi.fn();
|
||||
|
||||
// Event handler storage
|
||||
let connectHandler: (() => void) | null = null;
|
||||
let disconnectHandler: ((manually: boolean, reason?: Error) => void) | null = null;
|
||||
let authFailHandler: (() => void) | null = null;
|
||||
|
||||
// Event listener mocks that store handlers and return unbind function
|
||||
const mockOnConnect = vi.fn((handler: () => void) => {
|
||||
connectHandler = handler;
|
||||
return { unbind: mockUnbind };
|
||||
});
|
||||
|
||||
const mockOnDisconnect = vi.fn((handler: (manually: boolean, reason?: Error) => void) => {
|
||||
disconnectHandler = handler;
|
||||
return { unbind: mockUnbind };
|
||||
});
|
||||
|
||||
const mockOnAuthenticationFailure = vi.fn((handler: () => void) => {
|
||||
authFailHandler = handler;
|
||||
return { unbind: mockUnbind };
|
||||
});
|
||||
|
||||
// Connect mock that triggers the registered handler
|
||||
const defaultConnectImpl = async () => {
|
||||
// Simulate successful connection by calling the handler after a delay
|
||||
if (connectHandler) {
|
||||
// Use setTimeout to simulate async connection
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
connectHandler();
|
||||
}
|
||||
};
|
||||
|
||||
const mockConnect = vi.fn().mockImplementation(defaultConnectImpl);
|
||||
|
||||
const mockQuit = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
vi.mock("@twurple/chat", () => ({
|
||||
ChatClient: class {
|
||||
connect = mockConnect;
|
||||
quit = mockQuit;
|
||||
onConnect = mockOnConnect;
|
||||
onDisconnect = mockOnDisconnect;
|
||||
onAuthenticationFailure = mockOnAuthenticationFailure;
|
||||
},
|
||||
}));
|
||||
|
||||
@ -25,6 +62,10 @@ describe("probeTwitch", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
// Reset handlers
|
||||
connectHandler = null;
|
||||
disconnectHandler = null;
|
||||
authFailHandler = null;
|
||||
});
|
||||
|
||||
it("returns error when username is missing", async () => {
|
||||
@ -85,11 +126,18 @@ describe("probeTwitch", () => {
|
||||
expect(result.error).toContain("timeout");
|
||||
|
||||
// Reset mock
|
||||
mockConnect.mockResolvedValue(undefined);
|
||||
mockConnect.mockImplementation(defaultConnectImpl);
|
||||
});
|
||||
|
||||
it("cleans up client even on failure", async () => {
|
||||
mockConnect.mockRejectedValueOnce(new Error("Connection failed"));
|
||||
mockConnect.mockImplementationOnce(async () => {
|
||||
// Simulate connection failure by calling disconnect handler
|
||||
// onDisconnect signature: (manually: boolean, reason?: Error) => void
|
||||
if (disconnectHandler) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
disconnectHandler(false, new Error("Connection failed"));
|
||||
}
|
||||
});
|
||||
|
||||
const result = await probeTwitch(mockAccount, 5000);
|
||||
|
||||
@ -98,7 +146,7 @@ describe("probeTwitch", () => {
|
||||
expect(mockQuit).toHaveBeenCalled();
|
||||
|
||||
// Reset mocks
|
||||
mockConnect.mockResolvedValue(undefined);
|
||||
mockConnect.mockImplementation(defaultConnectImpl);
|
||||
});
|
||||
|
||||
it("measures elapsed time", async () => {
|
||||
@ -109,7 +157,14 @@ describe("probeTwitch", () => {
|
||||
});
|
||||
|
||||
it("handles connection errors gracefully", async () => {
|
||||
mockConnect.mockRejectedValueOnce(new Error("Network error"));
|
||||
mockConnect.mockImplementationOnce(async () => {
|
||||
// Simulate connection failure by calling disconnect handler
|
||||
// onDisconnect signature: (manually: boolean, reason?: Error) => void
|
||||
if (disconnectHandler) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
disconnectHandler(false, new Error("Network error"));
|
||||
}
|
||||
});
|
||||
|
||||
const result = await probeTwitch(mockAccount, 5000);
|
||||
|
||||
@ -117,7 +172,7 @@ describe("probeTwitch", () => {
|
||||
expect(result.error).toContain("Network error");
|
||||
|
||||
// Reset mock
|
||||
mockConnect.mockResolvedValue(undefined);
|
||||
mockConnect.mockImplementation(defaultConnectImpl);
|
||||
});
|
||||
|
||||
it("trims token before validation", async () => {
|
||||
@ -132,7 +187,14 @@ describe("probeTwitch", () => {
|
||||
});
|
||||
|
||||
it("handles non-Error objects in catch block", async () => {
|
||||
mockConnect.mockRejectedValueOnce("String error");
|
||||
mockConnect.mockImplementationOnce(async () => {
|
||||
// Simulate connection failure by calling disconnect handler
|
||||
// onDisconnect signature: (manually: boolean, reason?: Error) => void
|
||||
if (disconnectHandler) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
disconnectHandler(false, "String error" as unknown as Error);
|
||||
}
|
||||
});
|
||||
|
||||
const result = await probeTwitch(mockAccount, 5000);
|
||||
|
||||
@ -140,6 +202,6 @@ describe("probeTwitch", () => {
|
||||
expect(result.error).toBe("String error");
|
||||
|
||||
// Reset mock
|
||||
mockConnect.mockResolvedValue(undefined);
|
||||
mockConnect.mockImplementation(defaultConnectImpl);
|
||||
});
|
||||
});
|
||||
|
||||
@ -18,8 +18,23 @@ const mockConnect = vi.fn().mockResolvedValue(undefined);
|
||||
const mockJoin = vi.fn().mockResolvedValue(undefined);
|
||||
const mockSay = vi.fn().mockResolvedValue({ messageId: "test-msg-123" });
|
||||
const mockQuit = vi.fn();
|
||||
const mockOnMessage = vi.fn();
|
||||
const mockOnWhisper = vi.fn();
|
||||
const mockUnbind = vi.fn();
|
||||
|
||||
// Event handler storage for testing
|
||||
const messageHandlers: Array<(channel: string, user: string, message: string, msg: any) => void> = [];
|
||||
const whisperHandlers: Array<(user: string, message: string, msg: any) => void> = [];
|
||||
|
||||
// Mock functions that track handlers and return unbind objects
|
||||
const mockOnMessage = vi.fn((handler: any) => {
|
||||
messageHandlers.push(handler);
|
||||
return { unbind: mockUnbind };
|
||||
});
|
||||
|
||||
const mockOnWhisper = vi.fn((handler: any) => {
|
||||
whisperHandlers.push(handler);
|
||||
return { unbind: mockUnbind };
|
||||
});
|
||||
|
||||
const mockAddUserForToken = vi.fn().mockResolvedValue("123456");
|
||||
const mockOnRefresh = vi.fn();
|
||||
const mockOnRefreshFailure = vi.fn();
|
||||
@ -33,6 +48,14 @@ vi.mock("@twurple/chat", () => ({
|
||||
say = mockSay;
|
||||
quit = mockQuit;
|
||||
},
|
||||
LogLevel: {
|
||||
CRITICAL: "CRITICAL",
|
||||
ERROR: "ERROR",
|
||||
WARNING: "WARNING",
|
||||
INFO: "INFO",
|
||||
DEBUG: "DEBUG",
|
||||
TRACE: "TRACE",
|
||||
},
|
||||
}));
|
||||
|
||||
const mockAuthProvider = {
|
||||
@ -85,6 +108,10 @@ describe("TwitchClientManager", () => {
|
||||
// Clear all mocks first
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Clear handler arrays
|
||||
messageHandlers.length = 0;
|
||||
whisperHandlers.length = 0;
|
||||
|
||||
// Re-set up the default token mock implementation after clearing
|
||||
const { resolveTwitchToken } = await import("./token.js");
|
||||
vi.mocked(resolveTwitchToken).mockReturnValue({
|
||||
@ -396,7 +423,7 @@ describe("TwitchClientManager", () => {
|
||||
await manager.getClient(testAccount);
|
||||
|
||||
// Get the onMessage callback
|
||||
const onMessageCallback = mockOnMessage.mock.calls[0]?.[0];
|
||||
const onMessageCallback = messageHandlers[0];
|
||||
if (!onMessageCallback) throw new Error("onMessageCallback not found");
|
||||
|
||||
// Simulate Twitch message
|
||||
@ -426,7 +453,7 @@ describe("TwitchClientManager", () => {
|
||||
await manager.getClient(testAccount);
|
||||
|
||||
// Get the onWhisper callback
|
||||
const onWhisperCallback = mockOnWhisper.mock.calls[0]?.[0];
|
||||
const onWhisperCallback = whisperHandlers[0];
|
||||
if (!onWhisperCallback) throw new Error("onWhisperCallback not found");
|
||||
|
||||
// Simulate Twitch whisper
|
||||
@ -452,7 +479,7 @@ describe("TwitchClientManager", () => {
|
||||
it("should normalize channel names without # prefix", async () => {
|
||||
await manager.getClient(testAccount);
|
||||
|
||||
const onMessageCallback = mockOnMessage.mock.calls[0]?.[0];
|
||||
const onMessageCallback = messageHandlers[0];
|
||||
|
||||
onMessageCallback("testchannel", "testuser", "Test", {
|
||||
userInfo: {
|
||||
@ -473,7 +500,7 @@ describe("TwitchClientManager", () => {
|
||||
it("should include user role flags in message", async () => {
|
||||
await manager.getClient(testAccount);
|
||||
|
||||
const onMessageCallback = mockOnMessage.mock.calls[0]?.[0];
|
||||
const onMessageCallback = messageHandlers[0];
|
||||
|
||||
onMessageCallback("#testchannel", "moduser", "Test", {
|
||||
userInfo: {
|
||||
@ -497,7 +524,7 @@ describe("TwitchClientManager", () => {
|
||||
it("should handle broadcaster messages", async () => {
|
||||
await manager.getClient(testAccount);
|
||||
|
||||
const onMessageCallback = mockOnMessage.mock.calls[0]?.[0];
|
||||
const onMessageCallback = messageHandlers[0];
|
||||
|
||||
onMessageCallback("#testchannel", "broadcaster", "Test", {
|
||||
userInfo: {
|
||||
@ -528,7 +555,7 @@ describe("TwitchClientManager", () => {
|
||||
await manager.getClient(testAccount2);
|
||||
|
||||
// Simulate message for first account
|
||||
const onMessage1 = mockOnMessage.mock.calls[0]?.[0];
|
||||
const onMessage1 = messageHandlers[0];
|
||||
if (!onMessage1) throw new Error("onMessage1 not found");
|
||||
onMessage1("#testchannel", "user1", "msg1", {
|
||||
userInfo: {
|
||||
@ -544,7 +571,7 @@ describe("TwitchClientManager", () => {
|
||||
});
|
||||
|
||||
// Simulate message for second account
|
||||
const onMessage2 = mockOnMessage.mock.calls[1]?.[0];
|
||||
const onMessage2 = messageHandlers[1];
|
||||
if (!onMessage2) throw new Error("onMessage2 not found");
|
||||
onMessage2("#testchannel2", "user2", "msg2", {
|
||||
userInfo: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user