{"id":15552435,"url":"https://github.com/bahmutov/really-need","last_synced_at":"2025-09-29T00:33:07.253Z","repository":{"id":25301966,"uuid":"28728411","full_name":"bahmutov/really-need","owner":"bahmutov","description":"Node require wrapper with options for cache busting, pre- and post-processing","archived":false,"fork":false,"pushed_at":"2016-04-13T21:25:42.000Z","size":67,"stargazers_count":108,"open_issues_count":8,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-09-03T08:54:22.555Z","etag":null,"topics":["mock","mocking","node","require","testing"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bahmutov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-01-02T22:35:06.000Z","updated_at":"2025-04-09T14:24:58.000Z","dependencies_parsed_at":"2022-07-25T10:17:15.687Z","dependency_job_id":null,"html_url":"https://github.com/bahmutov/really-need","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/bahmutov/really-need","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahmutov%2Freally-need","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahmutov%2Freally-need/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahmutov%2Freally-need/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahmutov%2Freally-need/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bahmutov","download_url":"https://codeload.github.com/bahmutov/really-need/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahmutov%2Freally-need/sbom","scorecard":{"id":223537,"data":{"date":"2025-08-11","repo":{"name":"github.com/bahmutov/really-need","commit":"5702e51823ffb211e14e8c9e4e63f24763ea7628"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 1/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 3 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T03:09:09.624Z","repository_id":25301966,"created_at":"2025-08-17T03:09:09.625Z","updated_at":"2025-08-17T03:09:09.625Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":277450940,"owners_count":25819971,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-28T02:00:08.834Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mock","mocking","node","require","testing"],"created_at":"2024-10-02T14:19:45.437Z","updated_at":"2025-09-29T00:33:06.994Z","avatar_url":"https://github.com/bahmutov.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# really-need\n\n\u003e Node require wrapper with options for cache busting, pre- and post-processing\n\n[![NPM][really-need-icon] ][really-need-url]\n\n[![Build status][really-need-ci-image] ][really-need-ci-url]\n[![dependencies][really-need-dependencies-image] ][really-need-dependencies-url]\n[![devdependencies][really-need-devdependencies-image] ][really-need-devdependencies-url]\n[![semantic-release][semantic-image] ][semantic-url]\n[![manpm](https://img.shields.io/badge/manpm-%E2%9C%93-3399ff.svg)](https://github.com/bahmutov/manpm)\n\n[really-need-icon]: https://nodei.co/npm/really-need.png?downloads=true\n[really-need-url]: https://npmjs.org/package/really-need\n[really-need-ci-image]: https://travis-ci.org/bahmutov/really-need.png?branch=master\n[really-need-ci-url]: https://travis-ci.org/bahmutov/really-need\n[really-need-dependencies-image]: https://david-dm.org/bahmutov/really-need.png\n[really-need-dependencies-url]: https://david-dm.org/bahmutov/really-need\n[really-need-devdependencies-image]: https://david-dm.org/bahmutov/really-need/dev-status.png\n[really-need-devdependencies-url]: https://david-dm.org/bahmutov/really-need#info=devDependencies\n[semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg\n[semantic-url]: https://github.com/semantic-release/semantic-release\n\n\nFirst call to `require('really-need')` replaced `Module.prototype.require` with a better version.\nOther modules can use new `require` directly. The module making the call to `really-need` needs\nto use the returned value.\n\n```js\nrequire = require('really-need');\n// global require is now a better one!\n// evaluate foo.js again, busting the cache\nvar foo = require('./foo', {\n    // remove previously loaded foo module\n    bustCache: true,\n    // remove from cache AFTER loading\n    keep: false,\n    // skip the real or non-existent file and just use fake source\n    // fake can also be a JavaScript value, object or function\n    fake: 'fake source goes here',\n    pre: function (source, filename) {\n        // transform the source before compiling it\n        return source;\n    },\n    post: function (exported, filename) {\n        // transform the exported object / value from the file\n        return exported;\n    },\n    // inject additional values into foo.js\n    args: {\n        a: 10,\n        b: 5,\n        __dirname: '/some/path'\n    }\n});\n```\n\n\n### API\n\nThe `require` function provided by `really-need` takes a second argument: an options object.\n\n#### bust\n\nRemoves the previously cached module before loading.\nEquivalent to loading and compiling the JavaScript again.\nAlias *bustCache*, default `false`.\n\n#### keep\n\nDeletes loaded instance from the cache after loading to make sure the next `require` call loads\nit again. Alias *cache*, default `false`.\n\n#### pre\n\nGives you a chance to transform the loaded source before compiling it. Can be used to instrument the loaded code,\ncompile other languages into JavaScript, etc. See the related project [node-hook][node-hook] and\nread [Hooking into Node loader for fun and profit][hooking].\n\n```js\n// foo.js\nmodule.exports = function() { return 'foo'; };\n// index.js\nrequire = require('really-need');\nrequire('./foo', {\n    pre: function (source, filename) {\n        return 'console.log(\"loading ' + filename + '\");\\n' + source;\n    }\n});\n// loading /path/to/foo.js\n```\n\n[node-hook]: https://github.com/bahmutov/node-hook\n[hooking]: http://glebbahmutov.com/blog/hooking-into-node-loader-for-fun-and-profit/\n\n#### post\n\nFunction to transform the module's exported value. For example, you can replace the exported function with\nanother one on the fly.\n\n```js\n// foo.js\nmodule.exports = function() { return 'foo'; };\n// index.js\nrequire = require('really-need');\nvar foo = require('./foo', {\n    post: function (exported, filename) {\n        return function () { return 'bar'; }\n    }\n});\nconsole.log(foo()); // \"bar\"\n```\n\n#### parent\n\nYou can set the parent module to be `undefined` or a mock object. For example, to load\na module, but make it think it has no parent\n\n```js\nrequire('./foo', {\n  parent: undefined\n});\n```\n\nYou can use an object (not a plain string though) as a parent too\n\n```js\nrequire('./foo', {\n  parent: {\n    filename: 'ha/ha/mock.js'\n  }\n});\n```\n\n#### args\n\nYou can inject variables into the loaded module source. These variables will be declared at the top\nof the module.\n\n```js\nrequire('./foo', {\n    args: {\n        a: 10,\n        b: 20\n    }\n});\n// foo.js will have var a = 10, b = 20; at the top.\n```\n\nEach value will stringified to JSON, functions will be copied as a string.\n\n#### fake\n\nYou can load non-existing modules from JSON or JavaScript code. Both `pre` and `post` apply.\n\n```js\nrequire('./does-not-exist.json', {\n  fake: '{ \"foo\": 42 }',\n  pre: function (source, filename) { /* source is '{\"foo\": 42}' */ },\n  post: function (o, filename) { /* o is {foo: 42} */ }\n});\n```\n\n```js\nrequire('./does-not-exist.js', {\n  fake: 'module.exports = { foo: 42 }',\n  pre: function (source, filename) { /* source is 'module.exports = {foo: 42}' */ },\n  post: function (o, filename) { /* o is {foo: 42} */ }\n});\n```\n\nYou can even load fake value, without compiling it. The `post` hook still applies if needed\n\n```js\nvar loaded = require('./does-not-exist.js', {\n  fake: { foo: 42 },\n  post: function (o, filename) { /* o is {foo: 42} */ }\n})\n// loaded is { foo: 42 }\n```\n\nSee [Unit test using non-existent files](#unit-test-using-non-existent-files).\n\n#### verbose\n\nPrint debug messages while loading. Alias *debug*, default `false`.\n\n\n## Use examples\n\n### Load a different module\n\nI love [defensive programming][paranoid] and write a lot of assertions when programming.\nMy favorite predicate and type checking library is [check-types][check-types]. It was missing\na few checks we needed, so we wrote and open sourced a library [check-more-types][check-more-types].\nTypically, one needs to require `check-more-type` in any place where `check-types` is used to get\nour library. This means a lot of code editions to make.\n\nWe can use `really-need` to load `check-more-types` instead of `check-types`. Just include\nthis code in the beginning of the application to place `check-more-types` in the cache.\n\n```js\nrequire = require('really-need');\nrequire('check-types', {\n  post: function () {\n    return require('check-more-types');\n  }\n});\n// any code later will get check-more-type\nvar check = require('check-types');\nconsole.log('check.bit(1) =', check.bit(1));\n// check.bit(1) = true\n```\n\n[paranoid]: http://glebbahmutov.com/blog/paranoid-coding/\n[check-types]: https://github.com/philbooth/check-types.js\n[check-more-types]: https://github.com/kensho/check-more-types\n\nYou can see this in action when I work around a broken dependency twice removed from\nmy code in [manpm](https://github.com/bahmutov/manpm)\ninside the [github url parsing][c].\n\n[c]: https://github.com/bahmutov/manpm/blob/a713009fd068da4c99f354b70936ef5ccd3fe7e2/src/get-readme.js#L10\n\n### Instrument code on load\n\nOne can instrument the loaded JavaScript file to collect the code coverage information.\nI am using the excellent [istanbul][istanbul] library in the example below.\n\n```js\nvar istanbul = require('istanbul');\nvar instrumenter = new istanbul.Instrumenter();\nvar instrument = instrumenter.instrumentSync.bind(instrumenter);\nrequire = require('really-need');\nvar foo = require('./foo', {\n  bust: true, // make sure to load foo.js again\n  pre: instrument // signatures for post and instrument match exactly\n});\nconsole.log(foo());\nconsole.log(foo());\nconsole.log(foo());\n// how many times did foo run?\nvar fooFilename = require('path').resolve('./foo.js');\nconsole.log('function in foo.js ran', __coverage__[fooFilename].f[1], 'times');\n// or you can generate detailed reports\n```\n\noutput\n\n    foo\n    foo\n    foo\n    function in foo.js ran 3 times\n\n[istanbul]: https://www.npmjs.com/package/istanbul\n\n### Mock user module during testing\n\nRequire a user module during the suite setup, then modify the module's exports in the `post` function.\nAny module loaded afterwards that requires the mocked module will get the mock value.\n\n```js\n// foo.js\nmodule.exports = function () { return 'foo'; }\n// foo-spec.js\ndescribe('mocking a module', function () {\n  require = require('really-need');\n  var foo;\n  beforeEach(function () {\n    foo = require('./foo', {\n      debug: true,\n      post: function (exported) {\n        // return anything you want.\n        return function mockFoo() {\n          return 'bar';\n        };\n      }\n    });\n  });\n  it('mocked foo returns \"bar\"', function () {\n    console.assert(foo() === 'bar', foo());\n  });\n  it.only('works even if some other module requires ./foo', function () {\n    require('./foo-returns-bar');\n  });\n});\n// foo-returns-bar.js\nvar foo = require('./foo');\nconsole.assert(foo() === 'bar', 'OMG, ./foo.js was mocked!');\n```\n\n### Advanced mocking of environment during testing\n\nSometimes our end to end testing scenario requires using an external service,\nlike hitting Github API. Usually this runs into the throttling limit pretty quickly,\ngenerating a response like this\n\n    {\n      \"message\":\"API rate limit exceeded for 52.0.240.122.\n      (But here's the good news: Authenticated requests get a higher rate limit.\n      Check out the documentation for more details.)\",\n      \"documentation_url\":\"https://developer.github.com/v3/#rate-limiting\"\n    }\n\nWe like to be able to test the entire program though, so how do we mock the API in this case?\n\nAs an example, take a look at [changed-log](https://github.com/bahmutov/changed-log).\nIt shows the commit messages for any NPM package or Github repo between specific versions.\nOne can install and run `changed-log` like this\n\n    npm install -g changed-log\n    changed-log chalk 0.3.0 0.5.1\n\nDuring testing I like to run the above command to make sure it works. Thus I defined\na script in the `package.json`\n\n    \"scripts\": {\n      \"chalk\": \"node bin/changed-log.js chalk 0.3.0 0.5.1\"\n    }\n\nDuring the program's run, the Github api is hit twice: first to collect the commit ids\nbetween the two given versions, and then to collect the actual commit messages.\n\nFirst, I collected the JSON response from the API as received inside the source files\n`changed-log/src/get-commits-from-tags.js` and `changed-log/src/get-commits-between.js`.\nI saved these objects as plain JSON files in a folder\n[changed-log/mocks](https://github.com/bahmutov/changed-log/tree/master/mocks).\n\nSecond, I wrote a new source file that will mock the above two methods to return the\nJSON from the files. Take a look at [changed-log/mocks/mock-for-chalk.js][mock-for-chalk.js].\nThis file sets the mock functions to be loaded into the module cache.\n\n```js\n// load mock data\nvar Promise = require('bluebird');\nvar mockCommits = require('./mock-chalk-ids.json');\nvar mockComments = require('./mock-chalk-comments.json');\n// grab a better require\nrequire = require('really-need');\n// prepare the mock functions to be plugged in\nfunction mockGetCommitsFromTags(info) {\n  return Promise.resolve(mockCommits);\n}\nfunction mockGetComments(info) {\n  return Promise.resolve(mockComments);\n}\n// finally, place the mock functions into module cache\nrequire('../src/get-commits-from-tags', {\n  post: function (exported, filename) {\n    return mockGetCommitsFromTags;\n  }\n});\nrequire('../src/get-commits-between', {\n  post: function (exported, filename) {\n    return mockGetComments;\n  }\n});\n// to be continued ...\n```\n\nThis is how we run the `chalk` command with the mocked environment. We will run\nthe `mock-for-chalk.js` and let it load the normal `bin/changed-log.js`. Thus the test\nscript is now the following command\n\n    \"scripts\": {\n      \"chalk-with-mock\": \"node mocks/mock-for-chalk.js bin/changed-log.js chalk 0.3.0 0.5.1\",\n    }\n\nThe `mock-for-chalk.js` continues after cache mocking\n\n```js\n// same mock as above\n(function adjustProcessArgs() {\n  process.argv.splice(1, 1);\n  console.log('removed this filename from process arguments');\n  process.argv[1] = require('path').resolve(process.argv[1]);\n  console.log('resolved the name of the next script to load');\n}());\nconsole.log('loading the real script from %s', process.argv[1]);\nrequire(process.argv[1]);\n```\n\nAfter mocking we adjust the program's arguments array and let the actual program take over,\nas it was the original script. Mission accomplished - end to end testing, but with\nmocked code and data.\n\n[mock-for-chalk.js]: https://github.com/bahmutov/changed-log/blob/master/mocks/mock-for-chalk.js\n\n### Inject values into the script on load\n\nAfter the source for the module has been loaded and transformed using `pre` function, the `Module` compiles\nit into the exported value. You can inject extra variables using `args` property. For example, we\ncan pass values to be added\n\n```js\n// sum.js\nmodule.exports = a + b;\n// index.js\nrequire = require('really-need');\nvar sum = require('./sum', {\n  args: {\n    a: 10,\n    b: 2\n  }\n});\nconsole.log(sum);\n// output 12\n```\n\nNotice that variables `a` and `b` are not declared in `sum.js`. Usually this means a `ReferenceError`, but\nwe are injecting values at load time. We could have done similar thing using `pre` callback, but using `args`\nis simpler and does not replace any existing source transformations.\n\nYou can even mess with built-in variables. When `Module` compiles the source, it wraps the loaded source\ninto a function call. Print the `module` object from Node REPL to see before / after text\n\n```js\nrequire('module');\nwrapper:\n [ '(function (exports, require, module, __filename, __dirname) { ',\n   '\\n});' ],\n```\nBecause we are appending `args` directly to the loaded source, they take precedence. Thus we can do things like\noverwriting `__filename`.\n\n```js\n// filename.js\nconsole.log('filename', __filename);\n// index.js\nrequire = require('really-need');\nrequire('./filename', {\n  args: {\n    __filename: 'hi there'\n  }\n});\n// prints filename hi there\n```\n\nWe can even disable all calls to `require` from the given script\n\n```js\n// another-require.js\nrequire('something');\n// index.js\nrequire = require('really-need');\nrequire('./another-require', {\n  args: {\n    require: function (name) {\n      console.log('no requires allowed');\n    }\n  }\n});\n// prints \"no requires allowed\"\n```\n\n### Determine if a module was really used\n\nRead the blog post [Was NodeJS module used](http://glebbahmutov.com/blog/was-nodejs-module-used/)\nand see the project [was-it-used](https://github.com/bahmutov/was-it-used).\n\n### Unit test private variables / functions\n\nYou can quickly load / access most private functions and variables, see\n[describe-it](https://github.com/bahmutov/describe-it) project for details\n\n```js\n// get-foo.js\n(function reallyPrivate() {\n  function getFoo() {\n    return 'foo';\n  }\n}());\n```\n\nNotice that `getFoo` is not exported from the file, thus only can be tested indirectly. Or is it?\n\n```js\n// get-foo-spec.js\nvar describeIt = require('describe-it');\ndescribeIt(__dirname + '/foo.js', 'getFoo()', function (getFn) {\n  it('returns \"foo\"', function () {\n    var getFoo = getFn();\n    console.assert(getFoo() === 'foo');\n  });\n});\n```\n\nCustom loader with source modification makes it simple to gain access to any desired\nfunction declaration, functional expression and even most variables.\n\n### Unit test using non-existent files\n\nImagine a piece of code under test loads a file. You do not want to create a fake file\nfor every unit test. You can easily create fake modules before the code runs, letting it\nload cached fake copy.\n\n```js\n// get-version.js\nfunction getVersion() {\n  var pkg = require(process.cwd() + '/example.json');\n  return pkg.version;\n}\nmodule.exports = getVersion;\n```\n\nThe unit test places the fake module into the require cache\n\n```js\n// get-version-spec.js\nrequire = require('../..');\ndescribe('get version', function () {\n  var getVersion = require('./get-version');\n  var loaded = require(process.cwd() + '/example.json', {\n    fake: { version: '1.2.3' }\n  });\n  it('returns 1.2.3', function () {\n    console.assert(getVersion() === '1.2.3');\n  });\n});\n```\n\n\n### How it works\n\nRead [Hacking Node require](http://glebbahmutov.com/blog/hacking-node-require/)\n\n\n### Small print\n\nAuthor: Gleb Bahmutov \u0026copy; 2014\n\n* [@bahmutov](https://twitter.com/bahmutov)\n* [glebbahmutov.com](http://glebbahmutov.com)\n* [blog](http://glebbahmutov.com/blog)\n\nLicense: MIT - do anything with the code, but don't blame me if it does not work.\n\nSpread the word: tweet, star on github, etc.\n\nSupport: if you find any problems with this module, email / tweet /\n[open issue](https://github.com/bahmutov/really-need/issues) on Github\n\n\n\n## MIT License\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Gleb Bahmutov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbahmutov%2Freally-need","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbahmutov%2Freally-need","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbahmutov%2Freally-need/lists"}