rs-runner
Version:
RS is a CLI tool for quickly detecting package.json scripts, and running them.
162 lines (129 loc) • 4.33 kB
text/typescript
import * as fs from 'fs';
import * as os from 'os';
import path from 'path';
import { getConfig, writeConfig } from '../src/lib/config';
import { Config } from '../src/types';
jest.mock('fs');
jest.mock('os');
describe('config module', () => {
const mockHomedir = '/home/testuser';
const configDir = path.join(mockHomedir, '.rs-runner');
const configPath = path.join(configDir, 'config.json');
beforeEach(() => {
jest.resetAllMocks();
(os.homedir as jest.Mock).mockReturnValue(mockHomedir);
(fs.existsSync as jest.Mock).mockReturnValue(true);
});
describe('getConfig', () => {
it('should return valid config from file', () => {
const validConfig: Config = {
globalScripts: {
lint: 'eslint .',
format: 'prettier --write .',
},
directoryScripts: {},
};
(fs.readFileSync as jest.Mock).mockReturnValue(
JSON.stringify(validConfig),
);
const result = getConfig();
expect(result).toEqual(validConfig);
});
it('should return null when config file does not exist', () => {
(fs.existsSync as jest.Mock).mockImplementation((p) => {
if (p === configPath) return false;
return true;
});
expect(getConfig()).toBeNull();
});
it('should return null for invalid config (missing globalScripts)', () => {
const invalidConfig = {
directoryScripts: {},
};
(fs.readFileSync as jest.Mock).mockReturnValue(
JSON.stringify(invalidConfig),
);
expect(getConfig()).toBeNull();
});
it('should return null for invalid config (globalScripts not object)', () => {
const invalidConfig = {
globalScripts: 'not an object',
directoryScripts: {},
};
(fs.readFileSync as jest.Mock).mockReturnValue(
JSON.stringify(invalidConfig),
);
expect(getConfig()).toBeNull();
});
it('should accept config without directoryScripts', () => {
const config = {
globalScripts: { test: 'jest' },
};
(fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(config));
const result = getConfig();
expect(result).toEqual(config);
});
it('should create config directory if it does not exist', () => {
(fs.existsSync as jest.Mock).mockImplementation((p) => {
if (p === configDir) return false;
if (p === configPath) return true;
return false;
});
const validConfig: Config = {
globalScripts: {},
directoryScripts: {},
};
(fs.readFileSync as jest.Mock).mockReturnValue(
JSON.stringify(validConfig),
);
getConfig();
expect(fs.mkdirSync).toHaveBeenCalledWith(configDir, { recursive: true });
});
it('should return config with directoryScripts', () => {
const config: Config = {
globalScripts: { build: 'npm run build' },
directoryScripts: {
'/project/a': { test: 'jest' },
'/project/b': { test: 'vitest' },
},
};
(fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(config));
expect(getConfig()).toEqual(config);
});
});
describe('writeConfig', () => {
it('should write config to file with proper formatting', () => {
const config: Config = {
globalScripts: { test: 'jest' },
directoryScripts: {},
};
writeConfig(config);
expect(fs.writeFileSync).toHaveBeenCalledWith(
configPath,
JSON.stringify(config, null, 2),
'utf8',
);
});
it('should write complex config correctly', () => {
const config: Config = {
globalScripts: {
lint: 'eslint .',
format: 'prettier --write .',
typecheck: 'tsc --noEmit',
},
directoryScripts: {
'/home/user/project': {
dev: 'vite dev',
build: 'vite build',
},
},
};
writeConfig(config);
expect(fs.writeFileSync).toHaveBeenCalledWith(
configPath,
JSON.stringify(config, null, 2),
'utf8',
);
});
});
});