Profiling TS-based Jest tests
Asked Answered
S

2

15

I have a Typescript-based React project in which I am running jest tests (also in TS). I can run tests fine but am trying to profile the performance of some which take quite a long time to run. I have tried using Chrome Devtools to attach to the tests, which it does, however it fails due to it being TS and not plain Js. Is there any way I can profile my tests individually to see where the performance issue is occurring? Using VS Code.

Starlet answered 19/1, 2022 at 13:52 Comment(0)
A
13

Instead of a React project, it was just a regular TypeScript library for me, but I bet this also works for your use-case. I am leaving this here, in case it's usable, or for future me.

The ONLY solution I found that worked was manually setting up the profiler v8-profiler-next.

import * as fs from 'fs';
import * as v8Profiler from 'v8-profiler-next';
v8Profiler.setGenerateType(1);
const title = 'good-name';

describe('Should be able to generate with inputs', () => {
  v8Profiler.startProfiling(title, true);
  afterAll(() => {
    const profile = v8Profiler.stopProfiling(title);
    profile.export(function (error, result: any) {
      // if it doesn't have the extension .cpuprofile then
      // chrome's profiler tool won't like it.
      // examine the profile:
      //   Navigate to chrome://inspect
      //   Click Open dedicated DevTools for Node
      //   Select the profiler tab
      //   Load your file
      fs.writeFileSync(`${title}.cpuprofile`, result);
      profile.delete();
    });
  });
  test('....', async () => {
    // Add test
  });
});

This then gives you the CPU profile as such, which works fine with TypeScript.

enter image description here

Alphonsoalphonsus answered 17/11, 2022 at 17:49 Comment(2)
I had to change import v8Profiler from 'v8-profiler-next'; to import * as v8Profiler from 'v8-profiler-next';Item
@Alphonsoalphonsus You have "idle" taking up most of the time. Does that help us with diagnosing the slowness? Did you manage to reduce this time somehow?Lucullus
R
1

TL;DR

Search for your functional, daily test script and create your new profiler script just adding the --inspect or --inspect-brk to the node call. If your test script calls jest directly, make the new test:inspect script verbose, calling node on jest.

Detailed

I just had the same problem, and in my case the problem is that my jest config file is in a custom folder. It is pretty easy to discover if this is your case also.

First, go to the scripts entry in your package.json and find the script you usually run in your daily tests (the one that already works). In my case I had kind of a chain (an unnecessary and poorly designed chain, in my opinion, but I will add it here because it might help if you have the same case): the npm run test calls the test:unit without adding anything; the test:unit removes any flags passed, calling test:base with coverage and max-workers flags; finally, the test:base was the one that calls jest:

"test": "npm run test:unit",
"test:base": "cross-env NODE_ENV=test node --expose-gc --no-compilation-cache ./node_modules/jest/bin/jest.js --logHeapUsage --config ./config/jest.config.js --colors --rootDir . --passWithNoTests",
"test:unit": "npm run test:base -- --maxWorkers=4 --coverage",

As you can see, the final script run is test:base, which has many flags, including the --config, which points to the jest.config file--which is the one that instructs jest to use TsJest for typescript.

So, in the end I just created my test:debug (or test:profile, or whatever name you want to give it) adding the same script with the --inspect (or --inspect-brk, because it is easier to run the profiler when you break at the start):

"test:profiler": "cross-env NODE_ENV=test node --inspect-brk --expose-gc --no-compilation-cache ./node_modules/jest/bin/jest.js --logHeapUsage --config ./config/jest.config.js --colors --rootDir . --passWithNoTests",

As you can see, I just added the --inspect-brk to my already functional test script.

If your test script calls jest directly (something simple like "test": "jest", change it to the verbose call ("test:profiler": "node ./node_modules/jest/bin/jest.js"), or whatever you path to jest is inside "node_modules" (the path should not be different, but shit happens).

After this, I could open chrome devtools for node and inspect through the profiler (in my older version, the Performance tab).

Rufina answered 26/4 at 21:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.