How do I test if something is an array of a given class with Jasmine?

Viewed 778

I am writing an Angular application. I have a test for my component (losely following this manual), where I want to check that my ngOnInit() calls the provided (mock) service, and initialises my property foos with an array of Foo objects.

it('should have foos after Angular calls ngOnInit', () => {
  component.ngOnInit();
  expect(component.foos).toBeInstanceOf(Foo);
});

The above works for a single object, but not for an array. If I check for Array the test passes, but isn't particularly useful.

expect(component.foos).toBeInstanceOf(Array);

I tried Foo[], but that gave me an error.

An element access expression should take an argument.

I realise this test is not useful in general because typescript will complain if it returns something that is he wrong class. But I still want to know as a matter of principle.

1 Answers

There is no way to do this check in Jasmine out of the box, to my knowledge. However, you can use some additional code to achieve this result.

  • You can check the contents yourself with Array#every() and see if they match. Then use the toBeTrue() matcher.

    expect(someArray.every(x => x instanceof Foo))
      .toBeTrue("Some items don't match");
    
  • Loop over the array and use the toBeInstanceOf() matcher against each item. You can also add withContext() to give additional information, otherwise you won't know which item failed the matcher:

    for (const [index, x] of someArray.entries()) {
      expect(x)
        .withContext(`index [${index}]`)
        .toBeInstanceOf(Foo, "hello");
    }
    
  • Loop over the array and manually call fail() with an error message:

    for (const [index, x] of someArray.entries()) {
      if (!(x instanceof Foo)) 
        fail(`index [${index}] is not Foo`, x);
    }
    

class Foo { constructor(num) { this._num = num} }; // some dummy implementation
class Bar { constructor(str) { this._srr = str} }; // some dummy implementation

const arrayOfFoos  = [new Foo(1), new Foo(2), new Foo(3)];
const arrayOfBars  = [new Bar("one"), new Bar("two"), new Bar("three")];
const arrayOfMixed = [new Foo(1), new Bar("two"), new Foo(3)];

describe("All Foos", function() {
  beforeEach(function() {
    this.array = arrayOfFoos;
  });
  
  it("every() + toBeTrue()", function() {
    expect(this.array.every(x => x instanceof Foo))
      .toBeTrue("Some items don't match");
  });
  
  it("loop + toBeInstanceOf()", function() {
    for (const [index, x] of this.array.entries()) {
      expect(x)
        .withContext(`index [${index}]`)
        .toBeInstanceOf(Foo);
    }
  });
  
  it("loop + fail()", function() {
    for (const [index, x] of this.array.entries()) {
      if (!(x instanceof Foo)) 
        fail(`index [${index}] is not Foo`, x);
    }
  });
});

describe("All Bars", function() {
  beforeEach(function() {
    this.array = arrayOfBars;
  });
  
  it("every() + toBeTrue()", function() {
    expect(this.array.every(x => x instanceof Foo))
      .toBeTrue("Some items don't match");
  });
  
  it("loop + toBeInstanceOf()", function() {
    for (const [index, x] of this.array.entries()) {
      expect(x)
        .withContext(`index [${index}]`)
        .toBeInstanceOf(Foo);
    }
  });
  
  it("loop + fail()", function() {
    for (const [index, x] of this.array.entries()) {
      if (!(x instanceof Foo)) 
        fail(`index [${index}] is not Foo`, x);
    }
  });
});

describe("Mixed", function() {
  beforeEach(function() {
    this.array = arrayOfMixed;
  });
  
  it("every() + toBeTrue()", function() {
    expect(this.array.every(x => x instanceof Foo))
      .toBeTrue("Some items don't match");
  });
  
  it("loop + toBeInstanceOf()", function() {
    for (const [index, x] of this.array.entries()) {
      expect(x)
        .withContext(`index [${index}]`)
        .toBeInstanceOf(Foo);
    }
  });
  
  it("loop + fail()", function() {
    for (const [index, x] of this.array.entries()) {
      if (!(x instanceof Foo)) 
        fail(`index [${index}] is not Foo`, x);
    }
  });
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.6.0/jasmine.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.6.0/jasmine.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.6.0/jasmine-html.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.6.0/boot.min.js"></script>

Related