What is the best way to verify if an object is an instance of a particular class using Jasmine testing?

In the process of developing an Angular application, I am currently working on testing a component using this guide. My goal is to ensure that when my ngOnInit() method is called, it correctly initializes my foos property with an array of Foo objects based on a provided (mock) service.

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

While the test works for a single object, it doesn't fulfill the requirement for an array. Testing against Array passes but lacks meaningful validation.

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

Attempting to use Foo[] resulted in an error message.

An element access expression should take an argument.

Although TypeScript already provides type checking, I still want to confirm this behavior as a matter of principle.

Answer №1

There isn't a built-in way to perform this validation in Jasmine, as far as I know. However, you can incorporate additional code to accomplish the desired outcome.

  • You have the option to manually compare the contents using Array#every() and then utilize the toBeTrue() matcher.

    expect(someArray.every(x => x instanceof Foo))
      .toBeTrue("Some items don't match");
    
  • Iterate through the array and apply the toBeInstanceOf() matcher for each element. You can also include withContext() to provide more details in case of a mismatch:

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

    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} }; // dummy implementation
class Bar { constructor(str) { this._srr = str} }; // 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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What are the best practices for utilizing an array of routes?

I'm new to working with react but I noticed something strange. My routes are currently set up like this: <Main> <Route exact path="/home" component={Home} /> <Route exact path="/home1" com ...

What is the best approach to creating customizable modules in Angular2?

I'm exploring the most effective approach to configuring modules in Angular 2. In Angular 1, this was typically achieved through providers. As providers have been altered significantly, what is the preferred method for passing configuration parameters ...

What is the process for importing libraries from a different local directory?

What I mean by that title is: I have some code that was generated and now I am incorporating it into my Angular application. Currently, I am installing this code as a package using npm, but it is causing issues with my deployment setup. So, I would like ...

The error in Angular 6 is that the property 'controls' is not available on the type 'AbstractControl'

What happens when we use setvalue in a for loop? Everything seems to be running smoothly, but unfortunately an error is thrown: The property 'controls' is not recognized on the type 'AbstractControl'. In Angular 6, how can we resol ...

I'm curious if there is an eslint rule specifically designed to identify and flag any unnecessary spaces between a block comment and the function or

Can anyone help me find a solution to prevent the following issue: /** * This is a comment */ function foo() { ... } I need it to be corrected and formatted like this: /** * This is a comment */ function foo() { ... } ...

Dependency management with various versions of an NPM package

I'm feeling a bit puzzled about NPM package versions. In my ionic2 app's packages.json file, I have a dependency on [email protected]. Additionally, I have the latest version of ionic-native which is dependent on [email protected]. Th ...

Tips for effectively using ngOnChanges in Angular 2 to validate inputs without causing the 'Expression has changed after it was checked' error

I attempted to create my own custom component with basic validation using regex that can be passed as input to the component. There are two scenarios to consider: one where the form is initially empty (new item form) and another where data is already prese ...

Error: The "res.json" method is not defined in CustomerComponent

FetchData(){ this.http.get("http://localhost:3000/Customers") .subscribe(data=>this.OnSuccess(data),data=>this.OnError(data)); } OnError(data:any){ console.debug(data.json()); } OnSuccess(data:any){ this.FetchData(); } SuccessGe ...

I'm attempting to retrieve mlab data in the console using node.js, but unfortunately encountering an error

I came across this helpful YouTube tutorial:https://www.youtube.com/watch?v=PFP0oXNNveg&t=460s. I followed the steps outlined in the video and made necessary code adjustments based on current updates found through a Google search (to resolve errors enc ...

Can someone explain the distinction between 'return item' and 'return true' when it comes to JavaScript array methods?

Forgive me for any errors in my query, as I am not very experienced in asking questions. I have encountered the following two scenarios :- const comment = comments.find(function (comment) { if (comment.id === 823423) { return t ...

Creating JPEG images with specified dimensions. How can you add W x H sizing to an image?

I have been searching for a Deno/TypeScript code snippet that can create basic images with dimensions embedded on them. I have provided an example of the code below, which generates images in JPEG format, base64, and dataURL. The code works by adding RGB ...

Updating the background color using typescript

Before transitioning to angular development, I had experience working with vanilla Javascript. I encountered a challenge when trying to modify the css properties of specific elements using Typescript. Unfortunately, the traditional approach used in Javascr ...

Using TypeScript to send state through history.push({...})

I recently utilized the history.push method to redirect to a specific URL while passing along some information through the included state. Here's how I implemented it: const history = useHistory() history.push({ pathname: '/someurl/', ...

Make sure to verify if all values are contained within an array by utilizing JavaScript or TypeScript

These are the two arrays I'm working with. My goal is to ensure that every value in ValuesToBeCheckArr is present in ActualArr. If any values are missing from ActualArr, the function should return 0 or false. Additionally, there is an operator variabl ...

Attempting to create a login feature using phpMyAdmin in Ionic framework

Currently, I am in the process of developing a login feature for my mobile application using Ionic. I am facing some difficulties with sending data from Ionic to PHP and I can't seem to figure out what the issue is. This is how the HTML form looks li ...

Produce configuration files on the fly for Angular Component Testing using @Component declarations

Looking to test an Angular 11 component: @Component({ selector: 'app-foo-page', template: ` <app-header mode='operational' cool='true'></app-header> Some content ` }) export class FooPageComponent { } ...

Troubleshooting TypeScript when importing external JavaScript: Module not found or no type declaration file available

I recently acquired a VueJS admin template built in JS and am looking to integrate it into my existing TS application. However, when I attempt to transfer the components, views, and other elements, I encounter the following error message. Is there a way to ...

Utilize forRoot to pass configuration data

When using Angular, I encountered a challenge in passing configuration data to a custom library. Within the user's application, they are required to provide config data to my library through the forRoot method: // Importing the custom library import ...

Tips for creating an API URL request with two search terms using Angular and TypeScript

I have developed a MapQuest API application that includes two input boxes - one for the "from" location and another for the "to" location for navigation. Currently, I have hardcoded the values for these locations in my app.component file, which retrieves t ...

Is it possible to create a click event for a mat-icon within a mat form field (either in the matprefix or matsuffix)?

I am working with a mat-form-field and have incorporated a custom mat-icon within it as a matprefix. However, I am now looking to create a click method for that matprefix icon. Despite my attempts to write a click method, it does not seem to be functioning ...