mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-21 15:55:50 +00:00
style: 完成所有文件的lint
This commit is contained in:
@@ -1,172 +1,192 @@
|
||||
import { describe, test, expect, mock, beforeEach } from "bun:test";
|
||||
import { describe, test, expect, mock, beforeEach } from 'bun:test'
|
||||
|
||||
// In-memory localStorage mock
|
||||
let store: Record<string, string> = {};
|
||||
let store: Record<string, string> = {}
|
||||
|
||||
beforeEach(() => {
|
||||
store = {};
|
||||
(globalThis as any).localStorage = {
|
||||
store = {}
|
||||
;(globalThis as any).localStorage = {
|
||||
getItem: (k: string) => store[k] ?? null,
|
||||
setItem: (k: string, v: string) => { store[k] = v; },
|
||||
removeItem: (k: string) => { delete store[k]; },
|
||||
clear: () => { store = {}; },
|
||||
get length() { return Object.keys(store).length; },
|
||||
setItem: (k: string, v: string) => {
|
||||
store[k] = v
|
||||
},
|
||||
removeItem: (k: string) => {
|
||||
delete store[k]
|
||||
},
|
||||
clear: () => {
|
||||
store = {}
|
||||
},
|
||||
get length() {
|
||||
return Object.keys(store).length
|
||||
},
|
||||
key: () => null,
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
// Mock fetch
|
||||
const fetchMock = {
|
||||
lastUrl: "",
|
||||
lastUrl: '',
|
||||
lastOpts: {} as RequestInit,
|
||||
response: { ok: true, status: 200, statusText: "OK" },
|
||||
response: { ok: true, status: 200, statusText: 'OK' },
|
||||
responseData: {} as any,
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
fetchMock.lastUrl = "";
|
||||
fetchMock.lastOpts = {};
|
||||
fetchMock.response = { ok: true, status: 200, statusText: "OK" };
|
||||
fetchMock.responseData = {};
|
||||
client.setActiveApiToken(null);
|
||||
});
|
||||
fetchMock.lastUrl = ''
|
||||
fetchMock.lastOpts = {}
|
||||
fetchMock.response = { ok: true, status: 200, statusText: 'OK' }
|
||||
fetchMock.responseData = {}
|
||||
client.setActiveApiToken(null)
|
||||
})
|
||||
|
||||
(globalThis as any).fetch = async (url: string, opts: RequestInit) => {
|
||||
fetchMock.lastUrl = url;
|
||||
fetchMock.lastOpts = opts;
|
||||
;(globalThis as any).fetch = async (url: string, opts: RequestInit) => {
|
||||
fetchMock.lastUrl = url
|
||||
fetchMock.lastOpts = opts
|
||||
return {
|
||||
ok: fetchMock.response.ok,
|
||||
status: fetchMock.response.status,
|
||||
statusText: fetchMock.response.statusText,
|
||||
json: async () => fetchMock.responseData,
|
||||
} as Response;
|
||||
};
|
||||
} as Response
|
||||
}
|
||||
|
||||
const { getUuid, setUuid } = await import("../api/client");
|
||||
const { getUuid, setUuid } = await import('../api/client')
|
||||
|
||||
// Import api* functions - they depend on getUuid and fetch
|
||||
const client = await import("../api/client");
|
||||
const relayClient = await import("../acp/relay-client");
|
||||
const client = await import('../api/client')
|
||||
const relayClient = await import('../acp/relay-client')
|
||||
|
||||
// =============================================================================
|
||||
// getUuid()
|
||||
// =============================================================================
|
||||
|
||||
describe("getUuid", () => {
|
||||
test("returns existing UUID from localStorage", () => {
|
||||
store["rcs_uuid"] = "existing-uuid";
|
||||
expect(getUuid()).toBe("existing-uuid");
|
||||
});
|
||||
describe('getUuid', () => {
|
||||
test('returns existing UUID from localStorage', () => {
|
||||
store['rcs_uuid'] = 'existing-uuid'
|
||||
expect(getUuid()).toBe('existing-uuid')
|
||||
})
|
||||
|
||||
test("generates and stores new UUID when none exists", () => {
|
||||
const uuid = getUuid();
|
||||
test('generates and stores new UUID when none exists', () => {
|
||||
const uuid = getUuid()
|
||||
expect(uuid).toMatch(
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
|
||||
);
|
||||
expect(store["rcs_uuid"]).toBe(uuid);
|
||||
});
|
||||
)
|
||||
expect(store['rcs_uuid']).toBe(uuid)
|
||||
})
|
||||
|
||||
test("returns same UUID on subsequent calls", () => {
|
||||
const a = getUuid();
|
||||
const b = getUuid();
|
||||
expect(a).toBe(b);
|
||||
});
|
||||
});
|
||||
test('returns same UUID on subsequent calls', () => {
|
||||
const a = getUuid()
|
||||
const b = getUuid()
|
||||
expect(a).toBe(b)
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// setUuid()
|
||||
// =============================================================================
|
||||
|
||||
describe("setUuid", () => {
|
||||
test("writes UUID to localStorage", () => {
|
||||
setUuid("custom-uuid-999");
|
||||
expect(store["rcs_uuid"]).toBe("custom-uuid-999");
|
||||
});
|
||||
describe('setUuid', () => {
|
||||
test('writes UUID to localStorage', () => {
|
||||
setUuid('custom-uuid-999')
|
||||
expect(store['rcs_uuid']).toBe('custom-uuid-999')
|
||||
})
|
||||
|
||||
test("getUuid returns the set UUID", () => {
|
||||
setUuid("my-uuid");
|
||||
expect(getUuid()).toBe("my-uuid");
|
||||
});
|
||||
});
|
||||
test('getUuid returns the set UUID', () => {
|
||||
setUuid('my-uuid')
|
||||
expect(getUuid()).toBe('my-uuid')
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// api() — tested via apiFetchSession (GET) and apiBind (POST)
|
||||
// =============================================================================
|
||||
|
||||
describe("api functions", () => {
|
||||
test("GET request appends uuid to URL", async () => {
|
||||
store["rcs_uuid"] = "test-uuid";
|
||||
fetchMock.responseData = [];
|
||||
await client.apiFetchSessions();
|
||||
expect(fetchMock.lastUrl).toContain("uuid=test-uuid");
|
||||
expect(fetchMock.lastOpts.method).toBe("GET");
|
||||
});
|
||||
describe('api functions', () => {
|
||||
test('GET request appends uuid to URL', async () => {
|
||||
store['rcs_uuid'] = 'test-uuid'
|
||||
fetchMock.responseData = []
|
||||
await client.apiFetchSessions()
|
||||
expect(fetchMock.lastUrl).toContain('uuid=test-uuid')
|
||||
expect(fetchMock.lastOpts.method).toBe('GET')
|
||||
})
|
||||
|
||||
test("GET request uses ? for URL without existing query params", async () => {
|
||||
store["rcs_uuid"] = "test-uuid";
|
||||
fetchMock.responseData = [];
|
||||
await client.apiFetchSessions();
|
||||
expect(fetchMock.lastUrl).toContain("?uuid=");
|
||||
});
|
||||
test('GET request uses ? for URL without existing query params', async () => {
|
||||
store['rcs_uuid'] = 'test-uuid'
|
||||
fetchMock.responseData = []
|
||||
await client.apiFetchSessions()
|
||||
expect(fetchMock.lastUrl).toContain('?uuid=')
|
||||
})
|
||||
|
||||
test("GET request uses & for URL with existing query params", async () => {
|
||||
store["rcs_uuid"] = "test-uuid";
|
||||
fetchMock.responseData = [];
|
||||
await client.apiFetchAllSessions();
|
||||
test('GET request uses & for URL with existing query params', async () => {
|
||||
store['rcs_uuid'] = 'test-uuid'
|
||||
fetchMock.responseData = []
|
||||
await client.apiFetchAllSessions()
|
||||
// apiFetchAllSessions calls GET /web/sessions/all
|
||||
expect(fetchMock.lastUrl).toContain("?uuid=");
|
||||
});
|
||||
expect(fetchMock.lastUrl).toContain('?uuid=')
|
||||
})
|
||||
|
||||
test("POST request includes JSON body", async () => {
|
||||
store["rcs_uuid"] = "test-uuid";
|
||||
fetchMock.responseData = {};
|
||||
await client.apiBind("sess-1");
|
||||
expect(fetchMock.lastOpts.method).toBe("POST");
|
||||
expect(fetchMock.lastOpts.body).toBe(JSON.stringify({ sessionId: "sess-1" }));
|
||||
expect(fetchMock.lastOpts.headers).toEqual({ "Content-Type": "application/json" });
|
||||
});
|
||||
|
||||
test("active API token is sent only in Authorization header", async () => {
|
||||
store["rcs_uuid"] = "browser-uuid";
|
||||
fetchMock.responseData = [];
|
||||
client.setActiveApiToken("secret-token");
|
||||
|
||||
await client.apiFetchSessions();
|
||||
|
||||
expect(fetchMock.lastUrl).toContain("uuid=browser-uuid");
|
||||
expect(fetchMock.lastUrl).not.toContain("secret-token");
|
||||
test('POST request includes JSON body', async () => {
|
||||
store['rcs_uuid'] = 'test-uuid'
|
||||
fetchMock.responseData = {}
|
||||
await client.apiBind('sess-1')
|
||||
expect(fetchMock.lastOpts.method).toBe('POST')
|
||||
expect(fetchMock.lastOpts.body).toBe(
|
||||
JSON.stringify({ sessionId: 'sess-1' }),
|
||||
)
|
||||
expect(fetchMock.lastOpts.headers).toEqual({
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer secret-token",
|
||||
});
|
||||
});
|
||||
'Content-Type': 'application/json',
|
||||
})
|
||||
})
|
||||
|
||||
test("throws error on non-ok response", async () => {
|
||||
store["rcs_uuid"] = "test-uuid";
|
||||
fetchMock.response = { ok: false, status: 401, statusText: "Unauthorized" };
|
||||
fetchMock.responseData = { error: { type: "auth", message: "Invalid UUID" } };
|
||||
await expect(client.apiFetchSessions()).rejects.toThrow("Invalid UUID");
|
||||
});
|
||||
test('active API token is sent only in Authorization header', async () => {
|
||||
store['rcs_uuid'] = 'browser-uuid'
|
||||
fetchMock.responseData = []
|
||||
client.setActiveApiToken('secret-token')
|
||||
|
||||
test("throws with statusText when error message is missing", async () => {
|
||||
store["rcs_uuid"] = "test-uuid";
|
||||
fetchMock.response = { ok: false, status: 500, statusText: "Internal Server Error" };
|
||||
fetchMock.responseData = {};
|
||||
await expect(client.apiFetchSessions()).rejects.toThrow("Internal Server Error");
|
||||
});
|
||||
});
|
||||
await client.apiFetchSessions()
|
||||
|
||||
describe("ACP relay client", () => {
|
||||
test("builds relay URLs without UUID or token query params", () => {
|
||||
(globalThis as any).window = {
|
||||
expect(fetchMock.lastUrl).toContain('uuid=browser-uuid')
|
||||
expect(fetchMock.lastUrl).not.toContain('secret-token')
|
||||
expect(fetchMock.lastOpts.headers).toEqual({
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'Bearer secret-token',
|
||||
})
|
||||
})
|
||||
|
||||
test('throws error on non-ok response', async () => {
|
||||
store['rcs_uuid'] = 'test-uuid'
|
||||
fetchMock.response = { ok: false, status: 401, statusText: 'Unauthorized' }
|
||||
fetchMock.responseData = {
|
||||
error: { type: 'auth', message: 'Invalid UUID' },
|
||||
}
|
||||
await expect(client.apiFetchSessions()).rejects.toThrow('Invalid UUID')
|
||||
})
|
||||
|
||||
test('throws with statusText when error message is missing', async () => {
|
||||
store['rcs_uuid'] = 'test-uuid'
|
||||
fetchMock.response = {
|
||||
ok: false,
|
||||
status: 500,
|
||||
statusText: 'Internal Server Error',
|
||||
}
|
||||
fetchMock.responseData = {}
|
||||
await expect(client.apiFetchSessions()).rejects.toThrow(
|
||||
'Internal Server Error',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('ACP relay client', () => {
|
||||
test('builds relay URLs without UUID or token query params', () => {
|
||||
;(globalThis as any).window = {
|
||||
location: {
|
||||
protocol: "https:",
|
||||
host: "rcs.example.test",
|
||||
protocol: 'https:',
|
||||
host: 'rcs.example.test',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
expect(relayClient.buildRelayUrl("agent_123")).toBe(
|
||||
"wss://rcs.example.test/acp/relay/agent_123",
|
||||
);
|
||||
});
|
||||
});
|
||||
expect(relayClient.buildRelayUrl('agent_123')).toBe(
|
||||
'wss://rcs.example.test/acp/relay/agent_123',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, describe, test, expect } from "bun:test";
|
||||
import { afterEach, describe, test, expect } from 'bun:test'
|
||||
|
||||
const {
|
||||
formatTime,
|
||||
@@ -8,273 +8,284 @@ const {
|
||||
generateMessageUuid,
|
||||
extractEventText,
|
||||
isConversationClearedStatus,
|
||||
} = await import("../lib/utils");
|
||||
} = await import('../lib/utils')
|
||||
|
||||
type UuidCrypto = {
|
||||
randomUUID?: () => string;
|
||||
getRandomValues?: (array: Uint8Array) => Uint8Array;
|
||||
};
|
||||
randomUUID?: () => string
|
||||
getRandomValues?: (array: Uint8Array) => Uint8Array
|
||||
}
|
||||
|
||||
const originalCryptoDescriptor = Object.getOwnPropertyDescriptor(globalThis, "crypto");
|
||||
const originalCryptoDescriptor = Object.getOwnPropertyDescriptor(
|
||||
globalThis,
|
||||
'crypto',
|
||||
)
|
||||
|
||||
function setCryptoForTest(value: UuidCrypto): void {
|
||||
Object.defineProperty(globalThis, "crypto", {
|
||||
Object.defineProperty(globalThis, 'crypto', {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function restoreCryptoForTest(): void {
|
||||
if (originalCryptoDescriptor) {
|
||||
Object.defineProperty(globalThis, "crypto", originalCryptoDescriptor);
|
||||
Object.defineProperty(globalThis, 'crypto', originalCryptoDescriptor)
|
||||
} else {
|
||||
Reflect.deleteProperty(globalThis, "crypto");
|
||||
Reflect.deleteProperty(globalThis, 'crypto')
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
restoreCryptoForTest();
|
||||
});
|
||||
restoreCryptoForTest()
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// formatTime()
|
||||
// =============================================================================
|
||||
|
||||
describe("formatTime", () => {
|
||||
test("returns empty string for null", () => {
|
||||
expect(formatTime(null)).toBe("");
|
||||
});
|
||||
describe('formatTime', () => {
|
||||
test('returns empty string for null', () => {
|
||||
expect(formatTime(null)).toBe('')
|
||||
})
|
||||
|
||||
test("returns empty string for undefined", () => {
|
||||
expect(formatTime(undefined)).toBe("");
|
||||
});
|
||||
test('returns empty string for undefined', () => {
|
||||
expect(formatTime(undefined)).toBe('')
|
||||
})
|
||||
|
||||
test("returns empty string for 0", () => {
|
||||
expect(formatTime(0)).toBe("");
|
||||
});
|
||||
test('returns empty string for 0', () => {
|
||||
expect(formatTime(0)).toBe('')
|
||||
})
|
||||
|
||||
test("formats valid unix timestamp", () => {
|
||||
const result = formatTime(1700000000);
|
||||
expect(result).toContain("2023");
|
||||
});
|
||||
});
|
||||
test('formats valid unix timestamp', () => {
|
||||
const result = formatTime(1700000000)
|
||||
expect(result).toContain('2023')
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// statusClass()
|
||||
// =============================================================================
|
||||
|
||||
describe("statusClass", () => {
|
||||
test("maps known statuses correctly", () => {
|
||||
expect(statusClass("active")).toBe("active");
|
||||
expect(statusClass("running")).toBe("running");
|
||||
expect(statusClass("idle")).toBe("idle");
|
||||
expect(statusClass("inactive")).toBe("inactive");
|
||||
expect(statusClass("requires_action")).toBe("requires_action");
|
||||
expect(statusClass("archived")).toBe("archived");
|
||||
expect(statusClass("error")).toBe("error");
|
||||
});
|
||||
describe('statusClass', () => {
|
||||
test('maps known statuses correctly', () => {
|
||||
expect(statusClass('active')).toBe('active')
|
||||
expect(statusClass('running')).toBe('running')
|
||||
expect(statusClass('idle')).toBe('idle')
|
||||
expect(statusClass('inactive')).toBe('inactive')
|
||||
expect(statusClass('requires_action')).toBe('requires_action')
|
||||
expect(statusClass('archived')).toBe('archived')
|
||||
expect(statusClass('error')).toBe('error')
|
||||
})
|
||||
|
||||
test("returns default for unknown status", () => {
|
||||
expect(statusClass("unknown")).toBe("default");
|
||||
});
|
||||
test('returns default for unknown status', () => {
|
||||
expect(statusClass('unknown')).toBe('default')
|
||||
})
|
||||
|
||||
test("returns default for null", () => {
|
||||
expect(statusClass(null)).toBe("default");
|
||||
});
|
||||
test('returns default for null', () => {
|
||||
expect(statusClass(null)).toBe('default')
|
||||
})
|
||||
|
||||
test("returns default for undefined", () => {
|
||||
expect(statusClass(undefined)).toBe("default");
|
||||
});
|
||||
test('returns default for undefined', () => {
|
||||
expect(statusClass(undefined)).toBe('default')
|
||||
})
|
||||
|
||||
test("returns default for empty string", () => {
|
||||
expect(statusClass("")).toBe("default");
|
||||
});
|
||||
});
|
||||
test('returns default for empty string', () => {
|
||||
expect(statusClass('')).toBe('default')
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// isClosedSessionStatus()
|
||||
// =============================================================================
|
||||
|
||||
describe("isClosedSessionStatus", () => {
|
||||
test("returns true for archived", () => {
|
||||
expect(isClosedSessionStatus("archived")).toBe(true);
|
||||
});
|
||||
describe('isClosedSessionStatus', () => {
|
||||
test('returns true for archived', () => {
|
||||
expect(isClosedSessionStatus('archived')).toBe(true)
|
||||
})
|
||||
|
||||
test("returns true for inactive", () => {
|
||||
expect(isClosedSessionStatus("inactive")).toBe(true);
|
||||
});
|
||||
test('returns true for inactive', () => {
|
||||
expect(isClosedSessionStatus('inactive')).toBe(true)
|
||||
})
|
||||
|
||||
test("returns false for active", () => {
|
||||
expect(isClosedSessionStatus("active")).toBe(false);
|
||||
});
|
||||
test('returns false for active', () => {
|
||||
expect(isClosedSessionStatus('active')).toBe(false)
|
||||
})
|
||||
|
||||
test("returns false for null", () => {
|
||||
expect(isClosedSessionStatus(null)).toBe(false);
|
||||
});
|
||||
test('returns false for null', () => {
|
||||
expect(isClosedSessionStatus(null)).toBe(false)
|
||||
})
|
||||
|
||||
test("returns false for undefined", () => {
|
||||
expect(isClosedSessionStatus(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
test('returns false for undefined', () => {
|
||||
expect(isClosedSessionStatus(undefined)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// truncate()
|
||||
// =============================================================================
|
||||
|
||||
describe("truncate", () => {
|
||||
test("returns empty string for null", () => {
|
||||
expect(truncate(null, 10)).toBe("");
|
||||
});
|
||||
describe('truncate', () => {
|
||||
test('returns empty string for null', () => {
|
||||
expect(truncate(null, 10)).toBe('')
|
||||
})
|
||||
|
||||
test("returns empty string for undefined", () => {
|
||||
expect(truncate(undefined, 10)).toBe("");
|
||||
});
|
||||
test('returns empty string for undefined', () => {
|
||||
expect(truncate(undefined, 10)).toBe('')
|
||||
})
|
||||
|
||||
test("returns original string when shorter than max", () => {
|
||||
expect(truncate("hello", 10)).toBe("hello");
|
||||
});
|
||||
test('returns original string when shorter than max', () => {
|
||||
expect(truncate('hello', 10)).toBe('hello')
|
||||
})
|
||||
|
||||
test("returns original string when exactly max length", () => {
|
||||
expect(truncate("12345", 5)).toBe("12345");
|
||||
});
|
||||
test('returns original string when exactly max length', () => {
|
||||
expect(truncate('12345', 5)).toBe('12345')
|
||||
})
|
||||
|
||||
test("truncates and appends ... when longer than max", () => {
|
||||
expect(truncate("hello world", 5)).toBe("hello...");
|
||||
});
|
||||
});
|
||||
test('truncates and appends ... when longer than max', () => {
|
||||
expect(truncate('hello world', 5)).toBe('hello...')
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// generateMessageUuid()
|
||||
// =============================================================================
|
||||
|
||||
describe("generateMessageUuid", () => {
|
||||
test("returns an RFC 4122 v4 UUID", () => {
|
||||
const uuid = generateMessageUuid();
|
||||
expect(typeof uuid).toBe("string");
|
||||
describe('generateMessageUuid', () => {
|
||||
test('returns an RFC 4122 v4 UUID', () => {
|
||||
const uuid = generateMessageUuid()
|
||||
expect(typeof uuid).toBe('string')
|
||||
expect(uuid).toMatch(
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
|
||||
);
|
||||
});
|
||||
)
|
||||
})
|
||||
|
||||
test("uses crypto.randomUUID when available", () => {
|
||||
test('uses crypto.randomUUID when available', () => {
|
||||
setCryptoForTest({
|
||||
randomUUID: () => "11111111-1111-4111-8111-111111111111",
|
||||
randomUUID: () => '11111111-1111-4111-8111-111111111111',
|
||||
getRandomValues: () => {
|
||||
throw new Error("getRandomValues should not be called");
|
||||
throw new Error('getRandomValues should not be called')
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
expect(generateMessageUuid()).toBe("11111111-1111-4111-8111-111111111111");
|
||||
});
|
||||
expect(generateMessageUuid()).toBe('11111111-1111-4111-8111-111111111111')
|
||||
})
|
||||
|
||||
test("uses crypto.getRandomValues when randomUUID is unavailable", () => {
|
||||
test('uses crypto.getRandomValues when randomUUID is unavailable', () => {
|
||||
setCryptoForTest({
|
||||
getRandomValues: (array) => {
|
||||
getRandomValues: array => {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
array[i] = i;
|
||||
array[i] = i
|
||||
}
|
||||
return array;
|
||||
return array
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
expect(generateMessageUuid()).toBe("00010203-0405-4607-8809-0a0b0c0d0e0f");
|
||||
});
|
||||
expect(generateMessageUuid()).toBe('00010203-0405-4607-8809-0a0b0c0d0e0f')
|
||||
})
|
||||
|
||||
test("throws when no secure random source is available", () => {
|
||||
setCryptoForTest({});
|
||||
test('throws when no secure random source is available', () => {
|
||||
setCryptoForTest({})
|
||||
|
||||
expect(() => generateMessageUuid()).toThrow("crypto.getRandomValues is required");
|
||||
});
|
||||
});
|
||||
expect(() => generateMessageUuid()).toThrow(
|
||||
'crypto.getRandomValues is required',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// extractEventText()
|
||||
// =============================================================================
|
||||
|
||||
describe("extractEventText", () => {
|
||||
test("returns empty string for null", () => {
|
||||
expect(extractEventText(null)).toBe("");
|
||||
});
|
||||
describe('extractEventText', () => {
|
||||
test('returns empty string for null', () => {
|
||||
expect(extractEventText(null)).toBe('')
|
||||
})
|
||||
|
||||
test("returns empty string for undefined", () => {
|
||||
expect(extractEventText(undefined)).toBe("");
|
||||
});
|
||||
test('returns empty string for undefined', () => {
|
||||
expect(extractEventText(undefined)).toBe('')
|
||||
})
|
||||
|
||||
test("returns empty string for non-object", () => {
|
||||
expect(extractEventText("string" as any)).toBe("");
|
||||
});
|
||||
test('returns empty string for non-object', () => {
|
||||
expect(extractEventText('string' as any)).toBe('')
|
||||
})
|
||||
|
||||
test("extracts payload.content string", () => {
|
||||
expect(extractEventText({ content: "hello" })).toBe("hello");
|
||||
});
|
||||
test('extracts payload.content string', () => {
|
||||
expect(extractEventText({ content: 'hello' })).toBe('hello')
|
||||
})
|
||||
|
||||
test("extracts from message.content text blocks array", () => {
|
||||
test('extracts from message.content text blocks array', () => {
|
||||
const payload = {
|
||||
message: {
|
||||
content: [
|
||||
{ type: "text", text: "line 1" },
|
||||
{ type: "text", text: "line 2" },
|
||||
{ type: 'text', text: 'line 1' },
|
||||
{ type: 'text', text: 'line 2' },
|
||||
],
|
||||
},
|
||||
};
|
||||
expect(extractEventText(payload)).toBe("line 1\nline 2");
|
||||
});
|
||||
}
|
||||
expect(extractEventText(payload)).toBe('line 1\nline 2')
|
||||
})
|
||||
|
||||
test("ignores non-text blocks", () => {
|
||||
test('ignores non-text blocks', () => {
|
||||
const payload = {
|
||||
message: {
|
||||
content: [
|
||||
{ type: "image", data: "base64..." },
|
||||
{ type: "text", text: "only text" },
|
||||
{ type: 'image', data: 'base64...' },
|
||||
{ type: 'text', text: 'only text' },
|
||||
],
|
||||
},
|
||||
};
|
||||
expect(extractEventText(payload)).toBe("only text");
|
||||
});
|
||||
}
|
||||
expect(extractEventText(payload)).toBe('only text')
|
||||
})
|
||||
|
||||
test("returns empty string when message.content has no text blocks", () => {
|
||||
test('returns empty string when message.content has no text blocks', () => {
|
||||
const payload = {
|
||||
message: { content: [{ type: "image", data: "base64" }] },
|
||||
};
|
||||
expect(extractEventText(payload)).toBe("");
|
||||
});
|
||||
message: { content: [{ type: 'image', data: 'base64' }] },
|
||||
}
|
||||
expect(extractEventText(payload)).toBe('')
|
||||
})
|
||||
|
||||
test("returns empty string for empty object", () => {
|
||||
expect(extractEventText({})).toBe("");
|
||||
});
|
||||
});
|
||||
test('returns empty string for empty object', () => {
|
||||
expect(extractEventText({})).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// isConversationClearedStatus()
|
||||
// =============================================================================
|
||||
|
||||
describe("isConversationClearedStatus", () => {
|
||||
test("returns true when payload.status is conversation_cleared", () => {
|
||||
expect(isConversationClearedStatus({ status: "conversation_cleared" })).toBe(true);
|
||||
});
|
||||
describe('isConversationClearedStatus', () => {
|
||||
test('returns true when payload.status is conversation_cleared', () => {
|
||||
expect(
|
||||
isConversationClearedStatus({ status: 'conversation_cleared' }),
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
test("returns true when payload.raw.status is conversation_cleared", () => {
|
||||
expect(isConversationClearedStatus({ raw: { status: "conversation_cleared" } })).toBe(true);
|
||||
});
|
||||
test('returns true when payload.raw.status is conversation_cleared', () => {
|
||||
expect(
|
||||
isConversationClearedStatus({ raw: { status: 'conversation_cleared' } }),
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
test("returns false for null", () => {
|
||||
expect(isConversationClearedStatus(null)).toBe(false);
|
||||
});
|
||||
test('returns false for null', () => {
|
||||
expect(isConversationClearedStatus(null)).toBe(false)
|
||||
})
|
||||
|
||||
test("returns false for undefined", () => {
|
||||
expect(isConversationClearedStatus(undefined)).toBe(false);
|
||||
});
|
||||
test('returns false for undefined', () => {
|
||||
expect(isConversationClearedStatus(undefined)).toBe(false)
|
||||
})
|
||||
|
||||
test("returns false for other status", () => {
|
||||
expect(isConversationClearedStatus({ status: "active" })).toBe(false);
|
||||
});
|
||||
test('returns false for other status', () => {
|
||||
expect(isConversationClearedStatus({ status: 'active' })).toBe(false)
|
||||
})
|
||||
|
||||
test("returns false when raw has different status", () => {
|
||||
expect(isConversationClearedStatus({ raw: { status: "running" } })).toBe(false);
|
||||
});
|
||||
test('returns false when raw has different status', () => {
|
||||
expect(isConversationClearedStatus({ raw: { status: 'running' } })).toBe(
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
test("returns false for empty object", () => {
|
||||
expect(isConversationClearedStatus({})).toBe(false);
|
||||
});
|
||||
});
|
||||
test('returns false for empty object', () => {
|
||||
expect(isConversationClearedStatus({})).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user