From ded8e0ae3e6e3cae111b25ca9a4d12a35f209b19 Mon Sep 17 00:00:00 2001 From: Cascade Bot Date: Tue, 17 Mar 2026 18:19:07 +0000 Subject: [PATCH] test(cli): add unit tests for dashboard users, org, and agents commands --- .../unit/cli/dashboard/agents/agents.test.ts | 359 ++++++++++++++++++ tests/unit/cli/dashboard/org/org.test.ts | 122 ++++++ tests/unit/cli/dashboard/users/users.test.ts | 322 ++++++++++++++++ 3 files changed, 803 insertions(+) create mode 100644 tests/unit/cli/dashboard/agents/agents.test.ts create mode 100644 tests/unit/cli/dashboard/org/org.test.ts create mode 100644 tests/unit/cli/dashboard/users/users.test.ts diff --git a/tests/unit/cli/dashboard/agents/agents.test.ts b/tests/unit/cli/dashboard/agents/agents.test.ts new file mode 100644 index 00000000..a6d87075 --- /dev/null +++ b/tests/unit/cli/dashboard/agents/agents.test.ts @@ -0,0 +1,359 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const mockLoadConfig = vi.fn(); +const mockCreateDashboardClient = vi.fn(); + +vi.mock('../../../../../src/cli/dashboard/_shared/config.js', () => ({ + loadConfig: (...args: unknown[]) => mockLoadConfig(...args), +})); + +vi.mock('../../../../../src/cli/dashboard/_shared/client.js', () => ({ + createDashboardClient: (...args: unknown[]) => mockCreateDashboardClient(...args), +})); + +vi.mock('chalk', () => ({ + default: { + bold: (s: string) => s, + blue: (s: string) => s, + green: (s: string) => s, + red: (s: string) => s, + yellow: (s: string) => s, + dim: (s: string) => s, + }, +})); + +import AgentsCreate from '../../../../../src/cli/dashboard/agents/create.js'; +import AgentsDelete from '../../../../../src/cli/dashboard/agents/delete.js'; +import AgentsList from '../../../../../src/cli/dashboard/agents/list.js'; +import AgentsUpdate from '../../../../../src/cli/dashboard/agents/update.js'; + +// oclif's Command.parse() calls this.config.runHook internally +const oclifConfig = { + runHook: vi.fn().mockResolvedValue({ successes: [], failures: [] }), +}; + +const sampleAgentConfig = { + id: 1, + agentType: 'implementation', + projectId: 'my-project', + model: 'claude-sonnet-4-5-20250929', + maxIterations: 50, + agentEngine: 'llmist', + maxConcurrency: null, + prompt: null, +}; + +function makeClient(overrides: Record = {}) { + return { + agentConfigs: { + list: { query: vi.fn().mockResolvedValue([]) }, + create: { mutate: vi.fn().mockResolvedValue(sampleAgentConfig) }, + update: { mutate: vi.fn().mockResolvedValue(undefined) }, + delete: { mutate: vi.fn().mockResolvedValue(undefined) }, + }, + ...overrides, + }; +} + +const baseConfig = { serverUrl: 'http://localhost:3000', sessionToken: 'tok' }; + +// --------------------------------------------------------------------------- +// agents list +// --------------------------------------------------------------------------- +describe('AgentsList (list)', () => { + beforeEach(() => { + mockLoadConfig.mockReturnValue(baseConfig); + }); + + it('passes --project-id to client.agentConfigs.list.query', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsList(['--project-id', 'my-project'], oclifConfig as never); + await cmd.run(); + + expect(client.agentConfigs.list.query).toHaveBeenCalledWith({ projectId: 'my-project' }); + }); + + it('calls list query with --json flag', async () => { + const client = makeClient(); + (client.agentConfigs.list.query as ReturnType).mockResolvedValue([ + sampleAgentConfig, + ]); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsList(['--project-id', 'my-project', '--json'], oclifConfig as never); + await cmd.run(); + + expect(client.agentConfigs.list.query).toHaveBeenCalledWith({ projectId: 'my-project' }); + }); + + it('handles empty agent config list', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsList(['--project-id', 'my-project'], oclifConfig as never); + await expect(cmd.run()).resolves.toBeUndefined(); + }); + + it('requires --project-id flag', async () => { + mockCreateDashboardClient.mockReturnValue(makeClient()); + + const cmd = new AgentsList([], oclifConfig as never); + await expect(cmd.run()).rejects.toThrow(); + }); +}); + +// --------------------------------------------------------------------------- +// agents create +// --------------------------------------------------------------------------- +describe('AgentsCreate (create)', () => { + beforeEach(() => { + mockLoadConfig.mockReturnValue(baseConfig); + }); + + it('passes --agent-type and --project-id to client.agentConfigs.create.mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsCreate( + ['--agent-type', 'implementation', '--project-id', 'my-project'], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.agentConfigs.create.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + agentType: 'implementation', + projectId: 'my-project', + }), + ); + }); + + it('passes optional --model flag to mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsCreate( + [ + '--agent-type', + 'implementation', + '--project-id', + 'my-project', + '--model', + 'claude-sonnet-4-5-20250929', + ], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.agentConfigs.create.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + agentType: 'implementation', + projectId: 'my-project', + model: 'claude-sonnet-4-5-20250929', + }), + ); + }); + + it('passes optional --engine flag to mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsCreate( + ['--agent-type', 'review', '--project-id', 'my-project', '--engine', 'claude-code'], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.agentConfigs.create.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + agentType: 'review', + projectId: 'my-project', + agentEngine: 'claude-code', + }), + ); + }); + + it('passes all optional flags together', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsCreate( + [ + '--agent-type', + 'implementation', + '--project-id', + 'my-project', + '--model', + 'claude-sonnet-4-5-20250929', + '--engine', + 'llmist', + '--max-iterations', + '30', + '--max-concurrency', + '2', + ], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.agentConfigs.create.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + agentType: 'implementation', + projectId: 'my-project', + model: 'claude-sonnet-4-5-20250929', + agentEngine: 'llmist', + maxIterations: 30, + maxConcurrency: 2, + }), + ); + }); + + it('outputs json when --json flag is set', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsCreate( + ['--agent-type', 'implementation', '--project-id', 'my-project', '--json'], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.agentConfigs.create.mutate).toHaveBeenCalled(); + }); + + it('requires --agent-type and --project-id flags', async () => { + mockCreateDashboardClient.mockReturnValue(makeClient()); + + const cmd = new AgentsCreate(['--agent-type', 'implementation'], oclifConfig as never); + await expect(cmd.run()).rejects.toThrow(); + }); +}); + +// --------------------------------------------------------------------------- +// agents update +// --------------------------------------------------------------------------- +describe('AgentsUpdate (update)', () => { + beforeEach(() => { + mockLoadConfig.mockReturnValue(baseConfig); + }); + + it('passes ID with --model flag to client.agentConfigs.update.mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsUpdate( + ['1', '--model', 'claude-sonnet-4-5-20250929'], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.agentConfigs.update.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + id: 1, + model: 'claude-sonnet-4-5-20250929', + }), + ); + }); + + it('passes ID with --max-iterations flag to mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsUpdate(['1', '--max-iterations', '25'], oclifConfig as never); + await cmd.run(); + + expect(client.agentConfigs.update.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + id: 1, + maxIterations: 25, + }), + ); + }); + + it('passes ID with --engine flag to mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsUpdate(['1', '--engine', 'claude-code'], oclifConfig as never); + await cmd.run(); + + expect(client.agentConfigs.update.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + id: 1, + agentEngine: 'claude-code', + }), + ); + }); + + it('passes multiple update flags together', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsUpdate( + [ + '1', + '--model', + 'claude-sonnet-4-5-20250929', + '--max-iterations', + '40', + '--engine', + 'llmist', + ], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.agentConfigs.update.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + id: 1, + model: 'claude-sonnet-4-5-20250929', + maxIterations: 40, + agentEngine: 'llmist', + }), + ); + }); + + it('requires ID argument', async () => { + mockCreateDashboardClient.mockReturnValue(makeClient()); + + const cmd = new AgentsUpdate(['--model', 'claude-sonnet-4-5-20250929'], oclifConfig as never); + await expect(cmd.run()).rejects.toThrow(); + }); +}); + +// --------------------------------------------------------------------------- +// agents delete +// --------------------------------------------------------------------------- +describe('AgentsDelete (delete)', () => { + beforeEach(() => { + mockLoadConfig.mockReturnValue(baseConfig); + }); + + it('passes ID with --yes flag to client.agentConfigs.delete.mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsDelete(['1', '--yes'], oclifConfig as never); + await cmd.run(); + + expect(client.agentConfigs.delete.mutate).toHaveBeenCalledWith({ id: 1 }); + }); + + it('auto-accepts without --yes in non-TTY environments', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new AgentsDelete(['1'], oclifConfig as never); + await expect(cmd.run()).resolves.toBeUndefined(); + expect(client.agentConfigs.delete.mutate).toHaveBeenCalledWith({ id: 1 }); + }); + + it('requires ID argument', async () => { + mockCreateDashboardClient.mockReturnValue(makeClient()); + + const cmd = new AgentsDelete(['--yes'], oclifConfig as never); + await expect(cmd.run()).rejects.toThrow(); + }); +}); diff --git a/tests/unit/cli/dashboard/org/org.test.ts b/tests/unit/cli/dashboard/org/org.test.ts new file mode 100644 index 00000000..71b4e634 --- /dev/null +++ b/tests/unit/cli/dashboard/org/org.test.ts @@ -0,0 +1,122 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const mockLoadConfig = vi.fn(); +const mockCreateDashboardClient = vi.fn(); + +vi.mock('../../../../../src/cli/dashboard/_shared/config.js', () => ({ + loadConfig: (...args: unknown[]) => mockLoadConfig(...args), +})); + +vi.mock('../../../../../src/cli/dashboard/_shared/client.js', () => ({ + createDashboardClient: (...args: unknown[]) => mockCreateDashboardClient(...args), +})); + +vi.mock('chalk', () => ({ + default: { + bold: (s: string) => s, + blue: (s: string) => s, + green: (s: string) => s, + red: (s: string) => s, + yellow: (s: string) => s, + dim: (s: string) => s, + }, +})); + +import OrgShow from '../../../../../src/cli/dashboard/org/show.js'; +import OrgUpdate from '../../../../../src/cli/dashboard/org/update.js'; + +// oclif's Command.parse() calls this.config.runHook internally +const oclifConfig = { + runHook: vi.fn().mockResolvedValue({ successes: [], failures: [] }), +}; + +const sampleOrg = { + id: 'org-uuid-123', + name: 'My Organization', +}; + +function makeClient(overrides: Record = {}) { + return { + organization: { + get: { query: vi.fn().mockResolvedValue(sampleOrg) }, + update: { mutate: vi.fn().mockResolvedValue(undefined) }, + }, + ...overrides, + }; +} + +const baseConfig = { serverUrl: 'http://localhost:3000', sessionToken: 'tok' }; + +// --------------------------------------------------------------------------- +// org show +// --------------------------------------------------------------------------- +describe('OrgShow (show)', () => { + beforeEach(() => { + mockLoadConfig.mockReturnValue(baseConfig); + }); + + it('calls client.organization.get.query', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new OrgShow([], oclifConfig as never); + await cmd.run(); + + expect(client.organization.get.query).toHaveBeenCalledWith(); + }); + + it('outputs json when --json flag is set', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new OrgShow(['--json'], oclifConfig as never); + await cmd.run(); + + expect(client.organization.get.query).toHaveBeenCalledWith(); + }); + + it('handles null org response gracefully', async () => { + const client = makeClient(); + (client.organization.get.query as ReturnType).mockResolvedValue(null); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new OrgShow([], oclifConfig as never); + await expect(cmd.run()).resolves.toBeUndefined(); + }); +}); + +// --------------------------------------------------------------------------- +// org update +// --------------------------------------------------------------------------- +describe('OrgUpdate (update)', () => { + beforeEach(() => { + mockLoadConfig.mockReturnValue(baseConfig); + }); + + it('passes --name flag to client.organization.update.mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new OrgUpdate(['--name', 'New Org Name'], oclifConfig as never); + await cmd.run(); + + expect(client.organization.update.mutate).toHaveBeenCalledWith({ name: 'New Org Name' }); + }); + + it('outputs json when --json flag is set', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new OrgUpdate(['--name', 'New Org Name', '--json'], oclifConfig as never); + await cmd.run(); + + expect(client.organization.update.mutate).toHaveBeenCalledWith({ name: 'New Org Name' }); + }); + + it('requires --name flag', async () => { + mockCreateDashboardClient.mockReturnValue(makeClient()); + + const cmd = new OrgUpdate([], oclifConfig as never); + await expect(cmd.run()).rejects.toThrow(); + }); +}); diff --git a/tests/unit/cli/dashboard/users/users.test.ts b/tests/unit/cli/dashboard/users/users.test.ts new file mode 100644 index 00000000..8dbe69ef --- /dev/null +++ b/tests/unit/cli/dashboard/users/users.test.ts @@ -0,0 +1,322 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const mockLoadConfig = vi.fn(); +const mockCreateDashboardClient = vi.fn(); + +vi.mock('../../../../../src/cli/dashboard/_shared/config.js', () => ({ + loadConfig: (...args: unknown[]) => mockLoadConfig(...args), +})); + +vi.mock('../../../../../src/cli/dashboard/_shared/client.js', () => ({ + createDashboardClient: (...args: unknown[]) => mockCreateDashboardClient(...args), +})); + +vi.mock('chalk', () => ({ + default: { + bold: (s: string) => s, + blue: (s: string) => s, + green: (s: string) => s, + red: (s: string) => s, + yellow: (s: string) => s, + dim: (s: string) => s, + }, +})); + +import UsersCreate from '../../../../../src/cli/dashboard/users/create.js'; +import UsersDelete from '../../../../../src/cli/dashboard/users/delete.js'; +import UsersList from '../../../../../src/cli/dashboard/users/list.js'; +import UsersUpdate from '../../../../../src/cli/dashboard/users/update.js'; + +// oclif's Command.parse() calls this.config.runHook internally +const oclifConfig = { + runHook: vi.fn().mockResolvedValue({ successes: [], failures: [] }), +}; + +const sampleUser = { + id: 'user-uuid-123', + email: 'test@example.com', + name: 'Test User', + role: 'member', + createdAt: '2024-01-01T00:00:00.000Z', +}; + +function makeClient(overrides: Record = {}) { + return { + users: { + list: { query: vi.fn().mockResolvedValue([]) }, + create: { mutate: vi.fn().mockResolvedValue(sampleUser) }, + update: { mutate: vi.fn().mockResolvedValue(undefined) }, + delete: { mutate: vi.fn().mockResolvedValue(undefined) }, + }, + ...overrides, + }; +} + +const baseConfig = { serverUrl: 'http://localhost:3000', sessionToken: 'tok' }; + +// --------------------------------------------------------------------------- +// users list +// --------------------------------------------------------------------------- +describe('UsersList (list)', () => { + beforeEach(() => { + mockLoadConfig.mockReturnValue(baseConfig); + }); + + it('calls client.users.list.query', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersList([], oclifConfig as never); + await cmd.run(); + + expect(client.users.list.query).toHaveBeenCalledWith(); + }); + + it('calls client.users.list.query with --json flag', async () => { + const client = makeClient(); + (client.users.list.query as ReturnType).mockResolvedValue([sampleUser]); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersList(['--json'], oclifConfig as never); + await cmd.run(); + + expect(client.users.list.query).toHaveBeenCalledWith(); + }); + + it('handles empty user list', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersList([], oclifConfig as never); + await expect(cmd.run()).resolves.toBeUndefined(); + }); +}); + +// --------------------------------------------------------------------------- +// users create +// --------------------------------------------------------------------------- +describe('UsersCreate (create)', () => { + beforeEach(() => { + mockLoadConfig.mockReturnValue(baseConfig); + }); + + it('passes --email, --password, --name flags to client.users.create.mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersCreate( + ['--email', 'test@example.com', '--password', 'secret123', '--name', 'Test User'], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.users.create.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + email: 'test@example.com', + password: 'secret123', + name: 'Test User', + }), + ); + }); + + it('defaults role to "member" when not specified', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersCreate( + ['--email', 'test@example.com', '--password', 'secret123', '--name', 'Test User'], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.users.create.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + role: 'member', + }), + ); + }); + + it('passes --role flag to client.users.create.mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersCreate( + [ + '--email', + 'admin@example.com', + '--password', + 'secret123', + '--name', + 'Admin User', + '--role', + 'admin', + ], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.users.create.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + email: 'admin@example.com', + name: 'Admin User', + role: 'admin', + }), + ); + }); + + it('outputs json when --json flag is set', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersCreate( + ['--email', 'test@example.com', '--password', 'secret123', '--name', 'Test User', '--json'], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.users.create.mutate).toHaveBeenCalled(); + }); + + it('requires --email, --password, and --name flags', async () => { + mockCreateDashboardClient.mockReturnValue(makeClient()); + + const cmd = new UsersCreate(['--email', 'test@example.com'], oclifConfig as never); + await expect(cmd.run()).rejects.toThrow(); + }); +}); + +// --------------------------------------------------------------------------- +// users update +// --------------------------------------------------------------------------- +describe('UsersUpdate (update)', () => { + beforeEach(() => { + mockLoadConfig.mockReturnValue(baseConfig); + }); + + it('passes user ID with --name flag to client.users.update.mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersUpdate(['user-uuid-123', '--name', 'New Name'], oclifConfig as never); + await cmd.run(); + + expect(client.users.update.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'user-uuid-123', + name: 'New Name', + }), + ); + }); + + it('passes user ID with --email flag to client.users.update.mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersUpdate( + ['user-uuid-123', '--email', 'new@example.com'], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.users.update.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'user-uuid-123', + email: 'new@example.com', + }), + ); + }); + + it('passes user ID with --role flag to client.users.update.mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersUpdate(['user-uuid-123', '--role', 'admin'], oclifConfig as never); + await cmd.run(); + + expect(client.users.update.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'user-uuid-123', + role: 'admin', + }), + ); + }); + + it('passes user ID with --password flag to client.users.update.mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersUpdate( + ['user-uuid-123', '--password', 'newpassword'], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.users.update.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'user-uuid-123', + password: 'newpassword', + }), + ); + }); + + it('passes multiple partial flags together', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersUpdate( + ['user-uuid-123', '--name', 'Updated Name', '--email', 'updated@example.com'], + oclifConfig as never, + ); + await cmd.run(); + + expect(client.users.update.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'user-uuid-123', + name: 'Updated Name', + email: 'updated@example.com', + }), + ); + }); + + it('requires user ID argument', async () => { + mockCreateDashboardClient.mockReturnValue(makeClient()); + + const cmd = new UsersUpdate(['--name', 'Test'], oclifConfig as never); + await expect(cmd.run()).rejects.toThrow(); + }); +}); + +// --------------------------------------------------------------------------- +// users delete +// --------------------------------------------------------------------------- +describe('UsersDelete (delete)', () => { + beforeEach(() => { + mockLoadConfig.mockReturnValue(baseConfig); + }); + + it('passes user ID with --yes flag to client.users.delete.mutate', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersDelete(['user-uuid-123', '--yes'], oclifConfig as never); + await cmd.run(); + + expect(client.users.delete.mutate).toHaveBeenCalledWith({ id: 'user-uuid-123' }); + }); + + it('auto-accepts without --yes in non-TTY environments', async () => { + const client = makeClient(); + mockCreateDashboardClient.mockReturnValue(client); + + const cmd = new UsersDelete(['user-uuid-123'], oclifConfig as never); + await expect(cmd.run()).resolves.toBeUndefined(); + expect(client.users.delete.mutate).toHaveBeenCalledWith({ id: 'user-uuid-123' }); + }); + + it('requires user ID argument', async () => { + mockCreateDashboardClient.mockReturnValue(makeClient()); + + const cmd = new UsersDelete(['--yes'], oclifConfig as never); + await expect(cmd.run()).rejects.toThrow(); + }); +});