Skip to content

Commit fea1e8d

Browse files
committed
break: default to regular CSS
1 parent d35fe66 commit fea1e8d

File tree

4 files changed

+95
-19
lines changed

4 files changed

+95
-19
lines changed

README.md

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,52 @@ A Jest transformer which enables importing CSS into Jest's `jsdom`.
2020
2121
## Description
2222

23-
When you want to do Visual Regression Testing in Jest, it is important that the CSS of components is available to the test setup. So far, CSS was not part of tests as it was mocked away by `identity-obj-proxy`.
23+
When you want to do Visual Regression Testing in Jest, it is important that the CSS of components is available to the test setup. So far, CSS was not part of tests as it was mocked away by using `moduleNameMapper` like a file-mock or `identity-obj-proxy`.
2424

2525
`jest-transform-css` is intended to be used in an `jsdom` environment. When any component imports CSS in the test environment, then the loaded CSS will get added to `jsdom` using [`style-inject`](https://github.com/egoist/style-inject) - just like the Webpack CSS loader would do in a production environment. This means the full styles are added to `jsdom`.
2626

2727
This doesn't make much sense at first, as `jsdom` is headless (non-visual). However, we can copy the resulting document markup ("the HTML") of `jsdom` and copy it to a [`puppeteer`](https://github.com/googlechrome/puppeteer/) instance. We can let the markup render there and take a screenshot there. The [`jsdom-screenshot`](https://github.com/dferber90/jsdom-screenshot) package does exactly this.
2828

2929
Once we obtained a screenshot, we can compare it to the last version of that screenshot we took, and make tests fail in case they did. The [`jest-image-snapshot`](https://github.com/americanexpress/jest-image-snapshot) plugin does that.
3030

31-
## Installation
31+
## Setup
32+
33+
### Installation
3234

3335
```bash
3436
yarn add jest-transform-css --dev
3537
```
3638

37-
## Setup
39+
The old setup of CSS in jest needs to be removed, and the new setup needs to be added next.
40+
41+
### Removing module name mapping
42+
43+
If your project is using plain CSS imported in the components, then you're likely using a mock file. You can remove that configuration.
44+
45+
```diff
46+
// in the Jest config
47+
"moduleNameMapper": {
48+
- "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js"
49+
},
50+
```
51+
52+
If your project is using CSS Modules, then it's likely that `identity-obj-proxy` is configured. It needs to be removed in order for the styles of the `jest-transform-css` to apply.
53+
54+
So, remove these lines from `jest.config.js`:
55+
56+
```diff
57+
// in the Jest config
58+
"moduleNameMapper": {
59+
- "\\.(s?css|less)$": "identity-obj-proxy"
60+
},
61+
```
3862

39-
### Setup - adding `transform`
63+
### Adding `transform`
4064

4165
Open `jest.config.js` and modify the `transform`:
4266

4367
```
68+
// in the Jest config
4469
transform: {
4570
"^.+\\.js$": "babel-jest",
4671
"^.+\\.css$": "jest-transform-css"
@@ -55,32 +80,47 @@ transform: {
5580
>
5681
> See https://github.com/facebook/jest/tree/master/packages/babel-jest#setup
5782
58-
### Setup - removing `identity-obj-proxy`
83+
### Enabling CSS modules
5984

60-
If your project is using CSS Modules, then it's likely that `identity-obj-proxy` is configured. It needs to be removed in order for the styles of the `jest-transform-css` to apply.
85+
By default, `jest-transform-css` will treat every file it transforms as a regular CSS file.
6186

62-
So, remove these lines from `jest.config.js`:
87+
You need to opt into css-modules mode by specifying it in the configuration. Create a file called `jesttransformcss.config.js` at your project root and add
6388

64-
```diff
65-
"moduleNameMapper": {
66-
- "\\.(s?css|less)$": "identity-obj-proxy"
67-
},
89+
```js
90+
// jesttransformcss.config.js
91+
92+
module.exports = {
93+
modules: true
94+
};
95+
```
96+
97+
This will enable CSS module transformation for all CSS files transformed by `jest-transform-css`.
98+
99+
If your setup uses both, CSS modules and regular CSS, then you can determine how to load each file individually by specifying a function:
100+
101+
```js
102+
// jesttransformcss.config.js
103+
104+
module.exports = {
105+
modules: filename => filename.endsWith(".mod.css")
106+
};
68107
```
69108

109+
This will load all files with `.mod.css` as CSS modules and load all other files as regular CSS. Notice that the function will only be called for whichever regex you provided in the `transform` option of the Jest config.
110+
70111
## Further setup
71112

72-
There are many ways to setup styles in a project (CSS modules, global styles, external global styles, local global styles, CSS in JS, LESS, SASS just to name a few). How to continue from here on depends on your project.
113+
There are many ways to set up styles in a project (CSS modules, global styles, external global styles, local global styles, CSS in JS, LESS, SASS just to name a few). How to continue from here depends on your project.
73114

74-
### Further Setup - PostCSS
115+
### PostCSS
75116

76117
If your setup is using `PostCSS` then you should add a `postcss.config.js` at the root of your folder.
77118

78-
You can apply certain plugins only when `process.env.NODE_ENV === 'test'`. Ensure that valid CSS can be generated. It might be likely that more functionality (transforms) are required to make certain CSS work (like background-images).
79-
80-
### Further Setup - css-loader
119+
You can apply certain plugins only when `process.env.NODE_ENV === 'test'`. Ensure that valid CSS can be generated.
81120

82-
If your setup is using `css-loader` only, without PostCSS then you should be fine. When components import CSS in the test environment, then the CSS is transformed through PostCSS's `cssModules` plugin to generate the classnames. It also injects the styles into `jsdom`.
121+
> `jest-transform-css` is likley not flexible enough yet to support more sophisticated PostCSS configurations. However, we should be able to add this functionality by extending the configuration file. Feel free to open an issue with your setup and we'll try to support it.
83122
84-
## Known Limitations
123+
### css-loader
85124

86-
At the moment I struggled to get CSS from `node_modules` to transpile, due to the `jest` configuration. I might just be missing something obvious.
125+
If your setup is using `css-loader` only, without PostCSS then you should be fine.
126+
If you have `modules: true` enabled in `css-loader`, you need to also enable it for `jest-transform-css` (see "Enabling CSS modules"). When components import CSS modules in the test environment, then the CSS is transformed through PostCSS's `cssModules` plugin to generate the classnames. It also injects the styles into `jsdom`.

index.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
const fs = require("fs");
22
const crypto = require("crypto");
33
const crossSpawn = require("cross-spawn");
4+
const cosmiconfig = require("cosmiconfig");
45
const stripIndent = require("common-tags/lib/stripIndent");
56
const THIS_FILE = fs.readFileSync(__filename);
7+
const explorer = cosmiconfig("jesttransformcss");
8+
const transformConfig = explorer.searchSync();
69

710
module.exports = {
811
getCacheKey: (fileData, filename, configString, { instrument }) => {
@@ -16,6 +19,8 @@ module.exports = {
1619
.update(filename)
1720
.update("\0", "utf8")
1821
.update(configString)
22+
.update("\0", "utf8")
23+
.update(JSON.stringify(transformConfig))
1924
// TODO load postcssrc (the config) sync and make it part of the cache
2025
// key
2126
// .update("\0", "utf8")
@@ -27,6 +32,28 @@ module.exports = {
2732
},
2833

2934
process: (src, filename, config, options) => {
35+
// skip when plain CSS is used
36+
// You can create jesttransformcss.config.js in your project and add
37+
// module.exports = { modules: true };
38+
// or
39+
// module.exports = { modules: filename => filename.endsWith(".mod.css") };
40+
// to enable css module transformation. for all or for certain files.
41+
const useModules =
42+
transformConfig &&
43+
transformConfig.config &&
44+
((typeof transformConfig.config.modules === "boolean" &&
45+
transformConfig.config.modules) ||
46+
(typeof transformConfig.config.modules === "function" &&
47+
transformConfig.config.modules(filename)));
48+
if (!useModules) {
49+
return stripIndent`
50+
const styleInject = require('style-inject');
51+
52+
styleInject(${JSON.stringify(src)});
53+
module.exports = {};
54+
`;
55+
}
56+
3057
// The "process" function of this Jest transform must be sync,
3158
// but postcss is async. So we spawn a sync process to do an sync
3259
// transformation!

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"license": "MIT",
88
"dependencies": {
99
"common-tags": "1.8.0",
10+
"cosmiconfig": "5.0.6",
1011
"cross-spawn": "6.0.5",
1112
"postcss-load-config": "2.0.0",
1213
"postcss-modules": "1.3.2",

yarn.lock

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ [email protected]:
5858
version "1.8.0"
5959
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
6060

61+
62+
version "5.0.6"
63+
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.6.tgz#dca6cf680a0bd03589aff684700858c81abeeb39"
64+
dependencies:
65+
is-directory "^0.3.1"
66+
js-yaml "^3.9.0"
67+
parse-json "^4.0.0"
68+
6169
cosmiconfig@^4.0.0:
6270
version "4.0.0"
6371
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc"

0 commit comments

Comments
 (0)