Check out a free preview of the full Testing React Applications, v2 course:
The "CSS Imports" Lesson is part of the full, Testing React Applications, v2 course featured in this preview video. Here's what you'd learn in this lesson:

If webpack loaders exist, Kent shows how to configure Jest to be able to load CSS files. Kent takes questions from students.

Get Unlimited Access Now

Transcript from the "CSS Imports" Lesson

[00:00:00]
>> Okay so let's pull in another test and deal with the problems of configuration for that one. So I'll duplicate this and remove the .solution to get it in our code base here. So this is right next to the utils because auto-scaling-text is the one that we're trying to test.

[00:00:21] So this is a react component. And has some states doing a component of life cycles, all that stuffs. And in our tests, it's kind of a boring test. Just because we are not here right now talking about what the test should actually look like. Just configuring things. So I just wanna make sure that it can melt.

[00:00:43] And that it can be rendered. So now if we run npm t. We're gonna run it to your first error. And that error is, .auto-scaling-text. What on earth could that possibly be? So that actually looks like a class name to me. And it only looks like a class name to me because I know that's what it is.

[00:01:05] So, it's trying to treat this as a JavaScript module. The reason for that is, at the top here, we're importing this CSS. So we're using webpack loaders. This is really, really common for people will be doing and so that's why we're including it here in our configuration setup stuff.

[00:01:27] So how do we deal with this? Well node can't import CSS. It'll treat all, anything that you import as either JSON or JavaScript module. And so, that's why things are blowing up. So, what we can do. Let me just clear this out. Whoops. Is with jest, add some additional configuration.

[00:01:49] I'm actually gonna pull this out, and add a configuration file called jest.config.js. And Jest will pick that up by default module that exports equals jest configuration. Okay, so now with that, I'm going to add a new property in our configuration called moduleNameMapper. And this is an object where the key is a string of regex that matches a file and then the value is a module that is responsible for mapping that to something that's JavaScript.

[00:02:28] Okay? So here, our string regex could be something like .css, so something that ends in css, okay? So any time something ends in css, we're going to have it load a different file set. Let's go ahead and create that file real quick. No no, don't do that. Duplicate.

[00:02:58] Okay, so it's going to be in test, style-mock, and it's not really going to be anything all that interesting, just exporting an object. In fact, this is the default for module, so this could actually be enough for us. It just needs to be something that exists. If you're doing SPGs or if you're doing like various other things, it might make sense to put more in here, but for our purposes just having nothing is totally fine.

[00:03:24] So here we need to pass up a path to the module, so we'll say require.resolve('./test/style-mock'). And then with that we can run npm t to run our tests. We get a new error. document is not defined. Who knows why that happened? Because we switched things over to known.

[00:03:48] So I should be jazzed Tom. Which is the default so we can remove it. Cool. Any questions about that? All right. So let's, yes question.
>> Let's say you're trying to write. Code that's actually going to run both client and server?
>> Yeah, so that's a good question.

[00:04:19] The more difficult environment is the browser, and so I always test it as if it's running in the browser.
>> Where do you write separate tests?
>> So if I have a module that's gonna run in both, I'll treat it like it's running in the browser.
>> As a worse case.

[00:04:37]
>> Yeah, exactly. Does that make sense?
>> That makes sense.
>> So in a universal application, you might run in to a problem where because you're testing it with the browser environment installed, you could start using document dot and stuff in your components, and that will actually break on the server.

[00:04:57] So yeah, and there's some things you can do to get around that but, because not always would that be a problem. Like if you're using document dot but in components of mal, then that's fine because components in mal doesn't run on this server, when you render it that way.

[00:05:14] But if like somebody slips it in, like the root of the module or something like that. Then that could be a problem and you wouldn't catch it with your test. So something that you could do is you could actually have two different configurations and run them in parallel.

[00:05:28] And I'll show you how to do that. It's pretty crazy, like you would run all the same tests but with two other test environment settings. It should all work, which is kinda weird. Unless you wanted to, some of your tests, actually do mount the component and then you're like.

[00:05:44] And so it might be better just to have separate tests to make sure you can render to the initial render, to static HTML, whatever, or markup. Yeah?
>> Just curious about that double backslash in the regex?
>> Yeah, so in JavaScript strings, we're escaping the backslash, cuz the backslash is an escape.

[00:06:07] So the actual regex will be this, but because it's a string regex.
>> With a string, yeah, sure.
>> I know, it's kind of like, yeah. Sometimes you wish that the API was an array, and then the has named things like regex or whatever, but what do you do?

[00:06:23] It's not too bad. We don't use this feature a ton. Like, we'll have a couple of these, so. Any other questions? Remember, people three months from now are going to have the questions you're thinking of. Okay nothing. Okay cool. So let's actually, this is not entirely perfect. We're using CSS modules here, fun fact, create react app version two.

[00:06:47] We'll support CSS modules and this is how it will do it. You'll add a dot module before the dot CSS and it will treat that as a CSS module. What that means is what you get back is an object that has keys for every class name. So there will be a key, it’ll be camel cased.

[00:07:06] So you can do styles.auto-scaling-text. And that will be the class name that’s associated with those styles. So we’re using that right here, auto-scaling-text and if I go ahead and let's see. Where'd my test go? If we go console log div enter HTML and then run our test again, then we're going to see, it just has div and it's not showing me my class name.

[00:07:36] And the reason is because our mock here, the style mock is exporting an empty object. So when auto-scaling-text pulls that in, styles is an empty object, it's not one that we exported, right? And so then, when we try to access the auto-scaling-text, that's undefined. Okay, and so that's why we don't get that class name attributed here.

[00:08:00] I'm not actually sure at all why style isn't on here. Maybe it's using the properties under the header or something like that. So it doesn't appear in the HTML. And ref is like a dump thing anyways. And so that's why it's just a point of dev. So maybe we can improve that a little bit because it could be nice in our test to be able to see at least the title of the thing as the class name, and so we can actually do that pretty easily with a module.

[00:08:31] Instead of our style mock, there's a module called Identity something something, identity object proxy. And what it does is it will, well if you don't understand proxies, it's kinda confusing. But when we say, dot on this object, it will take that and consider that to be the thing it's returning.

[00:08:58] So whatever you say, or whatever, this is what it's going to return for that. Which is really perfect for our use case. I'm not sure if it was built for our use case, but it works great. So let's go ahead and install that module, npm install. As a dev identity-object-proxy.

[00:09:16] And then while that is installing we can have another match. So maybe some of our CSS is like normal dot CSS, but for anything that has dot module, dot CSS ends with that. We'll just say the path to the module is identity-object. Did I misspell it?
>> It's o, b, j.

[00:09:43]
>> O, b, j. Thank you. Obj-proxy, so it will match with this one first. And that's the one that it's going to use. And it will, instead of trying to require that CSS file, it's going to require this identity object proxy. And so that's what the Styles will be that identity object proxy.

[00:10:11] So any time I try to access anything off of that it's going to just return that thing as a string to me. And so with that, if I run my test again, We're gonna see our class. Yay. So if you're using CSS modules, which are really awesome, then this is how you kinda solve for that situation.

[00:10:35] And this is generally applicable as well. This module mapper concept is really useful when you're using loaders. You can have one of these for GraphQL and a whole bunch of stuff.