mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-07 02:58:02 +00:00
test(cli): cover full Codex setup flow
This commit is contained in:
parent
a7b8c302d4
commit
cbfdae0303
2 changed files with 141 additions and 0 deletions
|
|
@ -9,6 +9,7 @@ describe('setupCommand skills integration', () => {
|
|||
let tempHome: string;
|
||||
const originalHome = process.env.HOME;
|
||||
const originalUserProfile = process.env.USERPROFILE;
|
||||
const originalPath = process.env.PATH;
|
||||
const testId = `${Date.now()}-${process.pid}`;
|
||||
const flatSkillName = `test-flat-skill-${testId}`;
|
||||
const dirSkillName = `test-dir-skill-${testId}`;
|
||||
|
|
@ -47,6 +48,7 @@ describe('setupCommand skills integration', () => {
|
|||
await fs.rm(path.join(packageSkillsRoot, dirSkillName), { recursive: true, force: true });
|
||||
process.env.HOME = originalHome;
|
||||
process.env.USERPROFILE = originalUserProfile;
|
||||
process.env.PATH = originalPath;
|
||||
await fs.rm(tempHome, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
|
|
@ -85,4 +87,40 @@ describe('setupCommand skills integration', () => {
|
|||
);
|
||||
expect(nestedInstalled).toContain('Directory Nested File');
|
||||
});
|
||||
|
||||
it('falls back to Codex config.toml and installs skills into ~/.agents/skills when codex CLI is unavailable', async () => {
|
||||
await fs.mkdir(path.join(tempHome, '.codex'), { recursive: true });
|
||||
process.env.PATH = '';
|
||||
|
||||
await setupCommand();
|
||||
|
||||
const codexConfig = await fs.readFile(
|
||||
path.join(tempHome, '.codex', 'config.toml'),
|
||||
'utf-8',
|
||||
);
|
||||
expect(codexConfig).toContain('[mcp_servers.gitnexus]');
|
||||
expect(codexConfig).toContain('gitnexus@latest');
|
||||
|
||||
const codexSkill = await fs.readFile(
|
||||
path.join(tempHome, '.agents', 'skills', 'gitnexus-cli', 'SKILL.md'),
|
||||
'utf-8',
|
||||
);
|
||||
expect(codexSkill).toContain('GitNexus CLI Commands');
|
||||
});
|
||||
|
||||
it('does not duplicate the Codex MCP section on repeated fallback setup runs', async () => {
|
||||
await fs.mkdir(path.join(tempHome, '.codex'), { recursive: true });
|
||||
process.env.PATH = '';
|
||||
|
||||
await setupCommand();
|
||||
await setupCommand();
|
||||
|
||||
const codexConfig = await fs.readFile(
|
||||
path.join(tempHome, '.codex', 'config.toml'),
|
||||
'utf-8',
|
||||
);
|
||||
const sectionMatches = codexConfig.match(/\[mcp_servers\.gitnexus\]/g) ?? [];
|
||||
|
||||
expect(sectionMatches).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
103
gitnexus/test/unit/setup-codex.test.ts
Normal file
103
gitnexus/test/unit/setup-codex.test.ts
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import fs from 'fs/promises';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
const execFileMock = vi.fn((...args: any[]) => {
|
||||
const callback = args.at(-1);
|
||||
if (typeof callback === 'function') {
|
||||
callback(null, '', '');
|
||||
}
|
||||
});
|
||||
|
||||
vi.mock('child_process', () => ({
|
||||
execFile: execFileMock,
|
||||
}));
|
||||
|
||||
describe('setupCommand codex execution', () => {
|
||||
let tempHome: string;
|
||||
let originalHome: string | undefined;
|
||||
let originalUserProfile: string | undefined;
|
||||
let platformDescriptor: PropertyDescriptor | undefined;
|
||||
|
||||
const setPlatform = (value: NodeJS.Platform) => {
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value,
|
||||
configurable: true,
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
vi.clearAllMocks();
|
||||
|
||||
originalHome = process.env.HOME;
|
||||
originalUserProfile = process.env.USERPROFILE;
|
||||
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), 'gn-codex-setup-'));
|
||||
process.env.HOME = tempHome;
|
||||
process.env.USERPROFILE = tempHome;
|
||||
|
||||
await fs.mkdir(path.join(tempHome, '.codex'), { recursive: true });
|
||||
|
||||
platformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform');
|
||||
setPlatform('win32');
|
||||
vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
vi.restoreAllMocks();
|
||||
|
||||
if (platformDescriptor) {
|
||||
Object.defineProperty(process, 'platform', platformDescriptor);
|
||||
}
|
||||
|
||||
process.env.HOME = originalHome;
|
||||
process.env.USERPROFILE = originalUserProfile;
|
||||
await fs.rm(tempHome, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('invokes codex mcp add with shell enabled on Windows', async () => {
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
|
||||
await setupCommand();
|
||||
|
||||
expect(execFileMock).toHaveBeenCalledWith(
|
||||
'codex',
|
||||
['mcp', 'add', 'gitnexus', '--', 'cmd', '/c', 'npx', '-y', 'gitnexus@latest', 'mcp'],
|
||||
{ shell: true },
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it('invokes codex mcp add without shell on non-Windows and does not write fallback config', async () => {
|
||||
setPlatform('darwin');
|
||||
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
|
||||
await setupCommand();
|
||||
|
||||
expect(execFileMock).toHaveBeenCalledWith(
|
||||
'codex',
|
||||
['mcp', 'add', 'gitnexus', '--', 'npx', '-y', 'gitnexus@latest', 'mcp'],
|
||||
{ shell: false },
|
||||
expect.any(Function),
|
||||
);
|
||||
|
||||
await expect(
|
||||
fs.access(path.join(tempHome, '.codex', 'config.toml')),
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('skips Codex setup entirely when ~/.codex is missing', async () => {
|
||||
await fs.rm(path.join(tempHome, '.codex'), { recursive: true, force: true });
|
||||
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
|
||||
await setupCommand();
|
||||
|
||||
expect(execFileMock).not.toHaveBeenCalled();
|
||||
await expect(
|
||||
fs.access(path.join(tempHome, '.agents', 'skills')),
|
||||
).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue