Thugfix Thursday: Angular and Jasmine/Karma: Empty unit tests failing with "TypeError: Cannot read properties of undefined (reading"

Why do empty unit tests sometimes fail in Angular? All we have is an async beforeEach, a standard beforeEach that initializes the fixture and component, and...an empty it should create block:

describe("UserDevicesComponent", () => {
  let component: UserDevicesComponent;
  let fixture: ComponentFixture<UserDevicesComponent>;
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule,
        HttpClientTestingModule,
        FormsModule
      ],
      declarations: [
        UserDevicesComponent,
        AppComponent,
        NavComponent,
        FooterComponent,
        PhonePipe
      ],
      schemas: [
          CUSTOM_ELEMENTS_SCHEMA
        ],
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(UserDevicesComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it("should create", () => {
    // expect(component).toBeTruthy();
  });
});

This shouldn't fail, you know? Like...It's an empty unit test. 

But in some case, it does. The fixture.detectChanges() section will generally fail if this particular error occurs. Comment it out, and your empty unit test will pass. 

Why on earth does this occur? Errors don't get you much. Most are like this: 

TypeError: Cannot read properties of undefined (reading 'basically_anything')

Also see an earlier blog post in which I reference this here. With this bug it's super easy to spend hours and hours trying to fix an extremely basic innerHTML test. 

If you are experiencing this issue, look into your component file. You may find something like this: 

 @Input() user: User | any;

These inputs have to be defined, particularly if they're referenced anywhere in the corresponding HTML file. And considering that this should effectively be 100% of the time...yeah, you're probably going to encounter it. 

In my case it was all over the place in the HTML file. Example:

 <ng-container *ngIf="account.plan && user && user.roles">

Through further perusal, I note that the user references expect roles and adminRoles as properties. So we define them in our unit test, including whatever functions are expected. From this particular line in the ngIf of the HTML file, I see that adminRoles.includes is necessary to mock up:

user.adminRoles.includes(3)

Now, re-run:

describe("UserDevicesComponent", () => {
  let component: UserDevicesComponent;
  let fixture: ComponentFixture<UserDevicesComponent>;
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule,
        HttpClientTestingModule,
        FormsModule
      ],
      declarations: [
        UserDevicesComponent,
        AppComponent,
        NavComponent,
        FooterComponent,
        PhonePipe
      ],
      schemas: [
          CUSTOM_ELEMENTS_SCHEMA
        ],
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(UserDevicesComponent);
    component = fixture.componentInstance;
    component.user = {roles: 1, adminRoles: {includes: function(){}}}
    fixture.detectChanges();
  });

  it("should create", () => {
    // expect(component).toBeTruthy();
  });
});

...And now it passes. 

Note that the errors I got included variables that weren't even in here, such as netId

Also, I am SO sorry for calling this "Thugfix Thursday" because of how stupid it sounds but it's better than "Bugfix Thursday". And now it's time to actually write the tests...

websh*t moment

key phrases because idc enough to look into this seo for this blog: 

  • angular fixture.detectChanges fails unit test
  • typeerror: cannot read properties of undefined empty unit test
  • angular empty unit test failing

Comments

Popular posts from this blog

Unleashing my inner Disney Princess ✩₊˚.⋆☾⋆⁺₊✧ at the 2024 Disney Princesses Half Marathon

The 20-something types of Computer Science majors

The Evenstar