chore: initialize qiming workspace repository
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Unit tests for desktop/imageSearch.ts — findImage, waitForImage.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
// Mock fs
|
||||
const mockWriteFile = vi.fn();
|
||||
const mockUnlink = vi.fn();
|
||||
vi.mock('fs', () => ({
|
||||
promises: {
|
||||
writeFile: (...args: any[]) => mockWriteFile(...args),
|
||||
unlink: (...args: any[]) => mockUnlink(...args),
|
||||
},
|
||||
}));
|
||||
|
||||
// Mock nut.js
|
||||
const mockFind = vi.fn();
|
||||
const mockLoadImage = vi.fn();
|
||||
const mockScreenConfig = { confidence: 0.9 };
|
||||
|
||||
vi.mock('@nut-tree-fork/nut-js', () => ({
|
||||
screen: {
|
||||
find: (...args: any[]) => mockFind(...args),
|
||||
config: mockScreenConfig,
|
||||
},
|
||||
loadImage: (...args: any[]) => mockLoadImage(...args),
|
||||
}));
|
||||
|
||||
import { findImage, waitForImage } from '../../src/desktop/imageSearch.js';
|
||||
|
||||
describe('findImage', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockWriteFile.mockResolvedValue(undefined);
|
||||
mockUnlink.mockResolvedValue(undefined);
|
||||
mockLoadImage.mockResolvedValue('template-obj');
|
||||
});
|
||||
|
||||
it('returns found=true with region when match found', async () => {
|
||||
mockFind.mockResolvedValue({ left: 10, top: 20, width: 50, height: 30 });
|
||||
|
||||
const result = await findImage('dGVzdA==', 0.85);
|
||||
|
||||
expect(result.found).toBe(true);
|
||||
expect(result.region).toEqual({ x: 10, y: 20, width: 50, height: 30 });
|
||||
expect(result.confidence).toBe(0.85);
|
||||
expect(mockScreenConfig.confidence).toBe(0.85);
|
||||
});
|
||||
|
||||
it('returns found=false when no match', async () => {
|
||||
mockFind.mockRejectedValue(new Error('no match'));
|
||||
|
||||
const result = await findImage('dGVzdA==');
|
||||
expect(result.found).toBe(false);
|
||||
expect(result.region).toBeUndefined();
|
||||
});
|
||||
|
||||
it('writes template to temp file and cleans up', async () => {
|
||||
mockFind.mockResolvedValue({ left: 0, top: 0, width: 10, height: 10 });
|
||||
|
||||
await findImage('dGVzdA==');
|
||||
|
||||
expect(mockWriteFile).toHaveBeenCalledTimes(1);
|
||||
expect(mockUnlink).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('cleans up temp file even when match fails', async () => {
|
||||
mockFind.mockRejectedValue(new Error('no match'));
|
||||
|
||||
await findImage('dGVzdA==');
|
||||
expect(mockUnlink).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('uses default confidence of 0.9', async () => {
|
||||
mockFind.mockResolvedValue({ left: 0, top: 0, width: 10, height: 10 });
|
||||
|
||||
const result = await findImage('dGVzdA==');
|
||||
expect(result.confidence).toBe(0.9);
|
||||
});
|
||||
});
|
||||
|
||||
describe('waitForImage', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockWriteFile.mockResolvedValue(undefined);
|
||||
mockUnlink.mockResolvedValue(undefined);
|
||||
mockLoadImage.mockResolvedValue('template-obj');
|
||||
});
|
||||
|
||||
it('returns found=true with elapsed when image found immediately', async () => {
|
||||
mockFind.mockResolvedValue({ left: 5, top: 10, width: 20, height: 15 });
|
||||
|
||||
const result = await waitForImage('dGVzdA==', 5000, 0.8);
|
||||
|
||||
expect(result.found).toBe(true);
|
||||
expect(result.region).toEqual({ x: 5, y: 10, width: 20, height: 15 });
|
||||
expect(result.elapsed).toBeDefined();
|
||||
expect(result.elapsed).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
it('returns found=false with elapsed after timeout', async () => {
|
||||
mockFind.mockRejectedValue(new Error('no match'));
|
||||
|
||||
// Use a very short timeout to avoid slow tests
|
||||
const result = await waitForImage('dGVzdA==', 100, 0.9);
|
||||
|
||||
expect(result.found).toBe(false);
|
||||
expect(result.elapsed).toBeGreaterThanOrEqual(100);
|
||||
});
|
||||
|
||||
it('cleans up temp file after completion', async () => {
|
||||
mockFind.mockResolvedValue({ left: 0, top: 0, width: 10, height: 10 });
|
||||
|
||||
await waitForImage('dGVzdA==', 5000);
|
||||
expect(mockUnlink).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('cleans up temp file even after timeout', async () => {
|
||||
mockFind.mockRejectedValue(new Error('no match'));
|
||||
|
||||
await waitForImage('dGVzdA==', 100);
|
||||
expect(mockUnlink).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('writes temp file only once for reuse across polls', async () => {
|
||||
mockFind.mockRejectedValue(new Error('no match'));
|
||||
|
||||
await waitForImage('dGVzdA==', 100);
|
||||
// Only 1 writeFile call despite potentially multiple polls
|
||||
expect(mockWriteFile).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user