okta-auth-js icon indicating copy to clipboard operation
okta-auth-js copied to clipboard

Conditional exports fail with jest-resolve@npm:^28.1.x

Open macyabbey-okta opened this issue 2 years ago • 1 comments

Describe the bug?

The conditional exports block used in this library fails when a consuming package utilizes [email protected] and [email protected].

An error is omitted like:

    No known conditions for "." entry in "@okta/okta-auth-js" package

      at bail (../../../../.yarn/cache/resolve.exports-npm-1.1.0-680d12534c-52865af8ed.zip/node_modules/resolve.exports/dist/index.js:32:8)
      at resolve (../../../../.yarn/cache/resolve.exports-npm-1.1.0-680d12534c-52865af8ed.zip/node_modules/resolve.exports/dist/index.js:91:32)
      

This is because jest's resolver only supports nested export objects which contain one of the keys passed down by jest (default, browser, require), or more easy to reason about, the same key that maps to the nested conditional object.

Since this package.json does not a key for 'browser', 'require' or 'default' in the 'browser' sub condition of '.' resolution fails in jest 28.

  "exports": {
    ".": {
      "node": {.  // <-- jest passes down `require` not `node` to `resolve.exports`
        "types": "./build/lib/index.d.ts",
        "import": "./build/esm/node/index.js",
        "require": "./build/cjs/index.js"
      },
      "browser": {    // <-- specifically this would work if it also contained "browser"
        "types": "./build/lib/index.d.ts",
        "import": "./build/esm/browser/index.js"
      },
      "types": "./build/lib/index.d.ts",
      "default": "./build/dist/okta-auth-js.umd.js"
    },

What is expected to happen?

Ideally jest resolution would work out of the box.

What is the actual behavior?

Failure.

Reproduction Steps?

Consume this package from any other package using jest 28, notice jest module resolution fails.

SDK Versions

@okta/[email protected]

Execution Environment

[email protected], Node@lts/gallium

Additional Information?

The following hack gets around the problem in a custom jest resolver as described in jest docs: https://jestjs.io/docs/27.x/configuration#resolver-string

In jest.config.js:

  ...
  resolver: '<rootDir>/../resolver.js',
  ...

In resolver.js

module.exports = (request, options) => {
  return options.defaultResolver(request, {
    ...options,
    // Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb)
    packageFilter: pkg => {
      if (pkg.name && pkg.name === '@okta/okta-auth-js') {
        // Hack for conditional export in `@okta/[email protected]/7.x` containing `browser`
        // key but then no entry for default or browser within conditional object
        // for that key.
        delete pkg.exports['.'].browser;
        return {
          ...pkg,
        };
      }
      return pkg;
    },
  });
};

macyabbey-okta avatar Aug 08 '22 13:08 macyabbey-okta

@macyabbey-okta do you have a repo with a minimal jest config I can use to verify? I have been unable to repro the error you described (still had issues, just not the same issue).

I did some testing on my end and tests run fine in jest@27. I installed jest@28 and had to adjust our conditional exports (as you suggested), but I wasn't able to get my tests running (got a different error than you).

Lastly, tested on jest@28 with

// jest.config.js
moduleNameMapper: {
    '^@okta/okta-auth-js$': '<rootDir>/node_modules/@okta/okta-auth-js/dist/okta-auth-js.umd.js',
    ...

and all my tests ran and passed.

You may want to run your jest tests against the umd bundle. Jest considers there support for ESM (introduced in 28) to be experimental (it's based on a Node API that is considered experimental as of Node 14.13) Jest ESM Docs

jaredperreault-okta avatar Aug 10 '22 16:08 jaredperreault-okta