Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add vitest & cross-platform test support #540

Merged
merged 8 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions jest.config.cjs

This file was deleted.

8 changes: 3 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"sign": "node debug/sign.js",
"start": "node ./scripts/launchdev.js",
"test:e2e": "npx playwright test",
"test:unit": "jest --config jest.config.cjs",
"test:unit": "vitest run",
"test:update-snapshots": "npx playwright test --update-snapshots",
"todesktop:afterPack": "./scripts/todesktop/afterPack.cjs",
"todesktop:beforeInstall": "./scripts/todesktop/beforeInstall.cjs",
Expand All @@ -65,7 +65,6 @@
"@types/adm-zip": "^0.5.5",
"@types/electron-squirrel-startup": "^1.0.2",
"@types/eslint__js": "^8.42.3",
"@types/jest": "^29.5.14",
"@types/node": "^22.10.2",
"@types/tar": "6.1.13",
"@types/tmp": "^0.2.6",
Expand All @@ -79,16 +78,15 @@
"eslint-plugin-unicorn": "^56.0.1",
"globals": "^15.13.0",
"husky": "^9.1.6",
"jest": "^29.7.0",
"lint-staged": "^15.2.10",
"prettier": "^3.3.3",
"rimraf": "^6.0.1",
"ts-jest": "^29.2.5",
"ts-node": "^10.0.0",
"typescript": "^5.7.2",
"typescript-eslint": "^8.18.1",
"vite": "^6.0.3",
"vite-plugin-dts": "^4.3.0"
"vite-plugin-dts": "^4.3.0",
"vitest": "2.1.6"
},
"keywords": [],
"author": {
Expand Down
69 changes: 38 additions & 31 deletions tests/unit/comfyConfigManager.test.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,60 @@
import fs from 'node:fs';
import fs, { type PathLike } from 'node:fs';
import { ComfyConfigManager, DirectoryStructure } from '../../src/config/comfyConfigManager';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import path from 'node:path';

// Workaround for mock impls.
const { normalize } = path;

// Mock the fs module
jest.mock('node:fs');
jest.mock('electron-log/main', () => ({
info: jest.fn(),
error: jest.fn(),
warn: jest.fn(),
vi.mock('node:fs');
vi.mock('electron-log/main', () => ({
default: {
info: vi.fn(),
error: vi.fn(),
warn: vi.fn(),
},
}));

describe('ComfyConfigManager', () => {
// Reset all mocks before each test
beforeEach(() => {
jest.clearAllMocks();
(fs.existsSync as jest.Mock).mockReset();
(fs.mkdirSync as jest.Mock).mockReset();
(fs.writeFileSync as jest.Mock).mockReset();
(fs.renameSync as jest.Mock).mockReset();
vi.clearAllMocks();
vi.mocked(fs.existsSync).mockReset();
vi.mocked(fs.mkdirSync).mockReset();
vi.mocked(fs.writeFileSync).mockReset();
vi.mocked(fs.renameSync).mockReset();
});

describe('setUpComfyUI', () => {
it('should reject existing directory when it contains ComfyUI structure', () => {
(fs.existsSync as jest.Mock).mockReturnValue(true);
expect(() => ComfyConfigManager.setUpComfyUI('/existing/ComfyUI')).toThrow();
vi.mocked(fs.existsSync).mockReturnValue(true);
expect(() => ComfyConfigManager.setUpComfyUI(path.normalize('/existing/ComfyUI'))).toThrow();
});

it('should create ComfyUI subdirectory when it is missing', () => {
(fs.existsSync as jest.Mock).mockImplementationOnce((path: string) => {
if (['/some/base/path/ComfyUI'].includes(path)) {
vi.mocked(fs.existsSync).mockImplementationOnce((path: PathLike) => {
if ([normalize('/some/base/path/ComfyUI')].includes(path.toString())) {
return false;
}
return true;
});

ComfyConfigManager.setUpComfyUI('/some/base/path/ComfyUI');
ComfyConfigManager.setUpComfyUI(path.normalize('/some/base/path/ComfyUI'));
});
});

describe('isComfyUIDirectory', () => {
it('should return true when all required directories exist', () => {
(fs.existsSync as jest.Mock).mockImplementation((path: string) => {
vi.mocked(fs.existsSync).mockImplementation((path: PathLike) => {
const requiredDirs = [
'/fake/path/models',
'/fake/path/input',
'/fake/path/user',
'/fake/path/output',
'/fake/path/custom_nodes',
normalize('/fake/path/models'),
normalize('/fake/path/input'),
normalize('/fake/path/user'),
normalize('/fake/path/output'),
normalize('/fake/path/custom_nodes'),
];
return requiredDirs.includes(path);
return requiredDirs.includes(path.toString());
});

const result = ComfyConfigManager.isComfyUIDirectory('/fake/path');
Expand All @@ -57,7 +64,7 @@ describe('ComfyConfigManager', () => {
});

it('should return false when some required directories are missing', () => {
(fs.existsSync as jest.Mock)
vi.mocked(fs.existsSync)
.mockReturnValueOnce(true) // models exists
.mockReturnValueOnce(true) // input exists
.mockReturnValueOnce(false) // user missing
Expand All @@ -72,22 +79,22 @@ describe('ComfyConfigManager', () => {

describe('createComfyDirectories', () => {
it('should create all necessary directories when none exist', () => {
(fs.existsSync as jest.Mock).mockReturnValue(false);
vi.mocked(fs.existsSync).mockReturnValue(false);

ComfyConfigManager.createComfyDirectories('/fake/path/ComfyUI');

// Verify each required directory was created
expect(fs.mkdirSync).toHaveBeenCalledWith('/fake/path/ComfyUI/models', { recursive: true });
expect(fs.mkdirSync).toHaveBeenCalledWith('/fake/path/ComfyUI/input', { recursive: true });
expect(fs.mkdirSync).toHaveBeenCalledWith('/fake/path/ComfyUI/user', { recursive: true });
expect(fs.mkdirSync).toHaveBeenCalledWith('/fake/path/ComfyUI/output', { recursive: true });
expect(fs.mkdirSync).toHaveBeenCalledWith('/fake/path/ComfyUI/custom_nodes', { recursive: true });
expect(fs.mkdirSync).toHaveBeenCalledWith(path.normalize('/fake/path/ComfyUI/models'), { recursive: true });
expect(fs.mkdirSync).toHaveBeenCalledWith(path.normalize('/fake/path/ComfyUI/input'), { recursive: true });
expect(fs.mkdirSync).toHaveBeenCalledWith(path.normalize('/fake/path/ComfyUI/user'), { recursive: true });
expect(fs.mkdirSync).toHaveBeenCalledWith(path.normalize('/fake/path/ComfyUI/output'), { recursive: true });
expect(fs.mkdirSync).toHaveBeenCalledWith(path.normalize('/fake/path/ComfyUI/custom_nodes'), { recursive: true });
});
});

describe('createNestedDirectories', () => {
it('should create nested directory structure correctly', () => {
(fs.existsSync as jest.Mock).mockReturnValue(false);
vi.mocked(fs.existsSync).mockReturnValue(false);

const structure = ['dir1', ['dir2', ['subdir1', 'subdir2']], ['dir3', [['subdir3', ['subsubdir1']]]]];

Expand Down
1 change: 1 addition & 0 deletions tests/unit/comfyServer.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { describe, expect, it } from 'vitest';
import { ComfyServer } from '../../src/main-process/comfyServer';

describe('ComfyServer', () => {
Expand Down
44 changes: 31 additions & 13 deletions tests/unit/comfyServerConfig.test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
import { app } from 'electron';
import path from 'node:path';
import { ComfyServerConfig } from '../../src/config/comfyServerConfig';
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';
import { tmpdir } from 'node:os';

// Mock electron
jest.mock('electron', () => ({
vi.mock('electron', () => ({
app: {
getPath: jest.fn().mockReturnValue('/fake/user/data'),
getPath: vi.fn().mockReturnValue('/fake/user/data'),
},
}));

import { app } from 'electron';
import path from 'node:path';
import { ComfyServerConfig } from '../../src/config/comfyServerConfig';
import fsPromises from 'node:fs/promises';
vi.mock('electron-log/main', () => ({
default: {
info: vi.fn(),
error: vi.fn(),
},
}));

async function createTmpDir() {
const prefix = path.join(tmpdir(), 'vitest-');
return await mkdtemp(prefix);
}

describe('ComfyServerConfig', () => {
describe('configPath', () => {
it('should return the correct path', () => {
// Mock the userData path
const mockUserDataPath = '/fake/user/data';
(app.getPath as jest.Mock).mockImplementation((key: string) => {
vi.mocked(app.getPath).mockImplementation((key: string) => {
if (key === 'userData') {
return mockUserDataPath;
}
Expand All @@ -34,9 +48,13 @@ describe('ComfyServerConfig', () => {
});

describe('readBasePathFromConfig', () => {
const testConfigPath = path.join(__dirname, 'test_config.yaml');
let tmpdir = '';
let testConfigPath = '';

beforeAll(async () => {
tmpdir = await createTmpDir();
testConfigPath = path.join(tmpdir, 'test_config.yaml');

// Create a test YAML file
const testConfig = `# Test ComfyUI config
comfyui:
Expand All @@ -45,11 +63,11 @@ comfyui:
checkpoints: models/checkpoints/
loras: models/loras/`;

await fsPromises.writeFile(testConfigPath, testConfig, 'utf8');
await writeFile(testConfigPath, testConfig, 'utf8');
});

afterAll(async () => {
await fsPromises.rm(testConfigPath);
await rm(tmpdir, { recursive: true });
});

it('should read base_path from valid config file', async () => {
Expand All @@ -65,14 +83,14 @@ comfyui:
});

it('should detect invalid config file', async () => {
const invalidConfigPath = path.join(__dirname, 'invalid_config.yaml');
await fsPromises.writeFile(invalidConfigPath, 'invalid: yaml: content:', 'utf8');
const invalidConfigPath = path.join(tmpdir, 'invalid_config.yaml');
await writeFile(invalidConfigPath, 'invalid: yaml: content:', 'utf8');

const result = await ComfyServerConfig.readBasePathFromConfig(invalidConfigPath);
expect(result.status).toBe('invalid');
expect(result.path).toBeUndefined();

await fsPromises.rm(invalidConfigPath);
await rm(invalidConfigPath);
});
});
});
7 changes: 4 additions & 3 deletions tests/unit/handlers/appinfoHandlers.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ipcMain } from 'electron';
import { AppInfoHandlers } from '../../../src/handlers/appInfoHandlers';
import { IPC_CHANNELS } from '../../../src/constants';
import { beforeEach, describe, expect, it, vi } from 'vitest';

jest.mock('electron', () => ({
vi.mock('electron', () => ({
ipcMain: {
on: jest.fn(),
handle: jest.fn(),
on: vi.fn(),
handle: vi.fn(),
},
}));

Expand Down
7 changes: 4 additions & 3 deletions tests/unit/handlers/pathHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { ipcMain } from 'electron';

import { PathHandlers } from '../../../src/handlers/pathHandlers';
import { IPC_CHANNELS } from '../../../src/constants';
import { beforeEach, describe, expect, it, vi } from 'vitest';

jest.mock('electron', () => ({
vi.mock('electron', () => ({
ipcMain: {
on: jest.fn(),
handle: jest.fn(),
on: vi.fn(),
handle: vi.fn(),
},
}));

Expand Down
Loading
Loading