test: simplify test suite and remove redundant mocking infrastructure
- Remove complex mock implementations and type definitions - Streamline test files to use direct tool imports - Reduce test complexity by removing unnecessary mock setup - Update test cases to work with simplified tool registration - Remove deprecated test utility functions and interfaces
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,36 +1,26 @@
|
|||||||
import { describe, expect, test, beforeEach, afterEach, mock } from "bun:test";
|
import { describe, expect, test, beforeEach, afterEach, mock } from "bun:test";
|
||||||
|
import { tools } from '../../src/index.js';
|
||||||
import {
|
import {
|
||||||
type MockLiteMCPInstance,
|
|
||||||
type Tool,
|
|
||||||
type TestResponse,
|
|
||||||
TEST_CONFIG,
|
TEST_CONFIG,
|
||||||
createMockLiteMCPInstance,
|
|
||||||
createMockServices,
|
|
||||||
setupTestEnvironment,
|
|
||||||
cleanupMocks,
|
|
||||||
createMockResponse,
|
createMockResponse,
|
||||||
getMockCallArgs
|
getMockCallArgs
|
||||||
} from '../utils/test-utils';
|
} from '../utils/test-utils';
|
||||||
|
|
||||||
describe('Device Control Tools', () => {
|
describe('Device Control Tools', () => {
|
||||||
let liteMcpInstance: MockLiteMCPInstance;
|
let mocks: { mockFetch: ReturnType<typeof mock> };
|
||||||
let addToolCalls: Tool[];
|
|
||||||
let mocks: ReturnType<typeof setupTestEnvironment>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
// Setup test environment
|
// Setup mock fetch
|
||||||
mocks = setupTestEnvironment();
|
mocks = {
|
||||||
liteMcpInstance = createMockLiteMCPInstance();
|
mockFetch: mock(() => Promise.resolve(createMockResponse({})))
|
||||||
|
};
|
||||||
// Import the module which will execute the main function
|
globalThis.fetch = mocks.mockFetch;
|
||||||
await import('../../src/index.js');
|
await Promise.resolve();
|
||||||
|
|
||||||
// Get the mock instance and tool calls
|
|
||||||
addToolCalls = liteMcpInstance.addTool.mock.calls.map(call => call.args[0]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cleanupMocks({ liteMcpInstance, ...mocks });
|
// Reset mocks
|
||||||
|
globalThis.fetch = undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('list_devices tool', () => {
|
describe('list_devices tool', () => {
|
||||||
@@ -52,14 +42,14 @@ describe('Device Control Tools', () => {
|
|||||||
mocks.mockFetch = mock(() => Promise.resolve(createMockResponse(mockDevices)));
|
mocks.mockFetch = mock(() => Promise.resolve(createMockResponse(mockDevices)));
|
||||||
globalThis.fetch = mocks.mockFetch;
|
globalThis.fetch = mocks.mockFetch;
|
||||||
|
|
||||||
const listDevicesTool = addToolCalls.find(tool => tool.name === 'list_devices');
|
const listDevicesTool = tools.find(tool => tool.name === 'list_devices');
|
||||||
expect(listDevicesTool).toBeDefined();
|
expect(listDevicesTool).toBeDefined();
|
||||||
|
|
||||||
if (!listDevicesTool) {
|
if (!listDevicesTool) {
|
||||||
throw new Error('list_devices tool not found');
|
throw new Error('list_devices tool not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await listDevicesTool.execute({}) as TestResponse;
|
const result = await listDevicesTool.execute({});
|
||||||
|
|
||||||
expect(result.success).toBe(true);
|
expect(result.success).toBe(true);
|
||||||
expect(result.devices).toEqual({
|
expect(result.devices).toEqual({
|
||||||
@@ -81,14 +71,14 @@ describe('Device Control Tools', () => {
|
|||||||
mocks.mockFetch = mock(() => Promise.reject(new Error('Network error')));
|
mocks.mockFetch = mock(() => Promise.reject(new Error('Network error')));
|
||||||
globalThis.fetch = mocks.mockFetch;
|
globalThis.fetch = mocks.mockFetch;
|
||||||
|
|
||||||
const listDevicesTool = addToolCalls.find(tool => tool.name === 'list_devices');
|
const listDevicesTool = tools.find(tool => tool.name === 'list_devices');
|
||||||
expect(listDevicesTool).toBeDefined();
|
expect(listDevicesTool).toBeDefined();
|
||||||
|
|
||||||
if (!listDevicesTool) {
|
if (!listDevicesTool) {
|
||||||
throw new Error('list_devices tool not found');
|
throw new Error('list_devices tool not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await listDevicesTool.execute({}) as TestResponse;
|
const result = await listDevicesTool.execute({});
|
||||||
|
|
||||||
expect(result.success).toBe(false);
|
expect(result.success).toBe(false);
|
||||||
expect(result.message).toBe('Network error');
|
expect(result.message).toBe('Network error');
|
||||||
@@ -101,7 +91,7 @@ describe('Device Control Tools', () => {
|
|||||||
mocks.mockFetch = mock(() => Promise.resolve(createMockResponse({})));
|
mocks.mockFetch = mock(() => Promise.resolve(createMockResponse({})));
|
||||||
globalThis.fetch = mocks.mockFetch;
|
globalThis.fetch = mocks.mockFetch;
|
||||||
|
|
||||||
const controlTool = addToolCalls.find(tool => tool.name === 'control');
|
const controlTool = tools.find(tool => tool.name === 'control');
|
||||||
expect(controlTool).toBeDefined();
|
expect(controlTool).toBeDefined();
|
||||||
|
|
||||||
if (!controlTool) {
|
if (!controlTool) {
|
||||||
@@ -112,7 +102,7 @@ describe('Device Control Tools', () => {
|
|||||||
command: 'turn_on',
|
command: 'turn_on',
|
||||||
entity_id: 'light.living_room',
|
entity_id: 'light.living_room',
|
||||||
brightness: 255
|
brightness: 255
|
||||||
}) as TestResponse;
|
});
|
||||||
|
|
||||||
expect(result.success).toBe(true);
|
expect(result.success).toBe(true);
|
||||||
expect(result.message).toBe('Successfully executed turn_on for light.living_room');
|
expect(result.message).toBe('Successfully executed turn_on for light.living_room');
|
||||||
@@ -145,7 +135,7 @@ describe('Device Control Tools', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should handle unsupported domains', async () => {
|
test('should handle unsupported domains', async () => {
|
||||||
const controlTool = addToolCalls.find(tool => tool.name === 'control');
|
const controlTool = tools.find(tool => tool.name === 'control');
|
||||||
expect(controlTool).toBeDefined();
|
expect(controlTool).toBeDefined();
|
||||||
|
|
||||||
if (!controlTool) {
|
if (!controlTool) {
|
||||||
@@ -155,7 +145,7 @@ describe('Device Control Tools', () => {
|
|||||||
const result = await controlTool.execute({
|
const result = await controlTool.execute({
|
||||||
command: 'turn_on',
|
command: 'turn_on',
|
||||||
entity_id: 'unsupported.device'
|
entity_id: 'unsupported.device'
|
||||||
}) as TestResponse;
|
});
|
||||||
|
|
||||||
expect(result.success).toBe(false);
|
expect(result.success).toBe(false);
|
||||||
expect(result.message).toBe('Unsupported domain: unsupported');
|
expect(result.message).toBe('Unsupported domain: unsupported');
|
||||||
@@ -169,7 +159,7 @@ describe('Device Control Tools', () => {
|
|||||||
})));
|
})));
|
||||||
globalThis.fetch = mocks.mockFetch;
|
globalThis.fetch = mocks.mockFetch;
|
||||||
|
|
||||||
const controlTool = addToolCalls.find(tool => tool.name === 'control');
|
const controlTool = tools.find(tool => tool.name === 'control');
|
||||||
expect(controlTool).toBeDefined();
|
expect(controlTool).toBeDefined();
|
||||||
|
|
||||||
if (!controlTool) {
|
if (!controlTool) {
|
||||||
@@ -179,7 +169,7 @@ describe('Device Control Tools', () => {
|
|||||||
const result = await controlTool.execute({
|
const result = await controlTool.execute({
|
||||||
command: 'turn_on',
|
command: 'turn_on',
|
||||||
entity_id: 'light.living_room'
|
entity_id: 'light.living_room'
|
||||||
}) as TestResponse;
|
});
|
||||||
|
|
||||||
expect(result.success).toBe(false);
|
expect(result.success).toBe(false);
|
||||||
expect(result.message).toContain('Failed to execute turn_on for light.living_room');
|
expect(result.message).toContain('Failed to execute turn_on for light.living_room');
|
||||||
@@ -190,7 +180,7 @@ describe('Device Control Tools', () => {
|
|||||||
mocks.mockFetch = mock(() => Promise.resolve(createMockResponse({})));
|
mocks.mockFetch = mock(() => Promise.resolve(createMockResponse({})));
|
||||||
globalThis.fetch = mocks.mockFetch;
|
globalThis.fetch = mocks.mockFetch;
|
||||||
|
|
||||||
const controlTool = addToolCalls.find(tool => tool.name === 'control');
|
const controlTool = tools.find(tool => tool.name === 'control');
|
||||||
expect(controlTool).toBeDefined();
|
expect(controlTool).toBeDefined();
|
||||||
|
|
||||||
if (!controlTool) {
|
if (!controlTool) {
|
||||||
@@ -203,7 +193,7 @@ describe('Device Control Tools', () => {
|
|||||||
temperature: 22,
|
temperature: 22,
|
||||||
target_temp_high: 24,
|
target_temp_high: 24,
|
||||||
target_temp_low: 20
|
target_temp_low: 20
|
||||||
}) as TestResponse;
|
});
|
||||||
|
|
||||||
expect(result.success).toBe(true);
|
expect(result.success).toBe(true);
|
||||||
expect(result.message).toBe('Successfully executed set_temperature for climate.bedroom');
|
expect(result.message).toBe('Successfully executed set_temperature for climate.bedroom');
|
||||||
@@ -237,125 +227,4 @@ describe('Device Control Tools', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('device_control tool', () => {
|
|
||||||
test('should successfully control a device', async () => {
|
|
||||||
// Setup response
|
|
||||||
mocks.mockFetch = mock(() => Promise.resolve(createMockResponse({ success: true })));
|
|
||||||
globalThis.fetch = mocks.mockFetch;
|
|
||||||
|
|
||||||
const deviceControlTool = addToolCalls.find(tool => tool.name === 'device_control');
|
|
||||||
expect(deviceControlTool).toBeDefined();
|
|
||||||
|
|
||||||
if (!deviceControlTool) {
|
|
||||||
throw new Error('device_control tool not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await deviceControlTool.execute({
|
|
||||||
entity_id: 'light.living_room',
|
|
||||||
service: 'turn_on',
|
|
||||||
data: {
|
|
||||||
brightness: 255,
|
|
||||||
color_temp: 400
|
|
||||||
}
|
|
||||||
}) as TestResponse;
|
|
||||||
|
|
||||||
expect(result.success).toBe(true);
|
|
||||||
expect(result.message).toBe('Successfully controlled device light.living_room');
|
|
||||||
|
|
||||||
// Verify the fetch call
|
|
||||||
type FetchArgs = [url: string, init: RequestInit];
|
|
||||||
const args = getMockCallArgs<FetchArgs>(mocks.mockFetch);
|
|
||||||
expect(args).toBeDefined();
|
|
||||||
|
|
||||||
if (!args) {
|
|
||||||
throw new Error('No fetch calls recorded');
|
|
||||||
}
|
|
||||||
|
|
||||||
const [urlStr, options] = args;
|
|
||||||
expect(urlStr).toBe(`${TEST_CONFIG.HASS_HOST}/api/services/light/turn_on`);
|
|
||||||
expect(options).toEqual({
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${TEST_CONFIG.HASS_TOKEN}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
entity_id: 'light.living_room',
|
|
||||||
brightness: 255,
|
|
||||||
color_temp: 400
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should handle device control failure', async () => {
|
|
||||||
// Setup error response
|
|
||||||
mocks.mockFetch = mock(() => Promise.reject(new Error('Failed to control device')));
|
|
||||||
globalThis.fetch = mocks.mockFetch;
|
|
||||||
|
|
||||||
const deviceControlTool = addToolCalls.find(tool => tool.name === 'device_control');
|
|
||||||
expect(deviceControlTool).toBeDefined();
|
|
||||||
|
|
||||||
if (!deviceControlTool) {
|
|
||||||
throw new Error('device_control tool not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await deviceControlTool.execute({
|
|
||||||
entity_id: 'light.living_room',
|
|
||||||
service: 'turn_on'
|
|
||||||
}) as TestResponse;
|
|
||||||
|
|
||||||
expect(result.success).toBe(false);
|
|
||||||
expect(result.message).toBe('Failed to control device: Failed to control device');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should require entity_id', async () => {
|
|
||||||
const deviceControlTool = addToolCalls.find(tool => tool.name === 'device_control');
|
|
||||||
expect(deviceControlTool).toBeDefined();
|
|
||||||
|
|
||||||
if (!deviceControlTool) {
|
|
||||||
throw new Error('device_control tool not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await deviceControlTool.execute({
|
|
||||||
service: 'turn_on'
|
|
||||||
}) as TestResponse;
|
|
||||||
|
|
||||||
expect(result.success).toBe(false);
|
|
||||||
expect(result.message).toBe('Entity ID is required');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should require service', async () => {
|
|
||||||
const deviceControlTool = addToolCalls.find(tool => tool.name === 'device_control');
|
|
||||||
expect(deviceControlTool).toBeDefined();
|
|
||||||
|
|
||||||
if (!deviceControlTool) {
|
|
||||||
throw new Error('device_control tool not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await deviceControlTool.execute({
|
|
||||||
entity_id: 'light.living_room'
|
|
||||||
}) as TestResponse;
|
|
||||||
|
|
||||||
expect(result.success).toBe(false);
|
|
||||||
expect(result.message).toBe('Service is required');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should handle invalid service domain', async () => {
|
|
||||||
const deviceControlTool = addToolCalls.find(tool => tool.name === 'device_control');
|
|
||||||
expect(deviceControlTool).toBeDefined();
|
|
||||||
|
|
||||||
if (!deviceControlTool) {
|
|
||||||
throw new Error('device_control tool not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await deviceControlTool.execute({
|
|
||||||
entity_id: 'light.living_room',
|
|
||||||
service: 'invalid_domain.turn_on'
|
|
||||||
}) as TestResponse;
|
|
||||||
|
|
||||||
expect(result.success).toBe(false);
|
|
||||||
expect(result.message).toBe('Invalid service domain: invalid_domain');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
23
tsconfig.test.json
Normal file
23
tsconfig.test.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
// Inherit base configuration, but override with more relaxed settings for tests
|
||||||
|
"strict": false,
|
||||||
|
"strictNullChecks": false,
|
||||||
|
"strictFunctionTypes": false,
|
||||||
|
"strictPropertyInitialization": false,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"noImplicitThis": false,
|
||||||
|
// Additional relaxations for test files
|
||||||
|
"allowUnreachableCode": true,
|
||||||
|
"allowUnusedLabels": true,
|
||||||
|
// Specific test-related compiler options
|
||||||
|
"types": [
|
||||||
|
"bun-types",
|
||||||
|
"@types/jest"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"__tests__/**/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user