mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 01:53:53 +08:00
Optimize code : minify test files
This commit is contained in:
@@ -1,154 +1,72 @@
|
||||
/**
|
||||
* Audio recording module tests - Browser compatible version
|
||||
* Test microphone availability detection functionality
|
||||
*
|
||||
* This version works without Vitest - uses the simple test framework from test-runner.html
|
||||
*/
|
||||
|
||||
import { checkMicrophoneAvailability, isHttpNonLocalhost } from './recorder.js';
|
||||
|
||||
describe('Microphone Availability Detection', () => {
|
||||
beforeEach(() => {
|
||||
// Reset mocks before each test
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test checkMicrophoneAvailability function - success case
|
||||
*/
|
||||
test('should return true when microphone is available', async () => {
|
||||
// Mock navigator.mediaDevices.getUserMedia to return a successful stream
|
||||
const mockTrack = {
|
||||
stop: vi.fn()
|
||||
};
|
||||
const mockStream = {
|
||||
getTracks: () => [mockTrack]
|
||||
};
|
||||
|
||||
navigator.mediaDevices.getUserMedia = vi.fn().mockResolvedValue(mockStream);
|
||||
|
||||
const result = await checkMicrophoneAvailability();
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({
|
||||
audio: {
|
||||
echoCancellation: true,
|
||||
noiseSuppression: true,
|
||||
sampleRate: 16000,
|
||||
channelCount: 1
|
||||
}
|
||||
});
|
||||
expect(mockTrack.stop).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test checkMicrophoneAvailability function - failure case
|
||||
*/
|
||||
test('should return false when microphone is not available', async () => {
|
||||
// Mock getUserMedia to throw an error
|
||||
const mockError = new Error('Permission denied');
|
||||
navigator.mediaDevices.getUserMedia = vi.fn().mockRejectedValue(mockError);
|
||||
|
||||
const result = await checkMicrophoneAvailability();
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(navigator.mediaDevices.getUserMedia).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test checkMicrophoneAvailability function - browser not supported
|
||||
*/
|
||||
test('should return false when browser does not support getUserMedia', async () => {
|
||||
// Mock navigator.mediaDevices.getUserMedia to be undefined
|
||||
const originalGetUserMedia = navigator.mediaDevices.getUserMedia;
|
||||
navigator.mediaDevices.getUserMedia = undefined;
|
||||
|
||||
const result = await checkMicrophoneAvailability();
|
||||
|
||||
expect(result).toBe(false);
|
||||
|
||||
// Restore
|
||||
navigator.mediaDevices.getUserMedia = originalGetUserMedia;
|
||||
});
|
||||
|
||||
/**
|
||||
* Test isHttpNonLocalhost function - HTTP non-localhost
|
||||
* Note: window.location properties are read-only in browsers, so we test the logic indirectly
|
||||
*/
|
||||
test('should return true for HTTP non-localhost access', () => {
|
||||
// Since window.location is read-only, we'll test by checking the actual implementation
|
||||
// This test verifies the function works correctly with the current location
|
||||
// In a real browser environment, this would test against actual location
|
||||
const result = isHttpNonLocalhost();
|
||||
// Just verify the function runs without error
|
||||
expect(typeof result).toBe('boolean');
|
||||
});
|
||||
|
||||
/**
|
||||
* Test isHttpNonLocalhost function - localhost should return false
|
||||
* Note: window.location properties are read-only in browsers
|
||||
*/
|
||||
test('should return false for localhost', () => {
|
||||
// Test the logic by checking if current location is localhost
|
||||
const result = isHttpNonLocalhost();
|
||||
// If we're on localhost, result should be false
|
||||
if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
|
||||
expect(result).toBe(false);
|
||||
} else {
|
||||
// Otherwise just verify function returns boolean
|
||||
expect(typeof result).toBe('boolean');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Test isHttpNonLocalhost function - 127.0.0.1 should return false
|
||||
* Note: window.location properties are read-only in browsers
|
||||
*/
|
||||
test('should return false for 127.0.0.1', () => {
|
||||
// Test the logic by checking if current location is 127.0.0.1
|
||||
const result = isHttpNonLocalhost();
|
||||
// If we're on 127.0.0.1, result should be false
|
||||
if (window.location.hostname === '127.0.0.1') {
|
||||
expect(result).toBe(false);
|
||||
} else {
|
||||
// Otherwise just verify function returns boolean
|
||||
expect(typeof result).toBe('boolean');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Test isHttpNonLocalhost function - private IP should return false
|
||||
* Note: window.location properties are read-only in browsers
|
||||
*/
|
||||
test('should return false for private IP addresses', () => {
|
||||
// Test the logic by checking if current location is a private IP
|
||||
const result = isHttpNonLocalhost();
|
||||
const hostname = window.location.hostname;
|
||||
const isPrivateIP = hostname.startsWith('192.168.') ||
|
||||
hostname.startsWith('10.') ||
|
||||
hostname.startsWith('172.');
|
||||
|
||||
if (isPrivateIP && window.location.protocol === 'http:') {
|
||||
expect(result).toBe(false);
|
||||
} else {
|
||||
// Otherwise just verify function returns boolean
|
||||
expect(typeof result).toBe('boolean');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Test isHttpNonLocalhost function - HTTPS should return false
|
||||
* Note: window.location properties are read-only in browsers
|
||||
*/
|
||||
test('should return false for HTTPS protocol', () => {
|
||||
// Test the logic by checking if current protocol is HTTPS
|
||||
const result = isHttpNonLocalhost();
|
||||
// If we're on HTTPS, result should be false
|
||||
if (window.location.protocol === 'https:') {
|
||||
expect(result).toBe(false);
|
||||
} else {
|
||||
// Otherwise just verify function returns boolean
|
||||
expect(typeof result).toBe('boolean');
|
||||
}
|
||||
});
|
||||
});
|
||||
import { checkMicrophoneAvailability, isHttpNonLocalhost } from './recorder.js';
|
||||
|
||||
describe('Microphone Availability Detection', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
test('should return true when microphone is available', async () => {
|
||||
const mockTrack = { stop: vi.fn() };
|
||||
const mockStream = { getTracks: () => [mockTrack] };
|
||||
navigator.mediaDevices.getUserMedia = vi.fn().mockResolvedValue(mockStream);
|
||||
const result = await checkMicrophoneAvailability();
|
||||
expect(result).toBe(true);
|
||||
expect(navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({ audio: { echoCancellation: true, noiseSuppression: true, sampleRate: 16000, channelCount: 1 } });
|
||||
expect(mockTrack.stop).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should return false when microphone is not available', async () => {
|
||||
navigator.mediaDevices.getUserMedia = vi.fn().mockRejectedValue(new Error('Permission denied'));
|
||||
const result = await checkMicrophoneAvailability();
|
||||
expect(result).toBe(false);
|
||||
expect(navigator.mediaDevices.getUserMedia).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should return false when browser does not support getUserMedia', async () => {
|
||||
const originalGetUserMedia = navigator.mediaDevices.getUserMedia;
|
||||
navigator.mediaDevices.getUserMedia = undefined;
|
||||
const result = await checkMicrophoneAvailability();
|
||||
expect(result).toBe(false);
|
||||
navigator.mediaDevices.getUserMedia = originalGetUserMedia;
|
||||
});
|
||||
|
||||
test('should return true for HTTP non-localhost access', () => {
|
||||
expect(typeof isHttpNonLocalhost()).toBe('boolean');
|
||||
});
|
||||
|
||||
test('should return false for localhost', () => {
|
||||
const result = isHttpNonLocalhost();
|
||||
if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
|
||||
expect(result).toBe(false);
|
||||
} else {
|
||||
expect(typeof result).toBe('boolean');
|
||||
}
|
||||
});
|
||||
|
||||
test('should return false for 127.0.0.1', () => {
|
||||
const result = isHttpNonLocalhost();
|
||||
if (window.location.hostname === '127.0.0.1') {
|
||||
expect(result).toBe(false);
|
||||
} else {
|
||||
expect(typeof result).toBe('boolean');
|
||||
}
|
||||
});
|
||||
|
||||
test('should return false for private IP addresses', () => {
|
||||
const result = isHttpNonLocalhost();
|
||||
const hostname = window.location.hostname;
|
||||
const isPrivateIP = hostname.startsWith('192.168.') || hostname.startsWith('10.') || hostname.startsWith('172.');
|
||||
if (isPrivateIP && window.location.protocol === 'http:') {
|
||||
expect(result).toBe(false);
|
||||
} else {
|
||||
expect(typeof result).toBe('boolean');
|
||||
}
|
||||
});
|
||||
|
||||
test('should return false for HTTPS protocol', () => {
|
||||
const result = isHttpNonLocalhost();
|
||||
if (window.location.protocol === 'https:') {
|
||||
expect(result).toBe(false);
|
||||
} else {
|
||||
expect(typeof result).toBe('boolean');
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -40,7 +40,7 @@ export async function initMcpTools() {
|
||||
renderMcpTools();
|
||||
// Only setup event listeners if DOM elements exist
|
||||
if (document.getElementById('toggleMcpTools')) {
|
||||
setupMcpEventListeners();
|
||||
setupMcpEventListeners();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,155 +1,64 @@
|
||||
/**
|
||||
* MCP工具模块测试 - Browser compatible version
|
||||
* 测试Live2D动作工具执行功能
|
||||
*
|
||||
* This version works without Vitest - uses the simple test framework from test-runner.html
|
||||
*/
|
||||
|
||||
import { executeMcpTool, initMcpTools, setWebSocket } from './tools.js';
|
||||
|
||||
describe('Live2D Action Tools', () => {
|
||||
let mockLive2DManager;
|
||||
let originalChatApp;
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset mocks before each test
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Save original chatApp
|
||||
originalChatApp = window.chatApp;
|
||||
|
||||
// Mock Live2D manager
|
||||
mockLive2DManager = {
|
||||
motion: vi.fn()
|
||||
};
|
||||
|
||||
// Setup window.chatApp
|
||||
window.chatApp = {
|
||||
live2dManager: mockLive2DManager
|
||||
};
|
||||
|
||||
// Mock localStorage
|
||||
localStorage.getItem = vi.fn(() => null);
|
||||
|
||||
// Mock fetch for default-mcp-tools.json
|
||||
globalThis.fetch = vi.fn(() =>
|
||||
Promise.resolve({
|
||||
json: () => Promise.resolve([
|
||||
{
|
||||
name: 'live2d.smile',
|
||||
description: 'Make the virtual human smile',
|
||||
inputSchema: { type: 'object', properties: {} }
|
||||
},
|
||||
{
|
||||
name: 'live2d.wave',
|
||||
description: 'Make the virtual human wave',
|
||||
inputSchema: { type: 'object', properties: {} }
|
||||
},
|
||||
{
|
||||
name: 'live2d.action',
|
||||
description: 'Trigger a specified action',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
action: { type: 'string' }
|
||||
},
|
||||
required: ['action']
|
||||
}
|
||||
}
|
||||
])
|
||||
})
|
||||
);
|
||||
|
||||
// Mock DOM elements - ensure all required elements exist
|
||||
const mockContainer = {
|
||||
innerHTML: '',
|
||||
appendChild: vi.fn(),
|
||||
textContent: ''
|
||||
};
|
||||
|
||||
document.getElementById = vi.fn((id) => {
|
||||
// Return mock elements for all IDs that tools.js might access
|
||||
if (id === 'mcpToolsContainer' || id === 'mcpPropertiesContainer') {
|
||||
return mockContainer;
|
||||
}
|
||||
if (id === 'mcpToolsCount') {
|
||||
return { textContent: '' };
|
||||
}
|
||||
// Return null for other elements (they're checked with if statements)
|
||||
return null;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up
|
||||
window.chatApp = originalChatApp;
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - smile 动作
|
||||
*/
|
||||
test('should execute Live2D smile action', async () => {
|
||||
await initMcpTools();
|
||||
|
||||
const result = executeMcpTool('live2d.smile', {});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('FlickUp');
|
||||
expect(result.tool).toBe('live2d.smile');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('FlickUp');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - wave 动作
|
||||
*/
|
||||
test('should execute Live2D wave action', async () => {
|
||||
await initMcpTools();
|
||||
|
||||
const result = executeMcpTool('live2d.wave', {});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('Tap');
|
||||
expect(result.tool).toBe('live2d.wave');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('Tap');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - 通用动作工具
|
||||
*/
|
||||
test('should handle generic action tool', async () => {
|
||||
await initMcpTools();
|
||||
|
||||
const result = executeMcpTool('live2d.action', { action: 'FlickDown' });
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('FlickDown');
|
||||
expect(result.tool).toBe('live2d.action');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('FlickDown');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - Live2D管理器未初始化
|
||||
*/
|
||||
test('should handle missing Live2D manager gracefully', async () => {
|
||||
await initMcpTools();
|
||||
|
||||
window.chatApp = null;
|
||||
|
||||
const result = executeMcpTool('live2d.smile', {});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain('Live2D管理器未初始化');
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 executeMcpTool - 未知的工具
|
||||
*/
|
||||
test('should handle unknown tool gracefully', async () => {
|
||||
await initMcpTools();
|
||||
|
||||
const result = executeMcpTool('unknown.tool', {});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain('未知工具');
|
||||
});
|
||||
});
|
||||
import { executeMcpTool, initMcpTools } from './tools.js';
|
||||
|
||||
describe('Live2D Action Tools', () => {
|
||||
let mockLive2DManager, originalChatApp;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
originalChatApp = window.chatApp;
|
||||
mockLive2DManager = { motion: vi.fn() };
|
||||
window.chatApp = { live2dManager: mockLive2DManager };
|
||||
localStorage.getItem = vi.fn(() => null);
|
||||
globalThis.fetch = vi.fn(() => Promise.resolve({ json: () => Promise.resolve([{ name: 'live2d.smile', description: 'Make the virtual human smile', inputSchema: { type: 'object', properties: {} } }, { name: 'live2d.wave', description: 'Make the virtual human wave', inputSchema: { type: 'object', properties: {} } }, { name: 'live2d.action', description: 'Trigger a specified action', inputSchema: { type: 'object', properties: { action: { type: 'string' } }, required: ['action'] } }]) }));
|
||||
const mockContainer = { innerHTML: '', appendChild: vi.fn(), textContent: '' };
|
||||
document.getElementById = vi.fn((id) => {
|
||||
if (id === 'mcpToolsContainer' || id === 'mcpPropertiesContainer') return mockContainer;
|
||||
if (id === 'mcpToolsCount') return { textContent: '' };
|
||||
return null;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => { window.chatApp = originalChatApp; });
|
||||
|
||||
test('should execute Live2D smile action', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('live2d.smile', {});
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('FlickUp');
|
||||
expect(result.tool).toBe('live2d.smile');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('FlickUp');
|
||||
});
|
||||
|
||||
test('should execute Live2D wave action', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('live2d.wave', {});
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('Tap');
|
||||
expect(result.tool).toBe('live2d.wave');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('Tap');
|
||||
});
|
||||
|
||||
test('should handle generic action tool', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('live2d.action', { action: 'FlickDown' });
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.action).toBe('FlickDown');
|
||||
expect(result.tool).toBe('live2d.action');
|
||||
expect(mockLive2DManager.motion).toHaveBeenCalledWith('FlickDown');
|
||||
});
|
||||
|
||||
test('should handle missing Live2D manager gracefully', async () => {
|
||||
await initMcpTools();
|
||||
window.chatApp = null;
|
||||
const result = executeMcpTool('live2d.smile', {});
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain('Live2D管理器未初始化');
|
||||
});
|
||||
|
||||
test('should handle unknown tool gracefully', async () => {
|
||||
await initMcpTools();
|
||||
const result = executeMcpTool('unknown.tool', {});
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain('未知工具');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user