errors_test.ts•6.13 kB
/**
* Copyright 2025 Google LLC
*
* Licensed 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 CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { describe, expect, it } from '@jest/globals';
import {
getErrorCode,
getErrorDetails,
isConnectionRefusedError,
} from '../../src/utils/errors';
describe('errors.ts', () => {
describe('isConnectionRefusedError', () => {
it('should return false for null/undefined', () => {
expect(isConnectionRefusedError(null)).toBe(false);
expect(isConnectionRefusedError(undefined)).toBe(false);
});
it('should detect plain objects with connection error codes', () => {
expect(isConnectionRefusedError({ code: 'ECONNREFUSED' })).toBe(true);
expect(isConnectionRefusedError({ code: 'ConnectionRefused' })).toBe(
true
);
expect(isConnectionRefusedError({ code: 'ECONNRESET' })).toBe(true);
expect(isConnectionRefusedError({ code: 'OTHER_ERROR' })).toBe(false);
});
it('should detect Error instances with direct code', () => {
const err = new Error('Connection failed');
(err as any).code = 'ECONNREFUSED';
expect(isConnectionRefusedError(err)).toBe(true);
const err2 = new Error('Connection failed');
(err2 as any).code = 'ConnectionRefused';
expect(isConnectionRefusedError(err2)).toBe(true);
const err3 = new Error('Connection failed');
(err3 as any).code = 'ECONNRESET';
expect(isConnectionRefusedError(err3)).toBe(true);
});
it('should detect Node.js style errors with cause', () => {
const err = new Error('Fetch failed');
(err as any).cause = { code: 'ECONNREFUSED' };
expect(isConnectionRefusedError(err)).toBe(true);
});
it('should fallback to checking error messages', () => {
expect(
isConnectionRefusedError(
new Error('connect ECONNREFUSED 127.0.0.1:3000')
)
).toBe(true);
expect(
isConnectionRefusedError(new Error('Connection refused to server'))
).toBe(true);
expect(
isConnectionRefusedError(
new Error('ConnectionRefused: Unable to connect')
)
).toBe(true);
expect(
isConnectionRefusedError(new Error('Something else went wrong'))
).toBe(false);
});
it('should handle complex nested structures', () => {
const err = new Error('Outer error');
(err as any).cause = new Error('Inner error');
(err as any).cause.code = 'ECONNREFUSED';
expect(isConnectionRefusedError(err)).toBe(true);
});
});
describe('getErrorCode', () => {
it('should return undefined for null/undefined', () => {
expect(getErrorCode(null)).toBeUndefined();
expect(getErrorCode(undefined)).toBeUndefined();
});
it('should extract code from plain objects', () => {
expect(getErrorCode({ code: 'ECONNREFUSED' })).toBe('ECONNREFUSED');
expect(getErrorCode({ code: 'CUSTOM_ERROR' })).toBe('CUSTOM_ERROR');
expect(getErrorCode({ message: 'No code here' })).toBeUndefined();
});
it('should extract code from Error instances', () => {
const err = new Error('Test error');
(err as any).code = 'TEST_CODE';
expect(getErrorCode(err)).toBe('TEST_CODE');
});
it('should extract code from cause property', () => {
const err = new Error('Outer error');
(err as any).cause = { code: 'INNER_CODE' };
expect(getErrorCode(err)).toBe('INNER_CODE');
});
it('should prioritize direct code over cause code', () => {
const err = new Error('Test error');
(err as any).code = 'DIRECT_CODE';
(err as any).cause = { code: 'CAUSE_CODE' };
expect(getErrorCode(err)).toBe('DIRECT_CODE');
});
it('should handle non-string code values', () => {
expect(getErrorCode({ code: 123 })).toBeUndefined();
expect(getErrorCode({ code: null })).toBeUndefined();
expect(getErrorCode({ code: {} })).toBeUndefined();
});
});
describe('getErrorDetails', () => {
it('should return "Unknown error" for null/undefined', () => {
expect(getErrorDetails(null)).toBe('Unknown error');
expect(getErrorDetails(undefined)).toBe('Unknown error');
});
it('should format Error instances with code', () => {
const err = new Error('Connection failed');
(err as any).code = 'ECONNREFUSED';
expect(getErrorDetails(err)).toBe('Connection failed (ECONNREFUSED)');
});
it('should format Error instances without code', () => {
const err = new Error('Simple error');
expect(getErrorDetails(err)).toBe('Simple error');
});
it('should format plain objects with message and code', () => {
expect(getErrorDetails({ message: 'Failed', code: 'ERR123' })).toBe(
'Failed (ERR123)'
);
expect(getErrorDetails({ message: 'No code here' })).toBe('No code here');
});
it('should handle string errors', () => {
expect(getErrorDetails('String error')).toBe('String error');
});
it('should handle number errors', () => {
expect(getErrorDetails(123)).toBe('123');
});
it('should handle boolean errors', () => {
expect(getErrorDetails(true)).toBe('true');
expect(getErrorDetails(false)).toBe('false');
});
it('should handle objects without message', () => {
expect(getErrorDetails({ code: 'ERR_NO_MSG' })).toBe('[object Object]');
});
it('should extract code from cause for formatting', () => {
const err = new Error('Outer error');
(err as any).cause = { code: 'INNER_CODE' };
expect(getErrorDetails(err)).toBe('Outer error (INNER_CODE)');
});
});
});