0

I'm using Jasmine to test an Angular app and I'm trying to figure out how to test the value of a property that is set in the subscribe call on an Observable within the component. I've put together an example component here just to illustrate the point.

@Component({
    selector: 'app-list',
    templateUrl: './list.component.html',
    styleUrls: ['./list.component.css']
})
export class ListComponent {
    public Result[] Items;


    constructor(private myService: MyService) {

this.formControl.valueChanges.pipe( switchMap(value => myService.getResults(value)) ).subscribe(results => this.Items = results); } }

In this example, for my test I would be calling getResults() from within and I'd test to make sure that Items is populated. Since this is not guaranteed to happen immediately, but the subscribe logic is entirely within the component, how should I go about awaiting that to make sure I don't get undefined when I check the value of Items?

EDIT: Here’s a sample of how I’ve looked at testing it so far. Please note I’ve updated how the comment in the code above indicating that the observable is subscribe as a result of a FormControl value change, not just a button click, hence the detectChanges below.

it(‘should pull results’, () => {
    const componentFixture = TestBed.createComponent(ListComponent);
    const component = componentFixture.componentInstance;
    const myService = TestBed.inject(MyService);
    spyOn(myService, ‘getResults’).and.returnValue(of([myTestItems]));
    component.formControl.setValue(‘abcdefg’);
    componentFixture.detectChanges();
    expect(component.Items).toEqual([myTestItems]);
}
muttley91
  • 12,278
  • 33
  • 106
  • 160

2 Answers2

0

You have to implement request method in your test, to get result and status, the point is using status to make sure your api work well or not, also you can use timeout to getting response.

const request = require('request');
const endpoint = 'http://localhost:3000/city';

//get
it('should return 200 response code', function (done) {
    request.get(endpoint, function (error, response) {
        expect(response.statusCode).toEqual(200);
        done();
    });
});
//post
it('should fail on POST', function (done) {
    request.post(endpoint, {json: true, body: {}}, function (error, response) {
        expect(response.statusCode).toEqual(404);
        done();
    });
});
Dharman
  • 30,962
  • 25
  • 85
  • 135
Maher
  • 2,517
  • 1
  • 19
  • 32
  • Hmm I don't totally understand. In this case aren't I testing the component method specifically? The API method could be tested separately. – muttley91 Sep 27 '20 at 07:18
0

It depends on how you are mocking myService.getResults(). If it is returning an of(<IResult[]>) (which IMO it should be like this), the subscribe will run synchronously and therefore it will run instantaneously.

it('should set items on click', () => {
  // click on the element and make sure pullResults() gets called.
  // here we will call it directly
  // Make sure you are mocking myService.getResults() to return an observable in the form 
  // of `of([...])`
  component.pullResults();
  // go ahead and make the assertion right away
  expect(component.Items).toEqual(myTestItems);
});
AliF50
  • 16,947
  • 1
  • 21
  • 37
  • Yep I’m using `of`, but I oversimplified when transferring the code to the question. The code is actually triggered by FormControl.valueChange, not a button click. I’ve updated the question with this information and added a sample test to work off of, perhaps it’ll make it clearer where my problem is. – muttley91 Sep 27 '20 at 21:43
  • Your test looks fine for me, does it not pass? – AliF50 Sep 28 '20 at 02:28
  • no I get undefined in my `component.Items` so it fails the comparison to my test data. – muttley91 Sep 28 '20 at 03:17
  • I am thinking it never gets into your `subscribe`. Try putting a `console.log` inside of the subscribe to ensure it gets printed. If it doesn't go inside of the subscribe, I think you are facing this issue: https://stackoverflow.com/questions/51910630/angular-testing-formcontrol-valuechanges-observable. The answer shows how to do the value changes from the HTML though. Also, try putting the `fixture.detectChanges` before the `setValue` because the first `fixture.detectChanges()` after `createComponent` is when `ngOnInit` runs and maybe you have bindings in your `ngOnInit` that are needed. – AliF50 Sep 28 '20 at 03:34