- Replaced Express with Elysia for improved performance and type safety - Integrated Elysia middleware for rate limiting, security headers, and request validation - Refactored security utilities to work with Elysia's context and request handling - Updated token management and validation logic - Added comprehensive security headers and input sanitization - Simplified server initialization and error handling - Updated documentation with new setup and configuration details
144 lines
3.5 KiB
TypeScript
144 lines
3.5 KiB
TypeScript
import { config } from "dotenv";
|
|
import path from "path";
|
|
import {
|
|
beforeAll,
|
|
afterAll,
|
|
beforeEach,
|
|
describe,
|
|
expect,
|
|
it,
|
|
mock,
|
|
test,
|
|
} from "bun:test";
|
|
|
|
// Type definitions for mocks
|
|
type MockFn = ReturnType<typeof mock>;
|
|
|
|
interface MockInstance {
|
|
mock: {
|
|
calls: unknown[][];
|
|
results: unknown[];
|
|
instances: unknown[];
|
|
lastCall?: unknown[];
|
|
};
|
|
}
|
|
|
|
// Test configuration
|
|
const TEST_CONFIG = {
|
|
TEST_JWT_SECRET: "test_jwt_secret_key_that_is_at_least_32_chars",
|
|
TEST_TOKEN: "test_token_that_is_at_least_32_chars_long",
|
|
TEST_CLIENT_IP: "127.0.0.1",
|
|
};
|
|
|
|
// Load test environment variables
|
|
config({ path: path.resolve(process.cwd(), ".env.test") });
|
|
|
|
// Global test setup
|
|
beforeAll(() => {
|
|
// Set required environment variables
|
|
process.env.NODE_ENV = "test";
|
|
process.env.JWT_SECRET = TEST_CONFIG.TEST_JWT_SECRET;
|
|
process.env.TEST_TOKEN = TEST_CONFIG.TEST_TOKEN;
|
|
|
|
// Configure console output for tests
|
|
if (!process.env.DEBUG) {
|
|
console.error = mock(() => { });
|
|
console.warn = mock(() => { });
|
|
console.log = mock(() => { });
|
|
}
|
|
});
|
|
|
|
// Reset mocks between tests
|
|
beforeEach(() => {
|
|
// Clear all mock function calls
|
|
const mockFns = Object.values(mock).filter(
|
|
(value): value is MockFn => typeof value === "function" && "mock" in value,
|
|
);
|
|
mockFns.forEach((mockFn) => {
|
|
if (mockFn.mock) {
|
|
mockFn.mock.calls = [];
|
|
mockFn.mock.results = [];
|
|
mockFn.mock.instances = [];
|
|
mockFn.mock.lastCall = undefined;
|
|
}
|
|
});
|
|
});
|
|
|
|
// Custom test utilities
|
|
const testUtils = {
|
|
// Mock WebSocket for SSE tests
|
|
mockWebSocket: () => ({
|
|
on: mock(() => { }),
|
|
send: mock(() => { }),
|
|
close: mock(() => { }),
|
|
readyState: 1,
|
|
OPEN: 1,
|
|
removeAllListeners: mock(() => { }),
|
|
}),
|
|
|
|
// Mock HTTP response for API tests
|
|
mockResponse: () => {
|
|
const res = {
|
|
status: mock(() => res),
|
|
json: mock(() => res),
|
|
send: mock(() => res),
|
|
end: mock(() => res),
|
|
setHeader: mock(() => res),
|
|
writeHead: mock(() => res),
|
|
write: mock(() => true),
|
|
removeHeader: mock(() => res),
|
|
};
|
|
return res;
|
|
},
|
|
|
|
// Mock HTTP request for API tests
|
|
mockRequest: (overrides: Record<string, unknown> = {}) => ({
|
|
headers: { "content-type": "application/json" },
|
|
body: {},
|
|
query: {},
|
|
params: {},
|
|
ip: TEST_CONFIG.TEST_CLIENT_IP,
|
|
method: "GET",
|
|
path: "/api/test",
|
|
is: mock((type: string) => type === "application/json"),
|
|
...overrides,
|
|
}),
|
|
|
|
// Create test client for SSE tests
|
|
createTestClient: (id = "test-client") => ({
|
|
id,
|
|
ip: TEST_CONFIG.TEST_CLIENT_IP,
|
|
connectedAt: new Date(),
|
|
send: mock(() => { }),
|
|
rateLimit: {
|
|
count: 0,
|
|
lastReset: Date.now(),
|
|
},
|
|
connectionTime: Date.now(),
|
|
}),
|
|
|
|
// Create test event for SSE tests
|
|
createTestEvent: (type = "test_event", data: unknown = {}) => ({
|
|
event_type: type,
|
|
data,
|
|
origin: "test",
|
|
time_fired: new Date().toISOString(),
|
|
context: { id: "test" },
|
|
}),
|
|
|
|
// Create test entity for Home Assistant tests
|
|
createTestEntity: (entityId = "test.entity", state = "on") => ({
|
|
entity_id: entityId,
|
|
state,
|
|
attributes: {},
|
|
last_changed: new Date().toISOString(),
|
|
last_updated: new Date().toISOString(),
|
|
}),
|
|
|
|
// Helper to wait for async operations
|
|
wait: (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
};
|
|
|
|
// Export test utilities and Bun test functions
|
|
export { beforeAll, afterAll, beforeEach, describe, expect, it, mock, test, testUtils };
|