I’m writing tests for a node.js tool that I’m working on and hit a snag in trying to mock (i.e., simulate) a dynamic npm install of a module within a subdirectory. I tried a bunch of ideas and ended up with a simple, perhaps not ideal, but effective solution.
TL;DR: Pre-install all of the potentially used npm modules as devDependencies and then symlink the root’s node_modules folder within the subdirectory. In other words: root/subdir/node_modules -> root/node_modules.
A bit of context
The tool (a work in progress), called YA, is supposed to monitor a directory and download the necessary npm modules to help you achieve what you’re trying to do. For example, if you’re using SASS, the tool will try to install a Grunt plugin that helps you watch and compile your SASS files.
The test is supposed to do several things:
- Tell YA to monitor a sandbox/ folder within YA’s root folder
- Create a SASS file within sandbox/
- Tell YA to download what it needs to help process that SASS file
- YA should do an npm install of grunt-contrib-sass within sandbox/ (this is the problematic bit)
- YA should generate a Gruntfile.js file within sandbox/
- YA should then invoke a grunt task that will compile that SASS file into a CSS file within sandbox/
Step 4 is problematic for several reasons:
- We don’t want to delay the test suite to wait for the download to finish
- If npm is down, the test will fail
- I couldn’t find a way to dynamically/programatically npm install a module to a subdirectory
As a result, we should simulate/mock the install of that grunt-contrib-sass plugin.
Everything as a devDependency
I originally didn’t want grunt and all of the necessary/supported grunt plugins to be devDependencies for YA since the tool doesn’t actually need them for development. However, since you can’t dynamically npm install modules to a subdirectory, there didn’t seem to be another way. Also, it’s not a big deal since devDependencies aren’t downloaded for normal users (only developers).
Symlinks within the subdirectory
Now that the node_modules folder in YA’s root has all that we need to invoke grunt tasks during testing, we just need the sandbox/ folder to have access to the grunt plugins. You can use fs.symlink or fs.symlinkSync so that sandbox/node_modules is symbolically linked to YA’s node_modules folder.
Running grunt tasks within a subdirectory
The dynamic Gruntfile will exist within sandbox/, so we need grunt to not look at YA’s root but look at sandbox/Gruntfile.js. You can use the –gruntfile option to specify the directory that contains the gruntfile to use: grunt sass –gruntfile sandbox/.
Hope it helps.