Skip to content

Commit 591da4e

Browse files
authored
fix(device-profiler): display error message instead of [object Object] (#165)
Add formatError() helper to properly serialize error objects for display. Handles null, undefined, strings, Error instances, objects with message property, and JSON-serializable objects. Includes try/catch fallback for circular references and BigInt values. Closes #164
1 parent 77271d7 commit 591da4e

2 files changed

Lines changed: 103 additions & 1 deletion

File tree

packages/device-profiler/src/console-formatter.test.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,93 @@ describe('formatSummary', () => {
203203

204204
expect(output).toContain('12.3')
205205
})
206+
207+
it('should handle object errors gracefully', () => {
208+
// Bug scenario: error field contains an object instead of string,
209+
// which was displayed as "[object Object]" instead of a readable message
210+
const results: ScanResult[] = [
211+
{
212+
address: 78,
213+
type: RegisterType.Holding,
214+
success: false,
215+
timing: 3202.3,
216+
error: { code: 'EBUSY', message: 'Port is busy' } as unknown as string,
217+
errorType: ErrorType.Unknown,
218+
},
219+
]
220+
221+
const output = formatSummary(results)
222+
223+
// Should not display [object Object]
224+
expect(output).not.toContain('[object Object]')
225+
// Should display stringified error
226+
expect(output).toContain('Port is busy')
227+
})
228+
229+
it('should handle null error', () => {
230+
const results: ScanResult[] = [
231+
{
232+
address: 0,
233+
type: RegisterType.Holding,
234+
success: false,
235+
timing: 100,
236+
error: null as unknown as string,
237+
errorType: ErrorType.Unknown,
238+
},
239+
]
240+
241+
const output = formatSummary(results)
242+
// Count occurrences of '-' (should have at least 2: value and error)
243+
const dashes = (output.match(/-/g) ?? []).length
244+
expect(dashes).toBeGreaterThanOrEqual(2)
245+
})
246+
247+
it('should handle undefined error', () => {
248+
const results: ScanResult[] = [
249+
{
250+
address: 0,
251+
type: RegisterType.Holding,
252+
success: false,
253+
timing: 100,
254+
errorType: ErrorType.Unknown,
255+
},
256+
]
257+
258+
const output = formatSummary(results)
259+
const dashes = (output.match(/-/g) ?? []).length
260+
expect(dashes).toBeGreaterThanOrEqual(2)
261+
})
262+
263+
it('should handle Error instance', () => {
264+
const results: ScanResult[] = [
265+
{
266+
address: 0,
267+
type: RegisterType.Holding,
268+
success: false,
269+
timing: 100,
270+
error: new Error('Connection refused') as unknown as string,
271+
errorType: ErrorType.Unknown,
272+
},
273+
]
274+
275+
const output = formatSummary(results)
276+
expect(output).toContain('Connection refused')
277+
})
278+
279+
it('should handle object without message property', () => {
280+
const results: ScanResult[] = [
281+
{
282+
address: 0,
283+
type: RegisterType.Holding,
284+
success: false,
285+
timing: 100,
286+
error: { code: 'EBUSY', errno: -16 } as unknown as string,
287+
errorType: ErrorType.Unknown,
288+
},
289+
]
290+
291+
const output = formatSummary(results)
292+
// Should JSON stringify the object
293+
expect(output).toContain('EBUSY')
294+
})
206295
})

packages/device-profiler/src/console-formatter.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@ import Table from 'cli-table3'
66

77
import type { ScanResult } from './register-scanner.js'
88

9+
function formatError(error: unknown): string {
10+
if (error == null) return '-'
11+
if (typeof error === 'string') return error
12+
if (error instanceof Error) return error.message
13+
if (typeof error === 'object' && 'message' in error) return String(error.message)
14+
try {
15+
return JSON.stringify(error)
16+
} catch {
17+
// Fallback for circular references or BigInt - return type name
18+
return `[${typeof error}]`
19+
}
20+
}
21+
922
/**
1023
* Format progress message
1124
*
@@ -34,7 +47,7 @@ export function formatSummary(results: ScanResult[]): string {
3447
const value = result.success && result.value ? result.value.toString('hex').toUpperCase() : '-'
3548

3649
const status = result.success ? 'OK' : 'FAIL'
37-
const error = result.error ?? '-'
50+
const error = formatError(result.error)
3851
const timing = result.timing.toFixed(1)
3952

4053
table.push([result.address.toString(), result.type, status, value, timing, error])

0 commit comments

Comments
 (0)