0

In my Angular project I have this code in one of my components:

  delete(post: PostInterface): void {
    const delete$ = this.appDataService.proxy
      .delete(post, this.paginate)
      .pipe(switchMap(() => this.loadDatas()));

    this.subscriptions.add(
      this.appDataService.start(delete$, 'delete').subscribe()
    );
  }

And in my spec file:

describe('PostListComponent', () => {
  let component: PostListComponent;
  let fixture: ComponentFixture<PostListComponent>;
  let debugElement: DebugElement;

  beforeEach(async () => {

    await TestBed.configureTestingModule({
      // ...
    })
    .compileComponents()
    .then(() => {
      fixture = TestBed.createComponent(PostListComponent);
      component = fixture.componentInstance;
      debugElement = fixture.debugElement;

      fixture.detectChanges();
    });
  });

  describe('functions', () => {
    it('should be delete with proxy.delete() and reload datas', fakeAsync(() => {
      spyOn(component, 'loadDatas');

      component.delete(1);

      flush();

      expect(component.loadDatas).toHaveBeenCalledTimes(1);
    }));
  });
});

In real environment the switchMap works fine, but in test it fails with this message:

PostListComponent > functions > should be delete with proxy.delete() and reload datas

Expected spy loadDatas to have been called once. It was called 0 times.

Why isn't run the switchMap in my test? Any idea?

netdjw
  • 5,419
  • 21
  • 88
  • 162

1 Answers1

0

The reason the test is not working as expected lays probably in the fact that you do not subscribe the Observable.

It is the subscription that starts the stream, i.e. that fires the execution of whatever code is embedded in the Observable chain.

So, you may want to try this version of the test to see if the situation improves

 describe('functions', () => {
    it('should be delete with proxy.delete() and reload datas', (done) => {
      spyOn(component, 'loadDatas');

      component.delete(1).subscribe({
        next: err => done(err),
        complete: () => {
           expect(component.loadDatas).toHaveBeenCalledTimes(1);
           done();
        }
      });

      flush();

    });
  });

As you see I am not using fakeAsync and I assume that delete is actually exectued.

Picci
  • 16,775
  • 13
  • 70
  • 113
  • The `component.delete()` os a void. Not an observable. And in this function the subscribe is there. – netdjw Dec 12 '21 at 21:40
  • After reading again the question I see that `delete` returns a void. At the same time I am wondering whether `this.appDataService.start(delete$, 'delete').subscribe()` actually fires some async logic. If this code is executed asynchrnously, then the `expect` logic may be executed before the async logic completes and therefore before `loadDatas` gets executed. – Picci Dec 12 '21 at 21:50
  • Yes, but how can I solve the issue? Need to refsctor the component code to make it testable or is there any other way to test it in this form? – netdjw Dec 12 '21 at 21:54
  • I would move the code to an external service, passed to the Component via Dependency Injection, so that the Component needs only to subscribe either in some method or using the `async` pipe. The service, on the other hand, is a simpler Typscript class which you could test with the technique shown in my response – Picci Dec 12 '21 at 22:20
  • It sounds as a refactor on the code, and not a solution for the switchMap issue. – netdjw Dec 13 '21 at 05:44
  • Indeed it is, it is a refactoring. I still think it is the best way to proceed. Generally speaking, in my opinion at least, the less code is in the components and the more logic is moved to services the better it is. I am aware this is not science, so any different opinion may be as valid as mine. – Picci Dec 13 '21 at 08:36
  • I understand what you say, but if I move the code to a different file (a service) the problem still will be with us, just in another place. – netdjw Dec 13 '21 at 08:44
  • I tried your suggestion, but still say `Expected spy loadDatas to have been called once. It was called 0 times.` – netdjw Dec 13 '21 at 09:21
  • Can you reproduce this case on a stackblitz? – Picci Dec 13 '21 at 12:34
  • Sure, here is it: https://angular-3fs5jm.stackblitz.io – netdjw Dec 13 '21 at 13:19
  • Unfortunately I do not see the test – Picci Dec 13 '21 at 16:10