diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 1613426..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "@adobe/eslint-config-aio-lib-config", - "settings": { - "jsdoc": { - "ignorePrivate": true - } - }, - "rules": { - "jsdoc/tag-lines": [ - // The Error level should be `error`, `warn`, or `off` (or 2, 1, or 0) - "error", - "never", - { - "startLines": null - } - ] - } -} diff --git a/.gitignore b/.gitignore index b356c3c..5a9efe2 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ package-lock.json playground/ oclif.manifest.json .idea +.claude diff --git a/e2e/.eslintrc.json b/e2e/.eslintrc.json deleted file mode 100644 index ae74b09..0000000 --- a/e2e/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "node/no-unpublished-require": 0 - } -} diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..7e763d3 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,48 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +const aioLibConfig = require('@adobe/eslint-config-aio-lib-config') +const pluginJest = require('eslint-plugin-jest') + +module.exports = [ + ...aioLibConfig, + { + settings: { + jsdoc: { + ignorePrivate: true + } + }, + rules: { + 'jsdoc/tag-lines': [ + 'error', + 'never', + { + startLines: null + } + ] + } + }, + { + files: ['test/**/*.js'], + ...pluginJest.configs['flat/recommended'], + rules: { + ...pluginJest.configs['flat/recommended'].rules + } + }, + { + files: ['e2e/**/*.js'], + ...pluginJest.configs['flat/recommended'], + rules: { + ...pluginJest.configs['flat/recommended'].rules, + 'n/no-unpublished-require': 'off' + } + } +] diff --git a/package.json b/package.json index 07ab660..410f649 100644 --- a/package.json +++ b/package.json @@ -16,33 +16,27 @@ "@adobe/aio-lib-env": "^3", "@adobe/aio-lib-events": "^4", "@adobe/aio-lib-ims": "^7", - "@oclif/core": "^2.8.12", + "@oclif/core": "^4.9.0", "inquirer": "^8.2.5", "js-yaml": "^4.1.0" }, "repository": "adobe/aio-cli-plugin-events", "devDependencies": { - "@adobe/eslint-config-aio-lib-config": "^4.0.0", + "@adobe/eslint-config-aio-lib-config": "^5.0.0", "@types/jest": "^29.5.3", "acorn": "^8.10.0", "babel-runtime": "^6.26.0", "chalk": "^4.0.0", "eol": "^0.9.1", - "eslint": "^8.57.1", - "eslint-config-oclif": "^4.0.0", - "eslint-config-standard": "^17.1.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jest": "^27.9.0", + "eslint": "^9.39.4", + "eslint-plugin-jest": "^29.15.1", "eslint-plugin-jsdoc": "^48.11.0", - "eslint-plugin-n": "^15.7.0", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^6.6.0", - "eslint-plugin-standard": "^5.0.0", "execa": "^7.2.0", "jest": "^29.5.0", "jest-haste-map": "^29.5.0", "jest-junit": "^16.0.0", "jest-resolve": "^29.5.0", + "neostandard": "^0.13.0", "oclif": "^3.2.0", "stdout-stderr": "^0.1.13" }, diff --git a/src/commands/event/eventmetadata/create.js b/src/commands/event/eventmetadata/create.js index 42dc546..a3df820 100644 --- a/src/commands/event/eventmetadata/create.js +++ b/src/commands/event/eventmetadata/create.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const { sentenceValidatorWithMinOneChar, eventCodeValidator } = require('../../../utils/validator') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:eventmetadata:create', { provider: 'debug' }) @@ -41,9 +41,9 @@ class EventmetadataCreateCommand extends BaseCommand { description: response.description } - cli.action.start('Creating Event Metadata') + ux.action.start('Creating Event Metadata') const eventmetadata = await this.eventClient.createEventMetadataForProvider(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId, eventMetadataPayload) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(eventmetadata) diff --git a/src/commands/event/eventmetadata/delete.js b/src/commands/event/eventmetadata/delete.js index cd107df..ece3ce7 100644 --- a/src/commands/event/eventmetadata/delete.js +++ b/src/commands/event/eventmetadata/delete.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, ux: cli } = require('@oclif/core') +const { Args, ux } = require('@oclif/core') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:eventmetadata:delete', { provider: 'debug' }) @@ -29,10 +29,10 @@ class EventmetadataDeleteCommand extends BaseCommand { }]) if (response.delete) { - cli.action.start('Deleting ALL Event Metadata for provider') + ux.action.start('Deleting ALL Event Metadata for provider') await this.eventClient.deleteAllEventMetadata(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId) - cli.action.stop() + ux.action.stop() this.log('All event metadata of provider ' + args.providerId + ' has been deleted successfully') } else { this.log('Deletion operation has been cancelled. For more information on delete use --help') @@ -45,11 +45,11 @@ class EventmetadataDeleteCommand extends BaseCommand { }]) if (response.delete) { - cli.action.start('Deleting Event Metadata for provider') + ux.action.start('Deleting Event Metadata for provider') await this.eventClient.deleteEventMetadata(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId, args.eventCode) - cli.action.stop() + ux.action.stop() this.log(args.eventCode + ' event metadata of provider ' + args.providerId + ' has been deleted successfully') } else { this.log('Deletion operation has been cancelled. For more information on delete use --help') diff --git a/src/commands/event/eventmetadata/get.js b/src/commands/event/eventmetadata/get.js index cc3b91f..df4c53c 100644 --- a/src/commands/event/eventmetadata/get.js +++ b/src/commands/event/eventmetadata/get.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:eventmetadata:get', { provider: 'debug' }) class EventmetadataGetCommand extends BaseCommand { @@ -20,10 +20,10 @@ class EventmetadataGetCommand extends BaseCommand { try { await this.initSdk() - cli.action.start('Fetching the event metadata for the provider') + ux.action.start('Fetching the event metadata for the provider') const eventmetadata = await this.eventClient.getEventMetadataForProvider(args.providerId, args.eventCode) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(eventmetadata) diff --git a/src/commands/event/eventmetadata/list.js b/src/commands/event/eventmetadata/list.js index 7d4c37d..4006f6c 100644 --- a/src/commands/event/eventmetadata/list.js +++ b/src/commands/event/eventmetadata/list.js @@ -11,7 +11,8 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') +const { table } = require('../../../utils/table') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:eventmetadata:list', { provider: 'debug' }) class EventmetadataListCommand extends BaseCommand { @@ -19,9 +20,9 @@ class EventmetadataListCommand extends BaseCommand { const { args, flags } = await this.parse(EventmetadataListCommand) try { await this.initSdk() - cli.action.start('Fetching all Event Metadata for provider') + ux.action.start('Fetching all Event Metadata for provider') const eventmetadatas = await this.eventClient.getAllEventMetadataForProvider(args.providerId) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(eventmetadatas) } else if (flags.yml) { @@ -48,7 +49,7 @@ class EventmetadataListCommand extends BaseCommand { header: 'DESC' } } - cli.table(projects, columns) + table(projects, columns) } } diff --git a/src/commands/event/eventmetadata/update.js b/src/commands/event/eventmetadata/update.js index 05ea09d..4e10f13 100644 --- a/src/commands/event/eventmetadata/update.js +++ b/src/commands/event/eventmetadata/update.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const { sentenceValidatorWithMinOneChar } = require('../../../utils/validator') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:eventmetadata:update', { provider: 'debug' }) @@ -37,9 +37,9 @@ class EventmetadataUpdateCommand extends BaseCommand { description: response.description } - cli.action.start('Updating Event Metadata for Provider') + ux.action.start('Updating Event Metadata for Provider') const eventmetadata = await this.eventClient.updateEventMetadataForProvider(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId, args.eventCode, eventMetadataPayload) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(eventmetadata) } else if (flags.yml) { diff --git a/src/commands/event/provider/create.js b/src/commands/event/provider/create.js index a410df8..3bdb9d7 100644 --- a/src/commands/event/provider/create.js +++ b/src/commands/event/provider/create.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Flags, ux: cli } = require('@oclif/core') +const { Flags, ux } = require('@oclif/core') const { sentenceValidatorWithMinOneChar, sentenceValidatorWithMinZeroChar } = require('../../../utils/validator') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:provider:create', { provider: 'debug' }) @@ -40,9 +40,9 @@ class ProviderCreateCommand extends BaseCommand { docs_url: response.docs_url || undefined } - cli.action.start('Creating Event Provider') + ux.action.start('Creating Event Provider') const provider = await this.eventClient.createProvider(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, providerPayload) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(provider) } else if (flags.yml) { diff --git a/src/commands/event/provider/delete.js b/src/commands/event/provider/delete.js index c990776..5ea5902 100644 --- a/src/commands/event/provider/delete.js +++ b/src/commands/event/provider/delete.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, ux: cli } = require('@oclif/core') +const { Args, ux } = require('@oclif/core') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:provider:delete', { provider: 'debug' }) @@ -28,10 +28,10 @@ class ProviderDeleteCommand extends BaseCommand { }]) if (response.delete) { - cli.action.start('Deleting Event Provider') + ux.action.start('Deleting Event Provider') await this.eventClient.deleteProvider(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId) - cli.action.stop() + ux.action.stop() this.log('Provider ' + args.providerId + ' has been deleted successfully') } else { diff --git a/src/commands/event/provider/get.js b/src/commands/event/provider/get.js index f1e3323..93a4f5d 100644 --- a/src/commands/event/provider/get.js +++ b/src/commands/event/provider/get.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:provider:get', { provider: 'debug' }) class ProviderGetCommand extends BaseCommand { @@ -20,10 +20,10 @@ class ProviderGetCommand extends BaseCommand { try { await this.initSdk() - cli.action.start('Fetching the Event Provider') + ux.action.start('Fetching the Event Provider') const provider = await this.eventClient.getProvider(args.providerId, flags.fetchEventMetadata) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(provider) diff --git a/src/commands/event/provider/list.js b/src/commands/event/provider/list.js index a2ea77e..d0860f1 100644 --- a/src/commands/event/provider/list.js +++ b/src/commands/event/provider/list.js @@ -11,7 +11,8 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Flags, ux: cli } = require('@oclif/core') +const { Flags, ux } = require('@oclif/core') +const { table } = require('../../../utils/table') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:provider:list', { provider: 'debug' }) class ProviderListCommand extends BaseCommand { @@ -19,7 +20,7 @@ class ProviderListCommand extends BaseCommand { const { flags } = await this.parse(ProviderListCommand) try { await this.initSdk() - cli.action.start('Fetching all Event Providers') + ux.action.start('Fetching all Event Providers') const options = { fetchEventMetadata: flags.fetchEventMetadata, filterBy: { @@ -29,7 +30,7 @@ class ProviderListCommand extends BaseCommand { } } const providers = await this.eventClient.getAllProviders(this.conf.org.id, options) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(providers) } else if (flags.yml) { @@ -61,7 +62,7 @@ class ProviderListCommand extends BaseCommand { header: 'DOCS' } } - cli.table(projects, columns) + table(projects, columns) } } diff --git a/src/commands/event/provider/update.js b/src/commands/event/provider/update.js index 0de2869..7710b0d 100644 --- a/src/commands/event/provider/update.js +++ b/src/commands/event/provider/update.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const { sentenceValidatorWithMinOneChar, sentenceValidatorWithMinZeroChar } = require('../../../utils/validator') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:provider:update', { provider: 'debug' }) @@ -40,9 +40,9 @@ class ProviderUpdateCommand extends BaseCommand { docs_url: response.docs_url || undefined } - cli.action.start('Updating the Event Provider') + ux.action.start('Updating the Event Provider') const provider = await this.eventClient.updateProvider(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.providerId, providerPayload) - cli.action.stop() + ux.action.stop() if (flags.json) { this.printJson(provider) } else if (flags.yml) { diff --git a/src/commands/event/registration/create.js b/src/commands/event/registration/create.js index 9f63662..6635bdf 100644 --- a/src/commands/event/registration/create.js +++ b/src/commands/event/registration/create.js @@ -10,7 +10,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const fs = require('fs') const BaseCommand = require('../../../BaseCommand') @@ -31,9 +31,9 @@ class CreateCommand extends BaseCommand { // other checks are performed by the server aioLogger.debug(`create event registration with body ${body}`) - cli.action.start('Creating new Event Registration') + ux.action.start('Creating new Event Registration') const registration = await this.eventClient.createRegistration(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, body) - cli.action.stop() + ux.action.stop() aioLogger.debug(`create successful, id: ${registration.registration_id}, name: ${registration.name}`) if (flags.json) { diff --git a/src/commands/event/registration/delete.js b/src/commands/event/registration/delete.js index 282e171..3021d92 100644 --- a/src/commands/event/registration/delete.js +++ b/src/commands/event/registration/delete.js @@ -11,7 +11,7 @@ governing permissions and limitations under the License. */ const BaseCommand = require('../../../BaseCommand.js') -const { Args, ux: cli } = require('@oclif/core') +const { Args, ux } = require('@oclif/core') const inquirer = require('inquirer') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:registration:delete', { provider: 'debug' }) @@ -28,10 +28,10 @@ class DeleteCommand extends BaseCommand { }]) if (response.delete) { - cli.action.start('Deleting Registration') + ux.action.start('Deleting Registration') await this.eventClient.deleteRegistration(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.registrationId) - cli.action.stop() + ux.action.stop() this.log('Registration ' + args.registrationId + ' has been deleted successfully') } else { diff --git a/src/commands/event/registration/get.js b/src/commands/event/registration/get.js index afcb5cf..8c177c1 100644 --- a/src/commands/event/registration/get.js +++ b/src/commands/event/registration/get.js @@ -10,7 +10,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -const { Args, Flags, ux: cli } = require('@oclif/core') +const { Args, Flags, ux } = require('@oclif/core') const BaseCommand = require('../../../BaseCommand') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:registration:get', { provider: 'debug' }) @@ -23,9 +23,9 @@ class GetCommand extends BaseCommand { await this.initSdk() aioLogger.debug(`get registration: ${args.registrationId}`) - cli.action.start(`Retrieving Registration with id ${args.registrationId}`) + ux.action.start(`Retrieving Registration with id ${args.registrationId}`) const registration = await this.eventClient.getRegistration(this.conf.org.id, this.conf.project.id, this.conf.workspace.id, args.registrationId) - cli.action.stop() + ux.action.stop() aioLogger.debug(`get successful, name: ${registration.name}`) if (flags.json) { diff --git a/src/commands/event/registration/list.js b/src/commands/event/registration/list.js index a40b4f5..2c77ddd 100644 --- a/src/commands/event/registration/list.js +++ b/src/commands/event/registration/list.js @@ -9,7 +9,8 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -const { Flags, ux: cli } = require('@oclif/core') +const { Flags, ux } = require('@oclif/core') +const { table } = require('../../../utils/table') const BaseCommand = require('../../../BaseCommand') const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-events:registration:list', { provider: 'debug' }) @@ -22,9 +23,9 @@ class ListCommand extends BaseCommand { await this.initSdk() aioLogger.debug(`list registrations in the workspace ${this.conf.workspace.id}`) - cli.action.start(`Retrieving Registrations for the Workspace ${this.conf.workspace.id}`) + ux.action.start(`Retrieving Registrations for the Workspace ${this.conf.workspace.id}`) const registrationHalModel = await this.eventClient.getAllRegistrationsForWorkspace(this.conf.org.id, this.conf.project.id, this.conf.workspace.id) - cli.action.stop() + ux.action.stop() aioLogger.debug(`list successful, got ${registrationHalModel._embedded.registrations.length} elements with ids: ${registrationHalModel._embedded.registrations.map(r => r.id)}`) if (flags.json) { this.printJson(registrationHalModel) @@ -32,7 +33,7 @@ class ListCommand extends BaseCommand { this.printYaml(registrationHalModel) } else { // print formatted result - cli.table(registrationHalModel._embedded.registrations, { + table(registrationHalModel._embedded.registrations, { registration_id: { minWidth: 38, header: 'ID' }, name: { minWidth: 25, header: 'NAME' }, enabled: { minWidth: 10, header: 'ENABLED' }, diff --git a/src/utils/table.js b/src/utils/table.js new file mode 100644 index 0000000..40b05bf --- /dev/null +++ b/src/utils/table.js @@ -0,0 +1,57 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +/** + * Renders a simple text table, compatible with the ux.table API removed in @oclif/core v4. + * + * @param {Array} data rows to display + * @param {object} columns column definitions: { key: { header, minWidth } } + * @param {object} options optional options: { printLine } + */ +function table (data, columns, options = {}) { + const printLine = options.printLine || console.log.bind(console) + const headerKeys = Object.keys(columns) + + const colWidths = headerKeys.map(key => { + const col = columns[key] + const header = col.header || key.toUpperCase() + let maxWidth = col.minWidth || header.length + + if (header.length > maxWidth) maxWidth = header.length + data.forEach(row => { + const strValue = String(row[key] ?? '') + if (strValue.length > maxWidth) maxWidth = strValue.length + }) + + const isLastColumn = headerKeys.indexOf(key) === headerKeys.length - 1 + if (col.minWidth && maxWidth === col.minWidth && !isLastColumn) { + maxWidth-- + } + return maxWidth + }) + + const headers = headerKeys.map((key, idx) => + (columns[key].header || key.toUpperCase()).padEnd(colWidths[idx], ' ') + ) + printLine(' ' + headers.join(' ') + ' ') + + const separator = colWidths.map(w => '─'.repeat(w)).join(' ') + printLine(' ' + separator + ' ') + + data.forEach(row => { + const values = headerKeys.map((key, idx) => + String(row[key] ?? '').padEnd(colWidths[idx], ' ') + ) + printLine(' ' + values.join(' ') + ' ') + }) +} + +module.exports = { table } diff --git a/src/utils/validator.js b/src/utils/validator.js index dbbcd44..111a171 100644 --- a/src/utils/validator.js +++ b/src/utils/validator.js @@ -19,7 +19,6 @@ governing permissions and limitations under the License. * @returns {string|boolean} message or error message */ function validator (input, regex, message) { - // eslint-disable-next-line no-useless-escape const valid = regex if (valid.test(input)) { return true diff --git a/test/jest.setup.js b/test/jest.setup.js index f6da9f9..e5648f8 100644 --- a/test/jest.setup.js +++ b/test/jest.setup.js @@ -10,27 +10,6 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -jest.mock('@oclif/core/lib/cli-ux/config', () => ({ - fetch: jest.fn(() => Promise.resolve('{}')), - get: jest.fn(() => ({})), - set: jest.fn(), - clear: jest.fn() -})) - -jest.mock('@oclif/core/lib/util', () => { - const actual = jest.requireActual('@oclif/core/lib/util') - return { - ...actual, - requireJson: jest.fn((path) => { - try { - return actual.requireJson(path) - } catch (e) { - return {} - } - }) - } -}) - const mockUx = { action: { start: jest.fn(), @@ -75,20 +54,31 @@ const mockUx = { }) } +const mockConfig = { + runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] }), + bin: 'aio', + userAgent: 'aio', + scopedEnvVar: jest.fn().mockReturnValue(undefined), + scopedEnvVarKey: jest.fn().mockReturnValue(''), + scopedEnvVarKeys: jest.fn().mockReturnValue([]), + theme: null +} + jest.mock('@oclif/core', () => { const actual = jest.requireActual('@oclif/core') + const originalParse = actual.Command.prototype.parse + actual.Command.prototype.parse = function (options, argv) { + if (!this.config) { + this.config = mockConfig + } + return originalParse.call(this, options, argv) + } return { ...actual, ux: mockUx } }) -jest.mock('@oclif/core/lib/cli-ux', () => ({ - ux: mockUx, - cli: mockUx, - default: mockUx -})) - const { stdout, stderr } = require('stdout-stderr') const fs = jest.requireActual('fs') const eol = require('eol') diff --git a/test/utils/table.test.js b/test/utils/table.test.js new file mode 100644 index 0000000..8cc628c --- /dev/null +++ b/test/utils/table.test.js @@ -0,0 +1,76 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +const { table } = require('../../src/utils/table') + +describe('table utility', () => { + test('renders table with header and minWidth columns', () => { + const data = [{ id: 'ID01', label: 'LABEL01' }] + const columns = { + id: { header: 'ID', minWidth: 5 }, + label: { header: 'LABEL', minWidth: 10 } + } + const lines = [] + table(data, columns, { printLine: (l) => lines.push(l) }) + expect(lines).toHaveLength(3) + expect(lines[0]).toContain('ID') + expect(lines[0]).toContain('LABEL') + expect(lines[2]).toContain('ID01') + expect(lines[2]).toContain('LABEL01') + }) + + test('falls back to key.toUpperCase() when header is not provided', () => { + const data = [{ myKey: 'value' }] + const columns = { myKey: {} } + const lines = [] + table(data, columns, { printLine: (l) => lines.push(l) }) + expect(lines[0]).toContain('MYKEY') + }) + + test('falls back to header.length when minWidth is not provided', () => { + const data = [{ name: 'short' }] + const columns = { name: { header: 'LONGHEADER' } } + const lines = [] + table(data, columns, { printLine: (l) => lines.push(l) }) + expect(lines[0]).toContain('LONGHEADER') + }) + + test('handles null and undefined values in rows', () => { + const data = [{ id: null, label: undefined }] + const columns = { + id: { header: 'ID' }, + label: { header: 'LABEL' } + } + const lines = [] + table(data, columns, { printLine: (l) => lines.push(l) }) + expect(lines[2]).toBeDefined() + }) + + test('uses console.log when printLine is not provided', () => { + const spy = jest.spyOn(console, 'log').mockImplementation(() => {}) + const data = [{ id: 'x' }] + const columns = { id: { header: 'ID' } } + table(data, columns) + expect(spy).toHaveBeenCalled() + spy.mockRestore() + }) + + test('decrements maxWidth when minWidth equals maxWidth and not last column', () => { + const data = [{ a: 'x', b: 'y' }] + const columns = { + a: { header: 'A', minWidth: 5 }, + b: { header: 'B', minWidth: 5 } + } + const lines = [] + table(data, columns, { printLine: (l) => lines.push(l) }) + expect(lines).toHaveLength(3) + }) +})