Mocha Test Framework

repository·main·Indexed 12 days ago

https://github.com/mochajs/mocha

A flexible and reliable JavaScript test framework for Node.js and the browser. Mocha supports various assertion libraries, asynchronous testing patterns, and provides a robust CLI for executing test suites. Key features include exclusive tests with .only(), skipping tests with .skip() or this.skip(), pending tests, and retry logic via this.retries(). Version 12.0.0-rc.6 introduces enhanced CI integration with the --forbid-only flag.

Tokens
42.3K
Snippets
153
Records
209
Agent score
96%

What's inside Mocha

  1. Overview of Mocha test framework

    main

    Mocha is a feature-rich JavaScript test framework designed for both Node.js and the browser. It is built to make asynchronous testing straightforward. Key characteristics include:

    • Serial Execution: Mocha tests run serially, which enables flexible and accurate reporting.
    • Error Mapping: It automatically maps uncaught exceptions to the correct test cases.
    • Environment Support: Runs in Node.js and directly in the browser.
  2. Overview of Mocha test framework

    main

    Mocha is a classic, reliable, and trusted test framework designed for both Node.js and the browser. It is an independent open-source project maintained by volunteers and is one of the most widely used modules on npm.

    For detailed usage, API references, and configuration guides, visit the official Mocha Documentation.

  3. What is Mocha and what is its scope?

    main

    Mocha is a unopinionated, general-purpose testing framework for the JavaScript community. It is designed to be flexible and stable, focusing on providing a robust foundation for organizing and running tests rather than providing specific assertion or mocking logic.

    Core Capabilities (In-Scope)

    • Test APIs: Interfaces for writing and organizing tests in JavaScript or compile-to-JavaScript languages.
    • Execution Environments: A command-line interface (CLI) for Node.js-based terminals and an API for running tests in browser environments.
    • Reporters: Mechanisms to output test results and errors to the Terminal, Files, Browsers, or Memory.
    • Extensibility: APIs to extend Mocha's functionality.
    • Configuration: Support for both file-based and code-based configuration.
    • Test Levels: Support for unit, integration, functional/end-to-end, and operational readiness tests.

    Limitations (Out-of-Scope)

    • Assertions and Mocks: Mocha does not include built-in test assertions or mocking libraries. You must use third-party libraries (like Chai or Sinon) for these tasks.
    • Third-party Compatibility: While Mocha strives to maintain compatibility with popular tools, it does not explicitly support libraries not hosted under the mochajs GitHub organization unless stated otherwise.
    • Environment Constraints: Mocha is not intended for use with unmaintained versions of Node.js or browsers that do not meet maintainer-defined thresholds.
  4. Understand Mocha's execution flow in Serial Mode

    main

    In Serial Mode (the default), Mocha executes tests within a single process. The lifecycle follows these key stages:

    1. Initialization: Mocha loads configuration files, processes command-line options, and optionally spawns a node child process if specific flags are detected.
    2. Module Loading: Modules specified via --require are loaded. If these modules contain Mocha-specific exports (like root hook plugins), they are registered.
    3. Discovery: Mocha finds test files (searching for .js, .mjs, or .cjs in the test directory by default).
    4. Loading & Suite Construction: Test files are loaded via the chosen interface (e.g., bdd). During this phase, Mocha executes suites to find hooks and tests but does not execute the tests themselves. All top-level elements are attached to a single, invisible "root suite".
    5. Execution:
      • Global setup fixtures are run.
      • Mocha executes the root suite's "before all" hooks.
      • For each test: "before each" hooks $\rightarrow$ the test $\rightarrow$ "after each" hooks.
      • Child suites inherit "before each" and "after each" hooks from their parents.
      • Root suite's "after all" hooks are run.
    6. Teardown: A final summary is printed, and global teardown fixtures are executed.
  5. How root hooks behave in Parallel Mode

    main

    In serial mode, a root hook (a hook defined in a test file outside of any suite) is applied globally.

    In parallel mode, root hooks are NOT global. Each test file runs in its own instance of Mocha. A root hook defined in file_A.js will not be present when running tests in file_B.js.

    Recommended Workarounds:

    1. Root Hook Plugins (Best): Define your hooks in a file and use the Root Hook Plugin system.
    2. Manual Import: require('./setup.js') or import './setup.js' at the top of every test file.
    3. Global Fixtures: If you need code to run exactly once for the entire process, use global fixtures.
    // This root hook will NOT be global in parallel mode
    // It will only apply to the file it is defined in.
    beforeEach(function () {
      doMySetup();
    });
  6. Choose a test interface (DSL) in Mocha

    main
    Mocha provides different interfaces (Domain-Specific Languages) that determine the syntax and style you use to write your tests. By choosing an interface, you decide whether you want to use a traditional describe/it style or other available DSLs provided by Mocha. The interface you use dictates how you structure your test suites and individual test cases.
  7. How Mocha reporters handle terminal output

    main
    Mocha reporters automatically adjust their output to fit the current terminal window size. Additionally, to ensure compatibility with non-interactive environments (like CI/CD pipelines or log files), Mocha automatically disables ANSI-escape coloring whenever the standard input/output (stdio) streams are not associated with a TTY.
  8. Understand Mocha's execution flow in Parallel Mode

    main

    In Parallel Mode, Mocha distributes test files across a pool of worker subprocesses to improve performance. The lifecycle differs from Serial Mode in several ways:

    1. Main Process Setup: The main process handles configuration, module loading (--require), and discovery. It puts all found test files into a queue.
    2. Worker Bootstrapping: When a worker is created, it bootstraps itself by loading --require'd modules and registering root hook plugins. Note: Workers ignore global fixtures and custom reporters.
    3. Test Execution: Each worker creates a new Mocha instance specifically for the single test file it is assigned. It follows the standard execution loop (hooks $\rightarrow$ tests $\rightarrow$ hooks) but does not report results directly.
    4. Result Reporting: Workers buffer test results in memory and return them to the main process upon completion. The main process is responsible for passing these results to the user-specified reporter.
    5. Lifecycle: Global setup and teardown fixtures are managed by the main process, not the workers.
  9. How Global Fixtures work and when to use them

    main

    Mental Model

    Global fixtures are designed for managing external resources that exist outside the JavaScript memory space of your tests.

    Key Characteristics:

    • Execution: Guaranteed to run exactly once.
    • Consistency: Works in parallel, watch, and serial modes.
    • Isolation: They do not share a context with tests, suites, or other hooks. You cannot access properties attached to this inside a global fixture from within a describe or it block.
    • Context Sharing: mochaGlobalSetup and mochaGlobalTeardown do share a context (this), allowing you to pass data between setup and teardown.

    When to use

    Use global fixtures for spinning up external resources that tests access via I/O, such as:

    • Web servers
    • Sockets
    • Databases (to start/stop the process)

    When NOT to use

    Do not use global fixtures to manage in-memory values (like file handles or database connection objects) that you need to access directly in your tests. Because tests cannot access the fixture's context, they won't be able to see these values.

    Correct Pattern: Use a global fixture to start the external resource (e.g., the database process), and use root hook plugins or standard hooks to create the actual connection/client used by the tests.

    // Example of the recommended pattern:
    // 1. Global fixture starts the server
    // 2. Test hooks connect to the server
    
    // fixtures.mjs
    let server;
    export const mochaGlobalSetup = async () => {
      server = await startSomeServer({ port: process.env.TEST_PORT });
    };
    
    export const mochaGlobalTeardown = async () => {
      await server.stop();
    };
    
    // test.spec.mjs
    import { connect } from "my-server-connector-thingy";
    
    describe("my API", function () {
      let connection;
    
      before(async function () {
        connection = await connect({ port: process.env.TEST_PORT });
      });
    
      it("should be a nice API", function () {
        // assertions here
      });
    
      after(async function () {
        return connection.close();
      });
    });
  10. Use globstar for recursive test matching

    main

    If you prefer not to use the --recursive flag, you can use the globstar (**) wildcard to match files in subdirectories.

    Note that while shells like ZSH and Fish support this by default, Bash (version 4.3+) requires the globstar option to be enabled to achieve the same results as Mocha's --recursive flag. For maximum compatibility and to avoid shell-specific behavior, using the --recursive flag is recommended.

    $ mocha "./spec/**/*.js"
  11. Test Isolation and State in Parallel Mode

    main

    Mocha uses a pool of worker processes in parallel mode. Each worker may run multiple test files sequentially.

    Crucial Warning: Test files assigned to the same worker share process-level state, including the Node.js module cache and global variables. Mocha does not provide strict process-level isolation per test file.

    If your tests require absolute isolation (e.g., they modify globals or the module system), you should:

    • Invoke mocha separately for each test file.
    • Use a different test runner that supports process-level isolation per file.