PR Context and Goal0:00
Today, I'm working on filling in some missing tests for a recent PR that was merged. So I'm working on the Laravel Mix repo, and this PR from Sebastian ensures that when we're building up a webpack configuration file, if we have postCSS plugins, the auto-prefixer plugin needs to always occur last, no matter what. And we weren't doing that before. So we can see his patch here, and you know what? If you want to follow along for the video, you don't even need to know any of this. But for the quick 20-second explanation, we start by getting the default postCSS plugins that Mix provides. And then we check to see, well, did the user specify their own postCSS plugins?
Locating Missing Test0:56
But there's no test to confirm that. And then further, six months from now, if I do some refactoring, I may not exactly remember, okay, why are we doing it in this way? But if I make a change and I had a test that actually failed, I could visit that test and see, oh, okay, that's why this was done. Okay? So let's fill in that missing test so that I can tag this next release of Mix. So I'm going to open up the sidebar. And within my test directory here, the test for the webpack configuration builder. Okay?
Creating New Test Case1:22
And within my test directory here, the test for the webpack configuration builder. Okay? So if I were to run this, everything should return green at the moment. Okay. So I'm going to add a new one down here. We'll say test auto-prefixer should always be applied after all other post-CSS plugins. Yeah, I think that should do it. Okay. So how can we do this? Well, let's start by simulating or setting up a webpack.mix.js file.
So how can we do this? Well, let's start by simulating or setting up a webpack.mix.js file. So I could say, well, we're going to compile down Sass to the public css directory. But then let's imagine the user does want to apply a postCSS plugin after it. So I could say, I'm sorry, options and then postCSS. And this can be an array of plugins that you want to apply. So in effect, we'd say compile down Sass. And then after that, we want to run that compiled file through any postCSS plugins that I have here. And each of those files can manipulate the stylesheet however it needs to.
And that's a shame because it's really not a dev dependency. It's just a dependency we're pulling in because ultimately what's returned from this require, I need that to be in the proper format so that I can inspect it. Now what we could do is build up our own fake that takes the exact same shape. And then we could use our fake instead of requiring something like this. And that would be, I'd say, the proper way to go. But it would involve me figuring out the proper way to export a postCSS plugin. I doubt that's very difficult, but I just, I don't want to worry about it right now. So I will stick with this for the time being. So now that we have our mix file set up, let's build it up.
Building Webpack Config3:27
So I will stick with this for the time being. So now that we have our mix file set up, let's build it up. So I can say new WebpackConfig(). So using the mix file, the API that we've provided for you, I now want to build up my Webpack configuration. And then ultimately, of course, that config is what gets passed to Webpack. And that's what Webpack uses to compile everything down. Okay. So I could say let webpackConfig = ... and then let's just console.log() this so that you can take a look.
This is a tough test to write, and I'll tell you why. We're going to go to the code where the PR was applied. So this is what that PR changed. So I'll show you. In Safari, he added these lines of code right here. Okay. So we build up the PostCSS plugins, and then that just gets passed to a Webpack loader. And that gets tricky because I want to test against the structure here. But yeah, what I'm going to have to do is just fetch that corresponding rule out and inspect it.
Finding PostCSS Plugins5:15
So instead, I'm going to take the approach of just filtering down this object, finding the rules we need, and inspecting it. Okay. So if we come back, yeah, to start, let's say it's going to be one of these rules. So let's say WebpackConfig.Module.Rules. So let's say that Module.Rules, and we're going to do this a few times to track it down. Okay. So here's our rules. But the PostCSS loader that we apply is actually going to be part of our Sass call here. So it's going to be one of these object loaders.
But the PostCSS loader that we apply is actually going to be part of our Sass call here. So it's going to be one of these object loaders. So if I want to find this specific object, why don't we just say, well, find me the object where the test is equal to our sass.scss file. So we could say, find me the first one where the rule.test equals this string. Okay. So let's run that again. There we go. Okay. Next, we want to say .use, and then once again, so let's say .use, and then find me the loader.
Okay. Next, we want to say .use, and then once again, so let's say .use, and then find me the PostCSS loader options. So once again, find me the object where the loader name is PostCSS loader. And run it again. Yep. Kind of gross, right? But that's okay. The most important thing is get this under test. And then later, if you want to refactor, that's okay.
The most important thing is get this under test. And then later, if you want to refactor, that's okay. But the core thing is we want to make sure that if we change production code incorrectly, this test is going to fail and let you know. Okay. So now we have our PostCSS loader, and we can inspect the plugins here. So let's say options.plugins. Run it again. And there we go. So this first one will presumably be PostCSS custom properties, and the second one will
Failing Test via Revert7:02
And there we go. So this first one will presumably be PostCSS custom properties, and the second one will be auto-prefixer. But now at the moment, I'd like to start with a failing test. So if we go to Webpack rules, we can see we already have the code that we merged in, even though it wasn't under test. So what I sometimes do, even temporarily, is I will revert the code, write the test, I will see it fail, and then I will undo the revert. So I will revert the revert, and then see, okay, is the test now passing as a result of that.
So I will revert the revert, and then see, okay, is the test now passing as a result of that. So let's give that a shot here. We'll say git revert. Okay. So now we can see it's back to how it was before, and now we can write the test here. So once again, this is what we currently have, but I really just want to know the name of the PostCSS plugin. So let's inspect information about the creator. So let's get the very first one, and you can see here we can reference it as a function.
So let's inspect information about the creator. So let's get the very first one, and you can see here we can reference it as a function. So we're just going to call that and try it again, and there you go. All that work just to figure out the name of the PostCSS plugin. So now that should give me auto-prefixer, and then the next one should give me PostCSS custom properties. Okay. So with that in mind, why don't we now just say plugins.map, and then we'll say plugin.PostCSSPlugin. Yeah, because ultimately I just want an array of all the PostCSS plugins we're using. So I could say plugins, and then update that, try it again, and we should now have an array.
Yeah, because ultimately I just want an array of all the PostCSS plugins we're using. So I could say plugins, and then update that, try it again, and we should now have an array there. And yeah, immediately you can see that the code before that PR was wrong, because it applied autoPrefixer first. And we've already concluded that it always needs to be the final thing that takes place. So let's say our assertion is that the array for plugins should equal PostCSS customProperties. That enables native variables, essentially. You can use the native variable syntax. I don't know why you'd do that with Sass, but it's just a random PostCSS plugin there.
Restoring PR and Refactoring9:51
It must not have finished. Okay. So let's just say, git checkout, what we had before. All right. So now, if we come back to code, into Webpack rules, yeah, we have the PR that we merged back. So now at this point, if we give our test another run, it works. So we did fill in our missing test. And if we ever change anything, like for example we think, well that was already up here, we don't need this, or something like that, no.
And if we ever change anything, like for example we think, well that was already up here, we don't need this, or something like that, no. Now we have a test that will let us know immediately something ain't right. So I can bring that back. So now at this point, we could do any refactoring that might be necessary. For example, the only place we use this variable is down here. So that can be a little confusing. What if instead we just trigger a closure here where we figure it out? So let's see if I can grab all of that and just nest it within there. And then ultimately, we would return this.
So let's see if I can grab all of that and just nest it within there. And then ultimately, we would return this. All right. Let's run that test again. Okay. It is returning green, which means that's a fine refactor. And sometimes I just disable this to make sure. Yeah. Okay. So let's bring that back.
