diff --git a/packages/edge/src/__tests__/commands/edge/channels/enrollments.test.ts b/packages/edge/src/__tests__/commands/edge/channels/enrollments.test.ts deleted file mode 100644 index db2ce434..00000000 --- a/packages/edge/src/__tests__/commands/edge/channels/enrollments.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { outputList } from '@smartthings/cli-lib' -import { EnrolledChannel, HubdevicesEndpoint } from '@smartthings/core-sdk' - -import ChannelsEnrollmentsCommand from '../../../../commands/edge/channels/enrollments.js' -import { chooseHub } from '../../../../lib/commands/drivers-util.js' - - -jest.mock('@smartthings/cli-lib', () => { - const originalLib = jest.requireActual('@smartthings/cli-lib') - - return { - ...originalLib, - outputList: jest.fn(), - } -}) -jest.mock('../../../../../src/lib/commands/drivers-util') - -describe('ChannelsEnrollmentsCommand', () => { - const chooseHubMock = jest.mocked(chooseHub) - const outputListMock = jest.mocked(outputList) - const apiEnrolledChannelsSpy = jest.spyOn(HubdevicesEndpoint.prototype, 'enrolledChannels') - - it('displays enrolled channels', async () => { - chooseHubMock.mockResolvedValueOnce('chosen-hub-id') - outputListMock.mockResolvedValueOnce([]) - - await expect(ChannelsEnrollmentsCommand.run([])).resolves.not.toThrow() - - expect(chooseHubMock).toHaveBeenCalledTimes(1) - expect(chooseHubMock).toHaveBeenCalledWith(expect.any(ChannelsEnrollmentsCommand), - 'Select a hub.', undefined, { allowIndex: true, useConfigDefault: true }) - expect(outputListMock).toHaveBeenCalledTimes(1) - expect(outputListMock).toHaveBeenCalledWith(expect.any(ChannelsEnrollmentsCommand), - expect.objectContaining({ primaryKeyName: 'channelId' }), expect.any(Function)) - }) - - it('uses enrolledChannels to list enrolled channels', async () => { - chooseHubMock.mockResolvedValueOnce('chosen-hub-id') - outputListMock.mockResolvedValueOnce([]) - - await expect(ChannelsEnrollmentsCommand.run([])).resolves.not.toThrow() - - const channelList = [{ channelId: 'enrolled-channel-id' } as EnrolledChannel] - apiEnrolledChannelsSpy.mockResolvedValueOnce(channelList) - const listItems = outputListMock.mock.calls[0][2] - - expect(await listItems()).toBe(channelList) - }) -}) diff --git a/packages/edge/src/commands/edge/channels/enrollments.ts b/packages/edge/src/commands/edge/channels/enrollments.ts deleted file mode 100644 index c0a9271c..00000000 --- a/packages/edge/src/commands/edge/channels/enrollments.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { EnrolledChannel } from '@smartthings/core-sdk' - -import { outputList, OutputListConfig } from '@smartthings/cli-lib' - -import { chooseHub } from '../../../lib/commands/drivers-util.js' -import { EdgeCommand } from '../../../lib/edge-command.js' - - -export default class ChannelsEnrollmentsCommand extends EdgeCommand { - static description = 'list all channels a given hub is enrolled in' + - this.apiDocsURL('listDriverChannels') - - static flags = { - ...EdgeCommand.flags, - ...outputList.flags, - } - - static args = [{ - name: 'idOrIndex', - description: 'the hub id or number in list', - }] - - async run(): Promise { - const config: OutputListConfig = { - primaryKeyName: 'channelId', - sortKeyName: 'name', - listTableFieldDefinitions: ['channelId', 'name', 'description', 'createdDate', 'lastModifiedDate', 'subscriptionUrl'], - } - - const hubId = await chooseHub(this, 'Select a hub.', this.args.idOrIndex, - { allowIndex: true, useConfigDefault: true }) - - await outputList(this, config, () => this.client.hubdevices.enrolledChannels(hubId)) - } -} diff --git a/src/__tests__/commands/edge/channels/enrollments.test.ts b/src/__tests__/commands/edge/channels/enrollments.test.ts new file mode 100644 index 00000000..22df9373 --- /dev/null +++ b/src/__tests__/commands/edge/channels/enrollments.test.ts @@ -0,0 +1,97 @@ +import { jest } from '@jest/globals' + +import type { ArgumentsCamelCase, Argv } from 'yargs' + +import type { EnrolledChannel, HubdevicesEndpoint } from '@smartthings/core-sdk' + +import type { CommandArgs } from '../../../../commands/edge/channels/enrollments.js' +import type { APICommand, APICommandFlags } from '../../../../lib/command/api-command.js' +import type { outputList, outputListBuilder } from '../../../../lib/command/output-list.js' +import type { chooseHub } from '../../../../lib/command/util/hubs-choose.js' +import { apiCommandMocks } from '../../../test-lib/api-command-mock.js' +import { buildArgvMock, buildArgvMockStub } from '../../../test-lib/builder-mock.js' + + +const { apiCommandMock, apiCommandBuilderMock, apiDocsURLMock } = apiCommandMocks('../../../..') + +const outputListMock = jest.fn() +const outputListBuilderMock = jest.fn() +jest.unstable_mockModule('../../../../lib/command/output-list.js', () => ({ + outputList: outputListMock, + outputListBuilder: outputListBuilderMock, +})) + +const chooseHubMock = jest.fn() +jest.unstable_mockModule('../../../../lib/command/util/hubs-choose.js', () => ({ + chooseHub: chooseHubMock, +})) + + +const { default: cmd } = await import('../../../../commands/edge/channels/enrollments.js') + + +test('builder', async () => { + const yargsMock = buildArgvMockStub() + const { + yargsMock: apiCommandBuilderArgvMock, + positionalMock, + optionMock, + exampleMock, + epilogMock, + argvMock, + } = buildArgvMock() + + apiCommandBuilderMock.mockReturnValue(apiCommandBuilderArgvMock) + outputListBuilderMock.mockReturnValue(argvMock) + + const builder = cmd.builder as (yargs: Argv) => Argv + + expect(builder(yargsMock)).toBe(argvMock) + + expect(apiCommandBuilderMock).toHaveBeenCalledExactlyOnceWith(yargsMock) + expect(outputListBuilderMock).toHaveBeenCalledExactlyOnceWith(apiCommandBuilderArgvMock) + expect(positionalMock).toHaveBeenCalledTimes(1) + expect(optionMock).toHaveBeenCalledTimes(0) + expect(exampleMock).toHaveBeenCalledTimes(1) + expect(apiDocsURLMock).toHaveBeenCalledTimes(1) + expect(epilogMock).toHaveBeenCalledTimes(1) +}) + +test('handler', async () => { + const apiHubDevicesEnrolledChannelsMock = jest.fn() + const command = { + client: + { + hubdevices: { + enrolledChannels: apiHubDevicesEnrolledChannelsMock, + }, + }, + } as unknown as APICommand + apiCommandMock.mockResolvedValueOnce(command) + chooseHubMock.mockResolvedValueOnce('chosen-hub-id') + + const inputArgv = { + profile: 'default', + idOrIndex: 'cmd-line-id', + } as ArgumentsCamelCase + + await expect(cmd.handler(inputArgv)).resolves.not.toThrow() + + expect(apiCommandMock).toHaveBeenCalledExactlyOnceWith(inputArgv) + expect(chooseHubMock).toHaveBeenCalledExactlyOnceWith( + command, + 'cmd-line-id', + { allowIndex: true, useConfigDefault: true }, + ) + expect(outputListMock).toHaveBeenCalledExactlyOnceWith( + command, + expect.objectContaining({ primaryKeyName: 'channelId' }), + expect.any(Function), + ) + + const listFunction = outputListMock.mock.calls[0][2] + const channels = [{ channelId: 'channel-id' } as EnrolledChannel] + apiHubDevicesEnrolledChannelsMock.mockResolvedValueOnce(channels) + + expect(await listFunction()).toBe(channels) +}) diff --git a/src/commands/edge/channels/enrollments.ts b/src/commands/edge/channels/enrollments.ts new file mode 100644 index 00000000..ae97eb16 --- /dev/null +++ b/src/commands/edge/channels/enrollments.ts @@ -0,0 +1,68 @@ +import { type ArgumentsCamelCase, type Argv, type CommandModule } from 'yargs' + +import type { EnrolledChannel } from '@smartthings/core-sdk' + +import { apiCommand, apiCommandBuilder, apiDocsURL, type APICommandFlags } from '../../../lib/command/api-command.js' +import { + outputList, + outputListBuilder, + type OutputListConfig, + type OutputListFlags, +} from '../../../lib/command/output-list.js' +import { chooseHub } from '../../../lib/command/util/hubs-choose.js' + + +export type CommandArgs = + & APICommandFlags + & OutputListFlags + & { + idOrIndex?: string + } + +const command = 'edge:channels:enrollments [id-or-index]' + +const describe = 'list all channels a given hub is enrolled in' + + +const builder = (yargs: Argv): Argv => + outputListBuilder(apiCommandBuilder(yargs)) + .positional('id-or-index', { describe: 'hub id or number in list', type: 'string' }) + .example([ + [ + '$0 edge:channels:enrollments', + 'prompt for a hub (or use default) and display channels it is enrolled in', + ], + [ + '$0 edge:channels:enrollments 86042494-ae59-43a8-bc09-654103b5c5b3', + 'display channels the specified hub is enrolled in', + ], + ]) + .epilog(apiDocsURL('listDriverChannels')) + +const handler = async (argv: ArgumentsCamelCase): Promise => { + const command = await apiCommand(argv) + + const config: OutputListConfig = { + primaryKeyName: 'channelId', + sortKeyName: 'name', + listTableFieldDefinitions: [ + 'channelId', + 'name', + 'description', + 'createdDate', + 'lastModifiedDate', + 'subscriptionUrl', + ], + } + + const hubId = await chooseHub( + command, + argv.idOrIndex, + { allowIndex: true, useConfigDefault: true }, + ) + + await outputList(command, config, () => command.client.hubdevices.enrolledChannels(hubId)) +} + +const cmd: CommandModule = { command, describe, builder, handler } +export default cmd diff --git a/src/commands/index.ts b/src/commands/index.ts index 584e8ffa..903cf4b1 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -61,6 +61,7 @@ import edgeChannelsAssignCommand from './edge/channels/assign.js' import edgeChannelsCreateCommand from './edge/channels/create.js' import edgeChannelsDeleteCommand from './edge/channels/delete.js' import edgeChannelsDriversCommand from './edge/channels/drivers.js' +import edgeChannelsEnrollmentsCommand from './edge/channels/enrollments.js' import edgeChannelsInvitesCommand from './edge/channels/invites.js' import edgeChannelsInvitesAcceptCommand from './edge/channels/invites/accept.js' import edgeChannelsInvitesCreateCommand from './edge/channels/invites/create.js' @@ -186,6 +187,7 @@ export const commands: CommandModule[] = [ edgeChannelsCreateCommand, edgeChannelsDeleteCommand, edgeChannelsDriversCommand, + edgeChannelsEnrollmentsCommand, edgeChannelsInvitesCommand, edgeChannelsInvitesAcceptCommand, edgeChannelsInvitesCreateCommand,