84 lines
3.2 KiB
TypeScript
84 lines
3.2 KiB
TypeScript
import fs from 'node:fs/promises';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { restoreCwdSafely } from './fixtures/test-helpers.js';
|
|
|
|
process.env.MCPORTER_DISABLE_AUTORUN = '1';
|
|
const cliModulePromise = import('../src/cli.js');
|
|
|
|
describe('mcporter list --verbose end-to-end', () => {
|
|
let tempDir: string;
|
|
let originalCwd: string;
|
|
let restoreHomedir: (() => void) | undefined;
|
|
let originalEnv: NodeJS.ProcessEnv;
|
|
|
|
beforeEach(async () => {
|
|
originalCwd = process.cwd();
|
|
originalEnv = { ...process.env };
|
|
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-cli-verbose-'));
|
|
const spy = vi.spyOn(os, 'homedir');
|
|
spy.mockReturnValue(tempDir);
|
|
restoreHomedir = () => spy.mockRestore();
|
|
process.env.MCPORTER_NO_FORCE_EXIT = '1';
|
|
process.env.HOME = tempDir;
|
|
process.env.USERPROFILE = tempDir;
|
|
});
|
|
|
|
afterEach(async () => {
|
|
restoreHomedir?.();
|
|
delete process.env.MCPORTER_NO_FORCE_EXIT;
|
|
process.env = { ...originalEnv };
|
|
restoreCwdSafely(originalCwd);
|
|
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {});
|
|
process.exitCode = undefined;
|
|
});
|
|
|
|
it('prints verbose source markers in text output and includes sources in JSON', { concurrent: false }, async () => {
|
|
const projectConfigPath = path.join(tempDir, 'config', 'mcporter.json');
|
|
await fs.mkdir(path.dirname(projectConfigPath), { recursive: true });
|
|
await fs.writeFile(
|
|
projectConfigPath,
|
|
JSON.stringify(
|
|
{ imports: ['cursor'], mcpServers: { alpha: { baseUrl: 'https://primary.example.com/mcp' } } },
|
|
null,
|
|
2
|
|
),
|
|
'utf8'
|
|
);
|
|
|
|
const cursorConfigPath = path.join(tempDir, '.cursor', 'mcp.json');
|
|
await fs.mkdir(path.dirname(cursorConfigPath), { recursive: true });
|
|
await fs.writeFile(
|
|
cursorConfigPath,
|
|
JSON.stringify({ mcpServers: { alpha: { baseUrl: 'https://shadow.example.com/mcp' } } }, null, 2),
|
|
'utf8'
|
|
);
|
|
|
|
const { runCli } = await cliModulePromise;
|
|
|
|
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
|
|
// Text mode verbose should render primary + shadowed paths.
|
|
process.env.MCPORTER_CONFIG = projectConfigPath;
|
|
await runCli(['list', '--verbose']);
|
|
const textOutput = logSpy.mock.calls.map((call) => call.join(' ')).join('\n');
|
|
expect(textOutput).toContain('alpha');
|
|
expect(textOutput).toContain('(primary');
|
|
expect(textOutput).toContain('(shadowed by local');
|
|
expect(textOutput).toContain('cursor');
|
|
|
|
logSpy.mockClear();
|
|
|
|
// JSON mode with --sources should include the sources array even without --verbose.
|
|
await runCli(['list', '--json', '--sources']);
|
|
const jsonPayload = JSON.parse(logSpy.mock.calls.at(-1)?.[0] ?? '{}');
|
|
const server = jsonPayload.servers?.find((entry: { name: string }) => entry.name === 'alpha');
|
|
const sources = (server?.sources ?? []).map((entry: { path: string }) => entry.path.replace('/private', ''));
|
|
const expected = [projectConfigPath.replace('/private', ''), cursorConfigPath.replace('/private', '')];
|
|
expect(sources).toEqual(expected);
|
|
|
|
logSpy.mockRestore();
|
|
});
|
|
});
|