Lesson 25: Mastering JavaScript Automated Testing with Mocha + BDD

manoj ymkmanoj ymk
7 min read

🔹 1. Summarize the Concept Clearly

🧪 What is Mocha?

Mocha is a JavaScript test framework that runs on Node.js and in the browser. It's primarily used for unit and integration testing. It provides:

  • describe() – a way to group tests (suites)

  • it() – individual test cases

  • before, after, beforeEach, afterEach – hooks for setup/teardown

🧪 What is Chai?

Chai is an assertion library used with Mocha. It supports:

  • assert style (like Node.js's built-in assert)

  • expect and should styles (BDD, expressive syntax)

💡 Core Idea of BDD (Behavior-Driven Development)

In BDD, you write tests first, describing expected behavior in human-readable specs. These tests act as:

  • 🧪 Tests (fail early, pass when ready)

  • 📘 Documentation (describe use cases)

  • 💡 Examples (live demos of how to use a function)


💻 Code Sample

describe("pow", function () {
  it("2 raised to 3 should be 8", function () {
    assert.equal(pow(2, 3), 8);
  });
});

Mocha Test Flow Diagram

describe("feature", function() {
 └── it("should do something", function() {
      └── assertion
    });
});

Hooks in play:

before() → once before all
beforeEach() → before each it
afterEach() → after each it
after() → once after all

🔹 2. Fill Any Gaps (Advanced Insights, Edge Cases, Traps):

🔍 Hidden Concepts & Edge Cases:

🧨 Test File Order Pitfall

Mocha executes test files in lexical order. If you depend on test execution order, you’ll hit issues — structure your specs so they are isolated and independent.

🧪 Async Test Support

it("waits for async", function (done) {
  setTimeout(() => {
    assert.equal(2 + 2, 4);
    done();
  }, 100);
});

Or using Promises:

it("returns promise", function () {
  return Promise.resolve().then(() => assert.isTrue(true));
});

Or with async/await:

it("uses async/await", async function () {
  const result = await someAsyncFunc();
  assert.equal(result, 42);
});

🚫 Arrow Functions in describe/it?

Avoid them when using this.timeout() or this.skip() — because arrow functions don’t bind this.

📊 Non-Deterministic Tests

Avoid randomness unless you fix the seed. Random behavior leads to flaky tests.


🔍 Gotchas & Dev Mistakes:

  • ❌ Testing multiple concerns in a single it block

  • ❌ Overusing beforeEach to create deeply coupled setup

  • ❌ Forgetting to reset stubs/mocks after each test

  • ❌ Using assert.equal() instead of strictEqual() where needed

⚙️ Internal Mechanics

  • Mocha runs tests asynchronously, so you can return a Promise or use done() callback to handle async code.

  • Test order is not guaranteed, don’t rely on shared state unless scoped correctly with hooks.

  • BDD vs TDD: Mocha supports both styles. BDD is describe/it, TDD is suite/test.

❗ Common Pitfalls

MistakeWhy it's bad
Only testing happy pathsLeads to false confidence in reliability
Overusing beforeEach for unrelated setupSlows tests and introduces side effects
Testing implementation, not behaviorBreaks tests when refactoring
Not isolating testsCan cause flaky tests if state leaks
Using assert.equal(a, b) for objectsFails silently; use deepEqual instead

🔍 Assertion Traps

  • assert.equal(NaN, NaN) → Fails! Use assert.isNaN()

  • assert.equal([], []) → Fails! Use assert.deepEqual()

  • assert.equal(null, undefined) → Passes! Use assert.strictEqual() for accuracy

⚠️ Browser-Specific Quirks

  • DOM-related tests may behave differently across browsers unless normalized.

  • Timing-sensitive code (like animations or timers) needs fake timers via Sinon.


🔹 3. Challenge Me Deeply

🟢 Basic

  1. Write a test suite for a reverseString(str) function.

  2. Create tests for a capitalize(word) function that trims and capitalizes.

  3. Write tests to validate a sum(a, b) function handles negative numbers.

🟡 Intermediate

  1. Test a fetchData(url) function using fake XMLHttpRequest (Sinon).

  2. Write a spec for filterEven(arr) that verifies output is always a new array.

  3. Group tests with describe() and show when beforeEach runs.

🔴 Advanced

  1. Write tests for a function that takes a callback and executes it after 2 seconds.

  2. Test a caching function using spies to verify function calls are memoized.

  3. Validate debounce(fn, ms) with a fake timer that calls fn only once.

🧠 Bonus Brain-Twister

  1. Write a test for a function that returns true if given function throws an error — and false otherwise. The tricky part: make sure it catches async errors too!

🔹 4. Interview-Ready Questions

📘 Conceptual

  • What's the difference between unit and integration testing?

  • Why is BDD preferred in large teams?

  • How does Mocha execute async tests?

🧠 Debugging

  • A test that passes locally fails on CI. What would you check?

  • A test suite sometimes passes, sometimes fails. What could cause flaky behavior?

🔥 Real-World Pitfalls

  • Overuse of mocks/spies

  • Not testing edge cases (e.g., empty inputs, invalid types)

  • Coupling tests to DOM structure

✅ Best Practices

  • One it() per logical behavior

  • Always include edge/corner case tests

  • Use beforeEach/afterEach only when necessary

❌ Red Flags

  • 200+ line test files with no grouping

  • Tests that pass without actually asserting anything

  • Tests that mutate shared state


🔹 5. Real-World Usage

💼 Front-End

  • Testing React/Vue components via [Mocha + jsdom or Karma]

  • Ensuring animations/timers (debounce, throttle) work correctly

🖥️ Back-End

  • Unit testing business logic functions

  • Integration tests with mock databases (e.g., Sinon spies/fakes)

🛠️ Frameworks

  • Vue Test Utils + Mocha

  • React + Mocha + Enzyme

  • Electron apps often use Mocha for browser+Node tests

🧩 Open Source

  • Mocha itself is tested with Mocha

  • Chai: high usage in many testing stacks

  • Sinon: widely used for mocking/stubbing timers and APIs


🔹 6. Remember Like a Pro

🧠 Mnemonics

“DITCH” your bugs

  • Describe

  • It

  • Tests

  • Chai

  • Hooks

⚡ Cheatsheet

MethodUse Case
assert.equal(a, b)Primitive equality (not strict)
assert.strictEqual(a, b)Strict equality ===
assert.deepEqual(obj1, obj2)Object structure comparison
assert.isNaN(val)Value is NaN
assert.throws(fn)Function throws
assert.isTrue(val)val === true

🔹 7. Apply It in a Fun Way

📦 Mini Project: “Power Playground”

A UI + Test integration sandbox for exploring pow(x, n) with Mocha.

Steps to build:

  1. Create a simple HTML page with two inputs (x, n) and a button.

  2. Add a pow(x, n) function with input validation.

  3. Display result on the page.

  4. Add test.js to write tests for various power cases.

  5. Integrate Mocha & Chai via CDN.

  6. Show test results in a <div id="mocha">.

Bonus Extensions:

  • Add sliders for x and n

  • Show real-time test results as user changes input

  • Export test results as JSON or downloadable logs

🎯 Mini Project: "Calculator Test Harness"

Goal: Build a basic calculator with BDD-style tests.


✅ Steps:

  1. Create a calculator.js with functions: add, subtract, multiply, divide.

  2. Create a test.js file using Mocha + Chai.

  3. Write BDD-style specs like:

    • it("adds two numbers")

    • it("throws error on divide by 0")

  4. Add beforeEach() to reset any global state (if any).

  5. Run tests in browser or via Node CLI.

  6. Watch test suite grow as you add features!


➕ Extend It:

  • Add memory storage (store last result)

  • Add square root, exponentiation

  • Test edge cases: divide(1, 0), multiply(Number.MAX_SAFE_INTEGER)


➕ Bonus Section: Extra Value

⚙️ Performance Tips

  • Avoid redundant tests — use parameterized tests (makeTest) smartly

  • Run tests in parallel (via CI or test runners like Karma)

🧰 Polyfills / Modern Alternatives

  • Jest (modern alternative) includes Mocha-like syntax, mocking, and snapshots

  • Vitest (Vite + Jest-like) is trending for modern frontend setups

❌ Dev Mistakes

  • Writing tests after the fact

  • Skipping test writing for “small” changes (often the riskiest)

  • Confusing test coverage with test quality

0
Subscribe to my newsletter

Read articles from manoj ymk directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

manoj ymk
manoj ymk