Sklivvz
Sklivvz

Reputation: 31143

Getting the right stack trace out of jest

I am currently debugging some tests written with jest over typescript and I'm having a bit of a headache.

If a test, or tested class, runs Postgres SQL and there is an error in the query, I get the wrong stack trace, for example, this:

error: invalid input syntax for type integer: ""0""
    at Parser.parseErrorMessage (/Users/sklivvz/src/xxx/node_modules/pg-protocol/src/parser.ts:369:69)
    at Parser.handlePacket (/Users/sklivvz/src/xxx/node_modules/pg-protocol/src/parser.ts:188:21)
    at Parser.parse (/Users/sklivvz/src/xxx/node_modules/pg-protocol/src/parser.ts:103:30)
    at Socket.<anonymous> (/Users/sklivvz/src/xxx/node_modules/pg-protocol/src/index.ts:7:48)
    at Socket.emit (node:events:365:28)
    at addChunk (node:internal/streams/readable:314:12)
    at readableAddChunk (node:internal/streams/readable:289:9)
    at Socket.Readable.push (node:internal/streams/readable:228:10)
    at TCP.onStreamRead (node:internal/stream_base_commons:190:23)

The "error" line is very useful, however, the stack trace only tells me that the error was thrown by the pg-protocol driver. I would like to know which line within my code generated the error.

I am exactly 82.7% sure that this is due to PG's query being async.

It is incredibly time-consuming having to step debug or (gasp) console.log my way to each error when it would only be a matter of showing the correct call stack in order to make it better.

Has anyone found a way of making this developer-friendly?

Upvotes: 6

Views: 2492

Answers (2)

Hung Tran
Hung Tran

Reputation: 1645

I ran into a similar issue with aws-sdk for DynamoDb. This is a stacktrace I usually get from aws-sdk.

ResourceNotFoundException: Requested resource not found
at Request.extractError (D:\workspaces\typescript-starters\console-app\node_modules\aws-sdk\lib\protocol\json.js:52:27)
at Request.callListeners (D:\workspaces\typescript-starters\console-app\node_modules\aws-sdk\lib\sequential_executor.js:106:20)
at Request.emit (D:\workspaces\typescript-starters\console-app\node_modules\aws-sdk\lib\sequential_executor.js:78:10)
at Request.emit (D:\workspaces\typescript-starters\console-app\node_modules\aws-sdk\lib\request.js:688:14)
at Request.transition (D:\workspaces\typescript-starters\console-app\node_modules\aws-sdk\lib\request.js:22:10)
at AcceptorStateMachine.runTo (D:\workspaces\typescript-starters\console-app\node_modules\aws-sdk\lib\state_machine.js:14:12)
at D:\workspaces\typescript-starters\console-app\node_modules\aws-sdk\lib\state_machine.js:26:10
at Request.<anonymous> (D:\workspaces\typescript-starters\console-app\node_modules\aws-sdk\lib\request.js:38:9)
at Request.<anonymous> (D:\workspaces\typescript-starters\console-app\node_modules\aws-sdk\lib\request.js:690:12)
at Request.callListeners (D:\workspaces\typescript-starters\console-app\node_modules\aws-sdk\lib\sequential_executor.js:116:18)

My workaround is simply to catch async errors, and overwrite their stack traces. On the other hand, you may append Postgres stacktrace, or error message to your own errors.

  async function getPersonFromDb (personId: string): Promise<DocumentClient.AttributeMap | undefined> {
    const result = await documentClient.get({ // Similar to postgres.query()
      TableName: 'wrong-name',
      Key: { pk: personId, sk: personId }
    }).promise().catch(error => {
      Error.captureStackTrace(error)
      throw error
    })
    return result.Item
  }

  test('Get a person from DynamoDB', async () => {
    const person = await getPersonFromDb('hello')
    expect(person).not.toBeUndefined()
  })


// ========= new stacktrace ========
Error: Requested resource not found
    at D:\workspaces\typescript-starters\console-app\test\abc.test.ts:12:13
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at getPersonFromDb (D:\workspaces\typescript-starters\console-app\test\abc.test.ts:8:20) 
    at Object.<anonymous> (D:\workspaces\typescript-starters\console-app\test\abc.test.ts:18:20) // my code, and where my error is thrown

Upvotes: 1

VonC
VonC

Reputation: 1326524

Check if this is related to brianc/node-postgres issue 2484

is (there) a preferred package, extension, or method for providing more detail when you get a syntax error back from the parser?
(for instance, one that listed line number, column of the error)

for instance, right now:

error: syntax error at or near "as"
   at Parser.parseErrorMessage (/home/collspec/projects/staff-portal/sprint-server/node_modules/pg-protocol/dist/parser.js:278:15)

desired behavior:

error: syntax error at or near "as", line 5, column 7
   at Parser.parseErrorMessage (/home/collspec/projects/staff-portal/sprint-server/node_modules/pg-protocol/dist/parser.js:278:15)

Possible workaround from that issue:

There are a bunch of additional fields on Error objects populated by the driver.
If you log the error object you can see them. They correspond to the error fields returned by the server:

For example with the command:

SELECT foo
FROM bar

You can get an error like this:

{
 length: 102,
 severity: 'ERROR',
 code: '42P01',
 detail: undefined,
 hint: undefined,
 position: '17',
 internalPosition: undefined,
 internalQuery: undefined,
 where: undefined,
 schema: undefined,
 table: undefined,
 column: undefined,
 dataType: undefined,
 constraint: undefined,
 file: 'parse_relation.c',
 line: '1180',
 routine: 'parserOpenTable'
}

The one you want is position. It gives you the character offset in the SQL of the error.
In this example the position value of "17" refers to the start of the bar token in the SQL.
It's not always populated though as it depends on what caused the error (generally just parse errors).

Upvotes: 2

Related Questions