I use Webpack in my app and I defined aliases in config:
webpack.config.dev.js:
....
resolve: {
// We can now require('file') instead of require('file.jsx')
extensions: ['', '.js', '.jsx', '.scss'],
alias: {
actions: PATHS.app + '/actions',
components: PATHS.app + '/components',
store: PATHS.app + '/store',
reducers: PATHS.app + '/reducers',
helpers: PATHS.app + '/helpers',
sagas: PATHS.app + '/sagas',
services: PATHS.app + '/services',
},
}
....
And I import modules like so:
componts/LoginPage.js
import {login} from 'actions/Login'
instead of
import {login} from '../actions/Login'
But AVA doesn't allow to define aliases, so I'm unable to test componts/LoginPage.js with AVA since it throws that error:
Error: Cannot find module 'actions/Login'
Is there a solution?
I'm not familiar with Webpack, but it's not something AVA itself should be concerned about. You're using Webpack to add non-standard functionality (aliasing) to require, so it's up to you, or rather Webpack to make it compatible. I guess you could compile your code using Webpack and test the compiled code. There are also Babel plugins you could use, like babel-plugin-webpack-loaders or babel-resolve-relative-module.
Can anyone with Webpack experience comment here?
We should really have a recipe for using Webpack with AVA.
// @istarkov
Yes babel-plugin-webpack-loader could be used to resolve such imports
Not sure it supports aliases (as I does not use aliases), but it supports modulesDirectories webpack directive.
All aliases in @apedyashev example could be changed on just one modulesDirectories entry.
modulesDirectories: [
PATHS.app,
]
Thank you, guys for your help. It seems to work with following configs:
config/webpack.config.ava.js
const path = require('path');
const PATHS = {
app: path.resolve(__dirname, '../src'),
};
module.exports = {
resolve: {
modulesDirectories: [
__dirname,
'node_modules',
PATHS.app,
]
},
module: {
loaders: [
{
test: /\.css$/,
loader: 'style-loader!css-loader?modules&importLoaders=1!postcss-loader',
},
]
}
};
package.json
{
....
"scripts": {
"test": "CONFIG=$(pwd)/config/webpack.config.ava.js BABEL_DISABLE_CACHE=1 NODE_ENV=AVA ava"
},
....
"ava": {
"files": [
"src/**/*.spec.js"
],
"require": [
"babel-register"
],
"babel": "inherit"
}
}
.babelrc
{
"presets": ["es2015", "react", "stage-1", "stage-0"],
"env": {
"AVA": {
"plugins": [
[
"babel-plugin-webpack-loaders",
{
"config": "${CONFIG}",
"verbose": false
}
]
]
}
}
}
Tnx @apedyashev !! This should be in a recipe!
I put together a slightly different approach to this problem https://github.com/greyepoxy/webpack-ava-recipe. Where I use webpack as a pre-compile step for my tests before feeding them to Ava.
Curious what people think, is it better/worse then @apedyashev 's approach? Happy to put a recipe together if people think it is useful.
Btw, I have another solution of my problem (without using webpack):
env NODE_PATH=src ava
I implemented what I think is the easiest and cleanest approach without any pre-compile step as webpack-loaders seems like a dirty hack to begin with that didn't even work for me outside of using null transformer/loader for webpack. I use node-hook-filename to handle specific extensions and compile my pug files into functions as if it were handled by webpack. The scss files are inconsequential to testing, so I let it return the default, which is just a path.
import { join, dirname } from 'path';
import nhf from 'node-hook-filename';
import pug from 'pug';
nhf(['.scss']);
nhf(['.pug'], (path, parent) => pug.compileFile(join(dirname(parent.id), path)));
Most helpful comment
Thank you, guys for your help. It seems to work with following configs:
config/webpack.config.ava.js
package.json
.babelrc