1
votes

I am expecting an array to be undefined in a test of my Angular app. In order to do that, my test needs to first call a function of my tested component. Within that function, it subscribes to a service's function.

Here is my test class. Including the necessary set up of the service and mock service and the test itself. The test includes commented out lines of what I have already tried.

let service: Service;
const mockService = new MockService();
mockService.getById = of([]);

beforeEach(async(() => {
    return TestBed.configureTestingModule({
      declarations: [leaving out for now],
      imports: [leaving out for now],
      providers: [
        {
          provide: Service,
          useValue: mockService 
        }
      ]
    })
      .compileComponents();
  }));

beforeEach(() => {
    fixture = TestBed.createComponent(Component);
    component = fixture.componentInstance;

    service = fixture.debugElement.injector.get(Service);

    fixture.detectChanges();
  });

describe('describe test', function () {
    it('test', function () {
      //spyOn(mockService, 'getItemsById');
      //spyOn(mockService, 'getItemsById').and.returnValue(of('nothing'));
      //spyOn(service, 'getItemsById');
      //spyOn(mockService, 'getItemsById').and.callThrough();
      //spyOn(service, 'getItemsById').and.callThrough();
      //spyOn(service, 'getItemsById').and.returnValue(of('nothing')); syntax error
      //spyOn(service, 'getItemsById').and.returnValue({ subscribe: () => {} }); syntax error
      //spyOn(mockService, 'getItemsById').and.returnValue({ subscribe: () => {} }); syntax error
      component.getList();

      expect(component.array).toBeUndefined();
    });
  });

All of what I attempted still results in the error:

TypeError: Cannot read property 'subscribe' of undefined

and it references the line in my component's function where I subscribe to the service's getItemsById function

my mock service:

getById: Observable<any>;

constructor() {}

getItemsById(id: number){
    return this.getById;
  }

my tested component that subscribes to the original service's function:

getList(): Model[]{
    let temp: Model[] = [];
    for (let item of this.items){
      let id = item.id;
      this.service.getItemsById(id).subscribe(
        singleIdItem => {
          temp= temp.concat(singleIdItem);
        }
      );
    }
    return temp;
  }

I did not include my original service since it is being mocked, please let me know if that is needed. I'm assuming the solution is some form of spyOn but I have tried everything I have been able to find.

Using Angular 8

2
Could you please try and recreate the issue in a stackblitz or codepen or anything similar?Erbsenkoenig

2 Answers

1
votes

Try this right before the first beforeEach:

let service: Service;
const mockService = new MockService();
mockService.getById = of([]);

I am thinking adding mockService.getById = of([]); in the second beforeEach (remove it from here now that it is added at the top) is too late (the service without getById has already been injected in the providers of the configureTestingModule).

=======================Edit===================

I would use createSpyObj like so:

let mockService: any;

beforeEach(async(() => {
      // can name service (first argument) to anything you want, but I called in service in this scenario. It is internal for you
    mockService = jasmine.createSpyObj('service', ['getItemsById']);
    TestBed.configureTestingModule({
      declarations: [leaving out for now],
      imports: [leaving out for now],
      providers: [
        {
          provide: Service,
          useValue: mockService 
        }
      ]
    })
      .compileComponents();
  }));

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

it('should do something', () => {
   mockService.getItemsById.and.returnValue(of([]));
   component.getList();
   // the rest of your assertions.
});
0
votes

In my test, I needed to return the proper value from my service

describe('describe test', function () {
    it('test', function () {
      spyOn(service, 'getItemsById').and.returnValue(of([{name: 'name', id: 10, otherId: 12, startTime: 'time', endTime: 'time', description: 'desc', insertTime: 'time', insertUser:'user', updateTime: 'time', updateUser: 'user'}]));

      component.getList();

      expect(component.array.size).toEqual(1);
    });
  });

The value returned is of type Model[] as defined in my getList function in my service.