Introduction

James Kyle edited this page Nov 16, 2013 · 10 revisions

Introduction

Bootcamp is a behavior-driven development framework for testing Sass code. It does not depend on any other Sass frameworks. It does not require Compass. And it has a clean, obvious syntax so that you can easily write tests.

Suites: describe your tests

A test suite begins with a call to the global Bootcamp mixin describe with two parts: a string parameter and @content. The string is a name or title for a spec suite – usually what is under test. The @content is a block of code that implements the suite.

@include describe("A suite") {
  @include it("contains spec with an expectation") {
    @include should(expect(true), to(be(true)));
  }
}

Specs

Specs are defined by calling the global Bootcamp mixin it, which, like describe takes a string and @content. The string is a title for this spec and the @content is the spec, or test. A spec contains one or more expectations that test the state of the code under test.

An expectation in Bootcamp is an assertion that can be either true or false. A spec with all true expectations is a passing spec. A spec with one or more expectations that evaluate to false is a failing spec.

It’s Just Mixins

Since describe and it blocks are mixins, they can contain any executable code necessary to implement the test. Sass scoping rules apply, so variables declared in a describe are available to any it block inside the suite.

@include describe("A suite is just a mixin") {
  $a: null;

  @include it("and so is a spec") {
    $a: true;

    @include should(expect($a), to(be(true)));
  }
}

Expectations

Expectations are built with the mixin should which takes two parameters. A function expect, which takes a value called the actual. As well as nested Matcher functions which take the expected value.

@include describe("The 'toBe' matcher compares with ===") {

Matchers

Each matcher implements a boolean comparison between the actual value and the expected value. It is responsible for reporting to Bootcamp if the expectation is true or false. Bootcamp will then pass or fail the spec.

  @include it("and has a positive case ") {
    @include should(expect(true), to(be(true)));
  }

Any matcher can evaluate to a negative assertion by nesting the matcher in a not-to.

  @include it("and can have a negative case") {
    @include should(expect(false), not-to(be(true)));
  }
}

Included Matchers

Bootcamp has a rich set of matchers included.

There is also the ability to write custom matchers for when a project’s domain calls for specific assertions that are not included below.

@include describe("Included matchers:") {
  @include it("The 'be' matcher compares with ==") {
    $number: 12;
    $clone: $a;

    @include should(expect($number),     to(be($clone)));
    @include should(expect($number), not-to(be($clone)));
  }

  @include describe("The 'equal' matcher") {
    @include it("works for simple literals and variables") {
      $number: 12;

      @include should(expect($number), to(equal(12)));
    }

    @include it("should work for lists") {
      $foo: 12, 34;
      $bar: 12, 34;

      @include should(expect($foo), to(equal($bar)));
    }
  }

  @include it("The 'be-null' matcher compares against null") {
    $null: null;
    $foo: "foo";

    @include should(expect(null),     to(be-null()));
    @include should(expect($null),    to(be-null()));
    @include should(expect($foo), not-to(be-null()));
  }

  @include it("The 'be-truthy' matcher is for boolean casting testing") {
    $null: null;
    $foo:  "foo";

    @include should(expect($foo),      to(be-truthy()));
    @include should(expect($null), not-to(be-truthy()));
  }

  @include it("The 'be-falsy' matcher is for boolean casting testing") {
    $null: null;
    $foo:  "foo";

    @include should(expect($null),    to(be-falsy()));
    @include should(expect($foo), not-to(be-falsy()));
  }

  @include it("The 'have-type-of' matcher is for type testing") {
    $null: null;
    $foo:  "foo";

    @include should(expect($null),    to(have-type-of(null)));
    @include should(expect($foo), not-to(have-type-of(string)));
  }

  @include it("The 'be-less-than' matcher is for mathematical comparisons") {
    $pi: 3.1415926
    $e:  2.78;

    @include should(expect($e),      to(be-less-than($pi)));
    @include should(expect($pi), not-to(be-less-than($e) ));
  }

  @include it("The 'be-greater-than' matcher is for mathematical comparisons") {
    $pi: 3.1415926
    $e:  2.78;

    @include should(expect($pi),    to(be-greater-than($e) ));
    @include should(expect($e), not-to(be-greater-than($pi)));
  }

  @include it("The 'be-close-to' matcher is for precision math comparison") {
    $pi: 3.1415926
    $e:  2.78;

    @include should(expect($pi), not-to(be-close-to($e, 2)));
    @include should(expect($pi),     to(be-close-to($e, 0)));
  }

  @include it("The 'be-empty' matcher compares against an empty list") {
    $empty-list: ();
    $full-list:  1, 2, 3;

    @include should(expect($empty-list),     to(be-empty()));
    @include should(expect($full-list),  not-to(be-empty()));
  }

  @include it("The 'be-longer-than' matcher is for list comparisons") {
    $long-list:  1, 2, 3, 4;
    $short-list: 1, 2;

    @include should(expect($long-list),      to(be-longer-than(3)));
    @include should(expect($short-list), not-to(be-longer-than(3)));
  }

  @include it("The 'be-shorter-than' matcher is for list comparisons") {
    $long-list:  1, 2, 3, 4;
    $short-list: 1, 2;

    @include should(expect($short-list),     to(be-shorter-than(3)));
    @include should(expect($long-list),  not-to(be-shorter-than(3)));
  }

  @include it("The 'have-length-of' matcher is for list comparisons") {
    $list:  1, 2, 3;

    @include should(expect($list),     to(have-length-of(3)));
    @include should(expect($list), not-to(have-length-of(2)));
  }

  @include it("The 'contain' matcher is for finding an item in a list") {
    $list: "foo", "bar", "baz";

    @include should(expect($list),     to(contain("bar" )));
    @include should(expect($list), not-to(contain("quux")));
  }

  @include it("The 'deep-contain' matcher is for finding an item in a list") {
    $list: "foo", ("bar", "baz");

    @include should(expect($list),     to(deep-contain("bar" )));
    @include should(expect($list), not-to(deep-contain("quux")));
  }

  @include it("The 'deep-equal' matcher is for list comparisons") {
    $list: "foo", ("bar", "baz");

    @include should(expect($list),     to(deep-equal( ("foo", ("bar", "baz")) )));
    @include should(expect($list), not-to(deep-equal( ("foo", ("baz", "bar")) )));
  }
}

Grouping Related Specs with describe

The describe mixin is for grouping related specs. The string parameter is for naming the collection of specs, and will be concatenated with specs to make a spec’s full name. This aids in finding specs in a large suite. If you name them well, your specs read as full sentences in traditional BDD style.

@include describe("A spec") {
  @include it("is just a mixin, so it can contain any code") {
    $foo: 0;
    $foo: $foo + 1;

    @include should(expect($foo), to(equal(1)));
  }

  @include it("can have more than one expectation") {
    $foo: 0;
    $foo: $foo + 1;

    @include should(expect($foo), to(equal(1)   ));
    @include should(expect(true), to(equal(true)));
  }
}

Nesting describe Blocks

Includes of describe can be nested, with specs defined at any level. This allows a suite to be composed as a tree of mixins.

@include describe("A spec") {
  $foo: 1;

  @include it("is just a mixin, so it can contain any code") {
    @include should(expect($foo), to(equal(1)));
  }

  @include it("can have more than one expectation") {
    @include should(expect($foo), to(equal(1)   ));
    @include should(expect(true), to(equal(true)));
  }

  @include describe("nested inside a second describe", function() {
    @include it("can reference both scopes as needed") {
      @include should(expect($foo), to(equal(1)));
    }
  }
}

Disabling Specs and Suites

Suites and specs can be disabled with the xdescribe and xit mixin, respectively. These suites and specs are skipped when run and thus their results will not appear in the results.

@include xdescribe("A spec") {
  $foo: 1;

  @include xit("is just a mixin, so it can contain any code") {
    @include should(expect($foo), to(equal(1)));
  });
});

Sorry Pivotal Labs, I copied out of love