Search code examples
angularjasmine

Change Jasmine spy object value after initializing


I have the following component and service:

@Component({
  selector: 'app-root',
  template: '',
})
export class AppComponent implements OnInit {
  constructor(private service: Service) {}
  ngOnInit(): void {
    console.log('Init with', this.service.val);
  }
  getValue() {
    return this.service.val;
  }
}

@Injectable({
  providedIn: 'root',
})
export class Service {
  val: number = 0;
}

In my tests, I want to change the value of val from the service, for a particular test, and then run the component's onInit again:

describe('AppComponent', () => {
  let comp: AppComponent;
  let service: jasmine.SpyObj<Service>;
  beforeEach(() => {
    service = jasmine.createSpyObj('service', [], { val: 1 });
    TestBed.configureTestingModule({
      declarations: [AppComponent],
      providers: [{ provide: Service, useValue: service }],
    });

    const fixture = TestBed.createComponent(AppComponent);
    comp = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('service value is 1', () => {
    expect(comp.getValue()).toBe(1);
  });

  it('override service value to 2', () => {
    service.val = 2;
    TestBed.inject(Service).val = 2;
    expect(comp.getValue()).toBe(2); //  failed: Expected 1 to be 2.
    comp.ngOnInit();
   
  });
});

In the second test, I would expect getValue() from the component to return the updated service value (2), yet 1 is returned. Also ngOnInit prints "Init with 1" three(as expected) times, I would expect the last print to be "Init with 2". What's going on?


Solution

  • You have to do the following to change the value of instance variables on a spy object:

    it('override service value to 2', () => {
        (Object.getOwnPropertyDescriptor(service, 'val')?.get as jasmine.Spy<() => number>).and.returnValue(2);
        expect(comp.getValue()).toBe(2); //  Should work now
        comp.ngOnInit();
       
      });
    

    Full answer here: https://stackoverflow.com/a/64560773/7365461