如何使用 Jasmine 测试某物是否为给定 class 的数组?

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

我正在编写一个 Angular 应用程序。我对我的组件进行了测试(紧随 this manual),我想检查我的 ngOnInit() 是否调用了提供的(模拟)服务,并初始化了我的 属性 foos带有 Foo 个对象的数组。

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

以上适用于单个对象,但不适用于数组。如果我检查 Array 测试通过,但不是特别有用。

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

我试过 Foo[],但出现错误。

An element access expression should take an argument.

我意识到这个测试通常没有用,因为如果它returns他错了,打字稿会抱怨class。但原则上我还是想知道。

据我所知,无法立即在 Jasmine 中执行此检查。但是,您可以使用一些额外的代码来实现此结果。

  • 内容可自行查看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");
    
  • 遍历数组并使用 toBeInstanceOf() matcher against each item. You can also add withContext() 提供附加信息,否则您将不知道哪个项目未通过匹配器:

    for (const [index, x] of someArray.entries()) {
      expect(x)
        .withContext(`index [${index}]`)
        .toBeInstanceOf(Foo, "hello");
    }
    
  • 遍历数组并手动调用 fail() 并显示错误消息:

    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>