Sharing behaviors

Sometimes you may have multiple classes or methods that have similar behaviors, and you want to test those behaviors for all of them without writing duplicate specs. There are a number of ways to do this depending on your needs.

Inline describe/it loops

Using an inline loop to define describe or it blocks can avoid duplication for many identical, simple tests.

describe('Element', function() {
  beforeEach(function() {
    this.subject = new Element();
  });

  ['x', 'y', 'width', 'height'].forEach(name => {
    describe(name, function() {
      it('returns a number', function() {
        expect(typeof this.subject[name]()).toBe('number');
      });
    });
  });
});

Spec declaration helper

Creating a separate helper function that declares describe or it blocks allows you to reuse it in multiple tests. This may be useful when describing shared behaviors.

// Note that this function can exist outside any jasmine block, as long as you
// only call it from inside a jasmine block.
function itActsLikeAPet() {
  it('can be fed', function() {
    this.subject.feed();
    expect(this.subject.hungry()).toBe(false);
  });

  it('can be watered', function() {
    this.subject.drink();
    expect(this.subject.thirsty()).toBe(false);
  });
}

describe('Dog', function() {
  beforeEach(function() {
    this.subject = new Dog();
  });

  itActsLikeAPet();

  it('can bark', function() {
    this.subject.bark();
  });
});

describe('Cat', function() {
  beforeEach(function() {
    this.subject = new Cat();
  });

  itActsLikeAPet();

  it('can meow', function() {
    this.subject.meow();
  });
});

Caveats

Sharing behaviors in tests can be a powerful tool, but use them with caution.