├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── examples └── foobar │ ├── README.md │ ├── build.js │ ├── index.html │ ├── node_modules │ ├── browserify │ └── proxyquireify │ ├── package.json │ ├── src │ ├── bar.js │ └── foo.js │ └── test.js ├── index.js ├── lib ├── find-dependencies.js ├── prelude.js ├── replace-prelude.js └── transform.js ├── package.json ├── plugin.js └── test ├── clientside ├── argument-validation.js ├── falsy.js ├── independent-overrides.js ├── manipulating-overrides.js ├── noCallThru.js └── run.js ├── find-dependencies.js ├── fixtures ├── bar.js ├── dependencies.js ├── foo.js ├── stats.js ├── true.js ├── value.js └── var-declaration.js └── watchify-cli.js /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | 17 | bundle.js 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.12' 4 | - iojs 5 | before_install: 6 | - npm install -g npm 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013 Thorsten Lorenz. 2 | All rights reserved. 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # proxyquireify [![build status](https://secure.travis-ci.org/thlorenz/proxyquireify.svg?branch=master)](http://travis-ci.org/thlorenz/proxyquireify) 2 | 3 | browserify `>= v2` version of [proxyquire](https://github.com/thlorenz/proxyquire). 4 | 5 | Proxies browserify's require in order to make overriding dependencies during testing easy while staying **totally unobstrusive**. To run your tests in both Node and the browser, use [proxyquire-universal](https://github.com/bendrucker/proxyquire-universal). 6 | 7 | 8 | 9 | **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* 10 | 11 | - [Features](#features) 12 | - [Installation](#installation) 13 | - [Example](#example) 14 | - [With Other Transforms](#with-other-transforms) 15 | - [API](#api) 16 | - [proxyquire.plugin()](#proxyquireplugin) 17 | - [proxyquire.browserify()](#proxyquirebrowserify) 18 | - [Deprecation Warning](#deprecation-warning) 19 | - [proxyquire(request: String, stubs: Object)](#proxyquirerequest-string-stubs-object) 20 | - [Important Magic](#important-magic) 21 | - [noCallThru](#nocallthru) 22 | - [More Examples](#more-examples) 23 | 24 | 25 | 26 | 27 | ## Features 28 | 29 | - **no changes to your code** are necessary 30 | - non overriden methods of a module behave like the original 31 | - mocking framework agnostic, if it can stub a function then it works with **proxyquireify** 32 | - "use strict" compliant 33 | - [automatic injection](https://github.com/thlorenz/proxyquireify#important-magic) of `require` calls to ensure the 34 | module you are testing gets bundled 35 | 36 | ## Installation 37 | 38 | npm install proxyquireify 39 | 40 | To use with browserify `< 5.1` please `npm install proxyquireify@0.5` instead. To run your tests in PhantomJS, you may need to [use a shim](https://github.com/bendrucker/phantom-ownpropertynames). 41 | 42 | ## Example 43 | 44 | **foo.js**: 45 | 46 | ```js 47 | var bar = require('./bar'); 48 | 49 | module.exports = function () { 50 | return bar.kinder() + ' ist ' + bar.wunder(); 51 | }; 52 | ``` 53 | 54 | **foo.test.js**: 55 | 56 | ```js 57 | var proxyquire = require('proxyquireify')(require); 58 | 59 | var stubs = { 60 | './bar': { 61 | wunder: function () { return 'wirklich wunderbar'; } 62 | , kinder: function () { return 'schokolade'; } 63 | } 64 | }; 65 | 66 | var foo = proxyquire('./src/foo', stubs); 67 | 68 | console.log(foo()); 69 | ``` 70 | 71 | **browserify.build.js**: 72 | 73 | ```js 74 | var browserify = require('browserify'); 75 | var proxyquire = require('proxyquireify'); 76 | 77 | browserify() 78 | .plugin(proxyquire.plugin) 79 | .require(require.resolve('./foo.test'), { entry: true }) 80 | .bundle() 81 | .pipe(fs.createWriteStream(__dirname + '/bundle.js')); 82 | ``` 83 | 84 | load it in the browser and see: 85 | 86 | schokolade ist wirklich wunderbar 87 | 88 | ## With Other Transforms 89 | 90 | If you're transforming your source code to JavaScript, you must apply those transforms before applying the proxyquireify plugin: 91 | 92 | ```js 93 | browserify() 94 | .transform('coffeeify') 95 | .plugin(proxyquire.plugin) 96 | .require(require.resolve('./test.coffee'), { entry: true }) 97 | .bundle() 98 | .pipe(fs.createWriteStream(__dirname + '/bundle.js')); 99 | ``` 100 | 101 | proxyquireify needs to parse your code looking for `require` statements. If you `require` anything that's not valid JavaScript that [acorn](https://github.com/marijnh/acorn) can parse (e.g. CoffeeScript, TypeScript), you need to make sure the relevant transform runs before proxyquireify. 102 | 103 | ## API 104 | 105 | ### proxyquire.plugin() 106 | 107 | **proxyquireify** functions as a browserify plugin and needs to be registered with browserify like so: 108 | 109 | ```js 110 | var browserify = require('browserify'); 111 | var proxyquire = require('proxyquireify'); 112 | 113 | browserify() 114 | .plugin(proxyquire.plugin) 115 | .require(require.resolve('./test'), { entry: true }) 116 | .bundle() 117 | .pipe(fs.createWriteStream(__dirname + '/bundle.js')); 118 | ``` 119 | 120 | Alternatively you can register **proxyquireify** as a plugin from the command line like so: 121 | 122 | ```sh 123 | browserify -p proxyquireify/plugin test.js > bundle.js 124 | ``` 125 | 126 | ### proxyquire.browserify() 127 | 128 | #### Deprecation Warning 129 | 130 | This API to setup **proxyquireify** was used prior to [browserify plugin](https://github.com/substack/node-browserify#bpluginplugin-opts) support. 131 | 132 | It has not been removed yet to make upgrading **proxyquireify** easier for now, but it **will be deprecated in future 133 | versions**. Please consider using the plugin API (above) instead. 134 | 135 | **** 136 | 137 | To be used in build script instead of `browserify()`, autmatically adapts browserify to work for tests and injects 138 | require overrides into all modules via a browserify transform. 139 | 140 | ```js 141 | proxyquire.browserify() 142 | .require(require.resolve('./test'), { entry: true }) 143 | .bundle() 144 | .pipe(fs.createWriteStream(__dirname + '/bundle.js')); 145 | ``` 146 | 147 | **** 148 | 149 | ### proxyquire(request: String, stubs: Object) 150 | 151 | - **request**: path to the module to be tested e.g., `../lib/foo` 152 | - **stubs**: key/value pairs of the form `{ modulePath: stub, ... }` 153 | - module paths are relative to the tested module **not** the test file 154 | - therefore specify it exactly as in the require statement inside the tested file 155 | - values themselves are key/value pairs of functions/properties and the appropriate override 156 | 157 | ```js 158 | var proxyquire = require('proxyquireify')(require); 159 | var barStub = { wunder: function () { 'really wonderful'; } }; 160 | 161 | var foo = proxyquire('./foo', { './bar': barStub }) 162 | ``` 163 | 164 | #### Important Magic 165 | 166 | In order for browserify to include the module you are testing in the bundle, **proxyquireify** will inject a 167 | `require()` call for every module you are proxyquireing. So in the above example `require('./foo')` will be injected at 168 | the top of your test file. 169 | 170 | ### noCallThru 171 | 172 | By default **proxyquireify** calls the function defined on the *original* dependency whenever it is not found on the stub. 173 | 174 | If you prefer a more strict behavior you can prevent *callThru* on a per module or per stub basis. 175 | 176 | If *callThru* is disabled, you can stub out modules that weren't even included in the bundle. **Note**, that unlike in 177 | proxquire, there is no option to prevent call thru globally. 178 | 179 | ```js 180 | // Prevent callThru for path module only 181 | var foo = proxyquire('./foo', { 182 | path: { 183 | extname: function (file) { ... } 184 | , '@noCallThru': true 185 | } 186 | , fs: { readdir: function (..) { .. } } 187 | }); 188 | 189 | // Prevent call thru for all contained stubs (path and fs) 190 | var foo = proxyquire('./foo', { 191 | path: { 192 | extname: function (file) { ... } 193 | } 194 | , fs: { readdir: function (..) { .. } } 195 | , '@noCallThru': true 196 | }); 197 | 198 | // Prevent call thru for all stubs except path 199 | var foo = proxyquire('./foo', { 200 | path: { 201 | extname: function (file) { ... } 202 | , '@noCallThru': false 203 | } 204 | , fs: { readdir: function (..) { .. } } 205 | , '@noCallThru': true 206 | }); 207 | ``` 208 | 209 | ## More Examples 210 | 211 | - [foobar](https://github.com/thlorenz/proxyquireify/tree/master/examples/foobar) 212 | -------------------------------------------------------------------------------- /examples/foobar/README.md: -------------------------------------------------------------------------------- 1 | # foobar example 2 | 3 | Shows how `bar.wunder` function and non-existent `bar.kinder` are overridden. 4 | 5 | ## Run 6 | 7 | npm explore proxyquireify 8 | cd examples/foobar 9 | npm install && npm test 10 | -------------------------------------------------------------------------------- /examples/foobar/build.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | , proxyquire = require('proxyquireify') 3 | , browserify = require('browserify') 4 | ; 5 | 6 | browserify({ debug: true }) 7 | .plugin(proxyquire.plugin) 8 | .require(require.resolve('./test'), { entry: true }) 9 | .bundle() 10 | .pipe(fs.createWriteStream(__dirname + '/bundle.js')); 11 | -------------------------------------------------------------------------------- /examples/foobar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | foobar 6 | 7 | 8 | 9 |

proxyquireify - foobar test page

10 |

It should say "schokolade ist wirklich wunderbar" in the console

11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/foobar/node_modules/browserify: -------------------------------------------------------------------------------- 1 | ../../../node_modules/browserify -------------------------------------------------------------------------------- /examples/foobar/node_modules/proxyquireify: -------------------------------------------------------------------------------- 1 | ../../../ -------------------------------------------------------------------------------- /examples/foobar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foobar", 3 | "version": "0.0.0", 4 | "description": "proxyquireify foobar example", 5 | "scripts": { 6 | "test": "node build && open index.html" 7 | }, 8 | "dependencies": { 9 | }, 10 | "devDependencies": {}, 11 | "keywords": [], 12 | "author": { 13 | "name": "Thorsten Lorenz", 14 | "email": "thlorenz@gmx.de", 15 | "url": "http://thlorenz.com" 16 | }, 17 | "license": "MIT", 18 | "engine": { 19 | "node": ">=0.6" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/foobar/src/bar.js: -------------------------------------------------------------------------------- 1 | exports.wunder = function () { 2 | return 'wunderbar'; 3 | }; 4 | -------------------------------------------------------------------------------- /examples/foobar/src/foo.js: -------------------------------------------------------------------------------- 1 | var bar = require('./bar'); 2 | 3 | module.exports = function () { 4 | return bar.kinder() + ' ist ' + bar.wunder(); 5 | }; 6 | -------------------------------------------------------------------------------- /examples/foobar/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var proxyquire = require('proxyquireify')(require); 4 | 5 | var stubs = { 6 | './bar': { 7 | wunder: function () { return 'wirklich wunderbar'; } 8 | , kinder: function () { return 'schokolade'; } 9 | } 10 | }; 11 | 12 | var foo = proxyquire('./src/foo', stubs); 13 | console.log(foo()); 14 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fillMissingKeys = require('fill-keys'); 4 | var moduleNotFoundError = require('module-not-found-error'); 5 | 6 | function ProxyquireifyError(msg) { 7 | this.name = 'ProxyquireifyError'; 8 | Error.captureStackTrace(this, ProxyquireifyError); 9 | this.message = msg || 'An error occurred inside proxyquireify.'; 10 | } 11 | 12 | function validateArguments(request, stubs) { 13 | var msg = (function getMessage() { 14 | if (!request) 15 | return 'Missing argument: "request". Need it to resolve desired module.'; 16 | 17 | if (!stubs) 18 | return 'Missing argument: "stubs". If no stubbing is needed, use regular require instead.'; 19 | 20 | if (typeof request != 'string') 21 | return 'Invalid argument: "request". Needs to be a requirable string that is the module to load.'; 22 | 23 | if (typeof stubs != 'object') 24 | return 'Invalid argument: "stubs". Needs to be an object containing overrides e.g., {"path": { extname: function () { ... } } }.'; 25 | })(); 26 | 27 | if (msg) throw new ProxyquireifyError(msg); 28 | } 29 | 30 | var stubs; 31 | 32 | function stub(stubs_) { 33 | stubs = stubs_; 34 | // This cache is used by the prelude as an alternative to the regular cache. 35 | // It is not read or written here, except to set it to an empty object when 36 | // adding stubs and to reset it to null when clearing stubs. 37 | module.exports._cache = {}; 38 | } 39 | 40 | function reset() { 41 | stubs = undefined; 42 | module.exports._cache = null; 43 | } 44 | 45 | var proxyquire = module.exports = function (require_) { 46 | if (typeof require_ != 'function') 47 | throw new ProxyquireifyError( 48 | 'It seems like you didn\'t initialize proxyquireify with the require in your test.\n' 49 | + 'Make sure to correct this, i.e.: "var proxyquire = require(\'proxyquireify\')(require);"' 50 | ); 51 | 52 | reset(); 53 | 54 | return function(request, stubs) { 55 | 56 | validateArguments(request, stubs); 57 | 58 | // set the stubs and require dependency 59 | // when stub require is invoked by the module under test it will find the stubs here 60 | stub(stubs); 61 | var dep = require_(request); 62 | reset(); 63 | 64 | return dep; 65 | }; 66 | }; 67 | 68 | // Start with the default cache 69 | proxyquire._cache = null; 70 | 71 | proxyquire._proxy = function (require_, request) { 72 | function original() { 73 | return require_(request); 74 | } 75 | 76 | if (!stubs || !stubs.hasOwnProperty(request)) return original(); 77 | 78 | var stub = stubs[request]; 79 | 80 | if (stub === null) throw moduleNotFoundError(request) 81 | 82 | var stubWideNoCallThru = Boolean(stubs['@noCallThru']) && (stub == null || stub['@noCallThru'] !== false); 83 | var noCallThru = stubWideNoCallThru || (stub != null && Boolean(stub['@noCallThru'])); 84 | return noCallThru ? stub : fillMissingKeys(stub, original()); 85 | }; 86 | 87 | if (require.cache) { 88 | // only used during build, so prevent browserify from including it 89 | var replacePreludePath = './lib/replace-prelude'; 90 | var replacePrelude = require(replacePreludePath); 91 | proxyquire.browserify = replacePrelude.browserify; 92 | proxyquire.plugin = replacePrelude.plugin; 93 | } 94 | -------------------------------------------------------------------------------- /lib/find-dependencies.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var detective = require('detective'); 4 | var hasRequire = require('has-require'); 5 | 6 | function simpleRequire(n) { 7 | // var proxy = require('proxyquireify') 8 | return n.parent 9 | && n.parent.id 10 | && n.parent.id.name; 11 | } 12 | 13 | function requireWithImmediateCall(n) { 14 | // var proxy = require('proxyquireify')(require) 15 | var p = n.parent; 16 | return p.parent 17 | && p.parent.id 18 | && p.parent.id.name; 19 | } 20 | 21 | function requireWithImmediateCallWithoutVar(n) { 22 | // proxy = require('proxyquireify')(require) 23 | var p = n.parent; 24 | return p.parent 25 | && p.parent.left 26 | && p.parent.left.name; 27 | } 28 | 29 | function findProxyquireVars(src) { 30 | return detective 31 | .find(src, { nodes: true }).nodes 32 | .map(function (n) { 33 | var arg = n.arguments[0]; 34 | return arg 35 | && arg.value === 'proxyquireify' 36 | && arg.type === 'Literal' 37 | && ( simpleRequire(n) || requireWithImmediateCall(n) || requireWithImmediateCallWithoutVar(n) ); 38 | }) 39 | .filter(function (n) { return n; }) 40 | ; 41 | } 42 | 43 | module.exports = function(src) { 44 | if (!hasRequire(src, 'proxyquireify')) return []; 45 | 46 | // use hash to get unique values 47 | var hash = findProxyquireVars(src) 48 | .map(function (name) { 49 | return detective(src, { word: name }); 50 | }) 51 | .reduce(function (acc, arr) { 52 | arr.forEach(function (x) { acc[x] = true;}); 53 | return acc; 54 | }, {}); 55 | 56 | return Object.keys(hash); 57 | }; 58 | -------------------------------------------------------------------------------- /lib/prelude.js: -------------------------------------------------------------------------------- 1 | // modules are defined as an array 2 | // [ module function, map of requireuires ] 3 | // 4 | // map of requireuires is short require name -> numeric require 5 | // 6 | // anything defined in a previous bundle is accessed via the 7 | // orig method which is the requireuire for previous bundles 8 | 9 | (function outer (modules, cache, entry) { 10 | // Save the require from previous bundle to this closure if any 11 | var previousRequire = typeof require == "function" && require; 12 | 13 | function findProxyquireifyName() { 14 | var deps = Object.keys(modules) 15 | .map(function (k) { return modules[k][1]; }); 16 | 17 | for (var i = 0; i < deps.length; i++) { 18 | var pq = deps[i]['proxyquireify']; 19 | if (pq) return pq; 20 | } 21 | } 22 | 23 | var proxyquireifyName = findProxyquireifyName(); 24 | 25 | function newRequire(name, jumped){ 26 | // Find the proxyquireify module, if present 27 | var pqify = (proxyquireifyName != null) && cache[proxyquireifyName]; 28 | 29 | // Proxyquireify provides a separate cache that is used when inside 30 | // a proxyquire call, and is set to null outside a proxyquire call. 31 | // This allows the regular caching semantics to work correctly both 32 | // inside and outside proxyquire calls while keeping the cached 33 | // modules isolated. 34 | // When switching from one proxyquire call to another, it clears 35 | // the cache to prevent contamination between different sets 36 | // of stubs. 37 | var currentCache = (pqify && pqify.exports._cache) || cache; 38 | 39 | if(!currentCache[name]) { 40 | if(!modules[name]) { 41 | // if we cannot find the the module within our internal map or 42 | // cache jump to the current global require ie. the last bundle 43 | // that was added to the page. 44 | var currentRequire = typeof require == "function" && require; 45 | if (!jumped && currentRequire) return currentRequire(name, true); 46 | 47 | // If there are other bundles on this page the require from the 48 | // previous one is saved to 'previousRequire'. Repeat this as 49 | // many times as there are bundles until the module is found or 50 | // we exhaust the require chain. 51 | if (previousRequire) return previousRequire(name, true); 52 | var err = new Error('Cannot find module \'' + name + '\''); 53 | err.code = 'MODULE_NOT_FOUND'; 54 | throw err; 55 | } 56 | var m = currentCache[name] = {exports:{}}; 57 | 58 | // The normal browserify require function 59 | var req = function(x){ 60 | var id = modules[name][1][x]; 61 | return newRequire(id ? id : x); 62 | }; 63 | 64 | // The require function substituted for proxyquireify 65 | var moduleRequire = function(x){ 66 | var pqify = (proxyquireifyName != null) && cache[proxyquireifyName]; 67 | // Only try to use the proxyquireify version if it has been `require`d 68 | if (pqify && pqify.exports._proxy) { 69 | return pqify.exports._proxy(req, x); 70 | } else { 71 | return req(x); 72 | } 73 | }; 74 | 75 | modules[name][0].call(m.exports,moduleRequire,m,m.exports,outer,modules,currentCache,entry); 76 | } 77 | return currentCache[name].exports; 78 | } 79 | for(var i=0;i=0.6" 54 | }, 55 | "peerDependencies": { 56 | "browserify": ">=5.1.0" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /plugin.js: -------------------------------------------------------------------------------- 1 | // This file allows using proxyquireify as a browserify plugin named 2 | // 'proxyquireify/plugin' 3 | module.exports = require('./lib/replace-prelude').plugin; 4 | -------------------------------------------------------------------------------- /test/clientside/argument-validation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint asi: true, browser: true */ 3 | 4 | var proxyquire = require('proxyquireify')(require) 5 | , bar = { bar: function () { return 'bar'; } } 6 | 7 | function throws(t, action, regex, desc) { 8 | t.throws( 9 | action 10 | , function (err) { 11 | return err.name === 'ProxyquireifyError' && regex.test(err.message); 12 | } 13 | , desc 14 | ) 15 | } 16 | 17 | test('\nillegal parameters give meaningful errors', function (t) { 18 | 19 | throws( 20 | t 21 | , proxyquire.bind(null, null, {}) 22 | , /missing argument: "request"/i 23 | , 'throws for missing request' 24 | ) 25 | throws( 26 | t 27 | , proxyquire.bind(null, {}, bar) 28 | , /invalid argument: "request".+needs to be a requirable string/i 29 | , 'throws when request is not a string' 30 | ) 31 | throws( 32 | t 33 | , proxyquire.bind(null, './samples/foo') 34 | , /missing argument: "stubs".+use regular require instead/i 35 | , 'throws when no stubs are provided' 36 | ) 37 | throws( 38 | t 39 | , proxyquire.bind(null, '../fixtures/foo', 'stubs') 40 | , /invalid argument: "stubs".+needs to be an object/i 41 | , 'throws when a string is passed for stubs' 42 | ) 43 | t.end() 44 | }) 45 | 46 | test('\nuninitialized proxyquire', function (t) { 47 | var uninitialized = require('proxyquireify') 48 | throws( 49 | t 50 | , uninitialized.bind(null, '../fixtures/foo', {}) 51 | , /It seems like you didn't initialize proxyquireify with the require in your test/ 52 | , 'throws when proxyquireify was not initialized with require' 53 | ) 54 | t.end() 55 | }); 56 | -------------------------------------------------------------------------------- /test/clientside/falsy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint asi: true, browser: true */ 3 | 4 | var proxyquire = require('proxyquireify')(require) 5 | 6 | test('\nreturns original value with no stub', function (t) { 7 | var value = proxyquire('../fixtures/value', {}) 8 | t.equals(value, true) 9 | t.end() 10 | }) 11 | 12 | test('overriding dep with a false value', function (t) { 13 | var value = proxyquire('../fixtures/value', { './true': false }) 14 | t.equals(value, false) 15 | t.end() 16 | }) 17 | 18 | test('overriding dep with undefined', function (t) { 19 | var value = proxyquire('../fixtures/value', { './true': undefined }) 20 | t.equals(value, undefined) 21 | t.end() 22 | }) 23 | 24 | test('throws with a null value', function (t) { 25 | t.throws(load, /cannot find module/) 26 | t.end() 27 | 28 | function load () { 29 | proxyquire('../fixtures/value', { './true': null }) 30 | } 31 | }) 32 | -------------------------------------------------------------------------------- /test/clientside/independent-overrides.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint asi: true, browser: true */ 3 | 4 | var proxyquire = require('proxyquireify')(require) 5 | , stats = require('../fixtures/stats') 6 | , barber = { bar: function () { return 'barber'; } } 7 | ; 8 | 9 | var foober = proxyquire('../fixtures/foo', { './bar': barber }); 10 | var foo = proxyquire('../fixtures/foo', { './bar': { } }); 11 | 12 | test('\noverriding bar.bar for foober but not for foo', function (t) { 13 | t.equal(window.foostats.fooRequires(), 2, 'foo is required three times since one for each test and one for require detective') 14 | t.equal(foo.bigBar(), 'BAR', 'foo.bigBar == BAR') 15 | t.equal(foober.bigBar(), 'BARBER', 'foober.bigBar == BARBER'); 16 | 17 | t.equal(foober.bigExt('file.ext'), '.EXT', 'does not override bar.ext for foober') 18 | t.equal(foober.bigBas('/home/file.ext'), 'FILE.EXT', 'does not override bar.basename for foober') 19 | t.end() 20 | }) 21 | -------------------------------------------------------------------------------- /test/clientside/manipulating-overrides.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint asi: true, browser: true */ 3 | 4 | var proxyquire = require('proxyquireify')(require) 5 | , barber = { bar: function () { return 'barber'; } } 6 | ; 7 | 8 | var foober = proxyquire('../fixtures/foo', { './bar': barber }); 9 | 10 | test('\noverriding dep with stub and manipulating stub afterwards', function (t) { 11 | 12 | barber.bar = function () { return 'friseur'; } 13 | barber.rab = function () { return 'rabarber'; } 14 | 15 | t.equal(foober.bigBar(), 'FRISEUR', 'overrides previously stubbed func'); 16 | t.equal(foober.bigRab(), 'RABARBER', 'overrides func not previously stubbed'); 17 | 18 | barber.bar = undefined; 19 | 20 | t.throws(foober.bigBar, /Property 'bar' of object # is not a function/, 'returns undefined when I delete an override later') 21 | t.end() 22 | }) 23 | -------------------------------------------------------------------------------- /test/clientside/noCallThru.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint asi: true, browser: true */ 3 | 4 | var proxyquire = require('proxyquireify')(require) 5 | , file = '/folder/test.ext' 6 | ; 7 | 8 | test('\n# no noCallThru and extname overridden', function (t) { 9 | var foo = proxyquire('../fixtures/foo', { 10 | path:{ 11 | extname : function (file) { return 'override ' + file; } 12 | } 13 | }) 14 | 15 | t.equal(foo.bigExt(file), 'OVERRIDE /FOLDER/TEST.EXT', 'extname overridden') 16 | t.equal(foo.bigBas(file), 'TEST.EXT', 'basename original') 17 | t.end() 18 | }) 19 | 20 | test('\n# path noCallThru and extname overridden', function (t) { 21 | var foo = proxyquire('../fixtures/foo', { 22 | path:{ 23 | extname : function (file) { return 'override ' + file; } 24 | , '@noCallThru': true 25 | } 26 | }) 27 | 28 | t.equal(foo.bigExt(file), 'OVERRIDE /FOLDER/TEST.EXT', 'extname overridden') 29 | t.throws(foo.bigBas.bind(null, file), /TypeError: Object # has no method 'basename'/, 'basename throws') 30 | t.end() 31 | }) 32 | 33 | test('\n# stub wide noCallThru and extname overridden', function (t) { 34 | var foo = proxyquire('../fixtures/foo', { 35 | path:{ 36 | extname : function (file) { return 'override ' + file; } 37 | } 38 | , '@noCallThru': true 39 | }) 40 | 41 | t.equal(foo.bigExt(file), 'OVERRIDE /FOLDER/TEST.EXT', 'extname overridden') 42 | t.throws(foo.bigBas.bind(null, file), /TypeError: Object # has no method 'basename'/, 'basename throws') 43 | t.end() 44 | }) 45 | 46 | test('\n# stub wide noCallThru but for path noCallThru turned off and extname overridden', function (t) { 47 | var foo = proxyquire('../fixtures/foo', { 48 | path:{ 49 | extname : function (file) { return 'override ' + file; } 50 | , '@noCallThru': false 51 | } 52 | , '@noCallThru': true 53 | }) 54 | 55 | t.equal(foo.bigExt(file), 'OVERRIDE /FOLDER/TEST.EXT', 'extname overridden') 56 | t.equal(foo.bigBas(file), 'TEST.EXT', 'basename original') 57 | t.end() 58 | }) 59 | -------------------------------------------------------------------------------- /test/clientside/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint asi: true */ 3 | 4 | var browserify = require('browserify'); 5 | var proxyquire = require('../..'); 6 | var vm = require('vm'); 7 | var test = require('tape'); 8 | 9 | function compile(name, cb) { 10 | browserify() 11 | .plugin(proxyquire.plugin) 12 | .require(require.resolve('../..'), { expose: 'proxyquireify' }) 13 | .require(require.resolve('./' + name), { entry: true }) 14 | .bundle(function (err, src) { 15 | if (err) return cb(err); 16 | cb(null, { src: src, name: name }); 17 | }); 18 | } 19 | 20 | // run the compiled tests in a new context 21 | function run(args) { 22 | var name = args.name; 23 | var src = args.src; 24 | 25 | test(name, function(t) { 26 | vm.runInNewContext(src, { test: t.test.bind(t), window: {} }); 27 | }) 28 | } 29 | 30 | // compile all tests and fire a callback when the 31 | // all code is compiled and ready to be executed 32 | function compileAll(tests, cb) { 33 | var results = []; 34 | var pending = tests.length; 35 | tests.forEach(function (name, idx) { 36 | compile(name, function (err, result) { 37 | if (err) return cb(err); 38 | 39 | results[idx] = result; 40 | if (--pending === 0) { 41 | cb(null, results); 42 | } 43 | }); 44 | }); 45 | } 46 | 47 | var clientTests = [ 48 | 'independent-overrides' 49 | , 'manipulating-overrides' 50 | , 'noCallThru' 51 | , 'argument-validation' 52 | , 'falsy' 53 | ]; 54 | 55 | compileAll(clientTests, function (err, results) { 56 | if (err) { 57 | console.error(err); 58 | process.exit(1); 59 | return; 60 | } 61 | results.forEach(run); 62 | }); 63 | -------------------------------------------------------------------------------- /test/find-dependencies.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint asi: true */ 3 | 4 | var test = require('tap').test 5 | , fs = require('fs') 6 | , findDependencies = require('../lib/find-dependencies') 7 | 8 | test('multiple proxyquires with different names', function (t) { 9 | var src = fs.readFileSync(require.resolve('./fixtures/dependencies'), 'utf-8'); 10 | var deps = findDependencies(src) 11 | t.deepEqual(deps, [ './depuno', './foober', './foo' ], 'returns array with each proxyquired dep exactly once') 12 | t.end() 13 | }) 14 | 15 | test('proxyquire var declared before setting', function (t) { 16 | var src = fs.readFileSync(require.resolve('./fixtures/var-declaration'), 'utf-8'); 17 | var deps = findDependencies(src) 18 | t.deepEqual(deps, [ './depuno' ], 'returns array with each proxyquired dep exactly once') 19 | t.end() 20 | }) 21 | 22 | test('one proxyquire in actual test', function (t) { 23 | var src = fs.readFileSync(require.resolve('./clientside/independent-overrides'), 'utf-8'); 24 | var deps = findDependencies(src) 25 | t.deepEqual(deps, ['../fixtures/foo'], 'finds dependency') 26 | t.end() 27 | }) 28 | -------------------------------------------------------------------------------- /test/fixtures/bar.js: -------------------------------------------------------------------------------- 1 | function bar () { 2 | return 'bar'; 3 | } 4 | 5 | function rab () { 6 | return 'rab'; 7 | } 8 | 9 | module.exports = { bar : bar, rab: rab }; 10 | 11 | -------------------------------------------------------------------------------- /test/fixtures/dependencies.js: -------------------------------------------------------------------------------- 1 | var path = require("path") 2 | // required without immediately passing in original require 3 | , proxy = require("proxyquireify"); 4 | 5 | proxy = proxy(require); 6 | 7 | 8 | var depuno = proxy("./depuno", { path: { extname: function () { return 'blah'; } } }); 9 | 10 | function foo() { 11 | var stubs = { './bar': { wunder: function () { return 'bar'; } } }; 12 | // required and immediately passing in original require 13 | var proxy2 = require('proxyquireify')(require) 14 | , depdos = proxy2('./foo', stubs) 15 | , deptres = proxy('./foober', { path: { sep: '/' } }) 16 | // depuno proxyquired twice, but is only needed once 17 | , depquat = proxy2('./depuno', { path: {} }) 18 | ; 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/foo.js: -------------------------------------------------------------------------------- 1 | var stats = require('./stats') 2 | , bar = require('./bar') 3 | , path = require('path') 4 | ; 5 | 6 | window.foostats.incFooRequires(); 7 | 8 | function bigBar () { 9 | // inline require not working in proxquireify (unlike in original proxyquire) 10 | return bar.bar().toUpperCase(); 11 | } 12 | 13 | function bigRab () { 14 | // module wide require 15 | return bar.rab().toUpperCase(); 16 | } 17 | 18 | function bigExt (file) { 19 | return path.extname(file).toUpperCase(); 20 | } 21 | 22 | function bigBas (file) { 23 | return path.basename(file).toUpperCase(); 24 | } 25 | 26 | module.exports = { 27 | bigBar: bigBar 28 | , bigRab: bigRab 29 | , bigExt: bigExt 30 | , bigBas: bigBas 31 | }; 32 | -------------------------------------------------------------------------------- /test/fixtures/stats.js: -------------------------------------------------------------------------------- 1 | +function() { 2 | 3 | if (window.foostats) return; 4 | 5 | var fooRequires = 0; 6 | window.foostats = { 7 | fooRequires: function () { return fooRequires; } 8 | , incFooRequires: function () { fooRequires++; } 9 | , reset: function () { fooRequires = 0; } 10 | }; 11 | 12 | }(); 13 | -------------------------------------------------------------------------------- /test/fixtures/true.js: -------------------------------------------------------------------------------- 1 | module.exports = true 2 | -------------------------------------------------------------------------------- /test/fixtures/value.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./true') 2 | -------------------------------------------------------------------------------- /test/fixtures/var-declaration.js: -------------------------------------------------------------------------------- 1 | // "var proxy" before assignment 2 | 3 | var proxy, 4 | path = require("path") 5 | 6 | proxy = require("proxyquireify")(require); 7 | 8 | var depuno = proxy("./depuno", { path: { extname: function () { return 'blah'; } } }); 9 | -------------------------------------------------------------------------------- /test/watchify-cli.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tap').test 4 | , child = require('child_process') 5 | , path = require('path') 6 | 7 | test('compatible with watchify cli', function (t) { 8 | t.plan(1) 9 | 10 | var watchify = path.resolve(__dirname, '../node_modules/.bin/watchify') 11 | var plugin = path.resolve(__dirname, '../plugin') 12 | 13 | var options = {cwd: __dirname} 14 | var cp = child.execFile(watchify, ['fixtures/bar.js', '-v', '-p', plugin, '-o', '/dev/null'], options, onEnd) 15 | cp.stderr.on('data', cp.kill.bind(cp, 'SIGTERM')) 16 | 17 | function onEnd (err, stdout, stderr) { 18 | t.equal(err.signal, 'SIGTERM', 'no errors from watchify') 19 | } 20 | }) 21 | --------------------------------------------------------------------------------