Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 787
Sklivvz Avatar asked Jul 20 '21 15:07

Sklivvz


People also ask

How do I capture a stack trace?

You can obtain a stack trace from a thread – by calling the getStackTrace method on that Thread instance. This invocation returns an array of StackTraceElement, from which details about stack frames of the thread can be extracted.

How do I find stack trace error?

Use the console. trace() method to get the stack trace from an error. The console. trace() method outputs the stack trace and shows the call path taken to reach the point at which the method was called.

How can I check my browser stack trace?

You can easily see the stack trace in JavaScript by adding the following into your code: console. trace(); And you'll get an outputted stack trace.

Should stack traces be logged?

Therefore, you should log a stacktrace if, and only if, and always if, the exception indicates a bug in the program. However, that does not always indicate that a method you write should catch and log the exception.

How do I know which tests jest will run?

Lists all tests as JSON that Jest will run given the arguments, and exits. This can be used together with --findRelatedTests to know which tests Jest will run. Logs the heap usage after every test.

How to stop jest from exiting test cases?

Attempt to collect and print open handles preventing Jest from exiting cleanly. Use this in cases where you need to use --forceExit in order for Jest to exit to potentially track down the reason. This implies --runInBand, making tests run serially. Implemented using async_hooks.

How do I use the jest command line runner?

The jest command line runner has a number of useful options. You can run jest --help to view all available options. Many of the options shown below can also be used together to run tests exactly the way you want. Every one of Jest's Configuration options can also be specified through the CLI. Here is a brief overview: Run all tests (default):

How do I send jest test results to stderr?

Insert Jest's globals ( expect, test, describe, beforeEach etc.) into the global environment. If you set this to false, you should import from @jest/globals, e.g. Note: This option is only supported using the default jest-circus test runner. Prints the test results in JSON. This mode will send all other test output and user messages to stderr.


2 Answers

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).

like image 112
VonC Avatar answered Oct 23 '22 03:10

VonC


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
like image 25
Hung Tran Avatar answered Oct 23 '22 04:10

Hung Tran