mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-05 15:31:27 +00:00
fix ci test
This commit is contained in:
parent
1050163804
commit
30b4b47cd7
1 changed files with 69 additions and 366 deletions
|
|
@ -5,19 +5,22 @@
|
|||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { execCommand } from '@qwen-code/qwen-code-core';
|
||||
import {
|
||||
clipboardHasImage,
|
||||
saveClipboardImage,
|
||||
cleanupOldClipboardImages,
|
||||
} from './clipboardUtils.js';
|
||||
|
||||
// Mock execCommand
|
||||
vi.mock('@qwen-code/qwen-code-core', () => ({
|
||||
execCommand: vi.fn(),
|
||||
}));
|
||||
// Mock ClipboardManager
|
||||
const mockHasFormat = vi.fn();
|
||||
const mockGetImageData = vi.fn();
|
||||
|
||||
const mockExecCommand = vi.mocked(execCommand);
|
||||
vi.mock('@teddyzhu/clipboard', () => ({
|
||||
ClipboardManager: vi.fn().mockImplementation(() => ({
|
||||
hasFormat: mockHasFormat,
|
||||
getImageData: mockGetImageData,
|
||||
})),
|
||||
}));
|
||||
|
||||
describe('clipboardUtils', () => {
|
||||
beforeEach(() => {
|
||||
|
|
@ -25,319 +28,99 @@ describe('clipboardUtils', () => {
|
|||
});
|
||||
|
||||
describe('clipboardHasImage', () => {
|
||||
describe('macOS platform', () => {
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('process', {
|
||||
...process,
|
||||
platform: 'darwin',
|
||||
env: process.env,
|
||||
});
|
||||
});
|
||||
it('should return true when clipboard contains image', async () => {
|
||||
mockHasFormat.mockReturnValue(true);
|
||||
|
||||
it('should return true when clipboard contains PNG image', async () => {
|
||||
mockExecCommand.mockResolvedValue({
|
||||
stdout: '«class PNGf»',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
expect(mockExecCommand).toHaveBeenCalledWith(
|
||||
'osascript',
|
||||
['-e', 'clipboard info'],
|
||||
{ timeout: 1500 },
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true when clipboard contains JPEG image', async () => {
|
||||
mockExecCommand.mockResolvedValue({
|
||||
stdout: '«class JPEG»',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when clipboard contains WebP image', async () => {
|
||||
mockExecCommand.mockResolvedValue({
|
||||
stdout: '«class WEBP»',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when clipboard contains HEIC image', async () => {
|
||||
mockExecCommand.mockResolvedValue({
|
||||
stdout: 'public.heic',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when clipboard contains BMP image', async () => {
|
||||
mockExecCommand.mockResolvedValue({
|
||||
stdout: '«class BMPf»',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when clipboard contains text', async () => {
|
||||
mockExecCommand.mockResolvedValue({
|
||||
stdout: '«class utf8»',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false on error', async () => {
|
||||
mockExecCommand.mockRejectedValue(new Error('Command failed'));
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
expect(mockHasFormat).toHaveBeenCalledWith('image');
|
||||
});
|
||||
|
||||
describe('Windows platform', () => {
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('process', {
|
||||
...process,
|
||||
platform: 'win32',
|
||||
env: process.env,
|
||||
});
|
||||
});
|
||||
it('should return false when clipboard does not contain image', async () => {
|
||||
mockHasFormat.mockReturnValue(false);
|
||||
|
||||
it('should return true when clipboard contains image', async () => {
|
||||
mockExecCommand.mockResolvedValue({
|
||||
stdout: 'true',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
expect(mockExecCommand).toHaveBeenCalledWith(
|
||||
'powershell.exe',
|
||||
expect.arrayContaining([
|
||||
'-command',
|
||||
expect.stringContaining('Get-Clipboard'),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false when clipboard does not contain image', async () => {
|
||||
mockExecCommand.mockResolvedValue({
|
||||
stdout: 'false',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when all PowerShell hosts fail', async () => {
|
||||
mockExecCommand
|
||||
.mockRejectedValueOnce(new Error('PowerShell not found'))
|
||||
.mockRejectedValueOnce(new Error('PowerShell not found'))
|
||||
.mockRejectedValueOnce(new Error('PowerShell not found'));
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(false);
|
||||
expect(mockExecCommand).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(false);
|
||||
expect(mockHasFormat).toHaveBeenCalledWith('image');
|
||||
});
|
||||
|
||||
describe('Linux platform', () => {
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('process', {
|
||||
...process,
|
||||
platform: 'linux',
|
||||
env: process.env,
|
||||
});
|
||||
it('should return false on error', async () => {
|
||||
mockHasFormat.mockImplementation(() => {
|
||||
throw new Error('Clipboard error');
|
||||
});
|
||||
|
||||
it('should return true when xclip has PNG image', async () => {
|
||||
// First call: which xclip (success)
|
||||
// Second call: xclip get PNG (has content)
|
||||
mockExecCommand
|
||||
.mockResolvedValueOnce({
|
||||
stdout: '/usr/bin/xclip',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
})
|
||||
.mockResolvedValueOnce({ stdout: 'image-data', stderr: '', code: 0 });
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
it('should log errors in DEBUG mode', async () => {
|
||||
const originalEnv = process.env;
|
||||
vi.stubGlobal('process', {
|
||||
...process,
|
||||
env: { ...originalEnv, DEBUG: '1' },
|
||||
});
|
||||
|
||||
it('should try multiple formats with xclip', async () => {
|
||||
// which xclip succeeds
|
||||
mockExecCommand.mockResolvedValueOnce({
|
||||
stdout: '/usr/bin/xclip',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
// PNG fails
|
||||
mockExecCommand.mockRejectedValueOnce(new Error('No PNG'));
|
||||
// JPEG succeeds
|
||||
mockExecCommand.mockResolvedValueOnce({
|
||||
stdout: 'jpeg-data',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
const consoleErrorSpy = vi
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => {});
|
||||
mockHasFormat.mockImplementation(() => {
|
||||
throw new Error('Test error');
|
||||
});
|
||||
|
||||
it('should fallback to xsel when xclip not available', async () => {
|
||||
// which xclip fails
|
||||
mockExecCommand.mockRejectedValueOnce(new Error('xclip not found'));
|
||||
// which xsel succeeds
|
||||
mockExecCommand.mockResolvedValueOnce({
|
||||
stdout: '/usr/bin/xsel',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
// xsel -b -t returns image MIME types
|
||||
mockExecCommand.mockResolvedValueOnce({
|
||||
stdout: 'text/plain\nimage/png\ntext/html',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should fallback to wl-paste when xclip and xsel not available', async () => {
|
||||
// which xclip fails
|
||||
mockExecCommand.mockRejectedValueOnce(new Error('xclip not found'));
|
||||
// which xsel fails
|
||||
mockExecCommand.mockRejectedValueOnce(new Error('xsel not found'));
|
||||
// which wl-paste succeeds
|
||||
mockExecCommand.mockResolvedValueOnce({
|
||||
stdout: '/usr/bin/wl-paste',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
// wl-paste --list-types returns image MIME type
|
||||
mockExecCommand.mockResolvedValueOnce({
|
||||
stdout: 'text/plain\nimage/png\ntext/html',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when no clipboard tool available', async () => {
|
||||
// All tools fail
|
||||
mockExecCommand.mockRejectedValue(new Error('Not found'));
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when xsel has no image types', async () => {
|
||||
// which xclip fails
|
||||
mockExecCommand.mockRejectedValueOnce(new Error('xclip not found'));
|
||||
// which xsel succeeds
|
||||
mockExecCommand.mockResolvedValueOnce({
|
||||
stdout: '/usr/bin/xsel',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
// xsel -b -t returns only text types
|
||||
mockExecCommand.mockResolvedValueOnce({
|
||||
stdout: 'text/plain\ntext/html',
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
await clipboardHasImage();
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
||||
'Error checking clipboard for image:',
|
||||
expect.any(Error),
|
||||
);
|
||||
consoleErrorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('saveClipboardImage', () => {
|
||||
const testTempDir = '/tmp/test-clipboard';
|
||||
it('should return null when clipboard has no image', async () => {
|
||||
mockHasFormat.mockReturnValue(false);
|
||||
|
||||
it('should create clipboard directory when saving image', async () => {
|
||||
vi.stubGlobal('process', {
|
||||
...process,
|
||||
platform: 'darwin',
|
||||
env: process.env,
|
||||
});
|
||||
const result = await saveClipboardImage('/tmp/test');
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
// Mock all execCommand calls to fail (no image in clipboard)
|
||||
mockExecCommand.mockRejectedValue(new Error('No image'));
|
||||
it('should return null when image data buffer is null', async () => {
|
||||
mockHasFormat.mockReturnValue(true);
|
||||
mockGetImageData.mockReturnValue({ data: null });
|
||||
|
||||
const result = await saveClipboardImage(testTempDir);
|
||||
// Should return null when no image available
|
||||
const result = await saveClipboardImage('/tmp/test');
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
it('should handle errors gracefully and return null', async () => {
|
||||
const result = await saveClipboardImage(
|
||||
'/invalid/path/that/does/not/exist',
|
||||
);
|
||||
mockHasFormat.mockImplementation(() => {
|
||||
throw new Error('Clipboard error');
|
||||
});
|
||||
|
||||
const result = await saveClipboardImage('/tmp/test');
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
it('should support macOS platform', async () => {
|
||||
it('should log errors in DEBUG mode', async () => {
|
||||
const originalEnv = process.env;
|
||||
vi.stubGlobal('process', {
|
||||
...process,
|
||||
platform: 'darwin',
|
||||
env: process.env,
|
||||
env: { ...originalEnv, DEBUG: '1' },
|
||||
});
|
||||
|
||||
mockExecCommand.mockRejectedValue(new Error('No image'));
|
||||
const result = await saveClipboardImage();
|
||||
expect(result === null || typeof result === 'string').toBe(true);
|
||||
});
|
||||
|
||||
it('should support Windows platform', async () => {
|
||||
vi.stubGlobal('process', {
|
||||
...process,
|
||||
platform: 'win32',
|
||||
env: process.env,
|
||||
const consoleErrorSpy = vi
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => {});
|
||||
mockHasFormat.mockImplementation(() => {
|
||||
throw new Error('Test error');
|
||||
});
|
||||
|
||||
mockExecCommand.mockRejectedValue(new Error('No image'));
|
||||
const result = await saveClipboardImage();
|
||||
expect(result === null || typeof result === 'string').toBe(true);
|
||||
});
|
||||
|
||||
it('should support Linux platform', async () => {
|
||||
vi.stubGlobal('process', {
|
||||
...process,
|
||||
platform: 'linux',
|
||||
env: process.env,
|
||||
});
|
||||
|
||||
mockExecCommand.mockRejectedValue(new Error('No image'));
|
||||
const result = await saveClipboardImage();
|
||||
expect(result === null || typeof result === 'string').toBe(true);
|
||||
await saveClipboardImage('/tmp/test');
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
||||
'Error saving clipboard image:',
|
||||
expect.any(Error),
|
||||
);
|
||||
consoleErrorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -358,84 +141,4 @@ describe('clipboardUtils', () => {
|
|||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('multi-format support', () => {
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('process', {
|
||||
...process,
|
||||
platform: 'darwin',
|
||||
env: process.env,
|
||||
});
|
||||
});
|
||||
|
||||
const formats = [
|
||||
{ name: 'PNG', pattern: '«class PNGf»' },
|
||||
{ name: 'JPEG', pattern: '«class JPEG»' },
|
||||
{ name: 'WebP', pattern: '«class WEBP»' },
|
||||
{ name: 'HEIC', pattern: '«class heic»' },
|
||||
{ name: 'HEIF', pattern: 'public.heif' },
|
||||
{ name: 'TIFF', pattern: '«class TIFF»' },
|
||||
{ name: 'GIF', pattern: '«class GIFf»' },
|
||||
{ name: 'BMP', pattern: '«class BMPf»' },
|
||||
];
|
||||
|
||||
formats.forEach(({ name, pattern }) => {
|
||||
it(`should detect ${name} format on macOS`, async () => {
|
||||
mockExecCommand.mockResolvedValue({
|
||||
stdout: pattern,
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const result = await clipboardHasImage();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('error handling with DEBUG mode', () => {
|
||||
const originalEnv = process.env;
|
||||
|
||||
describe('clipboardHasImage', () => {
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('process', {
|
||||
...process,
|
||||
platform: 'darwin',
|
||||
env: { ...originalEnv, DEBUG: '1' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should log errors in DEBUG mode', async () => {
|
||||
const consoleErrorSpy = vi
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => {});
|
||||
mockExecCommand.mockRejectedValue(new Error('Test error'));
|
||||
|
||||
await clipboardHasImage();
|
||||
expect(consoleErrorSpy).toHaveBeenCalled();
|
||||
consoleErrorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('saveClipboardImage on Windows', () => {
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('process', {
|
||||
...process,
|
||||
platform: 'win32',
|
||||
env: { ...originalEnv, DEBUG: '1' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should log errors in DEBUG mode', async () => {
|
||||
const consoleErrorSpy = vi
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => {});
|
||||
mockExecCommand.mockRejectedValue(new Error('Test error'));
|
||||
|
||||
await saveClipboardImage('/invalid/path');
|
||||
expect(consoleErrorSpy).toHaveBeenCalled();
|
||||
consoleErrorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue