chore: initialize qiming workspace repository
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Unit tests for utils/errors.ts — 5 structured error classes.
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
ConfigError,
|
||||
DesktopError,
|
||||
CoordinateError,
|
||||
SafetyError,
|
||||
TaskExecutionError,
|
||||
} from '../../src/utils/errors.js';
|
||||
|
||||
describe('ConfigError', () => {
|
||||
it('sets name and message', () => {
|
||||
const err = new ConfigError('API_KEY is required');
|
||||
expect(err).toBeInstanceOf(Error);
|
||||
expect(err.name).toBe('ConfigError');
|
||||
expect(err.message).toBe('API_KEY is required');
|
||||
});
|
||||
});
|
||||
|
||||
describe('DesktopError', () => {
|
||||
it('sets name, operation, cause, and formatted message', () => {
|
||||
const cause = new Error('permission denied');
|
||||
const err = new DesktopError('mouse.click', cause);
|
||||
expect(err).toBeInstanceOf(Error);
|
||||
expect(err.name).toBe('DesktopError');
|
||||
expect(err.operation).toBe('mouse.click');
|
||||
expect(err.cause).toBe(cause);
|
||||
expect(err.message).toContain('mouse.click');
|
||||
expect(err.message).toContain('permission denied');
|
||||
});
|
||||
|
||||
it('operation is readonly', () => {
|
||||
const err = new DesktopError('screenshot', new Error('fail'));
|
||||
expect(err.operation).toBe('screenshot');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CoordinateError', () => {
|
||||
it('sets name, coordinateMode, rawX, rawY, and formatted message', () => {
|
||||
const err = new CoordinateError('normalized-1000', 500, 300);
|
||||
expect(err).toBeInstanceOf(Error);
|
||||
expect(err.name).toBe('CoordinateError');
|
||||
expect(err.coordinateMode).toBe('normalized-1000');
|
||||
expect(err.rawX).toBe(500);
|
||||
expect(err.rawY).toBe(300);
|
||||
expect(err.message).toContain('normalized-1000');
|
||||
expect(err.message).toContain('500');
|
||||
expect(err.message).toContain('300');
|
||||
});
|
||||
});
|
||||
|
||||
describe('SafetyError', () => {
|
||||
it('sets name, keys, reason, and formatted message', () => {
|
||||
const err = new SafetyError(['Meta', 'Q'], 'Quit application');
|
||||
expect(err).toBeInstanceOf(Error);
|
||||
expect(err.name).toBe('SafetyError');
|
||||
expect(err.keys).toEqual(['Meta', 'Q']);
|
||||
expect(err.reason).toBe('Quit application');
|
||||
expect(err.message).toContain('Meta+Q');
|
||||
expect(err.message).toContain('Quit application');
|
||||
});
|
||||
});
|
||||
|
||||
describe('TaskExecutionError', () => {
|
||||
it('sets name, taskText, step, cause, and formatted message', () => {
|
||||
const cause = new Error('element not found');
|
||||
const err = new TaskExecutionError('Open Finder', 3, cause);
|
||||
expect(err).toBeInstanceOf(Error);
|
||||
expect(err.name).toBe('TaskExecutionError');
|
||||
expect(err.taskText).toBe('Open Finder');
|
||||
expect(err.step).toBe(3);
|
||||
expect(err.cause).toBe(cause);
|
||||
expect(err.message).toContain('step 3');
|
||||
expect(err.message).toContain('element not found');
|
||||
});
|
||||
});
|
||||
119
qimingclaw/crates/agent-gui-server/tests/utils/platform.test.ts
Normal file
119
qimingclaw/crates/agent-gui-server/tests/utils/platform.test.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Unit tests for utils/platform.ts — getPlatform, getPlatformPasteKeys, permission checks.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
// Mock os module
|
||||
const mockPlatform = vi.fn();
|
||||
vi.mock('os', () => ({
|
||||
platform: () => mockPlatform(),
|
||||
}));
|
||||
|
||||
// Mock nut.js for permission checks
|
||||
const mockScreenWidth = vi.fn();
|
||||
const mockMouseGetPosition = vi.fn();
|
||||
|
||||
vi.mock('@nut-tree-fork/nut-js', () => ({
|
||||
screen: {
|
||||
width: () => mockScreenWidth(),
|
||||
},
|
||||
mouse: {
|
||||
getPosition: () => mockMouseGetPosition(),
|
||||
},
|
||||
}));
|
||||
|
||||
import { getPlatform, getPlatformPasteKeys, checkScreenRecordingPermission, checkAccessibilityPermission } from '../../src/utils/platform.js';
|
||||
|
||||
describe('getPlatform', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns "macos" for darwin', () => {
|
||||
mockPlatform.mockReturnValue('darwin');
|
||||
expect(getPlatform()).toBe('macos');
|
||||
});
|
||||
|
||||
it('returns "windows" for win32', () => {
|
||||
mockPlatform.mockReturnValue('win32');
|
||||
expect(getPlatform()).toBe('windows');
|
||||
});
|
||||
|
||||
it('returns "linux" for linux', () => {
|
||||
mockPlatform.mockReturnValue('linux');
|
||||
expect(getPlatform()).toBe('linux');
|
||||
});
|
||||
|
||||
it('returns "linux" for unknown platforms', () => {
|
||||
mockPlatform.mockReturnValue('freebsd');
|
||||
expect(getPlatform()).toBe('linux');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPlatformPasteKeys', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns Meta+V on macOS', () => {
|
||||
mockPlatform.mockReturnValue('darwin');
|
||||
expect(getPlatformPasteKeys()).toEqual(['Meta', 'V']);
|
||||
});
|
||||
|
||||
it('returns Control+V on Windows', () => {
|
||||
mockPlatform.mockReturnValue('win32');
|
||||
expect(getPlatformPasteKeys()).toEqual(['Control', 'V']);
|
||||
});
|
||||
|
||||
it('returns Control+V on Linux', () => {
|
||||
mockPlatform.mockReturnValue('linux');
|
||||
expect(getPlatformPasteKeys()).toEqual(['Control', 'V']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkScreenRecordingPermission', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns true on non-macOS platforms', async () => {
|
||||
mockPlatform.mockReturnValue('win32');
|
||||
const result = await checkScreenRecordingPermission();
|
||||
expect(result).toBe(true);
|
||||
expect(mockScreenWidth).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns true on macOS when screen.width succeeds', async () => {
|
||||
mockPlatform.mockReturnValue('darwin');
|
||||
mockScreenWidth.mockResolvedValue(1920);
|
||||
const result = await checkScreenRecordingPermission();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false on macOS when screen.width throws', async () => {
|
||||
mockPlatform.mockReturnValue('darwin');
|
||||
mockScreenWidth.mockRejectedValue(new Error('no permission'));
|
||||
const result = await checkScreenRecordingPermission();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkAccessibilityPermission', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns true on non-macOS platforms', async () => {
|
||||
mockPlatform.mockReturnValue('linux');
|
||||
const result = await checkAccessibilityPermission();
|
||||
expect(result).toBe(true);
|
||||
expect(mockMouseGetPosition).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns true on macOS when mouse.getPosition succeeds', async () => {
|
||||
mockPlatform.mockReturnValue('darwin');
|
||||
mockMouseGetPosition.mockResolvedValue({ x: 0, y: 0 });
|
||||
const result = await checkAccessibilityPermission();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false on macOS when mouse.getPosition throws', async () => {
|
||||
mockPlatform.mockReturnValue('darwin');
|
||||
mockMouseGetPosition.mockRejectedValue(new Error('no permission'));
|
||||
const result = await checkAccessibilityPermission();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user