Razzle: Run tests in a debugger

Created on 28 Jan 2021  ·  19Comments  ·  Source: jaredpalmer/razzle

🚀 Feature request

Current Behavior

I'm converting from a client-side only app to an isomorphic one using razzle. Before the conversion, I figured out how to run my unit tests using a debugger (kind of like how razzle start will work with the -- --inspect-brk flag). Here is my test-debug script:

node --inspect-brk node_modules/.bin/jest --config jest.config.json --runInBand

Right now there doesn't seem to be a way to debug tests using razzle test.

Desired Behavior

It would be nice if either I could do something similar for razzle test that I can do for razzle start

Suggested Solution

Consider adding a razzle test-debug command that runs node with the --inspect-brk then firing off the test script from within it

Who does this impact? Who is this for?

All users who may need to debug their unit tests

Describe alternatives you've considered

I haven't tried getting this to work yet

Additional context

N/A

All 19 comments

Should be doable

Added in canary, will release soon :)

I'm trying to run tests in Webstorm. Normally I can select specific tests to run or debug within the IDE, but because the jest config is handled internally by razzle I'm just getting parsing errors from JSX files, Typescript etc.

Will this fix help in my situation, do you think?

Don't think this will play nice with webstorm. I could add a --export-config arg to razzle test.

@fivethreeo that might help 👍

It's possible to create a dynamic jest config as jest.config.js, so this could potentially invoke something within razzle and re-export the config?

Config is async, can that work in jest.config.js?

On Tue, 16 Mar 2021 at 18:12, Robert Churchill @.*>
wrote:

@fivethreeo https://github.com/fivethreeo that might help 👍

It's possible to create a dynamic jest config as jest.config.js, so this
could potentially invoke something within razzle and re-export the config?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/jaredpalmer/razzle/issues/1531#issuecomment-800449308,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAAADGTZB76BVA77ZHMXKX3TD6GOFANCNFSM4WWDU4DA
.

--
Øyvind Saltvik

// jest.config.js
// Sync object
module.exports = {
  verbose: true,
};

// Or async function
module.exports = async () => {
  return {
    verbose: true,
  };
};

Seems it can :)

Should add this to all examples :)

Looks good, I thought this was going to be a big ask!

I'm juggling about 5 projects at the moment but will give it a try in a minute...

I got as far as below, but I'm struggling to get the resolve function to work outside the context of razzle.

require.resolve fails because there is no "main" definition in razzle, meaning node can't locate it. I'm in a monorepo so it's not safe to assume it's directly inside node_modules/razzle.

// test.config.js
const loadRazzleConfig = require("razzle/config/loadRazzleConfig.js");
const webpack = require("webpack");
const defaultPaths = require("razzle/config/paths");
const createJestConfig = require("razzle/config/createJestConfig");
const path = require("path");

module.exports = loadRazzleConfig(webpack, defaultPaths).then(
    async ({ razzle, razzleOptions, webpackObject, plugins, paths }) => {
        return await createJestConfig(
            relativePath => path.resolve(require.resolve("razzle"), relativePath),
            path.resolve(paths.appSrc, ".."),
            razzle,
            razzleOptions,
            webpackObject,
            plugins,
            paths
        );
    },
);

More like

// test.config.js
const loadRazzleConfig = require("razzle/config/loadRazzleConfig.js");
const webpack = require("webpack");
const defaultPaths = require("razzle/config/paths");
const createJestConfig = require("razzle/config/createJestConfig");
const path = require("path");

module.exports = async () => {

  const { razzle, razzleOptions, webpackObject, plugins, paths } = await loadRazzleConfig(webpack, defaultPaths);
  return await createJestConfig(
            relativePath => path.resolve(require.resolve("razzle"), relativePath),
            path.resolve(paths.appSrc, ".."),
            razzle,
            razzleOptions,
            webpackObject,
            plugins,
            paths
        );
};
// test.config.js
const loadRazzleConfig = require("razzle/config/loadRazzleConfig.js");
const webpack = require("webpack");
const defaultPaths = require("razzle/config/paths");
const createJestConfig = require("razzle/config/createJestConfig");
const path = require("path");

module.exports = async () => {

  const { razzle, razzleOptions, webpackObject, plugins, paths } = await loadRazzleConfig(webpack, defaultPaths);
  return await createJestConfig(
            relativePath => path.resolve(paths.ownPath, relativePath),
            path.resolve(paths.appSrc, ".."),
            razzle,
            razzleOptions,
            webpackObject,
            plugins,
            paths
        );
};

Will try adding this to razzle so it is easy to require and export:

https://github.com/jaredpalmer/razzle/commit/cf1ba7827accfbbbfc6a7e2a1cace11a054f73b6

Did it work?

@fivethreeo Nearly there!

Of course, this should return a promise directly, not an async function (my mistake).

I then get an It looks like you called mount() without a global document being loaded error, so I'm currently working out how --env=jsdom can be passed to this config.

    "test": "razzle test --env=jsdom"
// test.config.js
const loadRazzleConfig = require("razzle/config/loadRazzleConfig.js");
const webpack = require("webpack");
const defaultPaths = require("razzle/config/paths");
const createJestConfig = require("razzle/config/createJestConfig");
const path = require("path");

module.exports = loadRazzleConfig(
    webpack,
    defaultPaths,
).then(({ razzle, razzleOptions, webpackObject, plugins, paths }) =>
    createJestConfig(
        (relativePath) => path.resolve(paths.ownPath, relativePath),
        path.resolve(paths.appSrc, ".."),
        razzle,
        razzleOptions,
        webpackObject,
        plugins,
        paths,
    ),
);
/**
 * @jest-environment jsdom
 */

at the top of the file

or

config.testEnvirinment = 'jsdom';
// test.config.js
const loadRazzleConfig = require("razzle/config/loadRazzleConfig.js");
const webpack = require("webpack");
const defaultPaths = require("razzle/config/paths");
const createJestConfig = require("razzle/config/createJestConfig");
const path = require("path");

module.exports = async () => {

  const { razzle, razzleOptions, webpackObject, plugins, paths } = await loadRazzleConfig(webpack, defaultPaths);
  let config = await createJestConfig(
            relativePath => path.resolve(paths.ownPath, relativePath),
            path.resolve(paths.appSrc, ".."),
            razzle,
            razzleOptions,
            webpackObject,
            plugins,
            paths
        );
config.testEnvironment = 'jsdom';
return config;
};

Okay, success. For my purposes, I have done this:

// jest.config.js
const loadRazzleConfig = require('razzle/config/loadRazzleConfig.js');
const webpack = require('webpack');
const defaultPaths = require('razzle/config/paths');
const createJestConfig = require('razzle/config/createJestConfig');
const path = require('path');

// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';

module.exports = loadRazzleConfig(webpack, defaultPaths)
    .then(({ razzle, razzleOptions, webpackObject, plugins, paths }) =>
        createJestConfig(
            (relativePath) => path.resolve(paths.ownPath, relativePath),
            path.resolve(paths.appSrc, '..'),
            razzle,
            razzleOptions,
            webpackObject,
            plugins,
            paths,
        ),
    )
    .then((jestConfig) => ({
        ...jestConfig,
        testEnvironment: 'jsdom',
    }));

For ultimate flexibility, "jsdom" could be passed in from an environment variable. The built-in razzle test script also sets the NODE_ENV and BABEL_ENV vars etc. to "test" so I have added this in. It seems like jest.config.js runs in the same context as the tests (I tested passing a random env var through to the tests) though I'm not sure how much you can rely on this.

Thanks for your help @fivethreeo

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MaxGoh picture MaxGoh  ·  4Comments

GouthamKD picture GouthamKD  ·  3Comments

piersolenski picture piersolenski  ·  4Comments

ewolfe picture ewolfe  ·  4Comments

pseudo-su picture pseudo-su  ·  3Comments