Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List all mocha tests without executing them

Is there a way in mochajs to list all tests collected by test runner without executing them?

E.g. if there are specs that look like:

describe('First', function() {
    it('should test something', function() {
        ...
    })
});

describe('Second', function() {
    it('should test something else', function() {
        ...
    })
});

then I want to get console output similar to an output produced by test reporters, but without executing actual tests, like this:

First
    should test something
Second
    should test something else

UPD:

Currently I'm extracting all describes and its with regex, but looking for a cleaner solution.

like image 607
Vader Avatar asked Dec 29 '16 12:12

Vader


People also ask

How do you ignore a test in Mocha?

You can skip tests by placing an x in front of the describe or it block, or placing a . skip after it.

Can Mocha rerun tests?

Retrying Mocha testsMocha provides a this. retries() function that allows you specify the number of times a failed test can be retried. For each retry, Mocha reruns the beforeEach() and afterEach() Hooks but not the before() and after() Hooks.

What are pending tests in Mocha?

A pending test in many test framework is test that the runner decided to not run. Sometime it's because the test is flagged to be skipped. Sometime because the test is a just a placeholder for a TODO. For Mocha, the documentation says that a pending test is a test without any callback.

What is Mocha testing?

Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases. Hosted on GitHub. Use Mocha at Work?

How does Mocha know it should wait for a function?

By adding an argument (usually named done) to it () to a test callback, Mocha will know that it should wait for this function to be called to complete the test. This callback accepts both an Error instance (or subclass thereof) or a falsy value; anything else is invalid usage and throws an error (usually causing a failed test).

How do I skip a test case in Mocha?

By appending .skip (), you may tell Mocha to simply ignore test case (s). Anything skipped will be marked as pending, and reported as such. Here's an example of skipping an individual test: describe ('Array', function () { describe ('#indexOf ()', function () { it.skip ('should return -1 unless present',...

What happens when a test file is loaded in Mocha?

When a test file is loaded, Mocha executes all of its suites and finds– but does not execute –any hooks and tests therein. Top-level hooks, tests and suites are all made members of an “invisible” root suite; there is only one root suite for the entire process


Video Answer


2 Answers

The mocha-list-tests package is useful, but only works for BDD style describe() and it(), and it breaks if you .skip() any tests because it mocks it().

One way to do this yourself if you need to overcome either of those things, or get other information on the tests, is to exploit Mocha's root before() hook. This will be executed after Mocha has loaded all files but before it executes any tests, so all the information you need exists at that point.

This way, it is pretty easy to patch in a --list-only command line option to switch the behaviour of your test run without having to add or change anything else.

The key is that this in the before() hook is Mocha's Context, and the .test of that refers to the hook itself. So this.test.parent refers to the root suite. From there, you can walk down the tree of .suites arrays, and .tests arrays of each suite.

Having collected whatever you want, you have to then output that and exit the process to stop Mocha from continuing.

Plain Text Example

Given root.js:

#!/bin/env mocha

before(function() {
    if(process.argv.includes('--list-only')) {
        inspectSuite(this.test.parent, 0);
        process.exit(0);
    }
    // else let Mocha carry on as normal...
});

function inspectSuite(suite, depth) {
    console.log(indent(`Suite ${suite.title || '(root)'}`, depth));

    suite.suites.forEach(suite => inspectSuite(suite, depth +1));
    suite.tests.forEach(test => inspectTest(test, depth +1));
}

function inspectTest(test, depth) {
    console.log(indent(`Test ${test.title}`, depth));
}

function indent(text, by) {
    return '    '.repeat(by) + text;
}

And test.js:

#!/bin/env mocha

describe('foo', function() {
    describe('bar', function() {
        it('should do something', function() {
            // ...
        });
    });

    describe('baz', function() {
        it.skip('should do something else', function() {
            // ...
        });

        it('should do another thing', function() {
            // ...
        });
    });
});

Then running mocha as normal would give you the test results you expect:

  foo
    bar
      ✓ should do something
    baz
      - should do something else
      ✓ should do another thing


  2 passing (8ms)
  1 pending

But running mocha --list-only would give you (without running any tests):

Suite (root)
    Suite foo
        Suite bar
            Test should do something
        Suite baz
            Test should do something else
            Test should do another thing

JSON Example

root.js

#!/bin/env mocha

before(function() {
    let suites = 0;
    let tests = 0;
    let pending = 0;

    let root = mapSuite(this.test.parent);

    process.stdout.write(JSON.stringify({suites, tests, pending, root}, null, '    '));
    process.exit(0);

    function mapSuite(suite) {
        suites += +!suite.root;
        return {
            title: suite.root ? '(root)' : suite.title,
            suites: suite.suites.map(mapSuite),
            tests: suite.tests.map(mapTest)
        };
    }

    function mapTest(test) {
        ++tests;
        pending += +test.pending;
        return {
            title: test.title,
            pending: test.pending
        };
    }
});

With the same test script as before would give you:

{
    "suites": 3,
    "tests": 3,
    "pending": 1,
    "root": {
        "title": "(root)",
        "suites": [
            {
                "title": "foo",
                "suites": [
                    {
                        "title": "bar",
                        "suites": [],
                        "tests": [
                            {
                                "title": "should do something",
                                "pending": false
                            }
                        ]
                    },
                    {
                        "title": "baz",
                        "suites": [],
                        "tests": [
                            {
                                "title": "should do something else",
                                "pending": true
                            },
                            {
                                "title": "should do another thing",
                                "pending": false
                            }
                        ]
                    }
                ],
                "tests": []
            }
        ],
        "tests": []
    }
}
like image 117
randomsock Avatar answered Sep 28 '22 11:09

randomsock


Wrap all your describe blocks in a describe block and skip it.

describe.skip('Outline', function() {
    describe('First', function() {
        it('should test something', function() {
            ...
        })
    });

    describe('Second', function() {
        it('should test something else', function() {
            ...
        })
    });
});
like image 42
dNitro Avatar answered Sep 28 '22 11:09

dNitro