Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support named exports #8

Open
joaovieira opened this issue Apr 30, 2018 · 10 comments
Open

Support named exports #8

joaovieira opened this issue Apr 30, 2018 · 10 comments

Comments

@joaovieira
Copy link

joaovieira commented Apr 30, 2018

When using CSS modules with named exports (e.g. you're using Typescript and typings-for-css-modules-loader), they look like:

export const foo = 'foo';
export const barBaz = 'barBaz';

And the consumer uses as:

import * as styles from './styles.css';

...
<div className={styles.barBaz} />

This mock does not play nice. I've found that returning true for the __esModule check here does work - essentially saying that our mocked module is an ES module and the keys are the named exports.

Any ideas if and how this project could accommodate that? E.g. using identity-obj-proxy/esm?

@gabsprates
Copy link

@joaovieira, same problem here. Did you solve that?

@john-d-pelingo
Copy link

My work around for this is to mock style.scss like below.

jest.mock('./styles.scss', () => ({
  __esModule: true,
  default: {
    class1: 'class1',
    class2: 'class2',
  },
}))

Of course, having this automated by this plugin would be great. :)

@joaovieira
Copy link
Author

joaovieira commented Oct 16, 2018

@gabsprates @john-d-pelingo sorry for not answering here, what I did was to define my own css mock with the modified identity-obj-proxy as mentioned above:

// .jest/identity-obj-proxy-esm.js

// Modified identity-obj-proxy.

// This works around the fact we use ES named exports for styles, e.g.:
// import * as styles from './styles.scss'.
// https://github.com/keyanzhang/identity-obj-proxy/issues/8
module.exports = new Proxy(
  {},
  {
    get: function getter(target, key) {
      if (key === '__esModule') {
        // True instead of false to pretend we're an ES module.
        return true;
      }
      return key;
    },
  },
);
// jest.config.js

module.exports = {
  ...
  moduleNameMApper: {
    '\\.(jpg|jpeg|png|gif|webp|svg)$': 'identity-obj-proxy',
    '\\.(css|scss)$': '<rootDir>/.jest/identity-obj-proxy-esm.js',
  }
};

@john-d-pelingo
Copy link

@joaovieira @gabsprates

I was literally about to post that later today. Seems like it works like a charm. 👏

@flocbit
Copy link

flocbit commented Mar 7, 2019

@joaovieira Thank you so much! It works perfectly 🎉 👏

@webcarrot
Copy link

I use something like:

const proxy = new Proxy(
  {},
  {
    get: function getter(target, key) {
      switch (key) {
        case "__esModule":
          return true;
        case "default":
          return proxy;
        default:
          return key;
      }
    }
  }
);
module.exports = proxy;

To handle some re export quirks.

@nicolashemonic
Copy link

Hello guys,

Thank you all to share your solution.

There is a very more simple solution to make work Jest + Typescript + Css Module in 2020.

Typescript compilation
typings-for-css-modules-loader is a deprecated tool that can be replaced by the Typescript plugin typescript-plugin-css-modules. The main advantage is that this plugin generate "hidden" definition file on the fly for each css module. All the stuff is totally managed by the compiler itself (not Webpack).

Test snapshot
Along these versions:
jest 25.5
ts-Jest 25.5
identity-obj-proxy 3.0

You don't need to modify identity-obj-proxy. The problem you know is that Typescript not generate a default export for all class names. To fix that you just need two things:

1/ Set the esModuleInterop option of Typescript to true (you can remove allowSyntheticDefaultImports that will be enabled). And replace all of your import * as style from "./component.module.css" with import style from "./component.module.css". The compiler will generate for the compilation a helper that allow to retrieve all named export in a default one.

2/ Add the definition file created for typescript-for-css-modules here into the files property of the tsconfig.json.
For example a dedicated tsconfig.json for ts-jest that extends the app one:

{
    "extends": "../tsconfig",
    "files": [
        "../app/types/css-module.d.ts"
    ]
}

This file allow the Typescript compiler to understand the import of the Css file and proceed to the compilation before the test.

Test Result
Finally the snapshot contains the class names:

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<PrettyGraph /> rendering should display current situation 1`] = `
<p
  className="hello-world"
>
  Hello World!
</p>
`;

I hope that help!

@master-elodin
Copy link

I use something like:

const proxy = new Proxy(
  {},
  {
    get: function getter(target, key) {
      switch (key) {
        case "__esModule":
          return true;
        case "default":
          return proxy;
        default:
          return key;
      }
    }
  }
);
module.exports = proxy;

To handle some re export quirks.

This fixed it for me, thanks!

@joshunger
Copy link

@joaovieira thank you! 🙏

@bdrazen
Copy link

bdrazen commented Jul 12, 2022

@nicolashemonic Only solution that worked for me. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants