Skip to content

Commit

Permalink
fix: extract handler transform for ut, handle undefined (#530)
Browse files Browse the repository at this point in the history
  • Loading branch information
mshanemc committed Apr 11, 2024
1 parent 98d4550 commit 7eb46a8
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 25 deletions.
23 changes: 23 additions & 0 deletions src/errorHandling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { SfError } from '@salesforce/core';
import { OclifError } from '@oclif/core/lib/interfaces/errors.js';
import { SfCommandError } from './types.js';
import { removeEmpty } from './util.js';

/**
*
Expand Down Expand Up @@ -65,6 +66,28 @@ export const errorIsTypeError = (error: Error | SfError): boolean =>
Boolean(error.stack?.includes('TypeError')) ||
('cause' in error && error.cause instanceof Error && errorIsTypeError(error.cause));

export const errorToSfCommandError = (
codeFromError: number,
error: Error | SfError | SfCommandError,
commandName: string
): SfCommandError => ({
...removeEmpty({
code: codeFromError,
actions: 'actions' in error ? error.actions : null,
context: ('context' in error ? error.context : commandName) ?? commandName,
commandName: ('commandName' in error ? error.commandName : commandName) ?? commandName,
data: 'data' in error ? error.data : null,
result: 'result' in error ? error.result : null,
}),
...{
message: error.message,
name: error.name ?? 'Error',
status: codeFromError,
stack: error.stack,
exitCode: codeFromError,
},
});

/** custom typeGuard for handling the fact the SfCommand doesn't know about oclif error structure */
const isOclifError = <T extends Error | SfError | SfCommandError>(e: T): e is T & OclifError =>
'oclif' in e ? true : false;
28 changes: 4 additions & 24 deletions src/sfCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import { SfCommandError } from './types.js';
import { formatActions, formatError } from './errorFormatting.js';
import { StandardColors } from './ux/standardColors.js';
import { confirm, secretPrompt, PromptInputs } from './ux/prompts.js';
import { removeEmpty } from './util.js';
import { computeErrorCode } from './errorHandling.js';
import { computeErrorCode, errorToSfCommandError } from './errorHandling.js';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/sf-plugins-core', 'messages');
Expand All @@ -34,7 +33,7 @@ export type SfCommandInterface = {
configurationVariablesSection?: HelpSection;
envVariablesSection?: HelpSection;
errorCodes?: HelpSection;
} & Command.Class
} & Command.Class;

/**
* A base command that provided common functionality for all sf commands.
Expand Down Expand Up @@ -391,26 +390,7 @@ export abstract class SfCommand<T> extends Command {
const codeFromError = computeErrorCode(error);
process.exitCode = codeFromError;

const sfErrorProperties = removeEmpty({
code: codeFromError,
actions: 'actions' in error ? error.actions : null,
context: 'context' in error ? error.context : this.statics.name,
commandName: 'commandName' in error ? error.commandName : this.statics.name,
data: 'data' in error ? error.data : null,
result: 'result' in error ? error.result : null,
});

// Create printable error object
const sfCommandError: SfCommand.Error = {
...sfErrorProperties,
...{
message: error.message,
name: error.name ?? 'Error',
status: process.exitCode,
stack: error.stack,
exitCode: process.exitCode,
},
};
const sfCommandError = errorToSfCommandError(codeFromError, error, this.statics.name);

if (this.jsonEnabled()) {
this.logJson(this.toErrorJson(sfCommandError));
Expand Down Expand Up @@ -469,6 +449,6 @@ export namespace SfCommand {
status: number;
result: T;
warnings?: Warning[];
}
};
export type Error = SfCommandError;
}
49 changes: 48 additions & 1 deletion test/unit/errorHandling.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
import { expect } from 'chai';
import { SfError } from '@salesforce/core';
import { computeErrorCode, errorIsGack, errorIsTypeError } from '../../src/errorHandling.js';
import { computeErrorCode, errorIsGack, errorIsTypeError, errorToSfCommandError } from '../../src/errorHandling.js';

describe('typeErrors', () => {
let typeError: Error;
Expand Down Expand Up @@ -122,3 +122,50 @@ describe('precedence', () => {
expect(computeErrorCode(e)).to.equal(10);
});
});

describe('errorToSfCommandError', () => {
it('basic', () => {
const result = errorToSfCommandError(1, new Error('foo'), 'the:cmd');
expect(result).to.deep.include({
code: 1,
status: 1,
exitCode: 1,
commandName: 'the:cmd',
context: 'the:cmd',
message: 'foo',
name: 'Error', // this is the default
});
expect(result.stack).to.be.a('string').and.include('Error: foo');
});
describe('context', () => {
it('sfError with context', () => {
const sfError = SfError.create({ name: 'myError', message: 'foo', actions: ['bar'], context: 'myContext' });
const result = errorToSfCommandError(8, sfError, 'the:cmd');
expect(result).to.deep.include({
code: 8,
status: 8,
exitCode: 8,
commandName: 'the:cmd',
context: 'myContext',
message: 'foo',
name: 'myError',
});
expect(result.stack).to.be.a('string').and.include('myError: foo');
});
it('sfError with undefined context', () => {
const sfError = SfError.create({ name: 'myError', message: 'foo', actions: ['bar'], context: undefined });
const result = errorToSfCommandError(8, sfError, 'the:cmd');
expect(result).to.deep.include({
code: 8,
status: 8,
exitCode: 8,
commandName: 'the:cmd',
// defaults to the command name
context: 'the:cmd',
message: 'foo',
name: 'myError',
});
expect(result.stack).to.be.a('string').and.include('myError: foo');
});
});
});

0 comments on commit 7eb46a8

Please sign in to comment.