debug typescript mocha and server in vscode

We recently are developing a graphql api using apollo server and Typeorm on top of Aws Lambda. Code-wise is kind of straightforward with schema defined, then resolvers then service layer then dao layer then model defined typeorm with its annotations/decorators. However there are 2 issues related to debugging, unit test and run graphql local.

unit test

For unit test, our ci/cd pipeline uses nyc/mocha as runner. Those are good for running all test suites and generating reports on coverages etc. However when it comes to debugging we need to go to ide. And as we are using typescript, there is one more layer of transpile rather than vanilla es5/6 which is this a bit more complicated.

Good news is vscode comes with a powerful built-in node debugger, with the blow config, we can just open a ts​ file with mocha tests, set break point and start debug,

{
  "name": "TS Mocha Tests File",
  "type": "node",
  "request": "launch",
  "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
  "args": ["-r", "ts-node/register", "${relativeFile}"],
  "cwd": "${workspaceRoot}",
  "protocol": "inspector",
  "env": { "TS_NODE_PROJECT": "${workspaceRoot}/tsconfig.json"}
}
  • Sets up a node task, that launches mocha
  • Passes a -r argument, that tells mocha to require ts-node
  • Passes in the currently open file – ${relativeFile}
  • Sets the working directory to the project root – ${workspaceRoot}
  • Sets the node debug protocol to V8 Inspector mode
  • The last TS_NODE_PROJECT I have to set it as I am using Typeorm which uses annotation/decorator which requires emitDecoratorMetadata set to true which is not default.

Local Run with nodemon

Another issue is as we are using aws lambda, it is not easy to run our graphql server locally.
Need to set up a local Koa server with the schema that the Apollo lambda also uses. This way we can access our the graphiql service from the  localhost:8080/graphiql​.

import 'reflect-metadata';
import * as Koa from 'koa';
import { initDatabase } from '../../dao/data-source';
import * as Router from 'koa-router';
import * as koaBody from 'koa-bodyparser';
import {
    graphqlKoa,
    graphiqlKoa,
} from 'apollo-server-koa';
import { schema } from '../../gq-schema';
import { localConf } from '../../config/config';

export const routes = new Router();

// API entrypoint
const apiEntrypointPath = '/graphql';
const graphQlOpts = graphqlKoa({
    schema,
    context: {msg: 'hello context'}
});

// routes.get(apiEntrypointPath, graphQlOpts);
routes.post(apiEntrypointPath, koaBody(), graphQlOpts);

// GraphiQL entrypoint
routes.get('/graphiql', graphiqlKoa({ endpointURL: apiEntrypointPath }));

(async () => {
  initDatabase(localConf);
  const app = new Koa();
  app.use(routes.routes())
    .use(routes.allowedMethods())
    .listen(8080);
})();

Now we can have nodemon run this server so every time we make any code change, the server will reload with the new content. Put below content in the nodemon.json in the project root.

{
  "watch": ["./src"],
  "ext": "ts",
  "exec": "ts-node --inspect=0.0.0.0:9229 ./path/to/above/server.ts"
}

Notice we run ts-node with 9229 port flag which is the default debug port for chrome so that we can later do debug in the chrome’s built-in node-debugger which is a green cube icon in the chrome’s dev tool console.

Now we can run local server by adding command into package.json:

"local": "npm run build && nodemon"

Then run npm run local OR ​yarn local.

Option2 debug server with vscode

To debug the above  server with vscode, we need to add some config into the launch.json.

    {
      "name": "Local Graphql Server",
      "type": "node",
      "request": "launch",
      "args": [
        "${workspaceRoot}/path/to/above/server.ts"
      ],
      "runtimeArgs": [
        "--nolazy",
        "-r",
        "ts-node/register"
      ],
      "sourceMaps": true,
      "cwd": "${workspaceRoot}",
      "protocol": "inspector",
    },

  • Sets up a node task that starts the currently open file in VS Code (the${relativeFile} variable contains the currently open file)
  • Passes in the --nolazy arg for node, which tells v8 to compile your code ahead of time, so that breakpoints work correctly
  • Passes in -r ts-node/register for node, which ensures that ts-node is loaded before it tries to execute your code
  • Sets the working directory to the project root – ${workspaceRoot}
  • Sets the node debug protocol to V8 Inspector mode (see above)

Now we can set break point in vscode and start debugging.

PS: No Enum in x.d.ts

One thing I notice today is in the xxx.d.ts file which is the module definition file, never define thing like Enum inside as this file is used for type/interface definition only and the content will NOT compile to js hence will not available in the run time. So if you defined anything like enum here it will compile fine but when you run the application, as long as you use these enums​, you get runtime error.

One alternative solution is to use custom type and define the list of strings:

export type MessageLevel = "Unknown" | "Fatal" | "Critical" | "Error";
Advertisements

debug nodejs in chrome

The new chrome ships with the about:inspect and a dedicated debugger for nodejs which is super cool! At least we do not have to rely solely on console.log() magic.

To do that, run script with an additional flag:

node --inspect myServer.js

This should fire up the app and then go to a new tab and enter about:inspect. Then click on the open dedicated DevTools for Node link, which opens a debugger for node. Now you can start to put break points etc…

More options HERE and a video intro.

debug hover item in chrome devtools

Chrome devtools is our friend, always.

Today when I was developing an angular 4.x app with primeng library, i have to check the class set on the tooltip component. As we know the tooltip is hover event based, so if we hover on it to make it showup and then shift our focus to the dev tool element tab, the tooptip would disappear.

Chrome tool has a feature to activate the hover stuff(:hover) on specific element for CSS sake. It is quite handy but obviously it does not apply in this use case since this tooltip is js based.

Search around and finally find a solution: using F8 or CMD + \ which is pause the script execution.

Steps are quite straightforward:

Mouse over the tooltip, and press F8 while it is displayed.

Now you can now use the inspector to look at the CSS.

How Java Debug works

You can just attach your IDE to a running application (which has been runned for debug as we’ll see later), or you can even debug it from command line. And the application you debug can even be be in a different machine.

The magic lies in where the debug information actually resides. Apparently people normally think that is the IDE that knows how to debug your programs, but the truth is that is the program who knows how to debug itself, and makes that information available to whoever wants to use it.

The way it works is basically the following. When you compile a program, the .class files get debug information within them, like line numbers or local variables that are made accessible to others who want to access this information. You can then run the program in debug mode passing the following options to your java program execution(you can of course run any java program like this, including mvn goals, appllication servers, etc)

User Jdb

There are many ways to start a jdb session. The most frequently used way is to have jdb launch a new Java Virtual Machine (VM) with the main class of the application to be debugged. This is done by substituting the command jdb for java in the command line. For example, if your application’s main class is MyClass, you use the following command to debug it under JDB:

C:\> jdb MyClass 

When started this way, jdb invokes a second Java VM with any specified parameters, loads the specified class, and stops the VM before executing that class’s first instruction.

Another way(used by ide)

java -agentlib:jdwp=transport=dt_shmem,address=jdbconn,server=y,suspend=n Sum 3 4

You can then attach jdb to the VM with the following commmand:

C:\> jdb -attach jdbconn

This line basically says: Run this program in debug mode, use the jdwp protocol, with a socket that listens to port 4000 and waits for connections to continue.

The jdwp protocol is a communication protocol used by the Java application to receive and issue commands and reply to them.

For example, you can connect to this port when the application is running an issue commands like “print variablex” to know the value of a variable, “stop at x” to set a breakpoint, etc. The application issues notification commands like “breakpoint reached”.
The truth is that the protocol is a little more complex than this, but this is enough to know to illustriate the point.

With the previous said, we can see that it would be even possible to debug an application with the use of Telnet! (we’ll see later)

Well, enough theory. Let’s see an example Any simple example will do. We’ll make a simple program that takes two parameters from command line and prints the sum. The program won’t be well designed (In the sense that will include some useless temp variables, no validations, etc) but will do to illustrate the example.

class Sum{
    public static void main(String[] args){
        int sum1 = Integer.parseInt(args[0]);
        int sum2 = Integer.parseInt(args[1]);
        int suma= sum1+sum2;
        System.out.println("La suma es "+suma);
    }
}

So we compile it: javac -g Sum.java (the g option adds extra debug info to the class. Like local variable names)
And we run it in debug mode:

C:\> jdb Sum

you’ll get some output like
Initializing jdb …
>

That’s it, you have a debug session started. Now the interesting. Execute the following in your jdb session:

stop at Sum:6

You now have a breakpoint on line 6. execute run on the session, and the program will run until that breakpoint. you’ll get the output

Deferring breakpoint Sum:6.
It will be set after the class is loaded.

We can then type ‘run‘ to start jvm.

Now let’s see the value of our variables: run the following commands (one at a time) on the jdb session and see the results.

print sum1
print sum2
print suma
locals
set suma = 10
locals
cont

This is pretty cool stuff. You can debug your program from command line.

 

From here and here

debug nodejs with nodemon and intellij

Noticed that if I run nodemon within intellij, I would not be able to debug any more inside intellij.
Not sure what reason it is. If just run the nodejs, no problem. However once I add the ‘/usr/local/bin/nodemon’ into the Node parameters of the run config, the breakpoint would not work.

solution

To solve this problem, i have to use the Node.js remote debug.
Steps are

1. add a debug port to the Node parameters

–debug=3001. Note It is double dash. this should be the same as the port in the following remote debug config.

in the intellij doc, another option is to use –debug-brk which would enable the debug to run from the start. I tried this param, it works if I just change some front end html/js, however it would not work when backend js changed. Might have other workaround if you have to debug some init processes.

debug config intellij nodejs

debug config intellij nodejs

2. add a new Node.js remote debug config in Intellij

remote debug intellij node

remote debug intellij node

Now you should be able to use run RUN to start the server.js application and use DEBUG to start the ‘remote server debug’ and then set break point in your node app. 🙂