Skip to main content

{clairecodes}

Super quick Regex TDD setup

  4 minute read
  Categories: 

When you need to build a regex you could either (A) hack around in the console, getting confused and lost, or instead (B) use TDD and write some tests: you can have a clear list of strings your regex should match and those it shouldn’t, run them quickly and see whether the regex works and have readymade documentation for future use 🏆

But how do you set that up? If it sounds like a lot of work, it isn’t. Follow this post and in five minutes you’ll have a working example. :clock1:

Open up the terminal and follow along:

$ mkdir regexTest && cd "$_"

Make new directory and move into it in one command!

$ npm init -y

Set up a new package.json file the quick way - no more hitting enter for all the default options!

$ npm i -D mocha chai

Install the latest versions of the mocha and chai packages as devDependencies (although it doesn’t really matter if they’re devDependencies or normal dependencies as we’re not really creating a production ready app. To save as a regular dependency use the -S shortcut instead).

You should now have something like:

{
  "name": "regexTest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Maya Angelou <maya@gmail.com>",
  "license": "ISC",
  "devDependencies": {
    "chai": "^3.5.0",
    "mocha": "^3.0.2"
  }
}

Using you favourite text editor, change the test property to:

"test": "./node_modules/.bin/mocha -R spec"

If you have mocha installed globally (npm i -g mocha) you can just write mocha -R spec instead.

The -R flag is short for --reporter and tells mocha which one we want to use, i.e. how to print out our test results. Here we’re using the default spec but replace this with -R nyan if you want something a bit more fun.

We’ll now be able to run the tests with npm test. Let’s write some to run! From the command line:

$ mkdir test

$ touch test/regexTest.js

Mocha wants to run tests that are in the test directory but isn’t bothered what the files in it are called. You could have regexSpec.js or wazzock.js if you like.

Open up this file in your text editor and setup a skeleton for our tests:

var expect = require('chai').expect;

describe("My amazing regex", function() {
    it("should pass", function() {
        expect(42).to.equal(42);
    });

    it("should fail", function() {
        expect(42).not.to.equal("42");
    });
});

Now run from the command line:

$ npm test

And tada 🎉 you should see some working specs:

My First Specs

An explanation of how Mocha works is beyond the scope of this post, but a couple of notes: I prefer the “expect” style assertions rather than the BDD “assert” form as I think they are more readable. I’m using the chai matchers library to make our expectations even easier to read. Plus we’re going to group lots of expectations within the it functions because life is too short to write a new one for each expectation, especially as this is just a quick example.

Now we can set up some expectations to test a regex. Use this matcher structure:

expect("string").to.match(regex);

Write your test cases: replace the current contents with the strings your regex should match and the ones it shouldn’t (these are just as important and shouldn’t be overlooked).

describe("My amazing regex", function() {
    var myRegex = /foo/;

    it("should work", function() {
        expect("light").to.match(myRegex);
        expect("highlight").to.match(myRegex);
        expect("lighten").to.match(myRegex);
        expect("reenlighten").to.match(myRegex); // I made this word up 🙊
        expect(" light ").to.match(myRegex);
    });

    it("shouldn't work", function() {
        expect("highlighter").not.to.match(myRegex);
        expect("enlighten").not.to.match(myRegex);
        expect("").not.to.match(myRegex);
        expect("blah").not.to.match(myRegex);
        expect("LIGHT").not.to.match(myRegex);
    });
});

Note that we’ll add a variable to hold the regex but we won’t fill it in correctly just yet, because first, we want failing specs! Run npm test again:

Passing Specs

Well OK, the shouldn't work block is passing, as our regex is wrong and won’t match any of them, which we expect. We use those assertions as our safety net - when we start to write our regex properly, if some of these match then we know the regex is wrong.

And then all is left is to write a regex that makes all of the tests pass: some strings are matched and others aren’t. Spoiler alert:

var myRegex = /^(?!en).*light(?!er)/;

Each time you make a change to the regular expression, save and rerun the test command from the terminal. npm test:

Final Specs

And that’s all there is to it.

FIN