@capawesome/cli
Version:
The Capawesome Cloud Command Line Interface (CLI) to manage Live Updates and more.
133 lines (132 loc) • 6.5 kB
JavaScript
import { DEFAULT_API_BASE_URL } from '../../../config/consts.js';
import authorizationService from '../../../services/authorization-service.js';
import { prompt, promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
import userConfig from '../../../utils/user-config.js';
import consola from 'consola';
import nock from 'nock';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import createChannelCommand from './create.js';
// Mock dependencies
vi.mock('@/utils/user-config.js');
vi.mock('@/utils/prompt.js');
vi.mock('@/services/authorization-service.js');
vi.mock('consola');
vi.mock('@/utils/environment.js', () => ({
isInteractive: () => true,
}));
describe('apps-channels-create', () => {
const mockUserConfig = vi.mocked(userConfig);
const mockPrompt = vi.mocked(prompt);
const mockPromptOrganizationSelection = vi.mocked(promptOrganizationSelection);
const mockPromptAppSelection = vi.mocked(promptAppSelection);
const mockConsola = vi.mocked(consola);
const mockAuthorizationService = vi.mocked(authorizationService);
beforeEach(() => {
vi.clearAllMocks();
mockUserConfig.read.mockReturnValue({ token: 'test-token' });
mockAuthorizationService.getCurrentAuthorizationToken.mockReturnValue('test-token');
mockAuthorizationService.hasAuthorizationToken.mockReturnValue(true);
vi.spyOn(process, 'exit').mockImplementation((code) => {
throw new Error(`Process exited with code ${code}`);
});
});
afterEach(() => {
nock.cleanAll();
vi.restoreAllMocks();
});
it('should create channel with provided options', async () => {
const appId = 'app-123';
const channelName = 'production';
const protectedFlag = true;
const channelId = 'channel-456';
const testToken = 'test-token';
const options = { appId, name: channelName, protected: protectedFlag };
const scope = nock(DEFAULT_API_BASE_URL)
.post(`/v1/apps/${appId}/channels`, {
appId,
name: channelName,
protected: protectedFlag,
})
.matchHeader('Authorization', `Bearer ${testToken}`)
.reply(201, { id: channelId, name: channelName });
await createChannelCommand.action(options, undefined);
expect(scope.isDone()).toBe(true);
expect(mockConsola.success).toHaveBeenCalledWith('Channel created successfully.');
expect(mockConsola.info).toHaveBeenCalledWith(`Channel ID: ${channelId}`);
});
it('should prompt for app when not provided', async () => {
const channelName = 'staging';
const orgId = 'org-1';
const appId = 'app-1';
const channelId = 'channel-456';
const testToken = 'test-token';
const options = { name: channelName };
const createScope = nock(DEFAULT_API_BASE_URL)
.post(`/v1/apps/${appId}/channels`, {
appId,
name: channelName,
protected: undefined,
})
.matchHeader('Authorization', `Bearer ${testToken}`)
.reply(201, { id: channelId, name: channelName });
mockPromptOrganizationSelection.mockResolvedValueOnce(orgId);
mockPromptAppSelection.mockResolvedValueOnce(appId);
await createChannelCommand.action(options, undefined);
expect(createScope.isDone()).toBe(true);
expect(mockConsola.success).toHaveBeenCalledWith('Channel created successfully.');
});
it('should prompt for channel name when not provided', async () => {
const options = { appId: 'app-123' };
const scope = nock(DEFAULT_API_BASE_URL)
.post('/v1/apps/app-123/channels', {
appId: 'app-123',
name: 'development',
protected: undefined,
})
.matchHeader('Authorization', 'Bearer test-token')
.reply(201, { id: 'channel-456', name: 'development' });
mockPrompt.mockResolvedValueOnce('development');
await createChannelCommand.action(options, undefined);
expect(scope.isDone()).toBe(true);
expect(mockPrompt).toHaveBeenCalledWith('Enter the name of the channel:', { type: 'text' });
});
it('should handle error with ignoreErrors flag', async () => {
const options = { appId: 'app-123', name: 'production', ignoreErrors: true };
const scope = nock(DEFAULT_API_BASE_URL)
.post('/v1/apps/app-123/channels')
.matchHeader('Authorization', 'Bearer test-token')
.reply(400, { message: 'Channel name already exists' });
await expect(createChannelCommand.action(options, undefined)).rejects.toThrow('Process exited with code 0');
expect(scope.isDone()).toBe(true);
expect(mockConsola.error).toHaveBeenCalled();
});
it('should handle error without ignoreErrors flag', async () => {
const options = { appId: 'app-123', name: 'production' };
const scope = nock(DEFAULT_API_BASE_URL)
.post('/v1/apps/app-123/channels')
.matchHeader('Authorization', 'Bearer test-token')
.reply(400, { message: 'Channel name already exists' });
await expect(createChannelCommand.action(options, undefined)).rejects.toThrow();
expect(scope.isDone()).toBe(true);
});
it('should show warning when expiresInDays option is used', async () => {
const appId = 'app-123';
const channelName = 'production';
const expiresInDays = 30;
const channelId = 'channel-456';
const testToken = 'test-token';
const options = { appId, name: channelName, expiresInDays };
const scope = nock(DEFAULT_API_BASE_URL)
.post(`/v1/apps/${appId}/channels`, {
appId,
name: channelName,
protected: undefined,
})
.matchHeader('Authorization', `Bearer ${testToken}`)
.reply(201, { id: channelId, name: channelName });
await createChannelCommand.action(options, undefined);
expect(scope.isDone()).toBe(true);
expect(mockConsola.warn).toHaveBeenCalledWith('The `--expires-in-days` option is deprecated and will be removed in a future version. Channel expiration is now managed by the data retention policy of your organization billing plan.');
expect(mockConsola.success).toHaveBeenCalledWith('Channel created successfully.');
});
});