8

I have a simple component:

.html:

<h1>
  {{title}}
</h1>

<button (click)="changeTitle()">Change title</button>

.ts:

export class AppComponent {
  title = 'app works!';

  changeTitle() {
    this.title = 'New Title!';
  }
}

spec:

import {TestBed, async} from '@angular/core/testing';

import { AppComponent } from './app.component';

describe('AppComponent', () => {
  let fixture;
  let component;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
    }).compileComponents().then(() => {
      fixture = TestBed.createComponent(AppComponent);
      component = fixture.componentInsance;
    });
  }));

  it('should create the app', async(() => {
    const app = fixture.debugElement.componentInstance;
    expect(app).toBeTruthy();
  }));

  it(`should have as title 'app works!'`, async(() => {
    const app = fixture.debugElement.componentInstance;
    expect(app.title).toEqual('app works!');
  }));

  it('should render title in a h1 tag', async(() => {
    fixture.detectChanges();
    const compiled = fixture.debugElement.nativeElement;
    expect(compiled.querySelector('h1').textContent).toContain('app works!');
  }));

  it('should change the title to `New Title!`', async(() => {
    fixture.detectChanges();
    spyOn(component, 'changeTitle').and.callThrough();
    const compiled = fixture.debugElement.nativeElement;

    const button = compiled.querySelector('button');
    button.click();
    return fixture.whenStable().then(() => {
      fixture.detectChanges();
      expect(compiled.querySelector('h1').textContent).toBe('New Title!');
    });
  }));

});

The first 3 tests are passing, the last one returns Error: <spyOn> : could not find an object to spy upon for changeTitle()

Any idea what's wrong?

TheUnreal
  • 23,434
  • 46
  • 157
  • 277

1 Answers1

3

Fixed by updating:

spyOn(component, 'changeTitle').and.callThrough();

to:

jasmine.createSpy('changeTitle').and.callThrough();
TheUnreal
  • 23,434
  • 46
  • 157
  • 277
  • 12
    Can you explain why did you do this way and is it spying actually on your method? and whoever downvoted the answer can you explain why? do you have any concern? do you have a better solution? The documention in Jasmine's website says: When there is not a function to spy on, jasmine.createSpy can create a "bare" spy. This spy acts as any other spy - tracking calls, arguments, etc. But there is no implementation behind it. Spies are JavaScript objects and can be used as such. in your case you do have a function to spy on. – Janatbek Orozaly Aug 11 '17 at 22:22
  • 1
    I hate questions like this SO MUCH because all of @JanatbekSharsheyev's concerns are the exact question that I came here to solve! – Samuel Thompson Oct 26 '18 at 23:06
  • @JanatbekSharsheyev comment explains why this is not an answer. that test just assure that you created an unrelated mock spy to call on, not that you called your code – netalex Feb 27 '20 at 11:03
  • I don't understand why this answer is even accepted. It can be a workaround but not the answer we are looking for. Why would I create a bare spy? In my case also I've a method, and i know its implementation. @JanatbekOrozaly, I didn't downvote any answer but I would like to have a proper answer to this question. Please help. – Tanzeel May 22 '21 at 18:34
  • didn't read all, but seems like there is similar question answered here: https://stackoverflow.com/questions/40106801/spyon-could-not-find-an-object-to-spy-upon-for-start – Janatbek Orozaly May 25 '21 at 02:01