0d3cb498a3
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Waiting to run
Test and Publish Multi-arch Docker Image / test (push) Waiting to run
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Blocked by required conditions
Validate Renovate Config / Validate Renovate Configuration (push) Waiting to run
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
213 lines
7.1 KiB
TypeScript
213 lines
7.1 KiB
TypeScript
import { Command } from 'commander';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { viewCommand } from '../../src/commands/view';
|
|
import { getDefaultPort } from '../../src/constants';
|
|
import { startServer } from '../../src/server/server';
|
|
import { setConfigDirectoryPath } from '../../src/util/config/manage';
|
|
import { setupEnv } from '../../src/util/index';
|
|
import { BrowserBehavior } from '../../src/util/server';
|
|
|
|
vi.mock('../../src/util/config/manage', () => ({
|
|
getConfigDirectoryPath: vi.fn().mockReturnValue('/tmp/test-config'),
|
|
setConfigDirectoryPath: vi.fn(),
|
|
maybeReadConfig: vi.fn(),
|
|
readConfigs: vi.fn(),
|
|
}));
|
|
vi.mock('../../src/server/server');
|
|
vi.mock('../../src/util');
|
|
|
|
describe('viewCommand', () => {
|
|
let program: Command;
|
|
|
|
beforeEach(() => {
|
|
program = new Command();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('should register view command with correct options', () => {
|
|
viewCommand(program);
|
|
|
|
const viewCmd = program.commands[0];
|
|
expect(viewCmd.name()).toBe('view');
|
|
expect(viewCmd.description()).toBe('Start browser UI');
|
|
|
|
const options = viewCmd.opts();
|
|
expect(options).toEqual({
|
|
port: getDefaultPort(),
|
|
});
|
|
});
|
|
|
|
it('should call startServer with correct parameters when executed', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync(['node', 'test', '--port', '3001']);
|
|
|
|
expect(startServer).toHaveBeenCalledWith(3001, BrowserBehavior.ASK);
|
|
});
|
|
|
|
it('should handle directory parameter and set config directory', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync(['node', 'test', 'testdir', '--port', '3001']);
|
|
|
|
expect(setConfigDirectoryPath).toHaveBeenCalledWith('testdir');
|
|
});
|
|
|
|
it('should handle browser behavior options correctly', async () => {
|
|
viewCommand(program);
|
|
let viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync(['node', 'test', '--yes']);
|
|
expect(startServer).toHaveBeenCalledWith(getDefaultPort(), BrowserBehavior.OPEN);
|
|
|
|
vi.clearAllMocks();
|
|
|
|
// Reset program and viewCommand for the second test
|
|
program = new Command();
|
|
viewCommand(program);
|
|
viewCmd = program.commands[0];
|
|
|
|
// Use a unique port to avoid confusion with default port
|
|
await viewCmd.parseAsync(['node', 'test', '--no', '--port', '15500']);
|
|
// --no sets BrowserBehavior.SKIP
|
|
expect(startServer).toHaveBeenCalledWith(15500, BrowserBehavior.SKIP);
|
|
});
|
|
|
|
it('should ignore filter description option', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync(['node', 'test', '--filter-description', 'test-pattern']);
|
|
|
|
expect(startServer).toHaveBeenCalledWith(getDefaultPort(), BrowserBehavior.ASK);
|
|
});
|
|
|
|
it('should setup environment from env file path', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync(['node', 'test', '--env-path', '.env.test']);
|
|
|
|
expect(setupEnv).toHaveBeenCalledWith('.env.test');
|
|
});
|
|
|
|
it('should handle both --yes and --no options with --yes taking precedence', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync(['node', 'test', '--yes', '--no']);
|
|
|
|
expect(startServer).toHaveBeenCalledWith(getDefaultPort(), BrowserBehavior.OPEN);
|
|
});
|
|
|
|
it('should call startServer with default port if no port is specified', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync(['node', 'test']);
|
|
|
|
expect(startServer).toHaveBeenCalledWith(getDefaultPort(), BrowserBehavior.ASK);
|
|
});
|
|
|
|
it('should support all options together', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync([
|
|
'node',
|
|
'test',
|
|
'mydir',
|
|
'--port',
|
|
'9876',
|
|
'--yes',
|
|
'--filter-description',
|
|
'desc',
|
|
'--env-path',
|
|
'.env.foo',
|
|
]);
|
|
|
|
expect(setConfigDirectoryPath).toHaveBeenCalledWith('mydir');
|
|
expect(setupEnv).toHaveBeenCalledWith('.env.foo');
|
|
expect(startServer).toHaveBeenCalledWith(9876, BrowserBehavior.OPEN);
|
|
});
|
|
|
|
it('should pass undefined directory if not provided', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync(['node', 'test', '--port', '3002']);
|
|
expect(setConfigDirectoryPath).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should prefer --yes over --no if both are supplied', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync(['node', 'test', '--yes', '--no', '--port', '4444']);
|
|
expect(startServer).toHaveBeenCalledWith(4444, BrowserBehavior.OPEN);
|
|
});
|
|
|
|
it('should parse port as string if passed as number', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
// Simulate user passing a numeric port
|
|
await viewCmd.parseAsync(['node', 'test', '--port', '7777']);
|
|
expect(startServer).toHaveBeenCalledWith(7777, BrowserBehavior.ASK);
|
|
});
|
|
|
|
it('should call startServer with undefined filterDescription if not provided', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync(['node', 'test', '--yes', '--port', '2222']);
|
|
expect(startServer).toHaveBeenCalledWith(2222, BrowserBehavior.OPEN);
|
|
});
|
|
|
|
it('should handle --filter-description with empty string', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
await viewCmd.parseAsync(['node', 'test', '--filter-description', '']);
|
|
expect(startServer).toHaveBeenCalledWith(getDefaultPort(), BrowserBehavior.ASK);
|
|
});
|
|
|
|
it('should call setupEnv with undefined if --env-path not provided', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
await viewCmd.parseAsync(['node', 'test']);
|
|
expect(setupEnv).toHaveBeenCalledWith(undefined);
|
|
});
|
|
|
|
it('should call startServer with correct port and browserBehavior when only --no is supplied and --yes is not present', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
vi.clearAllMocks();
|
|
// Only --no, no --yes
|
|
await viewCmd.parseAsync(['node', 'test', '--no', '--port', '15501']);
|
|
// Commander sets --no to true, --yes to undefined, so browserBehavior should be SKIP
|
|
expect(startServer).toHaveBeenCalledWith(15501, BrowserBehavior.SKIP);
|
|
});
|
|
|
|
it('should call startServer with correct port and browserBehavior when only --yes is supplied', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
vi.clearAllMocks();
|
|
await viewCmd.parseAsync(['node', 'test', '--yes', '--port', '16600']);
|
|
expect(startServer).toHaveBeenCalledWith(16600, BrowserBehavior.OPEN);
|
|
});
|
|
|
|
it('should call startServer with ASK when neither --yes nor --no is supplied', async () => {
|
|
viewCommand(program);
|
|
const viewCmd = program.commands[0];
|
|
|
|
vi.clearAllMocks();
|
|
await viewCmd.parseAsync(['node', 'test', '--port', '17700']);
|
|
expect(startServer).toHaveBeenCalledWith(17700, BrowserBehavior.ASK);
|
|
});
|
|
});
|