From d671e7600bd96f3c6c23697575436e89fa407c99 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 18 Oct 2021 14:00:50 -0700 Subject: [PATCH] chore!: Normalize repository, dropping node <10.13 support (#118) --- .eslintrc | 1 - .github/workflows/dev.yml | 75 +++ .github/workflows/release.yml | 16 + .gitignore | 62 +- .npmrc | 1 + .prettierignore | 3 + .travis.yml | 19 - CHANGELOG | 127 ---- LICENSE | 37 +- README.md | 343 +++++++---- UPGRADING.md | 28 - appveyor.yml | 27 - index.js | 76 +-- lib/build_config_name.js | 4 +- lib/file_search.js | 2 +- lib/find_config.js | 6 +- lib/find_cwd.js | 2 +- lib/get_node_flags.js | 1 - lib/parse_options.js | 2 +- lib/register_loader.js | 10 +- lib/silent_require.js | 2 +- package.json | 59 +- test/.eslintrc | 3 - test/.gitkeep | 0 test/build_config_name.js | 80 +++ test/file_search.js | 15 + test/find_config.js | 104 ++++ test/find_cwd.js | 41 ++ test/fixtures/configfiles/index.json | 2 +- test/fixtures/configfiles/require-md.js | 16 +- test/fixtures/configfiles/require-txt.js | 16 +- .../developing_yourself/app1/index.js | 6 +- .../developing_yourself/app2/index.js | 6 +- test/fixtures/developing_yourself/main.js | 6 +- .../prepare-execute/nodeflags_only.js | 6 +- test/fixtures/prepare-execute/v8flags.js | 8 +- .../prepare-execute/v8flags_config.js | 6 +- .../fixtures/prepare-execute/v8flags_error.js | 14 +- .../prepare-execute/v8flags_function.js | 14 +- .../fixtures/prepare-execute/v8flags_value.js | 8 +- test/fixtures/register_loader/require-cfg.js | 16 +- test/fixtures/register_loader/require-conf.js | 16 +- .../register_loader/require-file-b.js | 16 +- .../register_loader/require-file-bc.js | 16 +- .../register_loader/require-file-cd.js | 16 +- .../register_loader/require-file-d.js | 16 +- .../register_loader/require-file-ecd.js | 16 +- .../register_loader/require-file-fcd.js | 16 +- test/fixtures/register_loader/require-rc.js | 16 +- test/fixtures/respawn_and_require.js | 23 +- test/get_node_flags.js | 117 ++++ test/index.js | 556 ++++++++++-------- test/lib/build_config_name.js | 58 -- test/lib/file_search.js | 12 - test/lib/find_config.js | 85 --- test/lib/find_cwd.js | 31 - test/lib/get_node_flags.js | 69 --- test/lib/parse_options.js | 64 -- test/lib/silent_require.js | 17 - test/parse_options.js | 75 +++ test/{lib => }/register_loader.js | 140 ++--- test/silent_require.js | 21 + 62 files changed, 1448 insertions(+), 1218 deletions(-) create mode 100644 .github/workflows/dev.yml create mode 100644 .github/workflows/release.yml create mode 100644 .npmrc create mode 100644 .prettierignore delete mode 100644 .travis.yml delete mode 100644 CHANGELOG delete mode 100644 UPGRADING.md delete mode 100644 appveyor.yml delete mode 100644 test/.eslintrc create mode 100644 test/.gitkeep create mode 100644 test/build_config_name.js create mode 100644 test/file_search.js create mode 100644 test/find_config.js create mode 100644 test/find_cwd.js create mode 100644 test/get_node_flags.js delete mode 100644 test/lib/build_config_name.js delete mode 100644 test/lib/file_search.js delete mode 100644 test/lib/find_config.js delete mode 100644 test/lib/find_cwd.js delete mode 100644 test/lib/get_node_flags.js delete mode 100644 test/lib/parse_options.js delete mode 100644 test/lib/silent_require.js create mode 100644 test/parse_options.js rename test/{lib => }/register_loader.js (67%) create mode 100644 test/silent_require.js diff --git a/.eslintrc b/.eslintrc index fb7a12c..b7c162c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,7 +1,6 @@ { "extends": "gulp", "rules": { - "max-len": [0, 90], "max-statements": [1, 50], "no-empty": ["error", { "allowEmptyCatch": true }] } diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml new file mode 100644 index 0000000..3b07263 --- /dev/null +++ b/.github/workflows/dev.yml @@ -0,0 +1,75 @@ +name: dev +on: + pull_request: + push: + branches: + - master + - main +env: + CI: true + +jobs: + prettier: + name: Format code + runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Prettier + uses: gulpjs/prettier_action@v3.0 + with: + commit_message: 'chore: Run prettier' + prettier_options: '--write .' + + test: + name: Tests for Node ${{ matrix.node }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + node: [10, 12, 14, 16] + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - name: Clone repository + uses: actions/checkout@v2 + + - name: Set Node.js version + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node }} + + - run: node --version + - run: npm --version + + - name: Install npm dependencies + run: npm install + + - name: Run lint + run: npm run lint + + - name: Run tests + run: npm test + + - name: Coveralls + uses: coverallsapp/github-action@v1.1.2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + flag-name: ${{matrix.os}}-node-${{ matrix.node }} + parallel: true + + coveralls: + needs: test + name: Finish up + + runs-on: ubuntu-latest + steps: + - name: Coveralls Finished + uses: coverallsapp/github-action@v1.1.2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + parallel-finished: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..87cd13c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,16 @@ +name: release +on: + push: + branches: + - master + - main + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: GoogleCloudPlatform/release-please-action@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + release-type: node + package-name: release-please-action diff --git a/.gitignore b/.gitignore index 7323c06..58a757a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,67 @@ # Logs logs *.log -npm-debug.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* -# Coverage direcory used by tools like istanbul +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul coverage + +# nyc test coverage .nyc_output -.coveralls.yml -# Dependency directory -node_modules +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ # Optional npm cache directory .npm -# Files generated by platform. +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next + +# Garbage files .DS_Store -# npm lock file -package-lock.json +# Test results +test.xunit diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..c96ebe0 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +coverage/ +.nyc_output/ +CHANGELOG.md diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 42ed191..0000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: node_js -node_js: - - "10" - - "8" - - "6" - - "5" - - "4" - - "0.12" - - "0.10" -matrix: - fast_finish: true -script: if [ $(echo "${TRAVIS_NODE_VERSION}" | cut -d'.' -f1) -ge 6 ]; then - npm run cover; - else - npm test; - fi -os: - - linux - - osx diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index e612f4e..0000000 --- a/CHANGELOG +++ /dev/null @@ -1,127 +0,0 @@ -v2.2.2: - date: 2016-05-20 - changes: - - Update dependencies. -v2.2.1: - date: 2016-03-23 - changes: - - Make sure that v8 flags are passed properly through the `respawn` event -v2.1.0: - date: 2015-05-20 - changes: - - Use rechoir to autoload modules. -v2.0.3: - date: 2015-03-31 - changes: - - Internal bugfix, don't wrap callback error in another error, idiot. -v2.0.2: - date: 2015-02-24 - changes: - - Support process.env.NODE_PATH when resolving module. -v2.0.1: - date: 2015-02-01 - changes: - - Find modulePath correctly when devving against yourself. -v2.0.0: - date: 2015-01-15 - changes: - - Rename `nodeFlags` to `v8Flags` and make it async. -v1.0.4: - date: 2015-01-04 - changes: - - Detect config extension using basename, not full path. -v1.0.0: - date: 2014-12-16 - changes: - - Update dependencies -v0.13.6: - date: 2014-11-07 - changes: - - Don't include artwork on npm. -v0.13.5: - date: 2014-10-10 - changes: - - Only attempt to resolve the real path of configFile if it is actually a symlink. -v0.13.4: - date: 2014-10-07 - changes: - - Set configBase to the directory of the symlink, not the directory of its real location. -v0.13.3: - date: 2014-10-06 - changes: - - Return the real location of symlinked config files. -v0.13.2: - date: 2014-09-12 - changes: - - Include flags in respawn event. I really miss `npm publish --force`. -v0.13.1: - date: 2014-09-12 - changes: - - Slight performance tweak. -v0.13.0: - date: 2014-09-12 - changes: - - Support passing flags to node with `nodeFlags` option. -v0.12.1: - date: 2014-06-27 - changes: - - Support preloading modules for compound extensions like `.coffee.md`. -v0.12.0: - date: 2014-06-27 - changes: - - Respect order of extensions when searching for config. - - Rename `configNameRegex` environment property to `configNameSearch`. -v0.11.3: - date: 2014-06-09 - changes: - - Make cwd match configBase if cwd isn't explicitly provided -v0.11.2: - date: 2014-06-04 - changes: - - Regression fix: coerce preloads into array before attempting to push more -v0.11.1: - date: 2014-06-02 - changes: - - Update dependencies. -v0.11.0: - date: 2014-05-27 - changes: - - Refactor and remove options parsing. -v0.10.0: - date: 2014-05-06 - changes: - - Remove `addExtension` in favor of `extension` option. - - Support preloading modules based on extension. -v0.9.7: - date: 2014-04-28 - changes: - - Locate local module in cwd even if config isn't present. -v0.9.6: - date: 2014-04-02 - changes: - - Fix regression where external modules are not properly required. - - Ignore configPathFlag / cwdFlag if the value isn't a string -v0.9.3: - date: 2014-02-28 - changes: - - Fix regression where developing against self doesn't correctly set cwd. -v0.9.0: - date: 2014-02-28 - changes: - - Use liftoff instance as context (`this`) for launch callback. - - Support split --cwd and --configfile locations. - - Rename `configLocationFlag` to `configPathFlag` - - Support node 0.8+ -v0.8.7: - date: 2014-02-24 - changes: - - Pass environment as first argument to `launch`. -v0.8.5: - date: 2014-02-19 - changes: - - Implement `addExtensions` option. - - Default to `index.js` if `modulePackage` has no `main` property. -v0.8.4: - date: 2014-02-05 - changes: - - Initial public release. diff --git a/LICENSE b/LICENSE index a55f5b7..0a01e92 100644 --- a/LICENSE +++ b/LICENSE @@ -1,22 +1,21 @@ -Copyright (c) 2014 Tyler Kellen +The MIT License (MIT) -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: +Copyright (c) 2014-2017 Tyler Kellen , 2017-2021 Blaine Bublitz , Eric Schoffstall and other contributors -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 50ec558..1f81a20 100644 --- a/README.md +++ b/README.md @@ -4,30 +4,33 @@

-# liftoff [![Build Status](http://img.shields.io/travis/js-cli/js-liftoff.svg?label=travis-ci)](http://travis-ci.org/js-cli/js-liftoff) [![Build status](https://img.shields.io/appveyor/ci/phated/js-liftoff.svg?label=appveyor)](https://ci.appveyor.com/project/phated/js-liftoff) +

+ + + +

+# liftoff -> Launch your command line tool with ease. +[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Coveralls Status][coveralls-image]][coveralls-url] -[![NPM](https://nodei.co/npm/liftoff.png)](https://nodei.co/npm/liftoff/) +Launch your command line tool with ease. ## What is it? -[See this blog post](http://weblog.bocoup.com/building-command-line-tools-in-node-with-liftoff/), [check out this proof of concept](https://github.com/js-cli/js-hacker), or read on. -Say you're writing a CLI tool. Let's call it [hacker](https://github.com/js-cli/js-hacker). You want to configure it using a `Hackerfile`. This is node, so you install `hacker` locally for each project you use it in. But, in order to get the `hacker` command in your PATH, you also install it globally. +[See this blog post][liftoff-blog], [check out this proof of concept][hacker], or read on. -Now, when you run `hacker`, you want to configure what it does using the `Hackerfile` in your current directory, and you want it to execute using the local installation of your tool. Also, it'd be nice if the `hacker` command was smart enough to traverse up your folders until it finds a `Hackerfile`—for those times when you're not in the root directory of your project. Heck, you might even want to launch `hacker` from a folder outside of your project by manually specifying a working directory. Liftoff manages this for you. +Say you're writing a CLI tool. Let's call it [hacker]. You want to configure it using a `Hackerfile`. This is node, so you install `hacker` locally for each project you use it in. But, in order to get the `hacker` command in your PATH, you also install it globally. -So, everything is working great. Now you can find your local `hacker` and `Hackerfile` with ease. Unfortunately, it turns out you've authored your `Hackerfile` in coffee-script, or some other JS variant. In order to support *that*, you have to load the compiler for it, and then register the extension for it with node. Good news, Liftoff can do that, and a whole lot more, too. +Now, when you run `hacker`, you want to configure what it does using the `Hackerfile` in your current directory, and you want it to execute using the local installation of your tool. Also, it'd be nice if the `hacker` command was smart enough to traverse up your folders until it finds a `Hackerfile`—for those times when you're not in the root directory of your project. Heck, you might even want to launch `hacker` from a folder outside of your project by manually specifying a working directory. Liftoff manages this for you. -## API - -### constructor(opts) +So, everything is working great. Now you can find your local `hacker` and `Hackerfile` with ease. Unfortunately, it turns out you've authored your `Hackerfile` in coffee-script, or some other JS variant. In order to support _that_, you have to load the compiler for it, and then register the extension for it with node. Good news, Liftoff can do that, and a whole lot more, too. -Create an instance of Liftoff to invoke your application. +## Usage -An example utilizing all options: ```js +const Liftoff = require('liftoff'); + const Hacker = new Liftoff({ name: 'hacker', processTitle: 'hacker', @@ -36,171 +39,198 @@ const Hacker = new Liftoff({ extensions: { '.js': null, '.json': null, - '.coffee': 'coffee-script/register' + '.coffee': 'coffee-script/register', }, - v8flags: ['--harmony'] // or v8flags: require('v8flags') + v8flags: ['--harmony'], // or v8flags: require('v8flags') +}); + +Hacker.prepare({}, function (env) { + Hacker.execute(env, function (env) { + // Do post-execute things + }); }); ``` +## API + +### constructor(opts) + +Create an instance of Liftoff to invoke your application. + #### opts.name Sugar for setting `processTitle`, `moduleName`, `configName` automatically. -Type: `String` +Type: `String` + Default: `null` These are equivalent: + ```js const Hacker = Liftoff({ processTitle: 'hacker', moduleName: 'hacker', - configName: 'hackerfile' + configName: 'hackerfile', }); ``` + ```js -const Hacker = Liftoff({name:'hacker'}); +const Hacker = Liftoff({ name: 'hacker' }); ``` -#### opts.moduleName +Type: `String` -Sets which module your application expects to find locally when being run. - -Type: `String` Default: `null` #### opts.configName -Sets the name of the configuration file Liftoff will attempt to find. Case-insensitive. +Sets the name of the configuration file Liftoff will attempt to find. Case-insensitive. + +Type: `String` -Type: `String` Default: `null` #### opts.extensions -Set extensions to include when searching for a configuration file. If an external module is needed to load a given extension (e.g. `.coffee`), the module name should be specified as the value for the key. +Set extensions to include when searching for a configuration file. If an external module is needed to load a given extension (e.g. `.coffee`), the module name should be specified as the value for the key. + +Type: `Object` -Type: `Object` Default: `{".js":null,".json":null}` **Examples:** -In this example Liftoff will look for `myappfile{.js,.json,.coffee}`. If a config with the extension `.coffee` is found, Liftoff will try to require `coffee-script/require` from the current working directory. +In this example Liftoff will look for `myappfile{.js,.json,.coffee}`. If a config with the extension `.coffee` is found, Liftoff will try to require `coffee-script/require` from the current working directory. + ```js const MyApp = new Liftoff({ name: 'myapp', extensions: { '.js': null, '.json': null, - '.coffee': 'coffee-script/register' - } + '.coffee': 'coffee-script/register', + }, }); ``` In this example, Liftoff will look for `.myapp{rc}`. + ```js const MyApp = new Liftoff({ name: 'myapp', configName: '.myapp', extensions: { - 'rc': null - } + rc: null, + }, }); ``` -In this example, Liftoff will automatically attempt to load the correct module for any javascript variant supported by [interpret](https://github.com/js-cli/js-interpret) (as long as it does not require a register method). +In this example, Liftoff will automatically attempt to load the correct module for any javascript variant supported by [interpret] (as long as it does not require a register method). ```js const MyApp = new Liftoff({ name: 'myapp', - extensions: require('interpret').jsVariants + extensions: require('interpret').jsVariants, }); ``` + #### opts.v8flags -Any flag specified here will be applied to node, not your program. Useful for supporting invocations like `myapp --harmony command`, where `--harmony` should be passed to node, not your program. This functionality is implemented using [flagged-respawn](http://github.com/js-cli/js-flagged-respawn). To support all v8flags, see [v8flags](https://github.com/js-cli/js-v8flags). +Any flag specified here will be applied to node, not your program. Useful for supporting invocations like `myapp --harmony command`, where `--harmony` should be passed to node, not your program. This functionality is implemented using [flagged-respawn]. To support all v8flags, see [v8flags]. + +Type: `Array` or `Function` -Type: `Array|Function` Default: `null` If this method is a function, it should take a node-style callback that yields an array of flags. #### opts.processTitle -Sets what the [process title](http://nodejs.org/api/process.html#process_process_title) will be. +Sets what the [process title][process-title] will be. + +Type: `String` -Type: `String` Default: `null` #### opts.completions(type) A method to handle bash/zsh/whatever completions. -Type: `Function` +Type: `Function` + Default: `null` #### opts.configFiles An object of configuration files to find. Each property is keyed by the default basename of the file being found, and the value is an object of [path arguments](#path-arguments) keyed by unique names. -__Note:__ This option is useful if, for example, you want to support an `.apprc` file in addition to an `appfile.js`. If you only need a single configuration file, you probably don't need this. In addition to letting you find multiple files, this option allows more fine-grained control over how configuration files are located. +**Note:** This option is useful if, for example, you want to support an `.apprc` file in addition to an `appfile.js`. If you only need a single configuration file, you probably don't need this. In addition to letting you find multiple files, this option allows more fine-grained control over how configuration files are located. + +Type: `Object` -Type: `Object` Default: `null` #### Path arguments -The [`fined`](https://github.com/js-cli/fined) module accepts a string representing the path to search or an object with the following keys: +The [`fined`][fined] module accepts a string representing the path to search or an object with the following keys: -* `path` __(required)__ +- `path` **(required)** The path to search. Using only a string expands to this property. - Type: `String` + Type: `String` + Default: `null` -* `name` +- `name` The basename of the file to find. Extensions are appended during lookup. - Type: `String` + Type: `String` + Default: Top-level key in `configFiles` -* `extensions` +- `extensions` The extensions to append to `name` during lookup. See also: [`opts.extensions`](#optsextensions). - Type: `String|Array|Object` + Type: `String` or `Array` or `Object` Default: The value of [`opts.extensions`](#optsextensions) -* `cwd` +- `cwd` The base directory of `path` (if relative). - Type: `String` + Type: `String` + Default: The value of [`opts.cwd`](#optscwd) -* `findUp` +- `findUp` Whether the `path` should be traversed up to find the file. - Type: `Boolean` + Type: `Boolean` + Default: `false` **Examples:** In this example Liftoff will look for the `.hacker.js` file relative to the `cwd` as declared in `configFiles`. + ```js const MyApp = new Liftoff({ name: 'hacker', configFiles: { '.hacker': { - cwd: '.' - } - } + cwd: '.', + }, + }, }); ``` In this example, Liftoff will look for `.hackerrc` in the home directory. + ```js const MyApp = new Liftoff({ name: 'hacker', @@ -209,15 +239,16 @@ const MyApp = new Liftoff({ home: { path: '~', extensions: { - 'rc': null - } - } - } - } + rc: null, + }, + }, + }, + }, }); ``` In this example, Liftoff will look in the `cwd` and then lookup the tree for the `.hacker.js` file. + ```js const MyApp = new Liftoff({ name: 'hacker', @@ -225,14 +256,15 @@ const MyApp = new Liftoff({ '.hacker': { up: { path: '.', - findUp: true - } - } - } + findUp: true, + }, + }, + }, }); ``` In this example, the `name` is overridden and the key is ignored so Liftoff looks for `.override.js`. + ```js const MyApp = new Liftoff({ name: 'hacker', @@ -240,14 +272,15 @@ const MyApp = new Liftoff({ hacker: { override: { path: '.', - name: '.override' - } - } - } + name: '.override', + }, + }, + }, }); ``` In this example, Liftoff will use the home directory as the `cwd` and looks for `~/.hacker.js`. + ```js const MyApp = new Liftoff({ name: 'hacker', @@ -255,22 +288,22 @@ const MyApp = new Liftoff({ '.hacker': { home: { path: '.', - cwd: '~' - } - } - } + cwd: '~', + }, + }, + }, }); ``` ### prepare(opts, callback(env)) -Prepares the environment for your application with provided options, and invokes your callback with the calculated environment as the first argument. The environment can be modified before using it as the first argument to `execute`. +Prepares the environment for your application with provided options, and invokes your callback with the calculated environment as the first argument. The environment can be modified before using it as the first argument to `execute`. **Example Configuration w/ Options Parsing:** ```js const Liftoff = require('liftoff'); -const MyApp = new Liftoff({name:'myapp'}); +const MyApp = new Liftoff({ name: 'myapp' }); const argv = require('minimist')(process.argv.slice(2)); const onExecute = function (env, argv) { // Do post-execute things @@ -280,12 +313,15 @@ const onPrepare = function (env) { console.log('my liftoff config is:', this); MyApp.execute(env, onExecute); }; -MyApp.prepare({ - cwd: argv.cwd, - configPath: argv.myappfile, - preload: argv.preload, - completion: argv.completion -}, onPrepare); +MyApp.prepare( + { + cwd: argv.cwd, + configPath: argv.myappfile, + preload: argv.preload, + completion: argv.completion, + }, + onPrepare +); ``` **Example w/ modified environment** @@ -296,21 +332,24 @@ const Hacker = new Liftoff({ name: 'hacker', configFiles: { '.hacker': { - home: { path: '.', cwd: '~' } - } - } + home: { path: '.', cwd: '~' }, + }, + }, }); const onExecute = function (env, argv) { // Do post-execute things }; const onPrepare = function (env) { - env.configProps = ['home', 'cwd'].map(function(dirname) { - return env.configFiles['.hacker'][dirname] - }).filter(function(filePath) { - return Boolean(filePath); - }).reduce(function(config, filePath) { - return mergeDeep(config, require(filePath)); - }, {}); + env.configProps = ['home', 'cwd'] + .map(function (dirname) { + return env.configFiles['.hacker'][dirname]; + }) + .filter(function (filePath) { + return Boolean(filePath); + }) + .reduce(function (config, filePath) { + return mergeDeep(config, require(filePath)); + }, {}); if (env.configProps.hackerfile) { env.configPath = path.resolve(env.configProps.hackerfile); @@ -324,20 +363,28 @@ Hacker.prepare({}, onPrepare); #### opts.cwd -Change the current working directory for this launch. Relative paths are calculated against `process.cwd()`. +Change the current working directory for this execution. Relative paths are calculated against `process.cwd()`. + +Type: `String` -Type: `String` Default: `process.cwd()` **Example Configuration:** + ```js const argv = require('minimist')(process.argv.slice(2)); -MyApp.launch({ - cwd: argv.cwd -}, invoke); +MyApp.prepare( + { + cwd: argv.cwd, + }, + function (env) { + MyApp.execute(env, invoke); + } +); ``` **Matching CLI Invocation:** + ``` myapp --cwd ../ ``` @@ -346,59 +393,76 @@ myapp --cwd ../ Don't search for a config, use the one provided. **Note:** Liftoff will assume the current working directory is the directory containing the config file unless an alternate location is explicitly specified using `cwd`. -Type: `String` +Type: `String` + Default: `null` **Example Configuration:** + ```js var argv = require('minimist')(process.argv.slice(2)); -MyApp.launch({ - configPath: argv.myappfile -}, invoke); +MyApp.prepare( + { + configPath: argv.myappfile, + }, + function (env) { + MyApp.execute(env, invoke); + } +); ``` **Matching CLI Invocation:** -``` + +```sh myapp --myappfile /var/www/project/Myappfile.js ``` **Examples using `cwd` and `configPath` together:** These are functionally identical: -``` + +```sh myapp --myappfile /var/www/project/Myappfile.js myapp --cwd /var/www/project ``` These can run myapp from a shared directory as though it were located in another project: -``` + +```sh myapp --myappfile /Users/name/Myappfile.js --cwd /var/www/project1 myapp --myappfile /Users/name/Myappfile.js --cwd /var/www/project2 ``` #### opts.preload -A string or array of modules to attempt requiring from the local working directory before invoking the launch callback. +A string or array of modules to attempt requiring from the local working directory before invoking the execute callback. -Type: `String|Array` +Type: `String|Array` Default: `null` **Example Configuration:** + ```js var argv = require('minimist')(process.argv.slice(2)); -MyApp.launch({ - preload: argv.preload -}, invoke); +MyApp.prepare( + { + preload: argv.preload, + }, + function (env) { + MyApp.execute(env, invoke); + } +); ``` **Matching CLI Invocation:** -```js + +```sh myapp --preload coffee-script/register ``` #### callback(env) -A function called after your environment is prepared. A good place to modify the environment before calling `execute`. When invoked, `this` will be your instance of Liftoff. The `env` param will contain the following keys: +A function called after your environment is prepared. A good place to modify the environment before calling `execute`. When invoked, `this` will be your instance of Liftoff. The `env` param will contain the following keys: - `cwd`: the current working directory - `preload`: an array of modules that liftoff tried to pre-load @@ -411,13 +475,13 @@ A function called after your environment is prepared. A good place to modify th ### execute(env, [forcedFlags], callback(env, argv)) -A function to start your application, based on the `env` given. Optionally takes an array of `forcedFlags`, which will force a respawn with those node or V8 flags during startup. Invokes your callback with the environment and command-line arguments (minus node & v8 flags) after the application has been executed. +A function to start your application, based on the `env` given. Optionally takes an array of `forcedFlags`, which will force a respawn with those node or V8 flags during startup. Invokes your callback with the environment and command-line arguments (minus node & v8 flags) after the application has been executed. **Example:** ```js const Liftoff = require('liftoff'); -const MyApp = new Liftoff({name:'myapp'}); +const MyApp = new Liftoff({ name: 'myapp' }); const onExecute = function (env, argv) { // Do post-execute things console.log('my environment is:', env); @@ -433,7 +497,7 @@ MyApp.prepare({}, onPrepare); #### callback(env, argv) -A function called after your application is executed. When invoked, `this` will be your instance of Liftoff, `argv` will be all command-line arguments (minus node & v8 flags), and `env` will contain the following keys: +A function called after your application is executed. When invoked, `this` will be your instance of Liftoff, `argv` will be all command-line arguments (minus node & v8 flags), and `env` will contain the following keys: - `cwd`: the current working directory - `preload`: an array of modules that liftoff tried to pre-load @@ -451,9 +515,9 @@ A function called after your application is executed. When invoked, `this` will Emitted before a module is pre-load. (But for only a module which is specified by `opts.preload`.) ```js -var Hacker = new Liftoff({name:'hacker', preload:'coffee-script'}); +var Hacker = new Liftoff({ name: 'hacker', preload: 'coffee-script' }); Hacker.on('preload:before', function (name) { - console.log('Requiring external module: '+name+'...'); + console.log('Requiring external module: ' + name + '...'); }); ``` @@ -462,9 +526,9 @@ Hacker.on('preload:before', function (name) { Emitted when a module has been pre-loaded. ```js -var Hacker = new Liftoff({name:'hacker'}); +var Hacker = new Liftoff({ name: 'hacker' }); Hacker.on('preload:success', function (name, module) { - console.log('Required external module: '+name+'...'); + console.log('Required external module: ' + name + '...'); // automatically register coffee-script extensions if (name === 'coffee-script') { module.register(); @@ -477,7 +541,7 @@ Hacker.on('preload:success', function (name, module) { Emitted when a requested module cannot be preloaded. ```js -var Hacker = new Liftoff({name:'hacker'}); +var Hacker = new Liftoff({ name: 'hacker' }); Hacker.on('preload:failure', function (name, err) { console.log('Unable to load:', name, err); }); @@ -491,11 +555,11 @@ Emitted when a loader that matches an extension has been loaded. var Hacker = new Liftoff({ name: 'hacker', extensions: { - '.ts': 'ts-node/register' - } + '.ts': 'ts-node/register', + }, }); Hacker.on('loader:success', function (name, module) { - console.log('Required external module: '+name+'...'); + console.log('Required external module: ' + name + '...'); }); ``` @@ -507,8 +571,8 @@ Emitted when no loader for an extension can be loaded. Emits an error for each f var Hacker = new Liftoff({ name: 'hacker', extensions: { - '.ts': 'ts-node/register' - } + '.ts': 'ts-node/register', + }, }); Hacker.on('loader:failure', function (name, err) { console.log('Unable to load:', name, err); @@ -522,7 +586,7 @@ Emitted when Liftoff re-spawns your process (when a [`v8flags`](#optsv8flags) is ```js var Hacker = new Liftoff({ name: 'hacker', - v8flags: ['--harmony'] + v8flags: ['--harmony'], }); Hacker.on('respawn', function (flags, child) { console.log('Detected node flags:', flags); @@ -535,13 +599,44 @@ Event will be triggered for this command: ## Examples -Check out how [gulp](https://github.com/gulpjs/gulp-cli/blob/master/index.js) uses Liftoff. +Check out how [gulp][gulp-cli-index] uses Liftoff. -For a bare-bones example, try [the hacker project](https://github.com/js-cli/js-hacker/blob/master/bin/hacker.js). +For a bare-bones example, try [the hacker project][hacker-index]. To try the example, do the following: 1. Install the sample project `hacker` with `npm install -g hacker`. 2. Make a `Hackerfile.js` with some arbitrary javascript it. 3. Install hacker next to it with `npm install hacker`. -3. Run `hacker` while in the same parent folder. +4. Run `hacker` while in the same parent folder. + +## License + +MIT + + +[downloads-image]: https://img.shields.io/npm/dm/liftoff.svg?style=flat-square +[npm-url]: https://www.npmjs.com/package/liftoff +[npm-image]: https://img.shields.io/npm/v/liftoff.svg?style=flat-square + +[ci-url]: https://github.com/gulpjs/liftoff/actions?query=workflow:dev +[ci-image]: https://img.shields.io/github/workflow/status/gulpjs/liftoff/dev?style=flat-square + +[coveralls-url]: https://coveralls.io/r/gulpjs/liftoff +[coveralls-image]: https://img.shields.io/coveralls/gulpjs/liftoff/master.svg?style=flat-square + + + +[liftoff-blog]: https://bocoup.com/blog/building-command-line-tools-in-node-with-liftoff + +[hacker]: https://github.com/gulpjs/hacker +[interpret]: https://github.com/gulpjs/interpret +[flagged-respawn]: http://github.com/gulpjs/flagged-respawn +[v8flag]: https://github.com/gulpjs/v8flags +[fined]: https://github.com/gulpjs/fined + +[process-title]: http://nodejs.org/api/process.html#process_process_title + +[gulp-cli-index]: https://github.com/gulpjs/gulp-cli/blob/master/index.js +[hacker-index]: https://github.com/gulpjs/js-hacker/blob/master/bin/hacker.js + diff --git a/UPGRADING.md b/UPGRADING.md deleted file mode 100644 index 7f95e3e..0000000 --- a/UPGRADING.md +++ /dev/null @@ -1,28 +0,0 @@ -# 1.0.0 -> 2.0.0 -The option `nodeFlags` was renamed to `v8flags` for accuracy. It can now be a callback taking method that yields an array of flags, **or** an array literal. - -# 0.11 -> 0.12 -For the environment passed into the `launch` callback, `configNameRegex` has been renamed to `configNameSearch`. It now returns an array of valid config names instead of a regular expression. - -# 0.10 -> 0.11 -The method signature for `launch` was changed in this version of Liftoff. - -You must now provide your own options parser and pass your desired params directly into `launch` as the first argument. The second argument is now the invocation callback that starts your application. - -To replicate the default functionality of 0.10, use the following: -```js -const Liftoff = require('liftoff'); -const MyApp = new Liftoff({name:'myapp'}); -const argv = require('minimist')(process.argv.slice(2)); -const invoke = function (env) { - console.log('my environment is:', env); - console.log('my cli options are:', argv); - console.log('my liftoff config is:', this); -}; -MyApp.launch({ - cwd: argv.cwd, - configPath: argv.myappfile, - require: argv.require, - completion: argv.completion -}, invoke); -``` diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index e523569..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,27 +0,0 @@ -# http://www.appveyor.com/docs/appveyor-yml -# http://www.appveyor.com/docs/lang/nodejs-iojs - -environment: - matrix: - # node.js - - nodejs_version: "0.10" - - nodejs_version: "0.12" - - nodejs_version: "4" - - nodejs_version: "6" - - nodejs_version: "8" - - nodejs_version: "10" - -install: - - npm install -g npm@^3 - - ps: Install-Product node $env:nodejs_version - - npm install - -test_script: - - node --version - - npm --version - - cmd: npm test - -build: off - -# build version format -version: "{build}" diff --git a/index.js b/index.js index e19e1b2..9e7957b 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,7 @@ var EE = require('events').EventEmitter; var extend = require('extend'); var resolve = require('resolve'); var flaggedRespawn = require('flagged-respawn'); -var isPlainObject = require('is-plain-object'); +var isPlainObject = require('is-plain-object').isPlainObject; var mapValues = require('object.map'); var fined = require('fined'); @@ -24,7 +24,7 @@ function Liftoff(opts) { } util.inherits(Liftoff, EE); -Liftoff.prototype.requireLocal = function(module, basedir) { +Liftoff.prototype.requireLocal = function (module, basedir) { try { this.emit('preload:before', module); var result = require(resolve.sync(module, { basedir: basedir })); @@ -35,7 +35,7 @@ Liftoff.prototype.requireLocal = function(module, basedir) { } }; -Liftoff.prototype.buildEnvironment = function(opts) { +Liftoff.prototype.buildEnvironment = function (opts) { opts = opts || {}; // get modules we want to preload @@ -89,8 +89,11 @@ Liftoff.prototype.buildEnvironment = function(opts) { var modulePath, modulePackage; try { var delim = path.delimiter; - var paths = (process.env.NODE_PATH ? process.env.NODE_PATH.split(delim) : []); - modulePath = resolve.sync(this.moduleName, { basedir: configBase || cwd, paths: paths }); + var paths = process.env.NODE_PATH ? process.env.NODE_PATH.split(delim) : []; + modulePath = resolve.sync(this.moduleName, { + basedir: configBase || cwd, + paths: paths, + }); modulePackage = silentRequire(fileSearch('package.json', [modulePath])); } catch (e) {} @@ -103,7 +106,10 @@ Liftoff.prototype.buildEnvironment = function(opts) { modulePackage = silentRequire(modulePackagePath); if (modulePackage && modulePackage.name === this.moduleName) { // if it does, our module path is `main` inside package.json - modulePath = path.join(path.dirname(modulePackagePath), modulePackage.main || 'index.js'); + modulePath = path.join( + path.dirname(modulePackagePath), + modulePackage.main || 'index.js' + ); cwd = configBase; } else { // clear if we just required a package for some other project @@ -117,9 +123,9 @@ Liftoff.prototype.buildEnvironment = function(opts) { var configFiles = {}; if (isPlainObject(this.configFiles)) { var notfound = { path: null }; - configFiles = mapValues(this.configFiles, function(prop, name) { + configFiles = mapValues(this.configFiles, function (prop, name) { var defaultObj = { name: name, cwd: cwd, extensions: exts }; - return mapValues(prop, function(pathObj) { + return mapValues(prop, function (pathObj) { var found = fined(pathObj, defaultObj) || notfound; if (isPlainObject(found.extension)) { registerLoader(eventEmitter, found.extension, found.path, cwd); @@ -142,9 +148,9 @@ Liftoff.prototype.buildEnvironment = function(opts) { }; }; -Liftoff.prototype.handleFlags = function(cb) { +Liftoff.prototype.handleFlags = function (cb) { if (typeof this.v8flags === 'function') { - this.v8flags(function(err, flags) { + this.v8flags(function (err, flags) { if (err) { cb(err); } else { @@ -152,13 +158,15 @@ Liftoff.prototype.handleFlags = function(cb) { } }); } else { - process.nextTick(function() { - cb(null, this.v8flags); - }.bind(this)); + process.nextTick( + function () { + cb(null, this.v8flags); + }.bind(this) + ); } }; -Liftoff.prototype.prepare = function(opts, fn) { +Liftoff.prototype.prepare = function (opts, fn) { if (typeof fn !== 'function') { throw new Error('You must provide a callback function.'); } @@ -170,7 +178,7 @@ Liftoff.prototype.prepare = function(opts, fn) { fn.call(this, env); }; -Liftoff.prototype.execute = function(env, forcedFlags, fn) { +Liftoff.prototype.execute = function (env, forcedFlags, fn) { var completion = env.completion; if (completion && this.completions) { return this.completions(completion); @@ -184,31 +192,33 @@ Liftoff.prototype.execute = function(env, forcedFlags, fn) { throw new Error('You must provide a callback function.'); } - this.handleFlags(function(err, flags) { - if (err) { - throw err; - } - flags = flags || []; + this.handleFlags( + function (err, flags) { + if (err) { + throw err; + } + flags = flags || []; - flaggedRespawn(flags, process.argv, forcedFlags, execute.bind(this)); + flaggedRespawn(flags, process.argv, forcedFlags, execute.bind(this)); - function execute(ready, child, argv) { - if (child !== process) { - var execArgv = getNodeFlags.fromReorderedArgv(argv); - this.emit('respawn', execArgv, child); - } - if (ready) { - preloadModules(this, env); - registerLoader(this, this.extensions, env.configPath, env.cwd); - fn.call(this, env, argv); + function execute(ready, child, argv) { + if (child !== process) { + var execArgv = getNodeFlags.fromReorderedArgv(argv); + this.emit('respawn', execArgv, child); + } + if (ready) { + preloadModules(this, env); + registerLoader(this, this.extensions, env.configPath, env.cwd); + fn.call(this, env, argv); + } } - } - }.bind(this)); + }.bind(this) + ); }; function preloadModules(inst, env) { var basedir = env.cwd; - env.preload.filter(toUnique).forEach(function(module) { + env.preload.filter(toUnique).forEach(function (module) { inst.requireLocal(module, basedir); }); } diff --git a/lib/build_config_name.js b/lib/build_config_name.js index 9005a36..b83e185 100644 --- a/lib/build_config_name.js +++ b/lib/build_config_name.js @@ -1,4 +1,4 @@ -module.exports = function(opts) { +module.exports = function (opts) { opts = opts || {}; var configName = opts.configName; var extensions = opts.extensions; @@ -11,7 +11,7 @@ module.exports = function(opts) { if (!Array.isArray(extensions)) { throw new Error('Please provide an array of valid extensions.'); } - return extensions.map(function(ext) { + return extensions.map(function (ext) { return configName + ext; }); }; diff --git a/lib/file_search.js b/lib/file_search.js index d95121d..db56894 100644 --- a/lib/file_search.js +++ b/lib/file_search.js @@ -1,6 +1,6 @@ var findup = require('findup-sync'); -module.exports = function(search, paths) { +module.exports = function (search, paths) { var path; var len = paths.length; for (var i = 0; i < len; i++) { diff --git a/lib/find_config.js b/lib/find_config.js index c55a677..fe1ad95 100644 --- a/lib/find_config.js +++ b/lib/find_config.js @@ -2,7 +2,7 @@ var fs = require('fs'); var path = require('path'); var fileSearch = require('./file_search'); -module.exports = function(opts) { +module.exports = function (opts) { opts = opts || {}; var configNameSearch = opts.configNameSearch; var configPath = opts.configPath; @@ -10,7 +10,9 @@ module.exports = function(opts) { // only search for a config if a path to one wasn't explicitly provided if (!configPath) { if (!Array.isArray(searchPaths)) { - throw new Error('Please provide an array of paths to search for config in.'); + throw new Error( + 'Please provide an array of paths to search for config in.' + ); } if (!configNameSearch) { throw new Error('Please provide a configNameSearch.'); diff --git a/lib/find_cwd.js b/lib/find_cwd.js index 89ffaba..97c1e8d 100644 --- a/lib/find_cwd.js +++ b/lib/find_cwd.js @@ -1,6 +1,6 @@ var path = require('path'); -module.exports = function(opts) { +module.exports = function (opts) { if (!opts) { opts = {}; } diff --git a/lib/get_node_flags.js b/lib/get_node_flags.js index c58165e..6393698 100644 --- a/lib/get_node_flags.js +++ b/lib/get_node_flags.js @@ -27,4 +27,3 @@ module.exports = { arrayOrFunction: arrayOrFunction, fromReorderedArgv: fromReorderedArgv, }; - diff --git a/lib/parse_options.js b/lib/parse_options.js index a478bdd..f0ea36c 100644 --- a/lib/parse_options.js +++ b/lib/parse_options.js @@ -1,6 +1,6 @@ var extend = require('extend'); -module.exports = function(opts) { +module.exports = function (opts) { var defaults = { extensions: { '.js': null, diff --git a/lib/register_loader.js b/lib/register_loader.js index 683f4e0..534c215 100644 --- a/lib/register_loader.js +++ b/lib/register_loader.js @@ -1,6 +1,6 @@ var rechoir = require('rechoir'); -module.exports = function(eventEmitter, extensions, configPath, cwd) { +module.exports = function (eventEmitter, extensions, configPath, cwd) { extensions = extensions || {}; if (typeof configPath !== 'string') { @@ -8,14 +8,16 @@ module.exports = function(eventEmitter, extensions, configPath, cwd) { } var autoloads = rechoir.prepare(extensions, configPath, cwd, true); - if (autoloads instanceof Error) { // Only errors - autoloads.failures.forEach(function(failed) { + if (autoloads instanceof Error) { + // Only errors + autoloads.failures.forEach(function (failed) { eventEmitter.emit('loader:failure', failed.moduleName, failed.error); }); return; } - if (!Array.isArray(autoloads)) { // Already required or no config. + if (!Array.isArray(autoloads)) { + // Already required or no config. return; } diff --git a/lib/silent_require.js b/lib/silent_require.js index 68c4864..7b4dfe4 100644 --- a/lib/silent_require.js +++ b/lib/silent_require.js @@ -1,4 +1,4 @@ -module.exports = function(path) { +module.exports = function (path) { try { return require(path); } catch (e) {} diff --git a/package.json b/package.json index 9de3776..289f690 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,16 @@ "name": "liftoff", "version": "3.1.0", "description": "Launch your command line tool with ease.", - "author": "Tyler Kellen (http://goingslowly.com/)", - "contributors": [], - "repository": "js-cli/js-liftoff", + "author": "Gulp Team (https://gulpjs.com/)", + "contributors": [ + "Blaine Bublitz (https://github.com/phated)", + "Tyler Kellen (https://github.com/tkellen)", + "Takayuki Sato (https://github.com/sttk)" + ], + "repository": "gulpjs/liftoff", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=10.13.0" }, "main": "index.js", "files": [ @@ -16,28 +20,39 @@ "LICENSE" ], "scripts": { - "pretest": "eslint .", - "test": "mocha -t 5000 -b -R spec test/index", - "cover": "nyc --reporter=lcov --reporter=text-summary npm test" + "lint": "eslint .", + "pretest": "npm run lint", + "test": "nyc mocha --async-only" }, "dependencies": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.7.0", - "resolve": "^1.1.7" + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^5.0.0", + "object.map": "^1.0.1", + "rechoir": "^0.8.0", + "resolve": "^1.20.0" }, "devDependencies": { - "chai": "^3.5.0", - "coffeescript": "^1.10.0", - "eslint": "^2.13.1", - "eslint-config-gulp": "^3.0.1", - "mocha": "^3.5.3", - "nyc": "^13.3.0", - "sinon": "~1.17.4" + "coffeescript": "^2.6.1", + "eslint": "^7.0.0", + "eslint-config-gulp": "^5.0.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-node": "^11.1.0", + "expect": "^27.0.0", + "mocha": "^8.0.0", + "nyc": "^15.0.0", + "sinon": "^11.0.0" + }, + "nyc": { + "reporter": [ + "lcov", + "text-summary" + ] + }, + "prettier": { + "singleQuote": true }, "keywords": [ "command line" diff --git a/test/.eslintrc b/test/.eslintrc deleted file mode 100644 index 06b940f..0000000 --- a/test/.eslintrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "gulp/test" -} diff --git a/test/.gitkeep b/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/build_config_name.js b/test/build_config_name.js new file mode 100644 index 0000000..4f381af --- /dev/null +++ b/test/build_config_name.js @@ -0,0 +1,80 @@ +var expect = require('expect'); + +var buildConfigName = require('../lib/build_config_name'); + +describe('buildConfigName', function () { + it('should throw if no configName is provided', function (done) { + expect(function () { + buildConfigName(); + }).toThrow(); + done(); + }); + + it('should use configName directly if it is a regex', function (done) { + var configNameSearch = /mocha/; + expect(buildConfigName({ configName: configNameSearch })).toEqual([ + configNameSearch, + ]); + done(); + }); + + it('should throw if no array of extensions are provided and config is not a regex already', function (done) { + expect(function () { + buildConfigName({ configName: 'foo' }); + }).toThrow(); + expect(function () { + buildConfigName({ configName: 'foo', extensions: '?' }); + }).toThrow(); + expect(function () { + buildConfigName({ configName: 'foo', extensions: ['.js'] }); + }).not.toThrow(); + done(); + }); + + it('should build an array of possible config names', function (done) { + var multiExtension = buildConfigName({ + configName: 'foo', + extensions: ['.js', '.coffee'], + }); + expect(multiExtension).toEqual(['foo.js', 'foo.coffee']); + var singleExtension = buildConfigName({ + configName: 'foo', + extensions: ['.js'], + }); + expect(singleExtension).toEqual(['foo.js']); + done(); + }); + + it('should throw error if opts is null or empty', function (done) { + expect(function () { + buildConfigName(); + }).toThrow(); + expect(function () { + buildConfigName(null); + }).toThrow(); + expect(function () { + buildConfigName({}); + }).toThrow(); + done(); + }); + + it('should throw error if .configName is null', function (done) { + expect(function () { + buildConfigName({ extensions: ['.js'] }); + }).toThrow(); + done(); + }); + + it('should throw error if .extension is not an array', function (done) { + expect(function () { + buildConfigName({ configName: 'foo' }); + }).toThrow(); + expect(function () { + buildConfigName({ configName: 'foo', extensions: null }); + }).toThrow(); + expect(function () { + buildConfigName({ configName: 'foo', extensions: '.js' }); + }).toThrow(); + done(); + }); +}); diff --git a/test/file_search.js b/test/file_search.js new file mode 100644 index 0000000..d600692 --- /dev/null +++ b/test/file_search.js @@ -0,0 +1,15 @@ +var path = require('path'); + +var expect = require('expect'); + +var fileSearch = require('../lib/file_search'); + +describe('fileSearch', function () { + it('should locate a file using findup from an array of possible base paths', function (done) { + expect(fileSearch('mochafile.js', ['../'])).toEqual(null); + expect(fileSearch('package.json', [process.cwd()])).toEqual( + path.resolve(__dirname, '..', 'package.json') + ); + done(); + }); +}); diff --git a/test/find_config.js b/test/find_config.js new file mode 100644 index 0000000..bc6c5ee --- /dev/null +++ b/test/find_config.js @@ -0,0 +1,104 @@ +var path = require('path'); + +var expect = require('expect'); + +var findConfig = require('../lib/find_config'); + +describe('findConfig', function () { + it("should throw if searchPaths or configNameRegex are empty when configName isn't explicltly provided", function (done) { + expect(function () { + findConfig(); + }).toThrow(); + expect(function () { + findConfig({ searchPaths: ['../'] }); + }).toThrow(); + expect(function () { + findConfig({ configNameRegex: 'dude' }); + }).toThrow(); + done(); + }); + + it("if configPath is explicitly provided, return the absolute path to the file or null if it doesn't actually exist", function (done) { + var configPath = path.resolve('test/fixtures/mochafile.js'); + expect(findConfig({ configPath: configPath })).toEqual(configPath); + expect(findConfig({ configPath: 'path/to/nowhere' })).toEqual(null); + done(); + }); + + it('should return the absolute path to the first config file found in searchPaths', function (done) { + expect( + findConfig({ + configNameSearch: ['mochafile.js', 'mochafile.coffee'], + searchPaths: ['test/fixtures'], + }) + ).toEqual(path.resolve('test/fixtures/mochafile.js')); + expect( + findConfig({ + configNameSearch: ['mochafile.js', 'mochafile.coffee'], + searchPaths: ['test/fixtures/search_path', 'test/fixtures/coffee'], + }) + ).toEqual(path.resolve('test/fixtures/search_path/mochafile.js')); + expect( + findConfig({ + configNameSearch: 'mochafile.js', + searchPaths: ['test/fixtures/search_path', 'test/fixtures/coffee'], + }) + ).toEqual(path.resolve('test/fixtures/search_path/mochafile.js')); + done(); + }); + + it('should throw error if .searchPaths is not an array', function (done) { + expect(function () { + findConfig({ + configNameSearch: ['mochafile.js', 'mochafile.coffee'], + }); + }).toThrow(); + expect(function () { + findConfig({ + configNameSearch: ['mochafile.js', 'mochafile.coffee'], + searchPaths: null, + }); + }).toThrow(); + expect(function () { + findConfig({ + configNameSearch: ['mochafile.js', 'mochafile.coffee'], + searchPaths: 'test/fixtures/search_path', + }); + }).toThrow(); + done(); + }); + + it('should throw error if .configNameSearch is null', function (done) { + expect(function () { + findConfig({ + searchPaths: ['test/fixtures/search_path', 'test/fixtures/coffee'], + }); + }).toThrow(); + expect(function () { + findConfig({ + configNameSearch: null, + searchPaths: ['test/fixtures/search_path', 'test/fixtures/coffee'], + }); + }).toThrow(); + expect(function () { + findConfig({ + configNameSearch: '', + searchPaths: ['test/fixtures/search_path', 'test/fixtures/coffee'], + }); + }).toThrow(); + done(); + }); + + it('should throw error if opts is null or empty', function (done) { + expect(function () { + findConfig(); + }).toThrow(); + expect(function () { + findConfig(null); + }).toThrow(); + expect(function () { + findConfig({}); + }).toThrow(); + done(); + }); +}); diff --git a/test/find_cwd.js b/test/find_cwd.js new file mode 100644 index 0000000..fea8138 --- /dev/null +++ b/test/find_cwd.js @@ -0,0 +1,41 @@ +var path = require('path'); + +var expect = require('expect'); + +var findCwd = require('../lib/find_cwd'); + +describe('findCwd', function () { + it('should return process.cwd if no options are passed', function (done) { + expect(findCwd()).toEqual(process.cwd()); + done(); + }); + + it('should return path from cwd if supplied', function (done) { + expect(findCwd({ cwd: '../' })).toEqual(path.resolve('../')); + done(); + }); + + it('should return directory of config if configPath defined', function (done) { + expect(findCwd({ configPath: 'test/fixtures/mochafile.js' })).toEqual( + path.resolve('test/fixtures') + ); + done(); + }); + + it('should return path from cwd if both it and configPath are defined', function (done) { + expect( + findCwd({ cwd: '../', configPath: 'test/fixtures/mochafile.js' }) + ).toEqual(path.resolve('../')); + done(); + }); + + it("should ignore cwd if it isn't a string", function (done) { + expect(findCwd({ cwd: true })).toEqual(process.cwd()); + done(); + }); + + it("should ignore configPath if it isn't a string", function (done) { + expect(findCwd({ configPath: true })).toEqual(process.cwd()); + done(); + }); +}); diff --git a/test/fixtures/configfiles/index.json b/test/fixtures/configfiles/index.json index 954fb25..1a8a27f 100644 --- a/test/fixtures/configfiles/index.json +++ b/test/fixtures/configfiles/index.json @@ -1 +1 @@ -{"aaa":"AAA"} +{ "aaa": "AAA" } diff --git a/test/fixtures/configfiles/require-md.js b/test/fixtures/configfiles/require-md.js index cccb19b..c287c0e 100644 --- a/test/fixtures/configfiles/require-md.js +++ b/test/fixtures/configfiles/require-md.js @@ -1,10 +1,8 @@ -(function() { +(function () { + var path = require('path'); -var path = require('path'); - -require.extensions['.md'] = function(module, filepath) { - module.loaded = true; - module.exports = 'Load ' + path.basename(filepath) + ' by require-md'; -}; - -}()); + require.extensions['.md'] = function (module, filepath) { + module.loaded = true; + module.exports = 'Load ' + path.basename(filepath) + ' by require-md'; + }; +})(); diff --git a/test/fixtures/configfiles/require-txt.js b/test/fixtures/configfiles/require-txt.js index b1b2fc1..a171ffb 100644 --- a/test/fixtures/configfiles/require-txt.js +++ b/test/fixtures/configfiles/require-txt.js @@ -1,10 +1,8 @@ -(function() { +(function () { + var path = require('path'); -var path = require('path'); - -require.extensions['.txt'] = function(module, filepath) { - module.loaded = true; - module.exports = 'Load ' + path.basename(filepath) + ' by require-txt'; -}; - -}()); + require.extensions['.txt'] = function (module, filepath) { + module.loaded = true; + module.exports = 'Load ' + path.basename(filepath) + ' by require-txt'; + }; +})(); diff --git a/test/fixtures/developing_yourself/app1/index.js b/test/fixtures/developing_yourself/app1/index.js index 4c9a9af..90b79ce 100644 --- a/test/fixtures/developing_yourself/app1/index.js +++ b/test/fixtures/developing_yourself/app1/index.js @@ -1,11 +1,11 @@ var Liftoff = require('../../../..'); var app1 = new Liftoff({ - name: 'app1' + name: 'app1', }); -app1.prepare({}, function(env) { - app1.execute(env, function(env) { +app1.prepare({}, function (env) { + app1.execute(env, function (env) { console.log(env.modulePackage); console.log(env.modulePath); console.log(env.cwd); diff --git a/test/fixtures/developing_yourself/app2/index.js b/test/fixtures/developing_yourself/app2/index.js index 87d9d81..7e16cfb 100644 --- a/test/fixtures/developing_yourself/app2/index.js +++ b/test/fixtures/developing_yourself/app2/index.js @@ -1,11 +1,11 @@ var Liftoff = require('../../../..'); var app2 = new Liftoff({ - name: 'app2' + name: 'app2', }); -app2.prepare({}, function(env) { - app2.execute(env, function(env) { +app2.prepare({}, function (env) { + app2.execute(env, function (env) { console.log(JSON.stringify(env.modulePackage)); console.log(env.modulePath); console.log(env.cwd); diff --git a/test/fixtures/developing_yourself/main.js b/test/fixtures/developing_yourself/main.js index 12bbf17..9c2ec96 100644 --- a/test/fixtures/developing_yourself/main.js +++ b/test/fixtures/developing_yourself/main.js @@ -1,11 +1,11 @@ var Liftoff = require('../../..'); var app0 = new Liftoff({ - name: 'app0' + name: 'app0', }); -app0.prepare({}, function(env) { - app0.execute(env, function(env) { +app0.prepare({}, function (env) { + app0.execute(env, function (env) { console.log(JSON.stringify(env.modulePackage)); console.log(env.modulePath); console.log(env.cwd); diff --git a/test/fixtures/prepare-execute/nodeflags_only.js b/test/fixtures/prepare-execute/nodeflags_only.js index 3b80617..5a2eb6a 100644 --- a/test/fixtures/prepare-execute/nodeflags_only.js +++ b/test/fixtures/prepare-execute/nodeflags_only.js @@ -4,13 +4,13 @@ var Test = new Liftoff({ name: 'test', }); -Test.on('respawn', function(execArgv) { +Test.on('respawn', function (execArgv) { console.log('saw respawn', execArgv); }); -Test.prepare({}, function(env) { +Test.prepare({}, function (env) { var forcedFlags = ['--lazy']; - Test.execute(env, forcedFlags, function(env, argv) { + Test.execute(env, forcedFlags, function (env, argv) { console.error(argv.slice(1).join(' ')); }); }); diff --git a/test/fixtures/prepare-execute/v8flags.js b/test/fixtures/prepare-execute/v8flags.js index 661545c..64d67d3 100644 --- a/test/fixtures/prepare-execute/v8flags.js +++ b/test/fixtures/prepare-execute/v8flags.js @@ -2,14 +2,14 @@ var Liftoff = require('../../..'); var Test = new Liftoff({ name: 'test', - v8flags: ['--lazy'] + v8flags: ['--lazy'], }); -Test.on('respawn', function(flags, proc) { +Test.on('respawn', function (flags, proc) { console.log('saw respawn'); }); -Test.prepare({}, function(env) { - Test.execute(env, function(env) { +Test.prepare({}, function (env) { + Test.execute(env, function (env) { console.error(process.execArgv.join('')); }); }); diff --git a/test/fixtures/prepare-execute/v8flags_config.js b/test/fixtures/prepare-execute/v8flags_config.js index ca44dd7..07c8322 100644 --- a/test/fixtures/prepare-execute/v8flags_config.js +++ b/test/fixtures/prepare-execute/v8flags_config.js @@ -5,13 +5,13 @@ var Test = new Liftoff({ v8flags: ['--harmony'], }); -Test.on('respawn', function(flags, proc) { +Test.on('respawn', function (flags, proc) { console.log('saw respawn', flags); }); -Test.prepare({}, function(env) { +Test.prepare({}, function (env) { var forcedFlags = ['--lazy']; - Test.execute(env, forcedFlags, function(env, argv) { + Test.execute(env, forcedFlags, function (env, argv) { console.error(argv.slice(1).join(' ')); }); }); diff --git a/test/fixtures/prepare-execute/v8flags_error.js b/test/fixtures/prepare-execute/v8flags_error.js index b36a9f7..cf2a90f 100644 --- a/test/fixtures/prepare-execute/v8flags_error.js +++ b/test/fixtures/prepare-execute/v8flags_error.js @@ -2,18 +2,18 @@ var Liftoff = require('../../..'); var Test = new Liftoff({ name: 'test', - v8flags: function(cb) { - process.nextTick(function() { + v8flags: function (cb) { + process.nextTick(function () { cb(new Error('v8flags error!'), ['--lazy']); - }) - } + }); + }, }); -Test.on('respawn', function(flags, proc) { +Test.on('respawn', function (flags, proc) { console.log('saw respawn'); }); -Test.prepare({}, function(env) { - Test.execute(env, function(env) { +Test.prepare({}, function (env) { + Test.execute(env, function (env) { console.error(process.execArgv.join('')); }); }); diff --git a/test/fixtures/prepare-execute/v8flags_function.js b/test/fixtures/prepare-execute/v8flags_function.js index 68cff09..dad86bc 100644 --- a/test/fixtures/prepare-execute/v8flags_function.js +++ b/test/fixtures/prepare-execute/v8flags_function.js @@ -2,18 +2,18 @@ var Liftoff = require('../../..'); var Test = new Liftoff({ name: 'test', - v8flags: function(cb) { - process.nextTick(function() { + v8flags: function (cb) { + process.nextTick(function () { cb(null, ['--lazy']); - }) - } + }); + }, }); -Test.on('respawn', function(flags, proc) { +Test.on('respawn', function (flags, proc) { console.log('saw respawn'); }); -Test.prepare({}, function(env) { - Test.execute(env, function(env) { +Test.prepare({}, function (env) { + Test.execute(env, function (env) { console.error(process.execArgv.join('')); }); }); diff --git a/test/fixtures/prepare-execute/v8flags_value.js b/test/fixtures/prepare-execute/v8flags_value.js index 9121301..17472f9 100644 --- a/test/fixtures/prepare-execute/v8flags_value.js +++ b/test/fixtures/prepare-execute/v8flags_value.js @@ -2,13 +2,13 @@ var Liftoff = require('../../..'); var Test = new Liftoff({ name: 'test', - v8flags: ['--stack_size'] + v8flags: ['--stack_size'], }); -Test.on('respawn', function(flags) { +Test.on('respawn', function (flags) { console.error(flags.join(' ')); }); -Test.prepare({}, function(env) { - Test.execute(env, function() {}); +Test.prepare({}, function (env) { + Test.execute(env, function () {}); }); diff --git a/test/fixtures/register_loader/require-cfg.js b/test/fixtures/register_loader/require-cfg.js index 147f712..8bd4ef1 100644 --- a/test/fixtures/register_loader/require-cfg.js +++ b/test/fixtures/register_loader/require-cfg.js @@ -1,10 +1,8 @@ -(function() { +(function () { + var path = require('path'); -var path = require('path'); - -require.extensions['.cfg'] = function(module, filepath) { - module.loaded = true; - module.exports = 'Load ' + path.basename(filepath) + ' by require-cfg'; -}; - -}()); + require.extensions['.cfg'] = function (module, filepath) { + module.loaded = true; + module.exports = 'Load ' + path.basename(filepath) + ' by require-cfg'; + }; +})(); diff --git a/test/fixtures/register_loader/require-conf.js b/test/fixtures/register_loader/require-conf.js index bf3fda1..3476230 100644 --- a/test/fixtures/register_loader/require-conf.js +++ b/test/fixtures/register_loader/require-conf.js @@ -1,10 +1,8 @@ -(function() { +(function () { + var path = require('path'); -var path = require('path'); - -require.extensions['.conf'] = function(module, filepath) { - module.loaded = true; - module.exports = 'Load ' + path.basename(filepath) + ' by require-conf'; -}; - -}()); + require.extensions['.conf'] = function (module, filepath) { + module.loaded = true; + module.exports = 'Load ' + path.basename(filepath) + ' by require-conf'; + }; +})(); diff --git a/test/fixtures/register_loader/require-file-b.js b/test/fixtures/register_loader/require-file-b.js index e1c7733..8fe24b8 100644 --- a/test/fixtures/register_loader/require-file-b.js +++ b/test/fixtures/register_loader/require-file-b.js @@ -1,10 +1,8 @@ -(function() { +(function () { + var path = require('path'); -var path = require('path'); - -require.extensions['.b'] = function(module, filepath) { - module.loaded = true; - module.exports = 'Load ' + path.basename(filepath) + ' by require-file-b'; -}; - -}()); + require.extensions['.b'] = function (module, filepath) { + module.loaded = true; + module.exports = 'Load ' + path.basename(filepath) + ' by require-file-b'; + }; +})(); diff --git a/test/fixtures/register_loader/require-file-bc.js b/test/fixtures/register_loader/require-file-bc.js index a8ca7f3..7b172f2 100644 --- a/test/fixtures/register_loader/require-file-bc.js +++ b/test/fixtures/register_loader/require-file-bc.js @@ -1,10 +1,8 @@ -(function() { +(function () { + var path = require('path'); -var path = require('path'); - -require.extensions['.c'] = function(module, filepath) { - module.loaded = true; - module.exports = 'Load ' + path.basename(filepath) + ' by require-file-bc'; -}; - -}()); + require.extensions['.c'] = function (module, filepath) { + module.loaded = true; + module.exports = 'Load ' + path.basename(filepath) + ' by require-file-bc'; + }; +})(); diff --git a/test/fixtures/register_loader/require-file-cd.js b/test/fixtures/register_loader/require-file-cd.js index f3f94c9..80049d7 100644 --- a/test/fixtures/register_loader/require-file-cd.js +++ b/test/fixtures/register_loader/require-file-cd.js @@ -1,10 +1,8 @@ -(function() { +(function () { + var path = require('path'); -var path = require('path'); - -require.extensions['.d'] = function(module, filepath) { - module.loaded = true; - module.exports = 'Load ' + path.basename(filepath) + ' by require-file-cd'; -}; - -}()); + require.extensions['.d'] = function (module, filepath) { + module.loaded = true; + module.exports = 'Load ' + path.basename(filepath) + ' by require-file-cd'; + }; +})(); diff --git a/test/fixtures/register_loader/require-file-d.js b/test/fixtures/register_loader/require-file-d.js index 10db7c4..0859980 100644 --- a/test/fixtures/register_loader/require-file-d.js +++ b/test/fixtures/register_loader/require-file-d.js @@ -1,10 +1,8 @@ -(function() { +(function () { + var path = require('path'); -var path = require('path'); - -require.extensions['.d'] = function(module, filepath) { - module.loaded = true; - module.exports = 'Load ' + path.basename(filepath) + ' by require-file-d'; -}; - -}()); + require.extensions['.d'] = function (module, filepath) { + module.loaded = true; + module.exports = 'Load ' + path.basename(filepath) + ' by require-file-d'; + }; +})(); diff --git a/test/fixtures/register_loader/require-file-ecd.js b/test/fixtures/register_loader/require-file-ecd.js index c4d356e..b09a7ac 100644 --- a/test/fixtures/register_loader/require-file-ecd.js +++ b/test/fixtures/register_loader/require-file-ecd.js @@ -1,10 +1,8 @@ -(function() { +(function () { + var path = require('path'); -var path = require('path'); - -require.extensions['.d'] = function(module, filepath) { - module.loaded = true; - module.exports = 'Load ' + path.basename(filepath) + ' by require-file-ecd'; -}; - -}()); + require.extensions['.d'] = function (module, filepath) { + module.loaded = true; + module.exports = 'Load ' + path.basename(filepath) + ' by require-file-ecd'; + }; +})(); diff --git a/test/fixtures/register_loader/require-file-fcd.js b/test/fixtures/register_loader/require-file-fcd.js index 57fc433..627ab9b 100644 --- a/test/fixtures/register_loader/require-file-fcd.js +++ b/test/fixtures/register_loader/require-file-fcd.js @@ -1,10 +1,8 @@ -(function() { +(function () { + var path = require('path'); -var path = require('path'); - -require.extensions['.d'] = function(module, filepath) { - module.loaded = true; - module.exports = 'Load ' + path.basename(filepath) + ' by require-file-fcd'; -}; - -}()); + require.extensions['.d'] = function (module, filepath) { + module.loaded = true; + module.exports = 'Load ' + path.basename(filepath) + ' by require-file-fcd'; + }; +})(); diff --git a/test/fixtures/register_loader/require-rc.js b/test/fixtures/register_loader/require-rc.js index 9fd529f..53b5acf 100644 --- a/test/fixtures/register_loader/require-rc.js +++ b/test/fixtures/register_loader/require-rc.js @@ -1,10 +1,8 @@ -(function() { +(function () { + var path = require('path'); -var path = require('path'); - -require.extensions['.rc'] = function(module, filepath) { - module.loaded = true; - module.exports = 'Load ' + path.basename(filepath) + ' by require-rc'; -}; - -}()); + require.extensions['.rc'] = function (module, filepath) { + module.loaded = true; + module.exports = 'Load ' + path.basename(filepath) + ' by require-rc'; + }; +})(); diff --git a/test/fixtures/respawn_and_require.js b/test/fixtures/respawn_and_require.js index fcc2030..d65937d 100644 --- a/test/fixtures/respawn_and_require.js +++ b/test/fixtures/respawn_and_require.js @@ -5,19 +5,22 @@ const Test = new Liftoff({ v8flags: ['--harmony'], }); -Test.on('respawn', function(flags, proc) { +Test.on('respawn', function (flags, proc) { console.log('saw respawn', flags); }); -Test.on('preload:success', function(name) { +Test.on('preload:success', function (name) { console.log('preload:success', name); }); -Test.prepare({ - preload: 'coffeescript/register', -}, function(env) { - var forcedFlags = ['--lazy']; - Test.execute(env, forcedFlags, function() { - console.log('execute'); - }); -}); +Test.prepare( + { + preload: 'coffeescript/register', + }, + function (env) { + var forcedFlags = ['--lazy']; + Test.execute(env, forcedFlags, function () { + console.log('execute'); + }); + } +); diff --git a/test/get_node_flags.js b/test/get_node_flags.js new file mode 100644 index 0000000..f403bbb --- /dev/null +++ b/test/get_node_flags.js @@ -0,0 +1,117 @@ +var expect = require('expect'); + +var getNodeFlags = require('../lib/get_node_flags'); + +describe('getNodeFlags', function () { + describe('arrayOrFunction', function () { + it('should return the first argument when it is an array', function (done) { + var env = { cwd: 'aaa' }; + expect(getNodeFlags.arrayOrFunction([], env)).toEqual([]); + expect( + getNodeFlags.arrayOrFunction( + ['--lazy', '--use_strict', '--harmony'], + env + ) + ).toEqual( + expect.arrayContaining(['--lazy', '--harmony', '--use_strict']) + ); + done(); + }); + + it('should return the exection result of the first argument when it is a function', function (done) { + var env = { cwd: 'aaa' }; + expect( + getNodeFlags.arrayOrFunction(function () { + return []; + }, env) + ).toEqual([]); + expect( + getNodeFlags.arrayOrFunction(function (arg) { + expect(arg).toEqual(env); + return ['--lazy', '--harmony']; + }, env) + ).toEqual(expect.arrayContaining(['--lazy', '--harmony'])); + done(); + }); + + it('should return an array which has an element of the first argument when the first argument is a string', function (done) { + var env = { cwd: 'aaa' }; + expect(getNodeFlags.arrayOrFunction('--lazy', env)).toEqual( + expect.arrayContaining(['--lazy']) + ); + done(); + }); + + it('should return an empty array when the first argument is neither an array, a function nor a string', function (done) { + var env = { cwd: 'aaa' }; + expect(getNodeFlags.arrayOrFunction(undefined, env)).toEqual([]); + expect(getNodeFlags.arrayOrFunction(null, env)).toEqual([]); + expect(getNodeFlags.arrayOrFunction(true, env)).toEqual([]); + expect(getNodeFlags.arrayOrFunction(false, env)).toEqual([]); + expect(getNodeFlags.arrayOrFunction(0, env)).toEqual([]); + expect(getNodeFlags.arrayOrFunction(123, env)).toEqual([]); + expect(getNodeFlags.arrayOrFunction({}, env)).toEqual([]); + expect(getNodeFlags.arrayOrFunction({ length: 1 }, env)).toEqual([]); + done(); + }); + }); + + describe('fromReorderedArgv', function () { + it('should return only node flags from respawning arguments', function (done) { + var env = { cwd: 'aaa' }; + var cmd = [ + 'node', + '--lazy', + '--harmony', + '--use_strict', + './aaa/bbb/app.js', + '--ccc', + 'ddd', + '-e', + 'fff', + ]; + expect(getNodeFlags.fromReorderedArgv(cmd, env)).toEqual([ + '--lazy', + '--harmony', + '--use_strict', + ]); + done(); + }); + + it('should end node flags before "--"', function (done) { + var env = { cwd: 'aaa' }; + var cmd = [ + 'node', + '--lazy', + '--', + '--harmony', + '--use_strict', + './aaa/bbb/app.js', + '--ccc', + 'ddd', + '-e', + 'fff', + ]; + expect(getNodeFlags.fromReorderedArgv(cmd, env)).toEqual(['--lazy']); + done(); + }); + + it('should return node flags when arguments are only node flags', function (done) { + var env = { cwd: 'aaa' }; + var cmd = ['node', '--lazy', '--harmony', '--use_strict']; + expect(getNodeFlags.fromReorderedArgv(cmd, env)).toEqual([ + '--lazy', + '--harmony', + '--use_strict', + ]); + done(); + }); + + it('should return an empty array when no node flags', function (done) { + var env = { cwd: 'aaa' }; + var cmd = ['node', './aaa/bbb/app.js', '--aaa', 'bbb', '-c', 'd']; + expect(getNodeFlags.fromReorderedArgv(cmd, env)).toEqual([]); + done(); + }); + }); +}); diff --git a/test/index.js b/test/index.js index af6abfb..37120cf 100644 --- a/test/index.js +++ b/test/index.js @@ -1,9 +1,11 @@ -var Liftoff = require('../'); var path = require('path'); -var expect = require('chai').expect; +var exec = require('child_process').exec; + +var expect = require('expect'); var sinon = require('sinon'); var resolve = require('resolve'); -var exec = require('child_process').exec; + +var Liftoff = require('../'); var NAME = 'mocha'; var app = new Liftoff({ @@ -19,378 +21,448 @@ var app = new Liftoff({ searchPaths: ['test/fixtures/search_path'], }); -describe('Liftoff', function() { - - describe('buildEnvironment', function() { +describe('Liftoff', function () { + this.timeout(5000); - it('should locate local module using cwd if no config is found', function() { + describe('buildEnvironment', function () { + it('should locate local module using cwd if no config is found', function (done) { var test = new Liftoff({ name: 'chai' }); var cwd = 'explicit/cwd'; var spy = sinon.spy(resolve, 'sync'); // NODE_PATH might be defined. delete process.env.NODE_PATH; test.buildEnvironment({ cwd: cwd }); - expect(spy.calledWith('chai', { basedir: path.join(process.cwd(), cwd), paths: [] })).to.be.true; + expect( + spy.calledWith('chai', { + basedir: path.join(process.cwd(), cwd), + paths: [], + }) + ).toBe(true); spy.restore(); + done(); }); - it('should locate global module using NODE_PATH if defined', function() { + it('should locate global module using NODE_PATH if defined', function (done) { var test = new Liftoff({ name: 'dummy' }); var cwd = 'explicit/cwd'; var spy = sinon.spy(resolve, 'sync'); process.env.NODE_PATH = path.join(process.cwd(), cwd); test.buildEnvironment(); - expect(spy.calledWith('dummy', { basedir: process.cwd(), paths: [path.join(process.cwd(), cwd)] })).to.be.true; + expect( + spy.calledWith('dummy', { + basedir: process.cwd(), + paths: [path.join(process.cwd(), cwd)], + }) + ).toBe(true); spy.restore(); + done(); }); - it('if cwd is explicitly provided, don\'t use search_paths', function() { - expect(app.buildEnvironment({ cwd: './' }).configPath).to.equal(null); + it("if cwd is explicitly provided, don't use search_paths", function (done) { + expect(app.buildEnvironment({ cwd: './' }).configPath).toEqual(null); + done(); }); - it('should find case sensitive configPath', function() { - var expected = path.resolve(__dirname, 'fixtures', 'case', (process.platform === 'linux' ? 'Mochafile.js' : 'mochafile.js')); - expect(app.buildEnvironment({ cwd: path.join(__dirname, 'fixtures', 'case') }).configPath).to.equal(expected); + it('should find case sensitive configPath', function (done) { + var expected = path.resolve( + __dirname, + 'fixtures', + 'case', + process.platform === 'linux' ? 'Mochafile.js' : 'mochafile.js' + ); + expect( + app.buildEnvironment({ cwd: path.join(__dirname, 'fixtures', 'case') }) + .configPath + ).toEqual(expected); + done(); }); - it('should find module in the directory next to config', function() { - expect(app.buildEnvironment().modulePath).to.equal(path.resolve('node_modules/mocha/index.js')); + it('should find module in the directory next to config', function (done) { + expect(app.buildEnvironment().modulePath).toEqual( + path.resolve('node_modules/mocha/index.js') + ); + done(); }); - it('should require the package sibling to the module', function() { - expect(app.buildEnvironment().modulePackage).to.equal(require('../node_modules/mocha/package.json')); + it('should require the package sibling to the module', function (done) { + expect(app.buildEnvironment().modulePackage).toEqual( + require('../node_modules/mocha/package.json') + ); + done(); }); - it('should set cwd to match the directory of the config file as long as cwd wasn\'t explicitly provided', function() { - expect(app.buildEnvironment().cwd).to.equal(path.resolve('test/fixtures/search_path')); + it("should set cwd to match the directory of the config file as long as cwd wasn't explicitly provided", function (done) { + expect(app.buildEnvironment().cwd).toEqual( + path.resolve('test/fixtures/search_path') + ); + done(); }); - describe('for developing against yourself', function() { - it('should find and load package.json', function(done) { + describe('for developing against yourself', function () { + it('should find and load package.json', function (done) { var fixturesDir = path.resolve(__dirname, 'fixtures'); var cwd = path.resolve(fixturesDir, 'developing_yourself'); exec('cd ' + cwd + ' && node main.js', cb); function cb(err, stdout, stderr) { - expect(err).to.equal(null); - expect(stderr).to.equal(''); + expect(err).toEqual(null); + expect(stderr).toEqual(''); var fp = path.resolve(cwd, 'package.json'); - expect(stdout).to.equal( - JSON.stringify(require(fp)) + '\n' + - path.resolve(cwd, 'main.js') + '\n' + - cwd + '\n' + expect(stdout).toEqual( + JSON.stringify(require(fp)) + + '\n' + + path.resolve(cwd, 'main.js') + + '\n' + + cwd + + '\n' ); done(); } }); - it('should clear modulePackage if package.json is of different project', - function(done) { + it('should clear modulePackage if package.json is of different project', function (done) { var fixturesDir = path.resolve(__dirname, 'fixtures'); var cwd = path.resolve(fixturesDir, 'developing_yourself/app1'); exec('cd ' + cwd + ' && node index.js', cb); function cb(err, stdout, stderr) { - expect(err).to.equal(null); - expect(stderr).to.equal(''); - expect(stdout).to.equal( - '{}\n' + - 'undefined\n' + - cwd + '\n' - ); + expect(err).toEqual(null); + expect(stderr).toEqual(''); + expect(stdout).toEqual('{}\n' + 'undefined\n' + cwd + '\n'); done(); } }); - it('should use `index.js` if `main` property in package.json ' + - 'does not exist', function(done) { - var fixturesDir = path.resolve(__dirname, 'fixtures'); - var cwd = path.resolve(fixturesDir, 'developing_yourself/app2'); + it( + 'should use `index.js` if `main` property in package.json ' + + 'does not exist', + function (done) { + var fixturesDir = path.resolve(__dirname, 'fixtures'); + var cwd = path.resolve(fixturesDir, 'developing_yourself/app2'); - exec('cd test/fixtures/developing_yourself/app2 && node index.js', cb); - function cb(err, stdout, stderr) { - expect(err).to.equal(null); - expect(stderr).to.equal(''); - var fp = './fixtures/developing_yourself/app2/package.json'; - expect(stdout).to.equal( - JSON.stringify(require(fp)) + '\n' + - path.resolve(cwd, 'index.js') + '\n' + - cwd + '\n' + exec( + 'cd test/fixtures/developing_yourself/app2 && node index.js', + cb ); - done(); + function cb(err, stdout, stderr) { + expect(err).toEqual(null); + expect(stderr).toEqual(''); + var fp = './fixtures/developing_yourself/app2/package.json'; + expect(stdout).toEqual( + JSON.stringify(require(fp)) + + '\n' + + path.resolve(cwd, 'index.js') + + '\n' + + cwd + + '\n' + ); + done(); + } } - }); - + ); }); - }); - describe('prepare', function() { - - it('should set the process.title to the moduleName', function() { - app.prepare({}, function() {}); - expect(process.title).to.equal(app.moduleName); + describe('prepare', function () { + it('should set the process.title to the moduleName', function (done) { + app.prepare({}, function () { + expect(process.title).toEqual(app.moduleName); + done(); + }); }); - it('should call prepare with liftoff instance as context', function(done) { - app.prepare({}, function() { - expect(this).to.equal(app); + it('should call prepare with liftoff instance as context', function (done) { + app.prepare({}, function () { + expect(this).toEqual(app); done(); }); }); - it('should pass environment to first argument of prepare callback', function(done) { - app.prepare({}, function(env) { - expect(env).to.deep.equal(app.buildEnvironment()); + it('should pass environment to first argument of prepare callback', function (done) { + app.prepare({}, function (env) { + expect(env).toEqual(app.buildEnvironment()); done(); }); }); - it('should throw if 2nd arg is not a function', function() { - expect(function() { + it('should throw if 2nd arg is not a function', function (done) { + expect(function () { app.prepare({}); - }).to.throw(); + }).toThrow(); + done(); }); }); - - describe('execute', function() { - it('should pass environment to first argument of execute callback', function(done) { + describe('execute', function () { + it('should pass environment to first argument of execute callback', function (done) { var testEnv = app.buildEnvironment(); - app.execute(testEnv, function(env) { - expect(env).to.deep.equal(testEnv); + app.execute(testEnv, function (env) { + expect(env).toEqual(testEnv); done(); }); }); - it('should throw if 2nd arg is not a function', function() { - expect(function() { + it('should throw if 2nd arg is not a function', function (done) { + expect(function () { app.execute({}); - }).to.throw(); + }).toThrow(); + done(); }); - it('should return early if completions are available and requested', function(done) { + it('should return early if completions are available and requested', function (done) { var test = new Liftoff({ name: 'whatever', - completions: function() { + completions: function () { done(); }, }); - test.prepare({ completion: true }, function(env) { + test.prepare({ completion: true }, function (env) { test.execute(env); }); }); - it('should skip respawning if process.argv has no values from v8flags in it', function(done) { - exec('node test/fixtures/prepare-execute/v8flags.js', function(err, stdout, stderr) { - expect(stderr).to.equal('\n'); - exec('node test/fixtures/prepare-execute/v8flags_function.js', function(err, stdout, stderr) { - expect(stderr).to.equal('\n'); - done(); - }); - }); + it('should skip respawning if process.argv has no values from v8flags in it', function (done) { + exec( + 'node test/fixtures/prepare-execute/v8flags.js', + function (err, stdout, stderr) { + expect(stderr).toEqual('\n'); + exec( + 'node test/fixtures/prepare-execute/v8flags_function.js', + function (err, stdout, stderr) { + expect(stderr).toEqual('\n'); + done(); + } + ); + } + ); + }); + + it('should respawn if process.argv has values from v8flags in it', function (done) { + exec( + 'node test/fixtures/prepare-execute/v8flags.js --lazy', + function (err, stdout, stderr) { + expect(stderr).toEqual('--lazy\n'); + exec( + 'node test/fixtures/prepare-execute/v8flags_function.js --lazy', + function (err, stdout, stderr) { + expect(stderr).toEqual('--lazy\n'); + done(); + } + ); + } + ); }); - it('should respawn if process.argv has values from v8flags in it', function(done) { - exec('node test/fixtures/prepare-execute/v8flags.js --lazy', function(err, stdout, stderr) { - expect(stderr).to.equal('--lazy\n'); - exec('node test/fixtures/prepare-execute/v8flags_function.js --lazy', function(err, stdout, stderr) { - expect(stderr).to.equal('--lazy\n'); + it('should throw if v8flags is a function and it causes an error', function (done) { + exec( + 'node test/fixtures/prepare-execute/v8flags_error.js --lazy', + function (err, stdout, stderr) { + expect(err).not.toEqual(null); + expect(stdout).toEqual(''); + expect(stderr).toMatch('v8flags error!'); done(); - }); - }); - }); - - it('should throw if v8flags is a function and it causes an error', function(done) { - exec('node test/fixtures/prepare-execute/v8flags_error.js --lazy', function(err, stdout, stderr) { - expect(err).not.to.equal(null); - expect(stdout).to.equal(''); - expect(stderr).to.include('v8flags error!'); - done(); - }); + } + ); }); - it('should respawn if v8flag is set by forcedFlags', function(done) { + it('should respawn if v8flag is set by forcedFlags', function (done) { exec('node test/fixtures/prepare-execute/v8flags_config.js 123', cb); function cb(err, stdout, stderr) { - expect(err).to.equal(null); - expect(stderr).to.equal([ - path.resolve('test/fixtures/prepare-execute/v8flags_config.js'), - '123', - ].join(' ') + '\n'); - expect(stdout).to.equal('saw respawn [ \'--lazy\' ]\n'); + expect(err).toEqual(null); + expect(stderr).toEqual( + [ + path.resolve('test/fixtures/prepare-execute/v8flags_config.js'), + '123', + ].join(' ') + '\n' + ); + expect(stdout).toEqual("saw respawn [ '--lazy' ]\n"); done(); } }); - it('should respawn if v8flag is set by both cli flag and forcedFlags', function(done) { - exec('node test/fixtures/prepare-execute/v8flags_config.js 123 --harmony abc', cb); + it('should respawn if v8flag is set by both cli flag and forcedFlags', function (done) { + exec( + 'node test/fixtures/prepare-execute/v8flags_config.js 123 --harmony abc', + cb + ); function cb(err, stdout, stderr) { - expect(err).to.equal(null); - expect(stderr).to.equal([ - path.resolve('test/fixtures/prepare-execute/v8flags_config.js'), - '123', - 'abc', - ].join(' ') + '\n'); - expect(stdout).to.equal('saw respawn [ \'--lazy\', \'--harmony\' ]\n'); + expect(err).toEqual(null); + expect(stderr).toEqual( + [ + path.resolve('test/fixtures/prepare-execute/v8flags_config.js'), + '123', + 'abc', + ].join(' ') + '\n' + ); + expect(stdout).toEqual("saw respawn [ '--lazy', '--harmony' ]\n"); done(); } }); - it('should emit a respawn event if a respawn is required', function(done) { - exec('node test/fixtures/prepare-execute/v8flags.js', function(err, stdout) { - expect(stdout).to.be.empty; - exec('node test/fixtures/prepare-execute/v8flags_function.js --lazy', function(err, stdout) { - expect(stdout).to.equal('saw respawn\n'); - done(); - }); - }); + it('should emit a respawn event if a respawn is required', function (done) { + exec( + 'node test/fixtures/prepare-execute/v8flags.js', + function (err, stdout) { + expect(stdout).toEqual(''); + exec( + 'node test/fixtures/prepare-execute/v8flags_function.js --lazy', + function (err, stdout) { + expect(stdout).toEqual('saw respawn\n'); + done(); + } + ); + } + ); }); - it('should respawn if process.argv has v8flags with values in it', function(done) { - exec('node test/fixtures/prepare-execute/v8flags_value.js --stack_size=2048', function(err, stdout, stderr) { - expect(stderr).to.equal('--stack_size=2048\n'); - done(); - }); + it('should respawn if process.argv has v8flags with values in it', function (done) { + exec( + 'node test/fixtures/prepare-execute/v8flags_value.js --stack_size=2048', + function (err, stdout, stderr) { + expect(stderr).toEqual('--stack_size=2048\n'); + done(); + } + ); }); - it('should respawn if v8flags is empty but forcedFlags are specified', function(done) { + it('should respawn if v8flags is empty but forcedFlags are specified', function (done) { exec('node test/fixtures/prepare-execute/nodeflags_only.js 123', cb); function cb(err, stdout, stderr) { - expect(err).to.equal(null); - expect(stderr).to.equal([ - path.resolve('test/fixtures/prepare-execute/nodeflags_only.js'), - '123', - ].join(' ') + '\n'); - expect(stdout).to.equal('saw respawn [ \'--lazy\' ]\n'); + expect(err).toEqual(null); + expect(stderr).toEqual( + [ + path.resolve('test/fixtures/prepare-execute/nodeflags_only.js'), + '123', + ].join(' ') + '\n' + ); + expect(stdout).toEqual("saw respawn [ '--lazy' ]\n"); done(); } }); }); - describe('requireLocal', function() { - - it('should attempt pre-loading local modules if they are requested', function(done) { + describe('requireLocal', function () { + it('should attempt pre-loading local modules if they are requested', function (done) { var app = new Liftoff({ name: 'test' }); var logs = []; - app.on('preload:success', function(moduleName, module) { - expect(moduleName).to.equal('coffeescript/register'); - expect(module).to.equal(require('coffeescript/register')); + app.on('preload:success', function (moduleName, module) { + expect(moduleName).toEqual('coffeescript/register'); + expect(module).toEqual(require('coffeescript/register')); logs.push('preload:success'); }); - app.on('preload:failure', function(moduleName, err) { + app.on('preload:failure', function (moduleName, err) { done(err); }); - app.prepare({ preload: ['coffeescript/register'] }, function(env) { - app.execute(env, function(env) { - expect(env.preload).to.deep.equal(['coffeescript/register']); - expect(logs).to.deep.equal(['preload:success']); + app.prepare({ preload: ['coffeescript/register'] }, function (env) { + app.execute(env, function (env) { + expect(env.preload).toEqual(['coffeescript/register']); + expect(logs).toEqual(['preload:success']); done(); }); }); }); - it('should attempt pre-loading a local module if it is requested', function(done) { + it('should attempt pre-loading a local module if it is requested', function (done) { var app = new Liftoff({ name: 'test' }); var logs = []; - app.on('preload:success', function(moduleName, module) { - expect(moduleName).to.equal('coffeescript/register'); - expect(module).to.equal(require('coffeescript/register')); + app.on('preload:success', function (moduleName, module) { + expect(moduleName).toEqual('coffeescript/register'); + expect(module).toEqual(require('coffeescript/register')); logs.push('preload:success'); }); - app.on('preload:failure', function(moduleName, err) { + app.on('preload:failure', function (moduleName, err) { done(err); }); - app.prepare({ preload: 'coffeescript/register' }, function(env) { - app.execute(env, function(env) { - expect(env.preload).to.deep.equal(['coffeescript/register']); - expect(logs).to.deep.equal(['preload:success']); + app.prepare({ preload: 'coffeescript/register' }, function (env) { + app.execute(env, function (env) { + expect(env.preload).toEqual(['coffeescript/register']); + expect(logs).toEqual(['preload:success']); done(); }); }); }); - it('should attempt pre-loading local modules but fail', function(done) { + it('should attempt pre-loading local modules but fail', function (done) { var app = new Liftoff({ name: 'test' }); var logs = []; - app.on('preload:failure', function(moduleName, err) { - expect(moduleName).to.equal('badmodule'); - expect(err).to.not.equal(null); + app.on('preload:failure', function (moduleName, err) { + expect(moduleName).toEqual('badmodule'); + expect(err).not.toEqual(null); logs.push('preload:failure'); }); - app.prepare({ preload: 'badmodule' }, function(env) { - app.execute(env, function(env) { - expect(env.preload).to.deep.equal(['badmodule']); - expect(logs).to.deep.equal(['preload:failure']); + app.prepare({ preload: 'badmodule' }, function (env) { + app.execute(env, function (env) { + expect(env.preload).toEqual(['badmodule']); + expect(logs).toEqual(['preload:failure']); done(); }); }); }); - it('should pre-load a local module only once even if be respawned', function(done) { + it('should pre-load a local module only once even if be respawned', function (done) { var fixturesDir = path.resolve(__dirname, 'fixtures'); exec('cd ' + fixturesDir + ' && node respawn_and_require.js', cb); function cb(err, stdout, stderr) { - expect(err).to.equal(null); - expect(stderr).to.equal(''); - expect(stdout).to.equal( - 'saw respawn [ \'--lazy\' ]\n' + - 'preload:success coffeescript/register\n' + - 'execute\n' + - ''); + expect(err).toEqual(null); + expect(stderr).toEqual(''); + expect(stdout).toEqual( + "saw respawn [ '--lazy' ]\n" + + 'preload:success coffeescript/register\n' + + 'execute\n' + + '' + ); done(); } }); - it('should emit `preload:before` and `preload:success` with the name of the module and the required module', function(done) { + it('should emit `preload:before` and `preload:success` with the name of the module and the required module', function (done) { var requireTest = new Liftoff({ name: 'require' }); var isEmittedBeforeRequired = false; - requireTest.on('preload:before', function(name) { - expect(name).to.equal('mocha'); + requireTest.on('preload:before', function (name) { + expect(name).toEqual('mocha'); isEmittedBeforeRequired = true; }); - requireTest.on('preload:success', function(name, module) { - expect(name).to.equal('mocha'); - expect(module).to.equal(require('mocha')); - expect(isEmittedBeforeRequired).to.equal(true); + requireTest.on('preload:success', function (name, module) { + expect(name).toEqual('mocha'); + expect(module).toEqual(require('mocha')); + expect(isEmittedBeforeRequired).toEqual(true); done(); }); requireTest.requireLocal('mocha', __dirname); }); - it('should emit `preload:before` and `preload:failure` with an error if a module can\'t be found.', function(done) { + it("should emit `preload:before` and `preload:failure` with an error if a module can't be found.", function (done) { var requireFailTest = new Liftoff({ name: 'preload:failure' }); var isEmittedBeforeRequired = false; - requireFailTest.on('preload:before', function(name) { - expect(name).to.equal('badmodule'); + requireFailTest.on('preload:before', function (name) { + expect(name).toEqual('badmodule'); isEmittedBeforeRequired = true; }); - requireFailTest.on('preload:failure', function(name) { - expect(name).to.equal('badmodule'); - expect(isEmittedBeforeRequired).to.equal(true); + requireFailTest.on('preload:failure', function (name) { + expect(name).toEqual('badmodule'); + expect(isEmittedBeforeRequired).toEqual(true); done(); }); requireFailTest.requireLocal('badmodule', __dirname); }); - }); - describe('configFiles', function() { - it('should be empty if not specified', function(done) { + describe('configFiles', function () { + it('should be empty if not specified', function (done) { var app = new Liftoff({ name: 'myapp', }); - app.prepare({}, function(env) { - expect(env.configFiles).to.deep.equal({}); + app.prepare({}, function (env) { + expect(env.configFiles).toEqual({}); done(); }); }); - it('should find multiple files if specified', function(done) { + it('should find multiple files if specified', function (done) { var app = new Liftoff({ name: 'myapp', configFiles: { @@ -418,8 +490,8 @@ describe('Liftoff', function() { }, }, }); - app.prepare({}, function(env) { - expect(env.configFiles).to.deep.equal({ + app.prepare({}, function (env) { + expect(env.configFiles).toEqual({ index: { currentdir: path.resolve('./index.js'), test: path.resolve('./test/fixtures/configfiles/index.json'), @@ -435,7 +507,7 @@ describe('Liftoff', function() { }); }); - it('should use default cwd if not specified', function(done) { + it('should use default cwd if not specified', function (done) { var app = new Liftoff({ name: 'myapp', configFiles: { @@ -447,19 +519,22 @@ describe('Liftoff', function() { }, }, }); - app.prepare({ - cwd: 'test/fixtures/configfiles', - }, function(env) { - expect(env.configFiles).to.deep.equal({ - index: { - cwd: path.resolve('./test/fixtures/configfiles/index.json'), - }, - }); - done(); - }); + app.prepare( + { + cwd: 'test/fixtures/configfiles', + }, + function (env) { + expect(env.configFiles).toEqual({ + index: { + cwd: path.resolve('./test/fixtures/configfiles/index.json'), + }, + }); + done(); + } + ); }); - it('should use default extensions if not specified', function(done) { + it('should use default extensions if not specified', function (done) { var app = new Liftoff({ extensions: { '.md': null, '.txt': null }, name: 'myapp', @@ -482,8 +557,8 @@ describe('Liftoff', function() { }, }, }); - app.prepare({}, function(env) { - expect(env.configFiles).to.deep.equal({ + app.prepare({}, function (env) { + expect(env.configFiles).toEqual({ README: { markdown: path.resolve('./README.md'), text: path.resolve('./test/fixtures/configfiles/README.txt'), @@ -495,7 +570,7 @@ describe('Liftoff', function() { }); }); - it('should use specified loaders', function(done) { + it('should use specified loaders', function (done) { var logRequire = []; var logFailure = []; @@ -541,7 +616,8 @@ describe('Liftoff', function() { index: { test: { path: 'test/fixtures/configfiles', - extensions: { // ignored + extensions: { + // ignored '.js': './test/fixtures/configfiles/require-js', '.json': './test/fixtures/configfiles/require-json', }, @@ -549,14 +625,14 @@ describe('Liftoff', function() { }, }, }); - app.on('loader:failure', function(moduleName, error) { + app.on('loader:failure', function (moduleName, error) { logFailure.push({ moduleName: moduleName, error: error }); }); - app.on('loader:success', function(moduleName, module) { + app.on('loader:success', function (moduleName, module) { logRequire.push({ moduleName: moduleName, module: module }); }); - app.prepare({}, function(env) { - expect(env.configFiles).to.deep.equal({ + app.prepare({}, function (env) { + expect(env.configFiles).toEqual({ README: { text: path.resolve('./test/fixtures/configfiles/README.txt'), text_null: null, @@ -570,34 +646,28 @@ describe('Liftoff', function() { }, }); - expect(logRequire.length).to.equal(2); - expect(logRequire[0].moduleName) - .to.equal('./test/fixtures/configfiles/require-txt'); - expect(logRequire[1].moduleName) - .to.equal('./test/fixtures/configfiles/require-md'); - - expect(logFailure.length).to.equal(1); - expect(logFailure[0].moduleName) - .to.equal('./test/fixtures/configfiles/require-non-exist'); - - expect(require(env.configFiles.README.markdown)) - .to.equal('Load README.md by require-md'); - expect(require(env.configFiles.README.text)).to - .to.equal('Load README.txt by require-txt'); - expect(require(env.configFiles.index.test)) - .to.deep.equal({ aaa: 'AAA' }); + expect(logRequire.length).toEqual(2); + expect(logRequire[0].moduleName).toEqual( + './test/fixtures/configfiles/require-txt' + ); + expect(logRequire[1].moduleName).toEqual( + './test/fixtures/configfiles/require-md' + ); + + expect(logFailure.length).toEqual(1); + expect(logFailure[0].moduleName).toEqual( + './test/fixtures/configfiles/require-non-exist' + ); + + expect(require(env.configFiles.README.markdown)).toEqual( + 'Load README.md by require-md' + ); + expect(require(env.configFiles.README.text)).toEqual( + 'Load README.txt by require-txt' + ); + expect(require(env.configFiles.index.test)).toEqual({ aaa: 'AAA' }); done(); }); }); }); - }); - -require('./lib/build_config_name'); -require('./lib/file_search'); -require('./lib/find_config'); -require('./lib/find_cwd'); -require('./lib/parse_options'); -require('./lib/silent_require'); -require('./lib/register_loader'); -require('./lib/get_node_flags'); diff --git a/test/lib/build_config_name.js b/test/lib/build_config_name.js deleted file mode 100644 index d117f7d..0000000 --- a/test/lib/build_config_name.js +++ /dev/null @@ -1,58 +0,0 @@ -var expect = require('chai').expect; -var buildConfigName = require('../../lib/build_config_name'); - -describe('buildConfigName', function() { - - it('should throw if no configName is provided', function() { - expect(function() { buildConfigName(); }).to.throw(); - }); - - it('should use configName directly if it is a regex', function() { - var configNameSearch = /mocha/; - expect(buildConfigName({ configName: configNameSearch })).to.deep.equal([configNameSearch]); - }); - - it('should throw if no array of extensions are provided and config is not a regex already', function() { - expect(function() { buildConfigName({ configName: 'foo' });}).to.throw(); - expect(function() { buildConfigName({ configName: 'foo', extensions: '?' }); }).to.throw(); - expect(function() { buildConfigName({ configName: 'foo', extensions: ['.js'] }); }).to.not.throw(); - }); - - it('should build an array of possible config names', function() { - var multiExtension = buildConfigName({ configName: 'foo', extensions: ['.js','.coffee'] }); - expect(multiExtension).to.deep.equal(['foo.js', 'foo.coffee']); - var singleExtension = buildConfigName({ configName: 'foo', extensions: ['.js'] }); - expect(singleExtension).to.deep.equal(['foo.js']); - }); - - it('should throw error if opts is null or empty', function() { - expect(function() { - buildConfigName(); - }).to.throw(); - expect(function() { - buildConfigName(null); - }).to.throw(); - expect(function() { - buildConfigName({}); - }).to.throw(); - }); - - it('should throw error if .configName is null', function() { - expect(function() { - buildConfigName({ extensions: ['.js'] }); - }).to.throw(); - }); - - it('should throw error if .extension is not an array', function() { - expect(function() { - buildConfigName({ configName: 'foo' }); - }).to.throw(); - expect(function() { - buildConfigName({ configName: 'foo', extensions: null }); - }).to.throw(); - expect(function() { - buildConfigName({ configName: 'foo', extensions: '.js' }); - }).to.throw(); - }); - -}); diff --git a/test/lib/file_search.js b/test/lib/file_search.js deleted file mode 100644 index 3e9eb4f..0000000 --- a/test/lib/file_search.js +++ /dev/null @@ -1,12 +0,0 @@ -var expect = require('chai').expect; -var fileSearch = require('../../lib/file_search'); -var path = require('path'); - -describe('fileSearch', function() { - - it('should locate a file using findup from an array of possible base paths', function() { - expect(fileSearch('mochafile.js', ['../../'])).to.be.null; - expect(fileSearch('package.json', [process.cwd()])).to.equal(path.resolve(__dirname,'..','..','package.json')); - }); - -}); diff --git a/test/lib/find_config.js b/test/lib/find_config.js deleted file mode 100644 index c86b812..0000000 --- a/test/lib/find_config.js +++ /dev/null @@ -1,85 +0,0 @@ -var path = require('path'); -var expect = require('chai').expect; -var findConfig = require('../../lib/find_config'); - -describe('findConfig', function() { - - it('should throw if searchPaths or configNameRegex are empty when configName isn\'t explicltly provided', function() { - expect(function() { findConfig(); }).to.throw(); - expect(function() { findConfig({ searchPaths: ['../'] }); }).to.throw(); - expect(function() { findConfig({ configNameRegex: 'dude' }); }).to.throw(); - }); - - it('if configPath is explicitly provided, return the absolute path to the file or null if it doesn\'t actually exist', function() { - var configPath = path.resolve('test/fixtures/mochafile.js'); - expect(findConfig({ configPath: configPath })).to.equal(configPath); - expect(findConfig({ configPath: 'path/to/nowhere' })).to.equal(null); - }); - - it('should return the absolute path to the first config file found in searchPaths', function() { - expect(findConfig({ - configNameSearch: ['mochafile.js', 'mochafile.coffee'], - searchPaths: ['test/fixtures'], - })).to.equal(path.resolve('test/fixtures/mochafile.js')); - expect(findConfig({ - configNameSearch: ['mochafile.js', 'mochafile.coffee'], - searchPaths: ['test/fixtures/search_path', 'test/fixtures/coffee'], - })).to.equal(path.resolve('test/fixtures/search_path/mochafile.js')); - expect(findConfig({ - configNameSearch: 'mochafile.js', - searchPaths: ['test/fixtures/search_path', 'test/fixtures/coffee'], - })).to.equal(path.resolve('test/fixtures/search_path/mochafile.js')); - }); - - it('should throw error if .searchPaths is not an array', function() { - expect(function() { - findConfig({ - configNameSearch: ['mochafile.js', 'mochafile.coffee'], - }); - }).to.throw(); - expect(function() { - findConfig({ - configNameSearch: ['mochafile.js', 'mochafile.coffee'], - searchPaths: null, - }); - }).to.throw(); - expect(function() { - findConfig({ - configNameSearch: ['mochafile.js', 'mochafile.coffee'], - searchPaths: 'test/fixtures/search_path', - }); - }).to.throw(); - }); - - it('should throw error if .configNameSearch is null', function() { - expect(function() { - findConfig({ - searchPaths: ['test/fixtures/search_path', 'test/fixtures/coffee'], - }); - }).to.throw(); - expect(function() { - findConfig({ - configNameSearch: null, - searchPaths: ['test/fixtures/search_path', 'test/fixtures/coffee'], - }); - }).to.throw(); - expect(function() { - findConfig({ - configNameSearch: '', - searchPaths: ['test/fixtures/search_path', 'test/fixtures/coffee'], - }); - }).to.throw(); - }); - - it('should throw error if opts is null or empty', function() { - expect(function() { - findConfig(); - }).to.throw(); - expect(function() { - findConfig(null); - }).to.throw(); - expect(function() { - findConfig({}); - }).to.throw(); - }); -}); diff --git a/test/lib/find_cwd.js b/test/lib/find_cwd.js deleted file mode 100644 index 9c33126..0000000 --- a/test/lib/find_cwd.js +++ /dev/null @@ -1,31 +0,0 @@ -var expect = require('chai').expect; -var findCwd = require('../../lib/find_cwd'); -var path = require('path'); - -describe('findCwd', function() { - - it('should return process.cwd if no options are passed', function() { - expect(findCwd()).to.equal(process.cwd()); - }); - - it('should return path from cwd if supplied', function() { - expect(findCwd({ cwd: '../' })).to.equal(path.resolve('../')); - }); - - it('should return directory of config if configPath defined', function() { - expect(findCwd({ configPath: 'test/fixtures/mochafile.js' })).to.equal(path.resolve('test/fixtures')); - }); - - it('should return path from cwd if both it and configPath are defined', function() { - expect(findCwd({ cwd: '../', configPath: 'test/fixtures/mochafile.js' })).to.equal(path.resolve('../')); - }); - - it('should ignore cwd if it isn\'t a string', function() { - expect(findCwd({ cwd: true })).to.equal(process.cwd()); - }); - - it('should ignore configPath if it isn\'t a string', function() { - expect(findCwd({ configPath: true })).to.equal(process.cwd()); - }); - -}); diff --git a/test/lib/get_node_flags.js b/test/lib/get_node_flags.js deleted file mode 100644 index 632e994..0000000 --- a/test/lib/get_node_flags.js +++ /dev/null @@ -1,69 +0,0 @@ -var expect = require('chai').expect; -var getNodeFlags = require('../../lib/get_node_flags'); - -describe('getNodeFlags', function() { - - describe('arrayOrFunction', function() { - it('should return the first argument when it is an array', function() { - var env = { cwd: 'aaa' }; - expect(getNodeFlags.arrayOrFunction([], env)).to.has.members([]); - expect(getNodeFlags.arrayOrFunction(['--lazy', '--use_strict', '--harmony'], env)) - .to.has.members(['--lazy', '--harmony', '--use_strict']); - }); - - it('should return the exection result of the first argument when it is a function', function() { - var env = { cwd: 'aaa' }; - expect(getNodeFlags.arrayOrFunction(function() { - return []; - }, env)).to.has.members([]); - expect(getNodeFlags.arrayOrFunction(function(arg) { - expect(arg).to.equal(env); - return ['--lazy', '--harmony']; - }, env)).to.has.members(['--lazy', '--harmony']); - }); - - it('should return an array which has an element of the first argument when the first argument is a string', function() { - var env = { cwd: 'aaa' }; - expect(getNodeFlags.arrayOrFunction('--lazy', env)).to.has.members(['--lazy']); - }); - - it('should return an empty array when the first argument is neither an array, a function nor a string', function() { - var env = { cwd: 'aaa' }; - expect(getNodeFlags.arrayOrFunction(undefined, env)).to.has.members([]); - expect(getNodeFlags.arrayOrFunction(null, env)).to.has.members([]); - expect(getNodeFlags.arrayOrFunction(true, env)).to.has.members([]); - expect(getNodeFlags.arrayOrFunction(false, env)).to.has.members([]); - expect(getNodeFlags.arrayOrFunction(0, env)).to.has.members([]); - expect(getNodeFlags.arrayOrFunction(123, env)).to.has.members([]); - expect(getNodeFlags.arrayOrFunction({}, env)).to.has.members([]); - expect(getNodeFlags.arrayOrFunction({ length: 1 }, env)).to.has.members([]); - }); - }); - - describe('fromReorderedArgv', function() { - it('should return only node flags from respawning arguments', function() { - var env = { cwd: 'aaa' }; - var cmd = ['node', '--lazy', '--harmony', '--use_strict', './aaa/bbb/app.js', '--ccc', 'ddd', '-e', 'fff']; - expect(getNodeFlags.fromReorderedArgv(cmd, env)).to.deep.equal(['--lazy', '--harmony', '--use_strict']); - }); - - it('should end node flags before "--"', function() { - var env = { cwd: 'aaa' }; - var cmd = ['node', '--lazy', '--', '--harmony', '--use_strict', './aaa/bbb/app.js', '--ccc', 'ddd', '-e', 'fff']; - expect(getNodeFlags.fromReorderedArgv(cmd, env)).to.deep.equal(['--lazy']); - - }); - - it('should return node flags when arguments are only node flags', function() { - var env = { cwd: 'aaa' }; - var cmd = ['node', '--lazy', '--harmony', '--use_strict']; - expect(getNodeFlags.fromReorderedArgv(cmd, env)).to.deep.equal(['--lazy', '--harmony', '--use_strict']); - }); - - it('should return an empty array when no node flags', function() { - var env = { cwd: 'aaa' }; - var cmd = ['node', './aaa/bbb/app.js', '--aaa', 'bbb', '-c', 'd']; - expect(getNodeFlags.fromReorderedArgv(cmd, env)).to.deep.equal([]); - }); - }); -}); diff --git a/test/lib/parse_options.js b/test/lib/parse_options.js deleted file mode 100644 index a06831a..0000000 --- a/test/lib/parse_options.js +++ /dev/null @@ -1,64 +0,0 @@ -var expect = require('chai').expect; -var parseOptions = require('../../lib/parse_options'); -var NAME = 'mocha'; - -describe('parseOptions', function() { - - it('should auto-set processTitle, moduleName, & configFile if `name` is provided.', function() { - var opts = parseOptions({ name: NAME }); - expect(opts.processTitle).to.equal(NAME); - expect(opts.configName).to.equal(NAME + 'file'); - expect(opts.moduleName).to.equal(NAME); - }); - - it('should set a title to be used for the process at launch', function() { - var opts = parseOptions({ name: NAME }); - expect(opts.processTitle).to.equal(NAME); - expect(function() { - parseOptions(); - }).to.throw('You must specify a processTitle.'); - }); - - it('should set the configuration file to look for at launch', function() { - var opts = parseOptions({ name: NAME }); - expect(opts.configName).to.equal(NAME + 'file'); - expect(function() { - parseOptions({ processTitle: NAME }); - }).to.throw('You must specify a configName.'); - }); - - it('should set a local module to resolve at launch', function() { - var opts = parseOptions({ name: NAME }); - expect(opts.moduleName).to.equal(NAME); - }); - - it('should use .processTitle/.configName/.moduleName preferencially', - function() { - var opts = parseOptions({ - name: 'a', - processTitle: 'b', - configName: 'c', - moduleName: 'd', - }); - expect(opts.processTitle).to.equal('b'); - expect(opts.configName).to.equal('c'); - expect(opts.moduleName).to.equal('d'); - }); - - it('should throw error if opts does not have .name and .moduleName', - function() { - expect(function() { - parseOptions({ - processTitle: 'a', - configName: 'b', - }); - }).to.throw(); - }); - - it('should throw error if opts is null or empty', function() { - expect(function() { parseOptions(null); }).to.throw(); - expect(function() { parseOptions(undefined); }).to.throw(); - expect(function() { parseOptions({}); }).to.throw(); - }); - -}); diff --git a/test/lib/silent_require.js b/test/lib/silent_require.js deleted file mode 100644 index fc4f94f..0000000 --- a/test/lib/silent_require.js +++ /dev/null @@ -1,17 +0,0 @@ -var expect = require('chai').expect; -var path = require('path'); -var silentRequire = require('../../lib/silent_require'); - -describe('silentRequire', function() { - - it('should require a file', function() { - expect(silentRequire(path.resolve('./package'))).to.deep.equal(require('../../package')); - }); - - it('should not throw if file is not found', function() { - expect(function() { - silentRequire('path/to/nowhere'); - }).to.not.throw(); - }); - -}); diff --git a/test/parse_options.js b/test/parse_options.js new file mode 100644 index 0000000..d0ae4cd --- /dev/null +++ b/test/parse_options.js @@ -0,0 +1,75 @@ +var expect = require('expect'); + +var parseOptions = require('../lib/parse_options'); + +var NAME = 'mocha'; + +describe('parseOptions', function () { + it('should auto-set processTitle, moduleName, & configFile if `name` is provided', function (done) { + var opts = parseOptions({ name: NAME }); + expect(opts.processTitle).toEqual(NAME); + expect(opts.configName).toEqual(NAME + 'file'); + expect(opts.moduleName).toEqual(NAME); + done(); + }); + + it('should set a title to be used for the process at launch', function (done) { + var opts = parseOptions({ name: NAME }); + expect(opts.processTitle).toEqual(NAME); + expect(function () { + parseOptions(); + }).toThrow('You must specify a processTitle.'); + done(); + }); + + it('should set the configuration file to look for at launch', function (done) { + var opts = parseOptions({ name: NAME }); + expect(opts.configName).toEqual(NAME + 'file'); + expect(function () { + parseOptions({ processTitle: NAME }); + }).toThrow('You must specify a configName.'); + done(); + }); + + it('should set a local module to resolve at launch', function (done) { + var opts = parseOptions({ name: NAME }); + expect(opts.moduleName).toEqual(NAME); + done(); + }); + + it('should use .processTitle/.configName/.moduleName preferencially', function (done) { + var opts = parseOptions({ + name: 'a', + processTitle: 'b', + configName: 'c', + moduleName: 'd', + }); + expect(opts.processTitle).toEqual('b'); + expect(opts.configName).toEqual('c'); + expect(opts.moduleName).toEqual('d'); + done(); + }); + + it('should throw error if opts does not have .name and .moduleName', function (done) { + expect(function () { + parseOptions({ + processTitle: 'a', + configName: 'b', + }); + }).toThrow(); + done(); + }); + + it('should throw error if opts is null or empty', function (done) { + expect(function () { + parseOptions(null); + }).toThrow(); + expect(function () { + parseOptions(undefined); + }).toThrow(); + expect(function () { + parseOptions({}); + }).toThrow(); + done(); + }); +}); diff --git a/test/lib/register_loader.js b/test/register_loader.js similarity index 67% rename from test/lib/register_loader.js rename to test/register_loader.js index 6937ff2..a630244 100644 --- a/test/lib/register_loader.js +++ b/test/register_loader.js @@ -1,32 +1,33 @@ -var expect = require('chai').expect; -var registerLoader = require('../../lib/register_loader'); var path = require('path'); var util = require('util'); var EE = require('events').EventEmitter; -var testDir = path.resolve(__dirname, '../fixtures/register_loader'); +var expect = require('expect'); + +var registerLoader = require('../lib/register_loader'); + +var testDir = path.resolve(__dirname, './fixtures/register_loader'); function App() { EE.call(this); } util.inherits(App, EE); -function handlerNotEmit(/* moduleName, moduleOrError */) { - expect.fail(null, null, 'Should not pass this line.'); +function handlerNotEmit() { + throw new Error('Should not have emitted'); } -describe('registerLoader', function() { - describe('register loader', function() { - it('Should emit a "require" event when registering loader succeeds', function(done) { - +describe('registerLoader', function () { + describe('register loader', function () { + it('Should emit a `loader:success` event when registering loader succeeds', function (done) { var loaderPath = path.join(testDir, 'require-cfg.js'); var configPath = path.join(testDir, 'app.cfg'); var extensions = { '.cfg': loaderPath }; var app = new App(); - app.on('loader:success', function(moduleName /* , module */) { - expect(moduleName).to.be.equal(loaderPath); - expect(require(configPath)).to.equal('Load app.cfg by require-cfg'); + app.on('loader:success', function (moduleName /* , module */) { + expect(moduleName).toEqual(loaderPath); + expect(require(configPath)).toEqual('Load app.cfg by require-cfg'); done(); }); app.on('loader:failure', handlerNotEmit); @@ -34,16 +35,15 @@ describe('registerLoader', function() { registerLoader(app, extensions, configPath); }); - it('Should emit only a "loader:success" event when registering loader failed and succeeds', function(done) { - + it('Should emit only a `loader:success` event when registering loader failed and succeeds', function (done) { var loaderPath = path.join(testDir, 'require-conf.js'); var configPath = path.join(testDir, 'app.conf'); var extensions = { '.conf': ['xxx', loaderPath] }; var app = new App(); - app.on('loader:success', function(moduleName /* , module */) { - expect(moduleName).to.be.equal(loaderPath); - expect(require(configPath)).to.equal('Load app.conf by require-conf'); + app.on('loader:success', function (moduleName /* , module */) { + expect(moduleName).toEqual(loaderPath); + expect(require(configPath)).toEqual('Load app.conf by require-conf'); done(); }); app.on('loader:failure', handlerNotEmit); @@ -51,23 +51,22 @@ describe('registerLoader', function() { registerLoader(app, extensions, configPath); }); - it('Should emit a "loader:failure" event when loader is not found', function(done) { - + it('Should emit a `loader:failure` event when loader is not found', function (done) { var loaderPath = path.join(testDir, 'require-tmp.js'); var configPath = path.join(testDir, 'app.tmp'); var extensions = { '.tmp': ['xxx', loaderPath] }; var app = new App(); var index = 0; - app.on('loader:failure', function(moduleName, error) { + app.on('loader:failure', function (moduleName, error) { if (index === 0) { - expect(moduleName).to.be.equal('xxx'); - expect(error).to.be.an('error'); - expect(error.message).to.contain('Cannot find module'); + expect(moduleName).toEqual('xxx'); + expect(error).toBeInstanceOf(Error); + expect(error.message).toMatch('Cannot find module'); } else if (index === 1) { - expect(moduleName).to.be.equal(loaderPath); - expect(error).to.be.an('error'); - expect(error.message).to.contain('Cannot find module'); + expect(moduleName).toEqual(loaderPath); + expect(error).toBeInstanceOf(Error); + expect(error.message).toMatch('Cannot find module'); done(); } else { done(new Error('Should not call more than two times')); @@ -79,16 +78,16 @@ describe('registerLoader', function() { registerLoader(app, extensions, configPath); }); - it('Should emit a "loader:failure" event when registering loader failed', function(done) { + it('Should emit a `loader:failure` event when registering loader failed', function (done) { var loaderPath = path.join(testDir, 'require-fail.js'); var configPath = path.join(testDir, 'app.tmp'); var extensions = { '.tmp': loaderPath }; var app = new App(); - app.on('loader:failure', function(moduleName, error) { - expect(moduleName).to.be.equal(loaderPath); - expect(error).to.be.an('error'); - expect(error.message).to.contain('Fail to register!'); + app.on('loader:failure', function (moduleName, error) { + expect(moduleName).toEqual(loaderPath); + expect(error).toBeInstanceOf(Error); + expect(error.message).toMatch('Fail to register!'); done(); }); app.on('loader:success', handlerNotEmit); @@ -97,18 +96,17 @@ describe('registerLoader', function() { }); }); - describe('cwd', function() { - it('Should use "cwd" as a base directory of loaded file path if specified', function(done) { - + describe('cwd', function () { + it('Should use "cwd" as a base directory of loaded file path if specified', function (done) { var loaderPath = path.join(testDir, 'require-rc.js'); var configPath = 'app.rc'; var extensions = { '.rc': loaderPath }; var app = new App(); - app.on('loader:success', function(moduleName /* , module */) { - expect(moduleName).to.be.equal(loaderPath); + app.on('loader:success', function (moduleName /* , module */) { + expect(moduleName).toEqual(loaderPath); var loadedFile = path.join(testDir, configPath); - expect(require(loadedFile)).to.equal('Load app.rc by require-rc'); + expect(require(loadedFile)).toEqual('Load app.rc by require-rc'); done(); }); app.on('loader:failure', handlerNotEmit); @@ -117,8 +115,8 @@ describe('registerLoader', function() { }); }); - describe('extensions', function() { - it('Should do nothing when extensions is null', function(done) { + describe('extensions', function () { + it('Should do nothing when extensions is null', function (done) { var app = new App(); app.on('loader:success', handlerNotEmit); app.on('loader:failure', handlerNotEmit); @@ -134,25 +132,25 @@ describe('registerLoader', function() { done(); }); - it('Should do nothing when extensions is illegal type', function(done) { + it('Should do nothing when extensions is illegal type', function (done) { var app = new App(); app.on('loader:success', handlerNotEmit); app.on('loader:failure', handlerNotEmit); registerLoader(app, 123, 'aaa/bbb.cfg'); registerLoader(app, true, 'aaa/bbb.cfg'); - registerLoader(app, function() {}, 'aaa/bbb.cfg'); + registerLoader(app, function () {}, 'aaa/bbb.cfg'); registerLoader(app, ['.rc', '.cfg'], 'aaa/bbb.cfg'); // .js is one of default extensions registerLoader(app, 123, 'aaa/bbb.js'); registerLoader(app, true, 'aaa/bbb.js'); - registerLoader(app, function() {}, 'aaa/bbb.js'); + registerLoader(app, function () {}, 'aaa/bbb.js'); registerLoader(app, ['.js', '.json'], 'aaa/bbb.js'); done(); }); - it('Should do nothing when extensions is a string', function(done) { + it('Should do nothing when extensions is a string', function (done) { var app = new App(); app.on('loader:success', handlerNotEmit); app.on('loader:failure', handlerNotEmit); @@ -163,8 +161,8 @@ describe('registerLoader', function() { }); }); - describe('configPath', function() { - it('Should do nothing when configPath is null', function(done) { + describe('configPath', function () { + it('Should do nothing when configPath is null', function (done) { var extensions0 = ['.js', '.json', '.coffee', '.coffee.md']; var extensions1 = { '.js': null, @@ -184,7 +182,7 @@ describe('registerLoader', function() { done(); }); - it('Should do nothing when configPath is illegal type', function(done) { + it('Should do nothing when configPath is illegal type', function (done) { var extensions0 = ['.js', '.json', '.coffee', '.coffee.md']; var extensions1 = { '.js': null, @@ -200,11 +198,11 @@ describe('registerLoader', function() { registerLoader(app, extensions0, 123); registerLoader(app, extensions0, ['aaa', 'bbb']); registerLoader(app, extensions1, {}); - registerLoader(app, extensions1, function() {}); + registerLoader(app, extensions1, function () {}); done(); }); - it('Should do nothing when configPath does not end with one of extensions', function(done) { + it('Should do nothing when configPath does not end with one of extensions', function (done) { var loaderPath = path.join(testDir, 'require-rc.js'); var configPath = path.join(testDir, 'app.xxx'); var extensions = { '.cfg': loaderPath }; @@ -217,7 +215,7 @@ describe('registerLoader', function() { done(); }); - it('Should do nothing when configPath ends with one of extensions of which the loader was already registered', function(done) { + it('Should do nothing when configPath ends with one of extensions of which the loader was already registered', function (done) { var loaderPath = path.join(testDir, 'require-cfg.js'); var configPath = path.join(testDir, 'app.cfg'); var extensions = { '.cfg': loaderPath }; @@ -231,40 +229,42 @@ describe('registerLoader', function() { }); }); - describe('Multiple extensions', function() { - it('should detect the shortest extension in extension candidates', function(done) { + describe('Multiple extensions', function () { + it('should detect the shortest extension in extension candidates', function (done) { var loaderPath = path.join(testDir, 'require-file-b.js'); var configPath = path.join(testDir, 'file.a.b'); var extensions = { '.b': loaderPath }; var app = new App(); app.on('loader:failure', handlerNotEmit); - app.on('loader:success', function(moduleName /* , module */) { - expect(moduleName).to.be.equal(loaderPath); - expect(require(configPath)).to.equal('Load file.a.b by require-file-b'); + app.on('loader:success', function (moduleName /* , module */) { + expect(moduleName).toEqual(loaderPath); + expect(require(configPath)).toEqual('Load file.a.b by require-file-b'); done(); }); registerLoader(app, extensions, configPath); }); - it('should detect not shortest extension in extension candidates', function(done) { + it('should detect not shortest extension in extension candidates', function (done) { var loaderPath = path.join(testDir, 'require-file-bc.js'); var configPath = path.join(testDir, 'file.a.b.c'); var extensions = { '.b.c': loaderPath }; var app = new App(); app.on('loader:failure', handlerNotEmit); - app.on('loader:success', function(moduleName /* , module */) { - expect(moduleName).to.be.equal(loaderPath); - expect(require(configPath)).to.equal('Load file.a.b.c by require-file-bc'); + app.on('loader:success', function (moduleName /* , module */) { + expect(moduleName).toEqual(loaderPath); + expect(require(configPath)).toEqual( + 'Load file.a.b.c by require-file-bc' + ); done(); }); registerLoader(app, extensions, configPath); }); - it('Should update a loader of a longer extension but not update a loader of a shorter extension', function(done) { + it('Should update a loader of a longer extension but not update a loader of a shorter extension', function (done) { var loaderPathD = path.join(testDir, 'require-file-d.js'); var loaderPathCD = path.join(testDir, 'require-file-cd.js'); var loaderPathECD = path.join(testDir, 'require-file-ecd.js'); @@ -285,21 +285,27 @@ describe('registerLoader', function() { var count = 0; var app = new App(); app.on('loader:failure', handlerNotEmit); - app.on('loader:success', function(moduleName /* , module */) { + app.on('loader:success', function (moduleName /* , module */) { switch (count) { case 0: { - expect(moduleName).to.be.equal(loaderPathCD); - expect(require(configPathCD)).to.equal('Load file.a.b.c.d by require-file-cd'); + expect(moduleName).toEqual(loaderPathCD); + expect(require(configPathCD)).toEqual( + 'Load file.a.b.c.d by require-file-cd' + ); break; } case 1: { - expect(moduleName).to.be.equal(loaderPathECD); - expect(require(configPathECD)).to.equal('Load file.a.e.c.d by require-file-ecd'); + expect(moduleName).toEqual(loaderPathECD); + expect(require(configPathECD)).toEqual( + 'Load file.a.e.c.d by require-file-ecd' + ); break; } case 2: { - expect(moduleName).to.be.equal(loaderPathFCD); - expect(require(configPathFCD)).to.equal('Load file.a.f.c.d by require-file-fcd'); + expect(moduleName).toEqual(loaderPathFCD); + expect(require(configPathFCD)).toEqual( + 'Load file.a.f.c.d by require-file-fcd' + ); done(); break; } @@ -313,6 +319,4 @@ describe('registerLoader', function() { registerLoader(app, extensions, configPathFCD); }); }); - }); - diff --git a/test/silent_require.js b/test/silent_require.js new file mode 100644 index 0000000..01040b0 --- /dev/null +++ b/test/silent_require.js @@ -0,0 +1,21 @@ +var path = require('path'); + +var expect = require('expect'); + +var silentRequire = require('../lib/silent_require'); + +describe('silentRequire', function () { + it('should require a file', function (done) { + expect(silentRequire(path.resolve('./package'))).toEqual( + require('../package') + ); + done(); + }); + + it('should not throw if file is not found', function (done) { + expect(function () { + silentRequire('path/to/nowhere'); + }).not.toThrow(); + done(); + }); +});