Files
wehub-resource-sync 0d3cb498a3
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
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
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) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:08 +08:00

286 lines
10 KiB
TypeScript

import confirm from '@inquirer/confirm';
import { Command } from 'commander';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { configCommand } from '../../src/commands/config';
import { getUserEmail, setUserEmail } from '../../src/globalConfig/accounts';
import { cloudConfig } from '../../src/globalConfig/cloud';
import logger from '../../src/logger';
vi.mock('../../src/globalConfig/accounts');
vi.mock('../../src/globalConfig/cloud');
vi.mock('../../src/logger', () => ({
default: {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
},
}));
vi.mock('@inquirer/confirm');
describe('config command', () => {
let program: Command;
beforeEach(() => {
vi.clearAllMocks();
program = new Command();
configCommand(program);
});
describe('set email', () => {
it('should not allow setting email when user is logged in', async () => {
// Mock logged in state
vi.mocked(cloudConfig.getApiKey).mockImplementation(function () {
return 'test-api-key';
});
// Execute set email command
const setEmailCmd = program.commands
.find((cmd) => cmd.name() === 'config')
?.commands.find((cmd) => cmd.name() === 'set')
?.commands.find((cmd) => cmd.name() === 'email');
await setEmailCmd?.parseAsync(['node', 'test', 'new@example.com']);
// Verify email was not set and error was shown
expect(setUserEmail).not.toHaveBeenCalled();
expect(logger.error).toHaveBeenCalledWith(
expect.stringContaining(
"Cannot update email while logged in. Email is managed through 'promptfoo auth login'",
),
);
expect(process.exitCode).toBe(1);
});
it('should allow setting email when user is not logged in', async () => {
// Mock logged out state
vi.mocked(cloudConfig.getApiKey).mockImplementation(function () {
return undefined;
});
// Execute set email command
const setEmailCmd = program.commands
.find((cmd) => cmd.name() === 'config')
?.commands.find((cmd) => cmd.name() === 'set')
?.commands.find((cmd) => cmd.name() === 'email');
await setEmailCmd?.parseAsync(['node', 'test', 'test@example.com']);
// Verify email was set
expect(setUserEmail).toHaveBeenCalledWith('test@example.com');
expect(logger.info).toHaveBeenCalledWith(
expect.stringContaining('Email set to test@example.com'),
);
});
it('should validate email format even when not logged in', async () => {
// Mock logged out state
vi.mocked(cloudConfig.getApiKey).mockImplementation(function () {
return undefined;
});
// Execute set email command with invalid email
const setEmailCmd = program.commands
.find((cmd) => cmd.name() === 'config')
?.commands.find((cmd) => cmd.name() === 'set')
?.commands.find((cmd) => cmd.name() === 'email');
await setEmailCmd?.parseAsync(['node', 'test', 'invalid-email']);
// Verify email was not set and error was shown
expect(setUserEmail).not.toHaveBeenCalled();
expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('Invalid email address'));
expect(process.exitCode).toBe(1);
});
});
describe('unset email', () => {
it('should not allow unsetting email when user is logged in', async () => {
// Mock logged in state
vi.mocked(cloudConfig.getApiKey).mockImplementation(function () {
return 'test-api-key';
});
vi.mocked(getUserEmail).mockImplementation(function () {
return 'test@example.com';
});
// Execute unset email command
const unsetEmailCmd = program.commands
.find((cmd) => cmd.name() === 'config')
?.commands.find((cmd) => cmd.name() === 'unset')
?.commands.find((cmd) => cmd.name() === 'email');
await unsetEmailCmd?.parseAsync(['node', 'test']);
// Verify email was not unset and error was shown
expect(setUserEmail).not.toHaveBeenCalled();
expect(logger.error).toHaveBeenCalledWith(
expect.stringContaining(
"Cannot update email while logged in. Email is managed through 'promptfoo auth login'",
),
);
expect(process.exitCode).toBe(1);
});
it('should allow unsetting email when user is not logged in with force flag', async () => {
// Mock logged out state
vi.mocked(cloudConfig.getApiKey).mockImplementation(function () {
return undefined;
});
vi.mocked(getUserEmail).mockImplementation(function () {
return 'test@example.com';
});
// Execute unset email command with force flag
const unsetEmailCmd = program.commands
.find((cmd) => cmd.name() === 'config')
?.commands.find((cmd) => cmd.name() === 'unset')
?.commands.find((cmd) => cmd.name() === 'email');
await unsetEmailCmd?.parseAsync(['node', 'test', '--force']);
// Verify email was unset
expect(setUserEmail).toHaveBeenCalledWith('');
expect(logger.info).toHaveBeenCalledWith('Email has been unset.');
});
it('should handle user confirmation for unsetting email', async () => {
// Mock logged out state and user confirmation
vi.mocked(cloudConfig.getApiKey).mockImplementation(function () {
return undefined;
});
vi.mocked(getUserEmail).mockImplementation(function () {
return 'test@example.com';
});
vi.mocked(confirm).mockResolvedValueOnce(true);
// Execute unset email command without force flag
const unsetEmailCmd = program.commands
.find((cmd) => cmd.name() === 'config')
?.commands.find((cmd) => cmd.name() === 'unset')
?.commands.find((cmd) => cmd.name() === 'email');
await unsetEmailCmd?.parseAsync(['node', 'test']);
// Verify email was unset after confirmation
expect(confirm).toHaveBeenCalledWith({
message: 'Are you sure you want to unset the email "test@example.com"?',
default: false,
});
expect(setUserEmail).toHaveBeenCalledWith('');
expect(logger.info).toHaveBeenCalledWith('Email has been unset.');
});
it('should handle user cancellation for unsetting email', async () => {
// Mock logged out state and user cancellation
vi.mocked(cloudConfig.getApiKey).mockImplementation(function () {
return undefined;
});
vi.mocked(getUserEmail).mockImplementation(function () {
return 'test@example.com';
});
vi.mocked(confirm).mockResolvedValueOnce(false);
// Execute unset email command without force flag
const unsetEmailCmd = program.commands
.find((cmd) => cmd.name() === 'config')
?.commands.find((cmd) => cmd.name() === 'unset')
?.commands.find((cmd) => cmd.name() === 'email');
await unsetEmailCmd?.parseAsync(['node', 'test']);
// Verify operation was cancelled
expect(setUserEmail).not.toHaveBeenCalled();
expect(logger.info).toHaveBeenCalledWith('Operation cancelled.');
});
it('should handle case when no email is set', async () => {
// Mock logged out state and no existing email
vi.mocked(cloudConfig.getApiKey).mockImplementation(function () {
return undefined;
});
vi.mocked(getUserEmail).mockImplementation(function () {
return null;
});
// Execute unset email command
const unsetEmailCmd = program.commands
.find((cmd) => cmd.name() === 'config')
?.commands.find((cmd) => cmd.name() === 'unset')
?.commands.find((cmd) => cmd.name() === 'email');
await unsetEmailCmd?.parseAsync(['node', 'test']);
// Verify appropriate message was shown
expect(logger.info).toHaveBeenCalledWith('No email is currently set.');
expect(setUserEmail).not.toHaveBeenCalled();
});
});
describe('get email', () => {
it('should show email when it exists', async () => {
// Mock existing email
vi.mocked(getUserEmail).mockImplementation(function () {
return 'test@example.com';
});
vi.mocked(cloudConfig.getApiKey).mockImplementation(function () {
return undefined;
});
// Execute get email command
const getEmailCmd = program.commands
.find((cmd) => cmd.name() === 'config')
?.commands.find((cmd) => cmd.name() === 'get')
?.commands.find((cmd) => cmd.name() === 'email');
await getEmailCmd?.parseAsync(['node', 'test']);
// Verify email was shown
expect(logger.info).toHaveBeenCalledWith('test@example.com');
});
it('should show message when no email is set', async () => {
// Mock no existing email
vi.mocked(getUserEmail).mockImplementation(function () {
return null;
});
vi.mocked(cloudConfig.getApiKey).mockImplementation(function () {
return undefined;
});
// Execute get email command
const getEmailCmd = program.commands
.find((cmd) => cmd.name() === 'config')
?.commands.find((cmd) => cmd.name() === 'get')
?.commands.find((cmd) => cmd.name() === 'email');
await getEmailCmd?.parseAsync(['node', 'test']);
// Verify message was shown
expect(logger.info).toHaveBeenCalledWith(
'No email set. Use "promptfoo config set email <email>" to set one.',
);
});
it('should show auth guidance when API key exists and no local email is set', async () => {
vi.mocked(getUserEmail).mockImplementation(function () {
return null;
});
vi.mocked(cloudConfig.getApiKey).mockImplementation(function () {
return 'test-api-key';
});
const getEmailCmd = program.commands
.find((cmd) => cmd.name() === 'config')
?.commands.find((cmd) => cmd.name() === 'get')
?.commands.find((cmd) => cmd.name() === 'email');
await getEmailCmd?.parseAsync(['node', 'test']);
expect(logger.info).toHaveBeenCalledWith(
"Email is managed through 'promptfoo auth login'. Run 'promptfoo auth whoami' to view the current account.",
);
});
});
});