├── .gitignore ├── .travis.yml ├── .npmignore ├── lib ├── cacheize.js ├── stringOrArray.js ├── dirHas.js ├── webpackInfo.js └── preprocessor.js ├── test ├── lib │ └── expect.js ├── stringOrArray.test.js ├── fixture │ ├── webpackInfo │ │ ├── profile-missing-resolve-root.js │ │ ├── no-profile.js │ │ ├── profile-not-array.js │ │ ├── profile-not-found.js │ │ ├── alt-config-location.js │ │ ├── profile-not-specified.js │ │ └── es6-default-exports.js │ ├── basic.js │ └── setup.js ├── dirHas.test.js ├── webpackInfo.test.js └── preprocessor.test.js ├── AUTHORS ├── LICENSE ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | /.coveralls.yml 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '4.2' 4 | script: npm run-script coverage 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .npmignore 3 | node_modules 4 | /.coveralls.yml 5 | /.travis.yml 6 | /test 7 | -------------------------------------------------------------------------------- /lib/cacheize.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function(dirList) { 3 | var dirTree = {}; 4 | dirList.forEach(function(dir) { dirTree[dir] = true; }); 5 | return dirTree; 6 | }; 7 | -------------------------------------------------------------------------------- /test/lib/expect.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | var chai = require('chai'); 3 | 4 | chai.config.includeStack = true; 5 | chai.config.showDiff = false; 6 | chai.use(require('sinon-chai')); 7 | 8 | module.exports = chai.expect; 9 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Michael Olson 2 | Adil Fulara 3 | Desmond Brand 4 | Ishi Ruy 5 | Richard Fung 6 | Andrew Meredith 7 | Gustav Ahlberg 8 | -------------------------------------------------------------------------------- /lib/stringOrArray.js: -------------------------------------------------------------------------------- 1 | function stringOrArray(thing) { 2 | if (thing === undefined || thing === null) { 3 | return thing; 4 | } else if (Array.isArray(thing)) { 5 | return thing; 6 | } else { 7 | return [thing]; 8 | } 9 | } 10 | 11 | module.exports = stringOrArray; 12 | -------------------------------------------------------------------------------- /lib/dirHas.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | var cacheize = require('./cacheize'); 3 | var fs = require('fs'); 4 | var has = _.has; 5 | 6 | var cache = {}; 7 | 8 | function readdir(dirname) { 9 | if (has(cache, dirname)) { 10 | return cache[dirname]; 11 | } else { 12 | var dirList; 13 | try { dirList = fs.readdirSync(dirname); } catch(e) { dirList = []; } 14 | var dirTree = cache[dirname] = cacheize(dirList); 15 | return dirTree; 16 | } 17 | } 18 | 19 | module.exports = function(dir, entry) { 20 | return has(readdir(dir), entry); 21 | }; 22 | -------------------------------------------------------------------------------- /test/stringOrArray.test.js: -------------------------------------------------------------------------------- 1 | var expect = require('./lib/expect'); 2 | 3 | describe('stringOrArray', function() { 4 | var stringOrArray = require('../lib/stringOrArray'); 5 | 6 | it('given an array, returns the array', function() { 7 | var input = ['arr']; 8 | expect(stringOrArray(input)).to.eq(input); 9 | }); 10 | 11 | it('given a string, returns an array containing that string', function() { 12 | var input = 'aString'; 13 | expect(stringOrArray(input)).to.deep.equal([input]); 14 | }); 15 | 16 | it('given undefined, returns undefined', function() { 17 | var input = undefined; 18 | expect(stringOrArray(input)).to.be.undefined; 19 | }); 20 | 21 | it('given null, returns null', function() { 22 | var input = null; 23 | expect(stringOrArray(input)).to.be.null; 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/fixture/webpackInfo/profile-missing-resolve-root.js: -------------------------------------------------------------------------------- 1 | var Setup = require('../setup'); 2 | var fixture = new Setup(); 3 | 4 | fixture.readdir = { 5 | '/top': ['node_modules', 'package.json', 'src', 'test', 'webpack'], 6 | '/top/test': ['file1.test.js'], 7 | '/top/src': ['dir1'], 8 | '/top/src/dir1': ['lib1a.js'], 9 | '/top/webpack': ['dev.config.js'] 10 | }; 11 | 12 | var webpackProfile = fixture.webpackProfile = 'dev'; 13 | 14 | var webpackSettings = fixture.webpackSettings = [ 15 | { 16 | name: webpackProfile 17 | } 18 | ]; 19 | 20 | fixture.requireContents = { 21 | '/top/webpack/dev.config.js': webpackSettings 22 | }; 23 | 24 | fixture.readFile = { 25 | '/top/package.json': JSON.stringify({ 26 | 'jest-webpack-alias': { 27 | configFile: 'webpack/dev.config.js', 28 | profile: webpackProfile 29 | } 30 | }) 31 | }; 32 | 33 | module.exports = fixture.getExports(); 34 | -------------------------------------------------------------------------------- /test/fixture/webpackInfo/no-profile.js: -------------------------------------------------------------------------------- 1 | var Setup = require('../setup'); 2 | var fixture = new Setup(); 3 | 4 | fixture.readdir = { 5 | '/top': ['node_modules', 'package.json', 'src', 'test', 'webpack'], 6 | '/top/test': ['file1.test.js'], 7 | '/top/src': ['dir1'], 8 | '/top/src/dir1': ['lib1a.js'], 9 | '/top/webpack': ['dev.config.js'] 10 | }; 11 | 12 | var webpackProfile = fixture.webpackProfile = null; 13 | 14 | var webpackSettings = fixture.webpackSettings = { 15 | resolve: { 16 | modules: ['/top/src', '/top/bogus_dir'], 17 | extensions: ["", ".js", ".jsx"], 18 | // omitted: fallback 19 | alias: { 20 | aliasNodeSubdir1Src: 'node1', 21 | aliasNodeSubdir2Src: 'node1/lib/submodule', 22 | aliasNodeFileSrc: 'aliasNodeFileDest', 23 | aliasPlainSubdirSrc: 'dir1/lib1a' 24 | } 25 | } 26 | }; 27 | 28 | fixture.requireContents = { 29 | '/top/webpack/dev.config.js': webpackSettings 30 | }; 31 | 32 | fixture.readFile = { 33 | '/top/package.json': JSON.stringify({ 34 | 'jest-webpack-alias': { 35 | configFile: 'webpack/dev.config.js', 36 | profile: webpackProfile 37 | } 38 | }) 39 | }; 40 | 41 | module.exports = fixture.getExports(); 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2016 Michael Olson 4 | Copyright (c) 2015 Ticketmaster® & Live Nation Entertainment® 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /test/fixture/webpackInfo/profile-not-array.js: -------------------------------------------------------------------------------- 1 | var Setup = require('../setup'); 2 | var fixture = new Setup(); 3 | 4 | fixture.readdir = { 5 | '/top': ['node_modules', 'package.json', 'src', 'test', 'webpack'], 6 | '/top/test': ['file1.test.js'], 7 | '/top/src': ['dir1'], 8 | '/top/src/dir1': ['lib1a.js'], 9 | '/top/webpack': ['dev.config.js'] 10 | }; 11 | 12 | var webpackProfile = fixture.webpackProfile = 'dev'; 13 | 14 | var webpackSettings = fixture.webpackSettings = { 15 | name: webpackProfile, 16 | resolve: { 17 | modules: ['/top/src', '/top/bogus_dir'], 18 | extensions: ["", ".js", ".jsx"], 19 | // omitted: fallback 20 | alias: { 21 | aliasNodeSubdir1Src: 'node1', 22 | aliasNodeSubdir2Src: 'node1/lib/submodule', 23 | aliasNodeFileSrc: 'aliasNodeFileDest', 24 | aliasPlainSubdirSrc: 'dir1/lib1a' 25 | } 26 | } 27 | }; 28 | 29 | fixture.requireContents = { 30 | '/top/webpack/dev.config.js': webpackSettings 31 | }; 32 | 33 | fixture.readFile = { 34 | '/top/package.json': JSON.stringify({ 35 | 'jest-webpack-alias': { 36 | configFile: 'webpack/dev.config.js', 37 | profile: webpackProfile 38 | } 39 | }) 40 | }; 41 | 42 | module.exports = fixture.getExports(); 43 | -------------------------------------------------------------------------------- /test/fixture/webpackInfo/profile-not-found.js: -------------------------------------------------------------------------------- 1 | var Setup = require('../setup'); 2 | var fixture = new Setup(); 3 | 4 | fixture.readdir = { 5 | '/top': ['node_modules', 'package.json', 'src', 'test', 'webpack'], 6 | '/top/test': ['file1.test.js'], 7 | '/top/src': ['dir1'], 8 | '/top/src/dir1': ['lib1a.js'], 9 | '/top/webpack': ['dev.config.js'] 10 | }; 11 | 12 | var webpackProfile = fixture.webpackProfile = 'dev'; 13 | 14 | var webpackSettings = fixture.webpackSettings = [ 15 | { 16 | name: 'notFound', 17 | resolve: { 18 | modules: ['/top/src', '/top/bogus_dir'], 19 | extensions: ["", ".js", ".jsx"], 20 | // omitted: fallback 21 | alias: { 22 | aliasNodeSubdir1Src: 'node1', 23 | aliasNodeSubdir2Src: 'node1/lib/submodule', 24 | aliasNodeFileSrc: 'aliasNodeFileDest', 25 | aliasPlainSubdirSrc: 'dir1/lib1a' 26 | } 27 | } 28 | } 29 | ]; 30 | 31 | fixture.requireContents = { 32 | '/top/webpack/dev.config.js': webpackSettings 33 | }; 34 | 35 | fixture.readFile = { 36 | '/top/package.json': JSON.stringify({ 37 | 'jest-webpack-alias': { 38 | configFile: 'webpack/dev.config.js', 39 | profile: webpackProfile 40 | } 41 | }) 42 | }; 43 | 44 | module.exports = fixture.getExports(); 45 | -------------------------------------------------------------------------------- /test/fixture/webpackInfo/alt-config-location.js: -------------------------------------------------------------------------------- 1 | var Setup = require('../setup'); 2 | var fixture = new Setup(); 3 | 4 | fixture.readdir = { 5 | '/top': ['node_modules', 'package.json', 'src', 'test', 'webpack'], 6 | '/top/test': ['file1.test.js'], 7 | '/top/src': ['dir1'], 8 | '/top/src/dir1': ['lib1a.js'], 9 | '/top/webpack': ['dev.config.js'] 10 | }; 11 | 12 | var webpackProfile = fixture.webpackProfile = 'dev'; 13 | 14 | var webpackSettings = fixture.webpackSettings = [ 15 | { 16 | name: webpackProfile, 17 | resolve: { 18 | modules: ['/top/src', '/top/bogus_dir'], 19 | extensions: ["", ".js", ".jsx"], 20 | // omitted: fallback 21 | alias: { 22 | aliasNodeSubdir1Src: 'node1', 23 | aliasNodeSubdir2Src: 'node1/lib/submodule', 24 | aliasNodeFileSrc: 'aliasNodeFileDest', 25 | aliasPlainSubdirSrc: 'dir1/lib1a' 26 | } 27 | } 28 | } 29 | ]; 30 | 31 | fixture.requireContents = { 32 | '/top/webpack/dev.config.js': webpackSettings 33 | }; 34 | 35 | fixture.readFile = { 36 | '/top/package.json': JSON.stringify({ 37 | 'jest-webpack-alias': { 38 | configFile: 'webpack/dev.config.js', 39 | profile: webpackProfile 40 | } 41 | }) 42 | }; 43 | 44 | module.exports = fixture.getExports(); 45 | -------------------------------------------------------------------------------- /test/fixture/webpackInfo/profile-not-specified.js: -------------------------------------------------------------------------------- 1 | var Setup = require('../setup'); 2 | var fixture = new Setup(); 3 | 4 | fixture.readdir = { 5 | '/top': ['node_modules', 'package.json', 'src', 'test', 'webpack'], 6 | '/top/test': ['file1.test.js'], 7 | '/top/src': ['dir1'], 8 | '/top/src/dir1': ['lib1a.js'], 9 | '/top/webpack': ['dev.config.js'] 10 | }; 11 | 12 | var webpackProfile = fixture.webpackProfile = null; 13 | 14 | var webpackSettings = fixture.webpackSettings = [ 15 | { 16 | name: webpackProfile, 17 | resolve: { 18 | modules: ['/top/src', '/top/bogus_dir'], 19 | extensions: ["", ".js", ".jsx"], 20 | // omitted: fallback 21 | alias: { 22 | aliasNodeSubdir1Src: 'node1', 23 | aliasNodeSubdir2Src: 'node1/lib/submodule', 24 | aliasNodeFileSrc: 'aliasNodeFileDest', 25 | aliasPlainSubdirSrc: 'dir1/lib1a' 26 | } 27 | } 28 | } 29 | ]; 30 | 31 | fixture.requireContents = { 32 | '/top/webpack/dev.config.js': webpackSettings 33 | }; 34 | 35 | fixture.readFile = { 36 | '/top/package.json': JSON.stringify({ 37 | 'jest-webpack-alias': { 38 | configFile: 'webpack/dev.config.js', 39 | profile: webpackProfile 40 | } 41 | }) 42 | }; 43 | 44 | module.exports = fixture.getExports(); 45 | -------------------------------------------------------------------------------- /test/fixture/webpackInfo/es6-default-exports.js: -------------------------------------------------------------------------------- 1 | var Setup = require('../setup'); 2 | var fixture = new Setup(); 3 | 4 | fixture.readdir = { 5 | '/top': ['node_modules', 'package.json', 'src', 'test', 'webpack'], 6 | '/top/test': ['file1.test.js'], 7 | '/top/src': ['dir1'], 8 | '/top/src/dir1': ['lib1a.js'], 9 | '/top/webpack': ['dev.config.js'] 10 | }; 11 | 12 | var webpackProfile = fixture.webpackProfile = 'dev'; 13 | 14 | var webpackSettings = fixture.webpackSettings = [ 15 | { 16 | name: webpackProfile, 17 | resolve: { 18 | modules: ['/top/src', '/top/bogus_dir'], 19 | extensions: ["", ".js", ".jsx"], 20 | // omitted: fallback 21 | alias: { 22 | aliasNodeSubdir1Src: 'node1', 23 | aliasNodeSubdir2Src: 'node1/lib/submodule', 24 | aliasNodeFileSrc: 'aliasNodeFileDest', 25 | aliasPlainSubdirSrc: 'dir1/lib1a' 26 | } 27 | } 28 | } 29 | ]; 30 | 31 | fixture.requireContents = { 32 | '/top/webpack/dev.config.js': { 33 | __esModule: true, 34 | 'default': webpackSettings 35 | } 36 | }; 37 | 38 | fixture.readFile = { 39 | '/top/package.json': JSON.stringify({ 40 | 'jest-webpack-alias': { 41 | configFile: 'webpack/dev.config.js', 42 | profile: webpackProfile 43 | } 44 | }) 45 | }; 46 | 47 | module.exports = fixture.getExports(); 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jest-webpack-alias", 3 | "version": "3.3.4", 4 | "description": "Preprocessor for Jest that is able to resolve require() statements using webpack aliases.", 5 | "main": "lib/preprocessor.js", 6 | "scripts": { 7 | "test": "mocha --reporter tap test", 8 | "coverage": "mocha test --require blanket -R mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js" 9 | }, 10 | "config": { 11 | "blanket": { 12 | "pattern": [ 13 | "lib" 14 | ], 15 | "data-cover-never": [ 16 | "node_modules", 17 | "test" 18 | ] 19 | } 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/mwolson/jest-webpack-alias.git" 24 | }, 25 | "author": "Michael Olson ", 26 | "license": "MIT", 27 | "keywords": [ 28 | "jest", 29 | "webpack", 30 | "require", 31 | "resolve", 32 | "alias" 33 | ], 34 | "dependencies": { 35 | "lodash": "^4.17.15", 36 | "pkginfo": "^0.3.0", 37 | "transform-jest-deps": "^2.2.2", 38 | "unwin": "^1.0.1" 39 | }, 40 | "devDependencies": { 41 | "blanket": "^1.2.1", 42 | "chai": "^3.2.0", 43 | "coveralls": "^3.0.7", 44 | "mocha": "^6.2.2", 45 | "mocha-lcov-reporter": "^1.0.0", 46 | "rewire": "^2.3.4", 47 | "sinon": "^1.16.1", 48 | "sinon-chai": "^2.8.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/dirHas.test.js: -------------------------------------------------------------------------------- 1 | var expect = require('./lib/expect'); 2 | var basicFixture = require('./fixture/basic'); 3 | var cacheize = require('../lib/cacheize'); 4 | 5 | describe('dirHas lib', function() { 6 | var cache, dirHas, fs, readdir; 7 | 8 | function setup() { 9 | var setup = basicFixture.getDirHas(); 10 | cache = setup.cache; 11 | dirHas = setup.dirHas; 12 | fs = setup.fs; 13 | readdir = setup.readdir; 14 | } 15 | 16 | beforeEach(setup); 17 | 18 | describe('with file hit in first dir', function() { 19 | it('resolves to first dir with caching', function() { 20 | var firstDir = '/top/src'; 21 | var output = dirHas(firstDir, 'dir1'); 22 | 23 | expect(fs.readdirSync).to.be.calledOnce; 24 | expect(fs.readdirSync.args[0][0]).to.eq('/top/src'); 25 | expect(cache[firstDir]).to.eql(cacheize(readdir[firstDir])); 26 | expect(output).to.be.ok; 27 | }); 28 | }); 29 | 30 | describe('with nonexistent directory', function() { 31 | it('returns false without throwing error', function() { 32 | var firstDir = '/top/src/bogus/directory'; 33 | var output = dirHas(firstDir, 'dir1'); 34 | 35 | expect(fs.readdirSync).to.be.calledOnce; 36 | expect(fs.readdirSync.args[0][0]).to.eq('/top/src/bogus/directory'); 37 | expect(cache[firstDir]).to.eql(cacheize([])); 38 | expect(output).to.not.be.ok; 39 | }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /lib/webpackInfo.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | var path = require('path'); 3 | var pkginfo = require('pkginfo'); 4 | 5 | function genProfileError(profile, rest) { 6 | return 'Specified jest-webpack-alias.webpackProfile = "' + profile + '", but ' + rest; 7 | } 8 | 9 | function extractES6DefaultExportsObject(inExports) { 10 | return typeof _.get(inExports, 'default') === 'object' ? inExports.default : inExports; 11 | } 12 | 13 | function read(pmodule, dir) { 14 | var packageJson = pkginfo.read(pmodule, dir); 15 | var pkgJsonFile = packageJson.dir; // misleading name from pkginfo library 16 | var pkgJsonDir = path.dirname(pkgJsonFile); 17 | 18 | var profile = _.get(packageJson['package'], 'jest-webpack-alias.profile'); 19 | var configFile = _.get(packageJson['package'], 'jest-webpack-alias.configFile', 'webpack.config.js'); 20 | var webpackFile = path.join(pkgJsonDir, configFile); 21 | var webpackSettings = extractES6DefaultExportsObject(require(webpackFile)); 22 | 23 | if (profile) { 24 | if (!_.isArray(webpackSettings)) { 25 | throw new Error(genProfileError(profile, webpackFile + ' does not export an array')); 26 | } 27 | webpackSettings = _.find(webpackSettings, ['name', profile]); 28 | if (!webpackSettings) { 29 | throw new Error(genProfileError(profile, webpackFile + ' does not contain this profile')); 30 | } 31 | } else { 32 | if (_.isArray(webpackSettings)) { 33 | throw new Error('jest-webpack-alias.webpackProfile not specified, but ' + webpackFile + ' exports an array'); 34 | } 35 | } 36 | 37 | if (!_.get(webpackSettings, 'resolve.modules') && !_.get(webpackSettings, 'resolve.root')) { 38 | throw new Error('Missing setting "resolve.modules" (webpack v2) or "resolve.root" (webpack v1) in ' + webpackFile); 39 | } 40 | 41 | return { 42 | config: webpackSettings, 43 | file: webpackFile 44 | }; 45 | } 46 | 47 | exports.read = read; 48 | -------------------------------------------------------------------------------- /test/fixture/basic.js: -------------------------------------------------------------------------------- 1 | var Setup = require('./setup'); 2 | var fixture = new Setup(); 3 | 4 | fixture.readdir = { 5 | '/top': ['node_modules', 'package.json', 'src', 'test', 'web_modules', 'webpack.config.js'], 6 | '/top/node_modules': ['aliasNodeFileDest.js', 'node1', 'node2'], 7 | '/top/node_modules/node1': ['lib'], 8 | '/top/node_modules/node1/lib': ['submodule.js'], 9 | '/top/web_modules': ['web1', 'web2.jsx'], 10 | '/top/src': ['aliasRelative.js', 'dir1', 'dir2'], 11 | '/top/src/dir1': ['lib1a.js', 'lib1b-2b.js', 'dir1-1'], 12 | '/top/src/dir1/dir1-1': ['lib1-1a.js'], 13 | '/top/src/dir2': ['lib2a.js', 'lib1b-2b.js'], 14 | '/top/src/dir3': ['dir3-1'], 15 | '/top/src/dir3/dir3-1': ['mocked.js'], 16 | '/top/test': ['file1.test.js', 'file2.test.js', '__mocks__'], 17 | '/top/test/__mocks__': ['dir3'], 18 | '/top/test/__mocks__/dir3': ['dir3-1'], 19 | '/top/test/__mocks__/dir3/dir3-1': ['mocked.js'] 20 | }; 21 | 22 | var webpackProfile = fixture.webpackProfile = 'dev'; 23 | 24 | var webpackSettings = fixture.webpackSettings = [ 25 | { 26 | name: 'wrongProfile' 27 | }, 28 | { 29 | otherField: 'nope' 30 | }, 31 | { 32 | name: webpackProfile, 33 | resolve: { 34 | modules: ['/top/test/__mocks__', '/top/src', '/top/bogus_dir', 'node_modules', 'web_modules'], 35 | extensions: ["", ".js", ".jsx"], 36 | // omitted: fallback 37 | alias: { 38 | aliasNodeSubdir1Src: 'node1', 39 | aliasNodeSubdir2Src: 'node1/lib/submodule', 40 | aliasNodeFileSrc: 'aliasNodeFileDest', 41 | aliasPlainSubdirSrc: 'dir1/lib1a', 42 | aliasAbsoluteSubdirSrc: '/top/src/dir1', 43 | aliasAbsoluteFileSrc: '/top/src/dir1/lib1a', 44 | aliasSubRelative: 'dir1/dir1-1', 45 | } 46 | } 47 | } 48 | ]; 49 | 50 | fixture.requireContents = { 51 | '/top/webpack.config.js': webpackSettings 52 | }; 53 | 54 | fixture.readFile = { 55 | '/top/package.json': JSON.stringify({ 56 | 'jest-webpack-alias': { 57 | profile: webpackProfile 58 | } 59 | }) 60 | }; 61 | 62 | module.exports = fixture.getExports(); 63 | -------------------------------------------------------------------------------- /test/fixture/setup.js: -------------------------------------------------------------------------------- 1 | var rewire = require('rewire'); 2 | var sinon = require('sinon'); 3 | var unwin = require('unwin'); 4 | 5 | function Setup() {} 6 | 7 | Setup.prototype.getDirHas = function getDirHas() { 8 | var dirHas = rewire('../../lib/dirHas'); 9 | 10 | var fs = { 11 | readdirSync: sinon.spy(function(inPath) { 12 | inPath = unwin(inPath); 13 | var dirList = this.readdir[inPath]; 14 | if (!dirList) { 15 | throw new Error('unmocked readdirSync for path ' + inPath); 16 | } 17 | return dirList; 18 | }.bind(this)) 19 | }; 20 | dirHas.__set__('fs', fs); 21 | 22 | return { 23 | cache: dirHas.__get__('cache'), 24 | dirHas: dirHas, 25 | fs: fs, 26 | readdir: this.readdir 27 | }; 28 | }; 29 | 30 | Setup.prototype.getWebpackInfo = function getWebpackInfo() { 31 | var webpackInfo = rewire('../../lib/webpackInfo'); 32 | 33 | var fakeRequire = sinon.spy(function(inPath) { 34 | return this.requireContents[unwin(inPath)] || require(inPath); 35 | }.bind(this)); 36 | webpackInfo.__set__('require', fakeRequire); 37 | 38 | var pkginfo = { 39 | read: sinon.spy(function(pmodule, dir) { 40 | return { 41 | dir: '/top/package.json', // misleading key name. lame. 42 | 'package': JSON.parse(this.readFile['/top/package.json']) 43 | }; 44 | }.bind(this)) 45 | }; 46 | webpackInfo.__set__('pkginfo', pkginfo); 47 | 48 | return { 49 | pkginfo: pkginfo, 50 | readFile: this.readFile, 51 | require: fakeRequire, 52 | requireContents: this.requireContents, 53 | webpackInfo: webpackInfo, 54 | webpackProfile: this.webpackProfile 55 | }; 56 | }; 57 | 58 | Setup.prototype.getWebpackAlias = function getWebpackAlias() { 59 | var webpackAlias = rewire('../../lib/preprocessor'); 60 | 61 | var fs = { 62 | existsSync: sinon.spy(function(inPath) { 63 | return !!this.readdir[unwin(inPath)]; 64 | }.bind(this)) 65 | }; 66 | webpackAlias.__set__('fs', fs); 67 | 68 | var setup = this.getDirHas(); 69 | var dirHas = sinon.spy(setup.dirHas); 70 | webpackAlias.__set__('dirHas', dirHas); 71 | 72 | setup = this.getWebpackInfo(); 73 | var webpackInfo = setup.webpackInfo; 74 | webpackInfo.read = sinon.spy(webpackInfo.read); 75 | webpackAlias.__set__('webpackInfo', webpackInfo); 76 | 77 | return { 78 | dirHas: dirHas, 79 | fs: fs, 80 | webpackAlias: webpackAlias, 81 | webpackInfo: webpackInfo 82 | }; 83 | }; 84 | 85 | Setup.prototype.getExports = function getExports() { 86 | return { 87 | getDirHas: this.getDirHas.bind(this), 88 | getWebpackAlias: this.getWebpackAlias.bind(this), 89 | getWebpackInfo: this.getWebpackInfo.bind(this) 90 | }; 91 | }; 92 | 93 | module.exports = Setup; 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jest-webpack-alias 2 | 3 | [![Build Status][travis-image]][travis-url] 4 | [![Coverage Status][coveralls-image]][coveralls-url] 5 | [![NPM][npm-image]][npm-url] 6 | 7 | Preprocessor for Jest that is able to resolve `require()` statements using webpack aliases. 8 | 9 | > :warning: 10 | > 11 | > **Consider using [babel-plugin-module-resolver](https://github.com/tleunen/babel-plugin-module-resolver) for new projects instead of `jest-webpack-alias`. An example setup can be seen at [the Next.js repo](https://github.com/zeit/next.js).** 12 | 13 | ## Install 14 | 15 | ```sh 16 | npm install --save-dev jest-webpack-alias 17 | ``` 18 | 19 | ## Setup 20 | 21 | File `__tests__/preprocessor.js`: 22 | 23 | ```js 24 | var babelJest = require('babel-jest'); 25 | require('babel-register'); // support ES6 'import' statements 26 | var webpackAlias = require('jest-webpack-alias'); 27 | 28 | module.exports = { 29 | process: function(src, filename) { 30 | if (filename.indexOf('node_modules') === -1) { 31 | src = babelJest.process(src, filename); 32 | src = webpackAlias.process(src, filename); 33 | } 34 | return src; 35 | } 36 | }; 37 | ``` 38 | 39 | File `package.json`: 40 | 41 | ``` 42 | { 43 | ... 44 | "jest": { 45 | ... 46 | "scriptPreprocessor": "/__tests__/preprocessor.js", 47 | }, 48 | "jest-webpack-alias": { 49 | "profile": "dev" 50 | } 51 | } 52 | ``` 53 | 54 | ## Common problems 55 | 56 | ### Importing CSS and SCSS files 57 | 58 | In order to use statements like `require('some-styles.css')` in a testing environment, it's best to use an npm module like [ignore-styles](https://www.npmjs.com/package/ignore-styles) to ignore files that match certain file extensions in `require()` statements. 59 | 60 | ### Manual package resolution 61 | 62 | Code like this will not work, because an AST parser is not smart enough to evaluate variables into strings. 63 | 64 | ```js 65 | var moduleName = 'myModName'; 66 | var computed = require(moduleName); 67 | ``` 68 | 69 | It can be rewritten like this, using the `resolve` function: 70 | 71 | ```js 72 | var resolve = require('jest-webpack-alias').resolve; 73 | var moduleName = 'myModName'; 74 | var computed = require(resolve(moduleName, __filename)); 75 | ``` 76 | 77 | ## Non-javascript package resolution. 78 | 79 | Code like this will fail, because it is resolved by webpack loader. 80 | 81 | File: `main.js` 82 | ```js 83 | require('./style.css'); 84 | ... 85 | ``` 86 | 87 | File: `__tests__/main.js` 88 | ```js 89 | jest.dontMock('../main.js'); 90 | require('../main.js'); 91 | ... 92 | ``` 93 | 94 | The workaround for this is to use [Manual Mocks](https://github.com/facebook/jest/blob/master/docs/ManualMocks.md). 95 | 96 | #### Example 97 | 98 | Project structure: 99 | ``` 100 | --+ / 101 | +- src / 102 | | +- main.js 103 | | +- style.css 104 | | +- __tests__ / main.js 105 | | +- __mocks__ / style.css 106 | +- __tests__ / 107 | | +- preprocessor.js 108 | +- node_modules / 109 | +- package.json 110 | +- webpack.config.js 111 | 112 | ``` 113 | 114 | File: `src/main.js` 115 | ``` 116 | ... 117 | require('style.css'); 118 | ... 119 | ``` 120 | 121 | File: `src/__tests__/main.js` (`__tests__` can actually be anywhere, not only next to tested files) 122 | ``` 123 | jest.dontMock('../main'); 124 | var main = require('../main'); 125 | ... 126 | ``` 127 | 128 | File: `src/__mocks__/style.css` (`__mocks__` __must__ be next to mocked files) 129 | ``` 130 | module.exports = 'src/style.css'; 131 | ``` 132 | 133 | ## package.json options 134 | 135 | - `jest-webpack-alias.configFile`: Optional, default is `"webpack.config.js"`. If provided, this should be a path 136 | fragment relative to your `package.json` file. Example: `"webpack/config.dev.js"`. 137 | 138 | - `jest-webpack-alias.profile`: Optional. If provided, will expect your webpack config to be an array of profiles, and 139 | will match against the `name` field of each to choose a webpack config that applies to your Jest tests. See 140 | https://github.com/webpack/webpack/tree/master/examples/multi-compiler for an example of this kind of setup. 141 | 142 | ## Known issues 143 | 144 | - `resolve.modulesDirectories` only searches the directory containing your package.json file, not all ancestors of current file 145 | 146 | ## License 147 | 148 | MIT 149 | 150 | [travis-image]: https://travis-ci.org/mwolson/jest-webpack-alias.svg?branch=master 151 | [travis-url]: https://travis-ci.org/mwolson/jest-webpack-alias 152 | 153 | [coveralls-image]: https://coveralls.io/repos/github/mwolson/jest-webpack-alias/badge.svg?branch=master 154 | [coveralls-url]: https://coveralls.io/github/mwolson/jest-webpack-alias?branch=master 155 | 156 | [npm-image]: https://img.shields.io/npm/v/jest-webpack-alias.svg?style=flat 157 | [npm-url]: https://www.npmjs.com/package/jest-webpack-alias 158 | -------------------------------------------------------------------------------- /lib/preprocessor.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | var dirHas = require('./dirHas'); 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | var stringOrArray = require('./stringOrArray'); 6 | var transformDeps = require('transform-jest-deps'); 7 | var unwin = require('unwin'); 8 | var webpackInfo = require('./webpackInfo'); 9 | 10 | var defaultAliases = {}; 11 | var defaultFallbackDirs = []; 12 | var defaultFileExtensions = ['', '.webpack.js', '.web.js', '.js', '.json']; 13 | var defaultModules = ['node_modules']; 14 | var defaultModulesDirs = ['node_modules', 'web_modules']; 15 | 16 | var aliases; 17 | var fileExtensions; 18 | var moduleDirs; 19 | var webpackSettings; 20 | 21 | function ensureWebpackInfo(filename) { 22 | if (webpackSettings) { 23 | return; 24 | } 25 | 26 | webpackSettings = webpackInfo.read({filename: filename}); 27 | var resolveConfig = webpackSettings.config.resolve; 28 | var webpackDir = path.dirname(webpackSettings.file); 29 | aliases = resolveConfig.alias || defaultAliases; 30 | fileExtensions = resolveConfig.extensions || defaultFileExtensions; 31 | moduleDirs = resolveConfig.modules || defaultModules; 32 | 33 | if (!resolveConfig.modules && resolveConfig.root) { 34 | // webpack 1.x path names 35 | var rootDirs = stringOrArray(resolveConfig.root); 36 | var modDirs = stringOrArray(resolveConfig.modulesDirectories) || defaultModulesDirs; 37 | var fallbackDirs = stringOrArray(resolveConfig.fallback) || defaultFallbackDirs; 38 | moduleDirs = _.union(rootDirs, modDirs, fallbackDirs); 39 | } 40 | 41 | moduleDirs = moduleDirs.map(function(dir) { 42 | return path.resolve(webpackDir, dir); 43 | }) 44 | .filter(function(dir) { 45 | return fs.existsSync(dir); 46 | }); 47 | } 48 | 49 | function firstDir(filename) { 50 | var segments; 51 | 52 | if (path.isAbsolute(filename)) { 53 | return filename; 54 | } else { 55 | return filename.split('/')[0]; 56 | } 57 | } 58 | 59 | function matchAlias(dependency) { 60 | var alias = aliases[dependency]; 61 | if (alias) { 62 | var dirname = firstDir(alias); 63 | return { 64 | dirname: dirname, 65 | rest: alias.slice(dirname.length + 1), 66 | path: alias 67 | }; 68 | } else { 69 | return undefined; 70 | } 71 | } 72 | 73 | function resolveExtension(matchingFirstDir, afterFirstDir) { 74 | var absMatch = afterFirstDir ? path.join(matchingFirstDir, afterFirstDir) : matchingFirstDir; 75 | var dirname = path.dirname(absMatch); 76 | var ext = _.find(fileExtensions, function(ext) { 77 | return dirHas(dirname, path.basename(absMatch + ext)); 78 | }); 79 | return ext; 80 | } 81 | 82 | function locate(dirname) { 83 | var matchingDir, matchingExt; 84 | 85 | if (path.isAbsolute(dirname)) { 86 | matchingDir = dirname; 87 | matchingExt = resolveExtension(dirname); 88 | } else { 89 | matchingDir = _.find(moduleDirs, function(candidate) { 90 | matchingExt = resolveExtension(candidate, dirname); 91 | return matchingExt !== undefined; 92 | }); 93 | } 94 | 95 | return { 96 | dir: matchingDir, 97 | ext: matchingDir ? (matchingExt || '') : '' 98 | }; 99 | } 100 | 101 | function resolveRelativeDependency(dependency, filename) { 102 | var absMatch = path.resolve(path.dirname(filename), dependency); 103 | var ext = resolveExtension(absMatch) || ''; 104 | return dependency + ext; 105 | } 106 | 107 | function resolveDependencyToMatch(matchingFirstDir, afterFirstDir, filename) { 108 | var absMatch = afterFirstDir ? path.join(matchingFirstDir, afterFirstDir) : matchingFirstDir; 109 | var srcDir = path.dirname(filename); 110 | var relPath = unwin(path.relative(srcDir, absMatch)); 111 | if (relPath.slice(0, 1) != '.') { 112 | relPath = './' + relPath; 113 | } 114 | return relPath; 115 | } 116 | 117 | function resolve(dependency, filename) { 118 | ensureWebpackInfo(filename); 119 | 120 | if (!dependency) { 121 | return undefined; 122 | } 123 | 124 | if (dependency.slice(0, 1) === '.') { 125 | return resolveRelativeDependency(dependency, filename); 126 | } 127 | 128 | var dirname = firstDir(dependency); 129 | var rest = dependency.slice(dirname.length + 1); 130 | 131 | var alias = matchAlias(dirname); 132 | if (alias) { 133 | // We want to get something relative to the alias 134 | if (rest) { 135 | dirname = alias.path; 136 | } else { 137 | dirname = alias.dirname; 138 | rest = alias.rest; 139 | } 140 | dependency = dirname + (rest ? '/' + rest : ''); 141 | } 142 | 143 | var match = locate(dependency); 144 | if (!match.dir) { 145 | return dependency; 146 | } 147 | 148 | var matchingDir; 149 | if (path.isAbsolute(dirname)) { 150 | matchingDir = dirname; 151 | } else { 152 | matchingDir = path.join(match.dir, dirname); 153 | } 154 | var relative = resolveDependencyToMatch(matchingDir, rest, filename); 155 | var ext = match.ext || ''; 156 | 157 | if (_.includes(relative, '/node_modules/')) { 158 | return dependency; 159 | } 160 | 161 | return relative + ext; 162 | } 163 | 164 | function process(src, filename) { 165 | ensureWebpackInfo(filename); 166 | var transformed = transformDeps(src, function(dependency) { 167 | return resolve(dependency, filename); 168 | }); 169 | return transformed; 170 | } 171 | 172 | exports.process = process; 173 | exports.resolve = resolve; 174 | -------------------------------------------------------------------------------- /test/webpackInfo.test.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | var expect = require('./lib/expect'); 3 | var unwin = require('unwin'); 4 | 5 | describe('webpackInfo lib', function() { 6 | var fakeRequire, pkginfo, readFile, requireContents, webpackInfo, webpackProfile; 7 | var filename, output, webpackFile; 8 | 9 | function setup(fixture) { 10 | filename = null; output = null; webpackFile = null; 11 | 12 | var setup = fixture.getWebpackInfo(); 13 | fakeRequire = setup.require; 14 | pkginfo = setup.pkginfo; 15 | requireContents = setup.requireContents, 16 | webpackInfo = setup.webpackInfo; 17 | webpackProfile = setup.webpackProfile; 18 | } 19 | 20 | function expectContainsProfile(profileContents) { 21 | expect(pkginfo.read).to.be.calledOnce; 22 | expect(pkginfo.read.args[0][0]).to.eql({filename: filename}); 23 | expect(fakeRequire).to.be.calledOnce; 24 | expect(unwin(fakeRequire.args[0][0])).to.eql(webpackFile); 25 | expect(output).to.have.deep.property('config', _.find(profileContents, ['name', webpackProfile])) 26 | .and.to.have.property('name', webpackProfile); 27 | expect(unwin(output.file)).to.eql(webpackFile); 28 | } 29 | 30 | function expectNoProfile() { 31 | expect(pkginfo.read).to.be.calledOnce; 32 | expect(pkginfo.read.args[0][0]).to.eql({filename: filename}); 33 | expect(fakeRequire).to.be.calledOnce; 34 | expect(unwin(fakeRequire.args[0][0])).to.eql(webpackFile); 35 | expect(output).to.have.deep.property('config', requireContents[webpackFile]); 36 | expect(unwin(output.file)).to.eql(webpackFile); 37 | } 38 | 39 | describe('with default config file and package.json in top dir', function() { 40 | beforeEach(function() { 41 | setup(require('./fixture/basic')); 42 | }); 43 | 44 | it('finds webpack.config.js and gets profile', function() { 45 | filename = '/top/test/file1.test.js'; 46 | webpackFile = '/top/webpack.config.js'; 47 | output = webpackInfo.read({filename: filename}); 48 | 49 | expectContainsProfile(requireContents[webpackFile]); 50 | }); 51 | 52 | describe('but wrong profile name', function() { 53 | beforeEach(function() { 54 | setup(require('./fixture/webpackInfo/profile-not-found')); 55 | }); 56 | 57 | it('throws an error', function() { 58 | filename = '/top/test/file1.test.js'; 59 | webpackFile = '/top/webpack/dev.config.js'; 60 | var expectedMsg = 'Specified jest-webpack-alias.webpackProfile = "dev", ' 61 | + 'but /top/webpack/dev.config.js does not contain this profile'; 62 | 63 | expect(webpackInfo.read.bind(null, {filename: filename})).to.throw(expectedMsg); 64 | }); 65 | }); 66 | 67 | describe('but profile setting omitted', function() { 68 | beforeEach(function() { 69 | setup(require('./fixture/webpackInfo/profile-not-specified')); 70 | }); 71 | 72 | it('throws an error', function() { 73 | filename = '/top/test/file1.test.js'; 74 | webpackFile = '/top/webpack/dev.config.js'; 75 | var expectedMsg = 'jest-webpack-alias.webpackProfile not specified, ' 76 | + 'but /top/webpack/dev.config.js exports an array'; 77 | 78 | expect(webpackInfo.read.bind(null, {filename: filename})).to.throw(expectedMsg); 79 | }); 80 | }); 81 | 82 | describe('but missing resolve.modules and resolve.root', function() { 83 | beforeEach(function() { 84 | setup(require('./fixture/webpackInfo/profile-missing-resolve-root')); 85 | }); 86 | 87 | it('throws an error', function() { 88 | filename = '/top/test/file1.test.js'; 89 | webpackFile = '/top/webpack/dev.config.js'; 90 | var expectedMsg = [ 91 | 'Missing setting "resolve.modules" (webpack v2) or "resolve.root" (webpack v1)', 92 | ' in /top/webpack/dev.config.js' 93 | ].join(''); 94 | 95 | expect(webpackInfo.read.bind(null, {filename: filename})).to.throw(expectedMsg); 96 | }); 97 | }); 98 | }); 99 | 100 | describe('with alternate webpack config file', function() { 101 | beforeEach(function() { 102 | setup(require('./fixture/webpackInfo/alt-config-location')); 103 | }); 104 | 105 | it('finds profile', function() { 106 | filename = '/top/test/file1.test.js'; 107 | webpackFile = '/top/webpack/dev.config.js'; 108 | output = webpackInfo.read({filename: filename}); 109 | 110 | expectContainsProfile(requireContents[webpackFile]); 111 | }); 112 | }); 113 | 114 | describe('with ES6 default exports', function() { 115 | beforeEach(function() { 116 | setup(require('./fixture/webpackInfo/es6-default-exports')); 117 | }); 118 | 119 | it('finds profile', function() { 120 | filename = '/top/test/file1.test.js'; 121 | webpackFile = '/top/webpack/dev.config.js'; 122 | output = webpackInfo.read({filename: filename}); 123 | 124 | expectContainsProfile(requireContents[webpackFile].default); 125 | }); 126 | }); 127 | 128 | describe('with no profile in webpack config', function() { 129 | beforeEach(function() { 130 | setup(require('./fixture/webpackInfo/no-profile')); 131 | }); 132 | 133 | it('returns entire config file', function() { 134 | filename = '/top/test/file1.test.js'; 135 | webpackFile = '/top/webpack/dev.config.js'; 136 | output = webpackInfo.read({filename: filename}); 137 | 138 | expectNoProfile(); 139 | }); 140 | 141 | describe('but profile specified', function() { 142 | beforeEach(function() { 143 | setup(require('./fixture/webpackInfo/profile-not-array')); 144 | }); 145 | 146 | it('throws an error', function() { 147 | filename = '/top/test/file1.test.js'; 148 | webpackFile = '/top/webpack/dev.config.js'; 149 | var expectedMsg = 'Specified jest-webpack-alias.webpackProfile = "dev", ' 150 | + 'but /top/webpack/dev.config.js does not export an array'; 151 | 152 | expect(webpackInfo.read.bind(null, {filename: filename})).to.throw(expectedMsg); 153 | }); 154 | }); 155 | }); 156 | }); 157 | -------------------------------------------------------------------------------- /test/preprocessor.test.js: -------------------------------------------------------------------------------- 1 | var expect = require('./lib/expect'); 2 | var path = require('path'); 3 | var rewire = require('rewire'); 4 | var sinon = require('sinon'); 5 | var unwin = require('unwin'); 6 | var basicFixture = require('./fixture/basic'); 7 | var cacheize = require('../lib/cacheize'); 8 | 9 | describe('jest-webpack-alias module', function() { 10 | var dirHas, filename, fs, webpackAlias, webpackInfo; 11 | 12 | function setup() { 13 | var setup = basicFixture.getWebpackAlias(); 14 | dirHas = setup.dirHas; 15 | fs = setup.fs; 16 | webpackAlias = setup.webpackAlias; 17 | webpackInfo = setup.webpackInfo; 18 | } 19 | 20 | function verifyDirHas(expected) { 21 | expect(dirHas).to.be.called; 22 | for (var i = 0; i < expected.length; i++) { 23 | if (dirHas.args[i] && expected[i]) { 24 | expect(unwin(dirHas.args[i][0]), 'call ' + i).to.eq(expected[i][0]); 25 | expect(dirHas.args[i][1], 'call ' + i).to.eq(expected[i][1]); 26 | } 27 | } 28 | expect(dirHas.args).to.have.length(expected.length); 29 | } 30 | 31 | function verifyExistsSync(expected) { 32 | expect(fs.existsSync).to.be.called; 33 | for (var i = 0; i < expected.length; i++) { 34 | if (fs.existsSync.args[i] && expected[i]) { 35 | expect(unwin(fs.existsSync.args[i][0]), 'call ' + i).to.eq(expected[i][0]); 36 | } 37 | } 38 | expect(fs.existsSync.args).to.have.length(expected.length); 39 | } 40 | 41 | beforeEach(setup); 42 | 43 | describe('with file in first dir', function() { 44 | beforeEach(function() { 45 | filename = '/top/test/file1.test.js'; 46 | }); 47 | 48 | it('resolves with file extension', function() { 49 | var src = "var lib1a = require('dir1/lib1a');"; 50 | var output = webpackAlias.process(src, filename); 51 | 52 | verifyExistsSync([ 53 | ['/top/test/__mocks__'], ['/top/src'], ['/top/bogus_dir'], ['/top/node_modules'], ['/top/web_modules'] 54 | ]); 55 | verifyDirHas([ 56 | ['/top/test/__mocks__/dir1', 'lib1a'], 57 | ['/top/test/__mocks__/dir1', 'lib1a.js'], 58 | ['/top/test/__mocks__/dir1', 'lib1a.jsx'], 59 | ['/top/src/dir1', 'lib1a'], 60 | ['/top/src/dir1', 'lib1a.js'] 61 | ]); 62 | expect(webpackInfo.read).to.be.calledOnce; 63 | expect(output).to.eq("var lib1a = require('../src/dir1/lib1a.js');"); 64 | }); 65 | 66 | it('if no exact match found, does not modify dependency', function() { 67 | var src = "var lib1a = require('dir1/lib1a.noext');"; 68 | var output = webpackAlias.process(src, filename); 69 | 70 | verifyDirHas([ 71 | ['/top/test/__mocks__/dir1', 'lib1a.noext'], 72 | ['/top/test/__mocks__/dir1', 'lib1a.noext.js'], 73 | ['/top/test/__mocks__/dir1', 'lib1a.noext.jsx'], 74 | ['/top/src/dir1', 'lib1a.noext'], 75 | ['/top/src/dir1', 'lib1a.noext.js'], 76 | ['/top/src/dir1', 'lib1a.noext.jsx'], 77 | ['/top/node_modules/dir1', 'lib1a.noext'], 78 | ['/top/node_modules/dir1', 'lib1a.noext.js'], 79 | ['/top/node_modules/dir1', 'lib1a.noext.jsx'], 80 | ['/top/web_modules/dir1', 'lib1a.noext'], 81 | ['/top/web_modules/dir1', 'lib1a.noext.js'], 82 | ['/top/web_modules/dir1', 'lib1a.noext.jsx'] 83 | ]); 84 | expect(output).to.eq("var lib1a = require('dir1/lib1a.noext');"); 85 | }); 86 | 87 | it('operates on jest.dontMock statements', function() { 88 | var src = "jest.dontMock('dir1/lib1a');"; 89 | var output = webpackAlias.process(src, filename); 90 | 91 | verifyDirHas([ 92 | ['/top/test/__mocks__/dir1', 'lib1a'], 93 | ['/top/test/__mocks__/dir1', 'lib1a.js'], 94 | ['/top/test/__mocks__/dir1', 'lib1a.jsx'], 95 | ['/top/src/dir1', 'lib1a'], 96 | ['/top/src/dir1', 'lib1a.js'] 97 | ]); 98 | expect(webpackInfo.read).to.be.calledOnce; 99 | expect(output).to.eq("jest.dontMock('../src/dir1/lib1a.js');"); 100 | }); 101 | }); 102 | 103 | describe('with file in same dir', function() { 104 | beforeEach(function() { 105 | filename = '/top/src/dir1/lib1b-2b.js'; 106 | }); 107 | 108 | it('uses ./ in relative path', function() { 109 | var src = "var lib1a = require('dir1/lib1a');"; 110 | var output = webpackAlias.process(src, filename); 111 | 112 | verifyDirHas([ 113 | ['/top/test/__mocks__/dir1', 'lib1a'], 114 | ['/top/test/__mocks__/dir1', 'lib1a.js'], 115 | ['/top/test/__mocks__/dir1', 'lib1a.jsx'], 116 | ['/top/src/dir1', 'lib1a'], 117 | ['/top/src/dir1', 'lib1a.js'] 118 | ]); 119 | expect(output).to.eq("var lib1a = require('./lib1a.js');"); 120 | }); 121 | }); 122 | 123 | describe('with file in node_modules', function() { 124 | beforeEach(function() { 125 | filename = '/top/test/file1.test.js'; 126 | }); 127 | 128 | it('resolves top-level dir, but leaves dependency alone', function() { 129 | var src = "var lib1a = require('node1');"; 130 | var output = webpackAlias.process(src, filename); 131 | 132 | verifyDirHas([ 133 | ['/top/test/__mocks__', 'node1'], 134 | ['/top/test/__mocks__', 'node1.js'], 135 | ['/top/test/__mocks__', 'node1.jsx'], 136 | ['/top/src', 'node1'], 137 | ['/top/src', 'node1.js'], 138 | ['/top/src', 'node1.jsx'], 139 | ['/top/node_modules', 'node1'] 140 | ]); 141 | expect(output).to.eq("var lib1a = require('node1');"); 142 | }); 143 | 144 | it('resolves submodule, trying first at file level, but leaves dependency alone', function() { 145 | var src = "var lib1a = require('node1/lib/submodule');"; 146 | var output = webpackAlias.process(src, filename); 147 | 148 | verifyDirHas([ 149 | ['/top/test/__mocks__/node1/lib', 'submodule'], 150 | ['/top/test/__mocks__/node1/lib', 'submodule.js'], 151 | ['/top/test/__mocks__/node1/lib', 'submodule.jsx'], 152 | ['/top/src/node1/lib', 'submodule'], 153 | ['/top/src/node1/lib', 'submodule.js'], 154 | ['/top/src/node1/lib', 'submodule.jsx'], 155 | ['/top/node_modules/node1/lib', 'submodule'], 156 | ['/top/node_modules/node1/lib', 'submodule.js'] 157 | ]); 158 | expect(output).to.eq("var lib1a = require('node1/lib/submodule');"); 159 | }); 160 | }); 161 | 162 | describe('with file in web_modules', function() { 163 | beforeEach(function() { 164 | filename = '/top/test/file1.test.js'; 165 | }); 166 | 167 | it('resolves top-level file, adding file extension', function() { 168 | var src = "var lib1a = require('web2');"; 169 | var output = webpackAlias.process(src, filename); 170 | 171 | verifyDirHas([ 172 | ['/top/test/__mocks__', 'web2'], 173 | ['/top/test/__mocks__', 'web2.js'], 174 | ['/top/test/__mocks__', 'web2.jsx'], 175 | ['/top/src', 'web2'], 176 | ['/top/src', 'web2.js'], 177 | ['/top/src', 'web2.jsx'], 178 | ['/top/node_modules', 'web2'], 179 | ['/top/node_modules', 'web2.js'], 180 | ['/top/node_modules', 'web2.jsx'], 181 | ['/top/web_modules', 'web2'], 182 | ['/top/web_modules', 'web2.js'], 183 | ['/top/web_modules', 'web2.jsx'] 184 | ]); 185 | expect(output).to.eq("var lib1a = require('../web_modules/web2.jsx');"); 186 | }); 187 | }); 188 | 189 | describe('with nonexistent file', function() { 190 | beforeEach(function() { 191 | filename = '/top/test/file1.test.js'; 192 | }); 193 | 194 | it('resolves top-level file, adding file extension', function() { 195 | var src = "var lib1a = require('bogus1');"; 196 | var output = webpackAlias.process(src, filename); 197 | 198 | verifyDirHas([ 199 | ['/top/test/__mocks__', 'bogus1'], 200 | ['/top/test/__mocks__', 'bogus1.js'], 201 | ['/top/test/__mocks__', 'bogus1.jsx'], 202 | ['/top/src', 'bogus1'], 203 | ['/top/src', 'bogus1.js'], 204 | ['/top/src', 'bogus1.jsx'], 205 | ['/top/node_modules', 'bogus1'], 206 | ['/top/node_modules', 'bogus1.js'], 207 | ['/top/node_modules', 'bogus1.jsx'], 208 | ['/top/web_modules', 'bogus1'], 209 | ['/top/web_modules', 'bogus1.js'], 210 | ['/top/web_modules', 'bogus1.jsx'] 211 | ]); 212 | expect(output).to.eq("var lib1a = require('bogus1');"); 213 | }); 214 | }); 215 | 216 | describe('with relative file', function() { 217 | beforeEach(function() { 218 | filename = '/top/src/dir1/lib1b-2b.js'; 219 | }); 220 | 221 | it('adds extension on ./', function() { 222 | var src = "var lib1a = require('./lib1a');"; 223 | var output = webpackAlias.process(src, filename); 224 | 225 | verifyDirHas([ 226 | ['/top/src/dir1', 'lib1a'], 227 | ['/top/src/dir1', 'lib1a.js'] 228 | ]); 229 | expect(output).to.eq("var lib1a = require('./lib1a.js');"); 230 | }); 231 | 232 | it('adds extension on ../', function() { 233 | filename = '/top/src/dir1/dir1-1/lib1-1a.js'; 234 | var src = "var lib1a = require('../lib1a');"; 235 | var output = webpackAlias.process(src, filename); 236 | 237 | verifyDirHas([ 238 | ['/top/src/dir1', 'lib1a'], 239 | ['/top/src/dir1', 'lib1a.js'] 240 | ]); 241 | expect(output).to.eq("var lib1a = require('../lib1a.js');"); 242 | }); 243 | 244 | it('uses no extension if no match found', function() { 245 | var src = "var lib1a = require('./bogus');"; 246 | var output = webpackAlias.process(src, filename); 247 | 248 | verifyDirHas([ 249 | ['/top/src/dir1', 'bogus'], 250 | ['/top/src/dir1', 'bogus.js'], 251 | ['/top/src/dir1', 'bogus.jsx'] 252 | ]); 253 | expect(output).to.eq("var lib1a = require('./bogus');"); 254 | }); 255 | }); 256 | 257 | describe('with alias', function() { 258 | beforeEach(function() { 259 | filename = '/top/test/file1.test.js'; 260 | }); 261 | 262 | describe('with destination of node_modules', function() { 263 | it('applies alias to top-level paths with no extension change', function() { 264 | var src = "var lib1a = require('aliasNodeFileSrc');"; 265 | var output = webpackAlias.process(src, filename); 266 | 267 | verifyDirHas([ 268 | ['/top/test/__mocks__', 'aliasNodeFileDest'], 269 | ['/top/test/__mocks__', 'aliasNodeFileDest.js'], 270 | ['/top/test/__mocks__', 'aliasNodeFileDest.jsx'], 271 | ['/top/src', 'aliasNodeFileDest'], 272 | ['/top/src', 'aliasNodeFileDest.js'], 273 | ['/top/src', 'aliasNodeFileDest.jsx'], 274 | ['/top/node_modules', 'aliasNodeFileDest'], 275 | ['/top/node_modules', 'aliasNodeFileDest.js'] 276 | ]); 277 | expect(output).to.eq("var lib1a = require('aliasNodeFileDest');"); 278 | }); 279 | 280 | it('applies alias to subdir paths', function() { 281 | var src = "var lib1a = require('aliasNodeSubdir1Src/lib/submodule');"; 282 | var output = webpackAlias.process(src, filename); 283 | 284 | verifyDirHas([ 285 | ['/top/test/__mocks__/node1/lib', 'submodule'], 286 | ['/top/test/__mocks__/node1/lib', 'submodule.js'], 287 | ['/top/test/__mocks__/node1/lib', 'submodule.jsx'], 288 | ['/top/src/node1/lib', 'submodule'], 289 | ['/top/src/node1/lib', 'submodule.js'], 290 | ['/top/src/node1/lib', 'submodule.jsx'], 291 | ['/top/node_modules/node1/lib', 'submodule'], 292 | ['/top/node_modules/node1/lib', 'submodule.js'] 293 | ]); 294 | expect(output).to.eq("var lib1a = require('node1/lib/submodule');"); 295 | }); 296 | 297 | it('applies alias definitions that contain subdirs', function() { 298 | var src = "var lib1a = require('aliasNodeSubdir2Src');"; 299 | var output = webpackAlias.process(src, filename); 300 | 301 | verifyDirHas([ 302 | ['/top/test/__mocks__/node1/lib', 'submodule'], 303 | ['/top/test/__mocks__/node1/lib', 'submodule.js'], 304 | ['/top/test/__mocks__/node1/lib', 'submodule.jsx'], 305 | ['/top/src/node1/lib', 'submodule'], 306 | ['/top/src/node1/lib', 'submodule.js'], 307 | ['/top/src/node1/lib', 'submodule.jsx'], 308 | ['/top/node_modules/node1/lib', 'submodule'], 309 | ['/top/node_modules/node1/lib', 'submodule.js'] 310 | ]); 311 | expect(output).to.eq("var lib1a = require('node1/lib/submodule');"); 312 | }); 313 | }); 314 | 315 | it('applies alias to subdir paths', function() { 316 | var src = "var lib1a = require('aliasPlainSubdirSrc');"; 317 | var output = webpackAlias.process(src, filename); 318 | 319 | verifyDirHas([ 320 | ['/top/test/__mocks__/dir1', 'lib1a'], 321 | ['/top/test/__mocks__/dir1', 'lib1a.js'], 322 | ['/top/test/__mocks__/dir1', 'lib1a.jsx'], 323 | ['/top/src/dir1', 'lib1a'], 324 | ['/top/src/dir1', 'lib1a.js'] 325 | ]); 326 | expect(output).to.eq("var lib1a = require('../src/dir1/lib1a.js');"); 327 | }); 328 | 329 | it('does not apply alias transformation to relative paths', function() { 330 | var src = "var lib1a = require('../src/aliasRelative');"; 331 | var output = webpackAlias.process(src, filename); 332 | 333 | verifyDirHas([ 334 | ['/top/src', 'aliasRelative'], 335 | ['/top/src', 'aliasRelative.js'] 336 | ]); 337 | expect(output).to.eq("var lib1a = require('../src/aliasRelative.js');"); 338 | }); 339 | 340 | it('applies alias to absolute subdir paths', function () { 341 | var src = "var lib1a = require('aliasAbsoluteSubdirSrc/lib1a');"; 342 | var output = webpackAlias.process(src, filename); 343 | 344 | verifyDirHas([ 345 | ['/top/src/dir1', 'lib1a'], 346 | ['/top/src/dir1', 'lib1a.js'], 347 | ]); 348 | 349 | expect(output).to.eq("var lib1a = require('../src/dir1/lib1a.js');"); 350 | }); 351 | 352 | it('applies alias to absolute path to a file', function() { 353 | var src = "var lib1a = require('aliasAbsoluteFileSrc');"; 354 | var output = webpackAlias.process(src, filename); 355 | 356 | verifyDirHas([ 357 | ['/top/src/dir1', 'lib1a'], 358 | ['/top/src/dir1', 'lib1a.js'], 359 | ]); 360 | 361 | expect(output).to.eq("var lib1a = require('../src/dir1/lib1a.js');"); 362 | }); 363 | 364 | it('applies alias when wanted file is relative to alias', function() { 365 | var src = "var lib11a = require('aliasSubRelative/lib1-1a');"; 366 | var output = webpackAlias.process(src, filename); 367 | 368 | verifyDirHas([ 369 | [ '/top/test/__mocks__/dir1/dir1-1', 'lib1-1a' ], 370 | [ '/top/test/__mocks__/dir1/dir1-1', 'lib1-1a.js' ], 371 | [ '/top/test/__mocks__/dir1/dir1-1', 'lib1-1a.jsx' ], 372 | [ '/top/src/dir1/dir1-1', 'lib1-1a' ], 373 | [ '/top/src/dir1/dir1-1', 'lib1-1a.js' ] 374 | ]); 375 | 376 | expect(output).to.eq("var lib11a = require('../src/dir1/dir1-1/lib1-1a.js');"); 377 | }); 378 | }); 379 | 380 | describe('resolve', function() { 381 | beforeEach(function() { 382 | filename = '/top/test/file1.test.js'; 383 | }); 384 | 385 | it('resolves with file extension', function() { 386 | var resolved = webpackAlias.resolve('dir1/lib1a', filename); 387 | 388 | verifyExistsSync([ 389 | ['/top/test/__mocks__'], ['/top/src'], ['/top/bogus_dir'], ['/top/node_modules'], ['/top/web_modules'] 390 | ]); 391 | verifyDirHas([ 392 | ['/top/test/__mocks__/dir1', 'lib1a'], 393 | ['/top/test/__mocks__/dir1', 'lib1a.js'], 394 | ['/top/test/__mocks__/dir1', 'lib1a.jsx'], 395 | ['/top/src/dir1', 'lib1a'], 396 | ['/top/src/dir1', 'lib1a.js'] 397 | ]); 398 | expect(webpackInfo.read).to.be.calledOnce; 399 | expect(resolved).to.eq('../src/dir1/lib1a.js'); 400 | }); 401 | }); 402 | }); 403 | --------------------------------------------------------------------------------