Mocha: Option exclude certain files by pattern when testing recursively

Created on 4 Mar 2015  ·  71Comments  ·  Source: mochajs/mocha

I would like the ability to provide an exclusion pattern so that I can only test files that match my test file pattern. This would allow data files to coexist with test files so long as they follow a reasonable pattern.

I think this would be simply providing an option that sets ignore option in glob.

Thoughts? I can make a PR for it real quick if you'd like.

feature good-first-issue help wanted usability

Most helpful comment

image

All 71 comments

You may better make two parallel directories, one for tests and the other
for data files. That's what I did.
Am 04.03.2015 15:52 schrieb "Kyle P Davis" [email protected]:

I would like the ability to provide an exclusion pattern so that I can
only test files that match my test file pattern. This would allow data
files to coexist with test files so long as they follow a reasonable
pattern.

I think this would be simply providing an option that sets ignore option
in glob.

Thoughts? I can make a PR for it real quick if you'd like.


Reply to this email directly or view it on GitHub
https://github.com/mochajs/mocha/issues/1577.

I could (and have in the past) but I'd rather not have to do that anymore now that I've realized that glob ignore is right there.

It should be pretty easy to add a command line argument to set the glob ignore option. I just wanted to get thoughts and discuss a little bit first.

Any objections to me creating a PR for this?

I was just needing this too and was surprised to see mocha did not already have it. I think it would be a great addition. We have a "testApp" inside our test folder that we use specifically for testing. We don't want mocha trying to run tests inside that folder. It would be nice to be able to just add an exclude to our mocha.opts file to exclude that specific path rather than having to explicitly include all the other test sub-folders we have.

While we could move the testApp out, it really doesn't fit anywhere else in the repo and its got relative pathing to certain files in the test folder.

This I think would be a nice addition. Certainly not critical, but helpful.

@KylePDavis @toddbluhm

If I needed this, I think I'd probably just

$ mocha $(find test/ ! -path '*testApp*')

So I'm not really thrilled about the idea. I'm kind of on the fence about the existence of the recursive flag even, since the same thing can be achieved with a shell command, Makefile, Gruntfile.js, gulpfile.js, etc., etc.

I think @boneskull makes a good point - this is already achievable in a variety of ways. And that's not including the fact that you can structure you directories to avoid this altogether. For example, given this structure:

$ tree .
.
└── spec
    ├── fixtures
    ├── integration
    └── unit

4 directories, 0 files

You just update your package.json so that you can simply run npm test

  "scripts": {
    "test": "mocha spec/unit spec/integration"
  }

Or with a structure like the following:

$ tree .
.
└── src
    └── models
        ├── user.js
        └── userSpec.js

2 directories, 2 files

You could run specs in a similar fashion as @boneskull's example (this will only run files containing Spec)

  "scripts": {
    "test": "mocha $(find src -name '*Spec.js')"
  }

Edit: Fixed :)

@danielstjules I think that will actually hit any dir with Spec in the name. Perhaps you want -name '*.spec.js'

Yup, you're right! Brainfart. Thanks for pointing that out.

Fixed command for the example:

  "scripts": {
    "test": "mocha $(find src -name '*Spec.js')"
  }

I think there is still a valid use case for this feature: I tend to group my files by feature, so each test file is next to the files containing the logic they're testing. Naming test files consistently works with the file argument or grep option but I would like to explicitly ignore things like node_modules.

For anyone looking - gulp-mocha can achieve this, I just hate to include gulp where I don't have to.

I'd like to take a moment and +1 this idea. Unlike typical JavaScript projects I like to follow the way GO does unit testing and I include a spec file next to every single file that gets tested. For example a directory in one of my projects may look like the following:

main.js
main.spec.js
utilities.js
utilities.spec.js

I find this type of organization makes it far easier to find test versus digging into a single directory of test files; you always expect the test to sit right next to the file that it tests and my build script scripts all .spec.js files out in the deployed version.

Due to my non-standard layout what I'd like to be able to do is run all unit tests with all of my folders excluding the node_modules directory.

I don't have a Windows box near me at the moment but I'm not sure if that find syntax would work in Windows or not; an exclude option would be far more intuitive anyway in my opinion. Plus almost all unit test frameworks include a way of ignoring files anyway so parity would be nice.

Hi, all my tests support *.test.js format. They are all in tests directory. Currently I have couple of tests that I want to exclude, and still retain the default path for mocha which is ./test/**/*.js. How do I do that?

Creating two separate directories will not work here, and you have to agree that moving tests between to directories would create a lot of noise in VCS.

@calebthebrewer Thankfully I'm using gulp in the project ;) thanks for the hint!

+1 @calebthebrewer

Angular 2.0 and Polymer have me in component mode so I agree with @KrisSiegel. Keeping all of your code in bundles keeps a clean, modular, easy-to-maintain file hierarchy.

Is there any foreseeable problem to loading the tests using the q promise library in a fashion such as this:

import q from 'q';

import authRouterTest from '../app/routes/_authentication.router.e2e.js';

import productRouterTest from '../app/routes/_product.router.e2e.js';

import productModelTest from '../app/models/product.model.spec.js';

// Dynamically constructed sequence of functions
let funcs = [ productModelTest(), authRouterTest(), productRouterTest() ];

// This function takes an array of promise-producing functions and
// runs them sequentially.
let execTests = () => {

    let result = q();

    funcs.forEach((f) => {

        result = result.then(f);
    });

    return result;
};

// Execute tests
execTests();

This way you can import your files from wherever and just have one test file in test/.

You can resolve the promise within the last test block and wrap each test up like this

import q from 'q'

export default () => {

    let Q = q.defer();

    describe('something', () => {

        it('should', (done) => {

            ...
        });
    });

    describe('something', () => {

        it('should', (done) => {

            ...
        });

        it('should', (done) => {

            ...

            Q.resolve('test complete');
        });
    });

    return Q.promise;
};

It seems to work pretty good, unless there is something I am not considering.

We should still have an ignore for the glob. Using bash commands is not a cross platform solution.

+1

I really would like to exclude node_modules. Exclusion seems like a pretty handy companion to recursive.

@godspeedelbow Why would that particular directory need explicitly ignored? I don't normally hear about node_modules being in a test directory.

FWIW, I could really use this as well. I've got a couple projects where the tests scale far more than the library itself, and this would enable me to better organize them (fixtures belong in a test directory IMHO).

Ignoring node_modules becomes important when you're either doing something unexpected (like me where I keep spec files next to the file it tests versus keeping them in a single folder, away from the code it tests) or if you want to run unit tests against a main project and some of its included projects (perhaps they're internal libraries, not in the npm repo, that you would like to test) but you don't want to run the unit tests within their own dependencies.

This issue has been around for almost a full year now so I don't have much hope of it being implemented. It's important, in my opinion, to implement because the workarounds either require platform specific terminal commands or you explicitly specify patterns for each directory you want to test (so additional directories need to be added to the testing script). I would fork it and just do it myself but using the hacky method of specifying each directory and a pattern is just easier than finding the time to implement it into mocha.

@KrisSiegel You could always do src/**/*.js and src/**/*.spec.js. I see that more often in Go and Rust projects than starting in the project root. Matter of fact, the latter is relatively uncommon.

Although I think they're just waiting on someone to just take the time to do it themselves. It doesn't seem like a difficult patch to create (unless that logic is a spaghetti code state machine mess).

I'm not as driven to do this personally because I'm actually working on a test framework of my own, intended to be a complete alternative to Mocha, Jasmine, Tape, etc., although simpler and more powerful at its core. It's still too much a work in progress for even toy projects ATM, though.

I'm using Mocha to effectively bootstrap the framework. I used Chai initially for the assertions until I got those stabilized (they're practically API locked now, since I'm using the framework's assertions to test itself).

Yeah that's a workaround I just don't see many JavaScript projects structured that way though the same could be said about pairing the spec and source file as well. I essentially use that pattern though when I come into projects that are already pretty large with their own custom build systems it's not always easy to change it up.

Exclude is a pretty basic pattern a lot of utilities have. I think mocha needs it :). Though I guess my impression, since this issue was closed based around platform specific workarounds, that it was not desired versus awaiting a patch. If this is something the mocha folks would actually want then if it's not done in a few weeks I could certainly crank out a patch.

@KrisSiegel I'm pretty sure that if someone actually cranked out a patch, it would probably get merged, as long as it doesn't involve some unintuitive, special syntax or extra flag. FWIW, there's yet to be a PR for _this_, and the reason this issue was closed was pretty weak if you consider the platform-dependent. And I don't see very many Windows users that are willing to install GNU find just to run a few tests.

It may be closed, but a similar situation is already happening to Node with Web workers, although Node's implementation will slightly deviate (closed issue, PR in progress).

+1 for what it's worth. A project I've built doesn't require an app or src folder, but instead has a variable amount of named folders with different interface implementations. I would also like to keep my tests bundled for each interface, and not be forced to use a single folder for tests.

Being able to specify files to ignore with a .mochaignore or other option would be ideal, as that way I could just run it with a **/*.spec.js glob and not worry that it might include tests from the node_modules folder.

Almost all other build tools allow this, we have .npmignore, .gitignore, .jshintignore, and jscs provides an option to configure it via .jscsrc. It would be useful if Mocha would support it as well, as more and more people are moving towards the component/feature file and folder organisation, away from the sock drawer approach.

@isiahmeadows like others mentioned, I'm stuck with a folder structure I can't easily change, therefore services/, routes/, etc. are in the root of the project just like node_modules is. I got inspired to put test files next to the files they test. This works really great, but I need a third tool (be it command line, or gulp, or something else) to exclude node_modules so that only my own tests get tested.

I'd love to implement it myself in mocha, if I'd knew where to start :)

@godspeedelbow @adambuczynski A temporary solution :)

  "scripts": {
    "test": "mocha $(find . -name '*.spec.js' ! -ipath '*node_modules*')"
  }

Hi @danielstjules thanks! Tried it, but for some reason find . -name '*.spec.js' ! -ipath '*node_modules*' only finds one test file.

Did you update '*.spec.js' to fit the pattern your tests follow? E.g. to match _all_ js files, you'd use:

  "scripts": {
    "test": "mocha $(find . -name '*.js' ! -ipath '*node_modules*')"
  }

@danielstjules cheers, but that wouldn't work on windows I believe, and while for this app it's not a problem, I am hesitant to put it in.

In the mean time, I've resorted to moving the app code and tests to an app subfolder so that I can target that folder for the tests and not worry about node_modules or other folders.

@danielstjules yeah, all test files are in format of *.spec.js. For some reason it didn't work earlier, but now when it does without problems. Thanks for this *NIX work around.

I want to see this done for an upcoming major; specifically supporting .mochaignore seems reasonable to me

@boneskull Thanks, that'd be great.

For the next major release, would you also consider implementation of a more "standard" .mocharc for passing options, which can be put in the root of the project, rather than having to use a mocha.opts in the test folder?

That would make configuring Mocha much easier, and in line with the way it's done with other tools out there. Plus, it wouldn't force us to have a test folder just for the mocha.opts. (We put all our tests alongside the modules they test).

@adambuczynski absolutely. I am no fan of mocha.opts

@adambuczynski great comment. I agree, I would like to have a standard .mocharc option file too, I no longer use a test directory either, since it is so nice to keep tests next to the code.

+1, I think exclude is really needed.

@adambuczynski @boneskull Documentation indicates you can use --opts to specify any path to your opts file, though it doesn't give any examples. I am using this in my current project and can confirm it works as mocha --opts .mocharc

Thanks @GRUBES. In the end, I kept using the test folder because I place my test setup helpers in there as well, but it's good to know it's possible.

Glob has an ignore option, so it should not be a big deal to just add an exlude option and forward it to glob ignore.

ignore Add a pattern or an array of glob patterns to exclude matches. Note: ignore patterns are always in dot:true mode, regardless of any other settings.

I am not sure why this takes more than a year. :-)

@inf3rno BTW, this would've probably been resolved much earlier had someone actually sat down and wrote the patch.

@isiahmeadows Ye, but that won't be me. :D

So does this still need a PR? I would be happy to add this, since I would prefer to use test file colocation instead of the multiple directories for test and test-integration

2036, which is for basically the same general sort of thing only a file rather than a commandline option, has a PR #2173

Maybe it's nice to add option like --exclude.

Or support something like mocha test/*.js !test/_*.js

Figured Glob out: mocha "./{,!(node_modules)/**/}*.test.js" to get all *.test.js files except in node_modules, and mocha "./test/**/!(notThisOne).js" to get everything in the test folder and subfolders except notThisOne.js

See also:
https://github.com/isaacs/node-glob#glob-primer
https://github.com/isaacs/node-glob/issues/62

@ScottFreeCode

When running in terminal I get

mocha "./{,!(node_modules)/**/}*.test.js"
-bash: !: event not found

Should this character be escaped?

@mdumouchel Use single quotes. Otherwise, yes it does.

@isiahmeadows

Still getting error

node_modules/mocha/lib/utils.js:630
        throw new Error("cannot resolve path (or pattern) '" + path + "'");
              ^
Error: cannot resolve path (or pattern) './{,!(node_modules)/**/}*.test.js'

I ended up just using the find command

mocha $(find . -type d -name node_modules -prune -o -name '*.test.js')

@mdumouchel If you're using version 2.x (i.e. what's on npm), it's not going to work, anyways. Support will start in 3.x, IIRC.

That's weird, I thought I tried in Bash and was able to use double-quotes. Does anyone know a syntax/escaping that will work both on Windows and in Bash?

Also, I'm pretty sure the "cannot resolve path" error means that the path doesn't match any files in your project; the path I gave worked in the current version when I had test files with names ending in ".test.js" alongside the corresponding source files, unless I screwed up copying it from my test to the issue comment...

See #2173

Eslint does a great job ignoring files with --ignore-path (and .eslintignore).
See: http://eslint.org/docs/user-guide/command-line-interface#ignoring-files

Something similar for mocha would be awesome :two_hearts:


My workaround :

eslint "test/!(fixtures)/**/*.js" "test/*.js"

My file structure

.
└── src
└── test
    └── fixtures
        └── data.js
    ├── foo.js
    └── bar.js

Problem: Mocha gives me a Error: cannot resolve path (or pattern) if any of the 2 paths does not match something.. :disappointed_relieved:

OK, so I relent. This is just not user-friendly.

This is what I think we should do:

  1. Support --exclude <glob-or-path>
  2. Support _multiple_ instances of --exclude
  3. Combine all --exclude options with all non-option arguments into a single list (basically what globby does)
  4. Load those files

Currently we support _n_ non-option arguments, which can all be globs, but this is only _additive_; this doesn't work like you'd expect:

$ mocha 'src/**/*.spec.js' '!src/forbidden/**/*.spec.js'

So the above should work, and --exclude is really just sugar for !.

In addition, .mochaignore (#2036) support sounds good, but is a separate issue. There should be a 3p module we can pull in to have .gitignore-like behavior; I'm sure whatever ESLint is doing is good enough for our purposes.

...and if it isn't clear, don't use unquoted globs on the command line; see #2355

Surprisingly there's still no option like --ignore-path, besides putting all tests into a tests folder, there's no reason why we can't put tests along with modules.

+1
ignore files or directories by pattern is a very useful feature

@isiahmeadows

You could always do src//.js and src//.spec.js

No, you couldn't - the **/* pattern matching is broken and doesn't work recursively.

EDIT: @ScottFreeCode has the answer below

the **/* pattern matching is broken and doesn't work recursively.

Are your paths quoted?

+1

image

As describe in https://github.com/zinserjan/mocha-webpack/issues/124:

Inside src/ there is a file called server.ts which fires an express server, and runs at the background. The server is typically up when running coverage, so the port is already in use.

So we don't want this and only this file to be excluded.

Voicing my opinion that mocha needs an ignore because even after all this time, maintainers still need convincing.

Mocha is canon. why not raise the bar for the cross-platform feature set of the test framework that all other test frameworks aspire to be? We should stop aspiring to leaving everything up to Bash. Its 2017 already.

I'll also point out that Windows people don't have anything equivalent to Bash's !(glob) (which is actually a Bash-ism, not even POSIX standard).

There shouldn't be any Bash dependency in Mocha's globbing as-is, since it is processed through the Glob JS module. (Note: quoting the paths may be required to avoid the shell processing globs differently from how Mocha would, e.g. ** without the globstar extension or whatever it is that makes that special.)

@ScottFreeCode Do you use extglob: true when you use glob? If that's the case, then this can be closed with that syntax as a workaround (since glob/minimatch supports it with that option enabled).

It looks like we're just passing the path to glob. I am pretty sure that I got negation working through a glob pattern at some point, but that may have been an older version of the module? In any case, we do have tests for the double-star behavior, so if anyone wants to submit tests to confirm that some negation patterns work too (or if anyone finds any flaws in the globbing tests we already have), that would be great.

However, there's a definite advantage to having an explicit ignore/exclude option. Multiple advantages, actually:

  • less obscure
  • easier to avoid clashes with different OSes special characters and quoting rules
  • an include list minus an exclude list is simpler in many cases than an include list with negated pieces

I merely wanted to clarify that the status quo isn't meant to be relying on any particular shell. ;^)

an include list minus an exclude list is simpler in many cases than an include list with negated pieces

True, and I had almost forgotten about that 😄

Anyone coming to this issue:

The workaround is now to use globs, as this should be supported. If someone wants this particular behavior, please send a PR.

Does --exclude option work ?
Can't find it in docs.

@sepo-one I opened PR to update the document.
You can see all available options vis mocha -h.

Yea, i've been using old version of mocha. Upgraded and --exclude option is there.
Docs should be updated anyway i guess.

Thanks @outsideris

Was this page helpful?
0 / 5 - 0 ratings