Angular Jasmine test not firing subscribe inside ngOnInit










1















I have a basic component class, inside ngOnInit it subscribes to a service call



ngOnInit() 
this.activityService.getActivities().subscribe(activities =>
console.log('inside sub');
this.recentActivities = activities;
);



So I included this console.log to see if this subscribe ever executes.



In my test I spyOn this activity service method to return an Observable collection of the data I need. Then in the test, I do the whole fixture.detectChanges() deal and expect my array to be of length 1.



fit('should populate recent activities', () => 
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));

fixture.detectChanges();
fixture.whenStable().then(() =>
fixture.detectChanges();
);
fixture.detectChanges();

expect(component.recentActivities.length).toBe(1);
);


According to the Angular docs, they pretty much do the same thing, I even tried the fakeAsync approach, but to no avail. What am I missing here? Why does the subscribe block not execute?










share|improve this question
























  • Please include all the relevant sections of your .spec file, including where you set up your TestBed, any beforeEach() functions that affect this spec, and variables declared. Even better would be a link to a stackblitz. Trying to take a swag based on what you showed so far I would guess that you haven't gotten a hold of the actual activityService that was actually injected into the component being tested.

    – dmcgrandle
    Nov 14 '18 at 16:32











  • Seeing the full context would be incredibly valuable to provide a more accurate recommendation. Once you've got the test spec passing, you can probably delete a few instances of your fixture.detectChanges(). The initial invocation triggers the ngOnInit behavior, which you need. However, any additional calls to fixture.detectChanges are only relevant if you intend to make assertions about the rendered HTML (change detection in test specs is off by default).

    – ericksoen
    Nov 14 '18 at 18:19
















1















I have a basic component class, inside ngOnInit it subscribes to a service call



ngOnInit() 
this.activityService.getActivities().subscribe(activities =>
console.log('inside sub');
this.recentActivities = activities;
);



So I included this console.log to see if this subscribe ever executes.



In my test I spyOn this activity service method to return an Observable collection of the data I need. Then in the test, I do the whole fixture.detectChanges() deal and expect my array to be of length 1.



fit('should populate recent activities', () => 
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));

fixture.detectChanges();
fixture.whenStable().then(() =>
fixture.detectChanges();
);
fixture.detectChanges();

expect(component.recentActivities.length).toBe(1);
);


According to the Angular docs, they pretty much do the same thing, I even tried the fakeAsync approach, but to no avail. What am I missing here? Why does the subscribe block not execute?










share|improve this question
























  • Please include all the relevant sections of your .spec file, including where you set up your TestBed, any beforeEach() functions that affect this spec, and variables declared. Even better would be a link to a stackblitz. Trying to take a swag based on what you showed so far I would guess that you haven't gotten a hold of the actual activityService that was actually injected into the component being tested.

    – dmcgrandle
    Nov 14 '18 at 16:32











  • Seeing the full context would be incredibly valuable to provide a more accurate recommendation. Once you've got the test spec passing, you can probably delete a few instances of your fixture.detectChanges(). The initial invocation triggers the ngOnInit behavior, which you need. However, any additional calls to fixture.detectChanges are only relevant if you intend to make assertions about the rendered HTML (change detection in test specs is off by default).

    – ericksoen
    Nov 14 '18 at 18:19














1












1








1








I have a basic component class, inside ngOnInit it subscribes to a service call



ngOnInit() 
this.activityService.getActivities().subscribe(activities =>
console.log('inside sub');
this.recentActivities = activities;
);



So I included this console.log to see if this subscribe ever executes.



In my test I spyOn this activity service method to return an Observable collection of the data I need. Then in the test, I do the whole fixture.detectChanges() deal and expect my array to be of length 1.



fit('should populate recent activities', () => 
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));

fixture.detectChanges();
fixture.whenStable().then(() =>
fixture.detectChanges();
);
fixture.detectChanges();

expect(component.recentActivities.length).toBe(1);
);


According to the Angular docs, they pretty much do the same thing, I even tried the fakeAsync approach, but to no avail. What am I missing here? Why does the subscribe block not execute?










share|improve this question
















I have a basic component class, inside ngOnInit it subscribes to a service call



ngOnInit() 
this.activityService.getActivities().subscribe(activities =>
console.log('inside sub');
this.recentActivities = activities;
);



So I included this console.log to see if this subscribe ever executes.



In my test I spyOn this activity service method to return an Observable collection of the data I need. Then in the test, I do the whole fixture.detectChanges() deal and expect my array to be of length 1.



fit('should populate recent activities', () => 
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));

fixture.detectChanges();
fixture.whenStable().then(() =>
fixture.detectChanges();
);
fixture.detectChanges();

expect(component.recentActivities.length).toBe(1);
);


According to the Angular docs, they pretty much do the same thing, I even tried the fakeAsync approach, but to no avail. What am I missing here? Why does the subscribe block not execute?







typescript unit-testing rxjs angular6 karma-jasmine






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 31 '18 at 9:01









Cœur

17.9k9107146




17.9k9107146










asked Nov 13 '18 at 23:14









develmatikdevelmatik

265




265












  • Please include all the relevant sections of your .spec file, including where you set up your TestBed, any beforeEach() functions that affect this spec, and variables declared. Even better would be a link to a stackblitz. Trying to take a swag based on what you showed so far I would guess that you haven't gotten a hold of the actual activityService that was actually injected into the component being tested.

    – dmcgrandle
    Nov 14 '18 at 16:32











  • Seeing the full context would be incredibly valuable to provide a more accurate recommendation. Once you've got the test spec passing, you can probably delete a few instances of your fixture.detectChanges(). The initial invocation triggers the ngOnInit behavior, which you need. However, any additional calls to fixture.detectChanges are only relevant if you intend to make assertions about the rendered HTML (change detection in test specs is off by default).

    – ericksoen
    Nov 14 '18 at 18:19


















  • Please include all the relevant sections of your .spec file, including where you set up your TestBed, any beforeEach() functions that affect this spec, and variables declared. Even better would be a link to a stackblitz. Trying to take a swag based on what you showed so far I would guess that you haven't gotten a hold of the actual activityService that was actually injected into the component being tested.

    – dmcgrandle
    Nov 14 '18 at 16:32











  • Seeing the full context would be incredibly valuable to provide a more accurate recommendation. Once you've got the test spec passing, you can probably delete a few instances of your fixture.detectChanges(). The initial invocation triggers the ngOnInit behavior, which you need. However, any additional calls to fixture.detectChanges are only relevant if you intend to make assertions about the rendered HTML (change detection in test specs is off by default).

    – ericksoen
    Nov 14 '18 at 18:19

















Please include all the relevant sections of your .spec file, including where you set up your TestBed, any beforeEach() functions that affect this spec, and variables declared. Even better would be a link to a stackblitz. Trying to take a swag based on what you showed so far I would guess that you haven't gotten a hold of the actual activityService that was actually injected into the component being tested.

– dmcgrandle
Nov 14 '18 at 16:32





Please include all the relevant sections of your .spec file, including where you set up your TestBed, any beforeEach() functions that affect this spec, and variables declared. Even better would be a link to a stackblitz. Trying to take a swag based on what you showed so far I would guess that you haven't gotten a hold of the actual activityService that was actually injected into the component being tested.

– dmcgrandle
Nov 14 '18 at 16:32













Seeing the full context would be incredibly valuable to provide a more accurate recommendation. Once you've got the test spec passing, you can probably delete a few instances of your fixture.detectChanges(). The initial invocation triggers the ngOnInit behavior, which you need. However, any additional calls to fixture.detectChanges are only relevant if you intend to make assertions about the rendered HTML (change detection in test specs is off by default).

– ericksoen
Nov 14 '18 at 18:19






Seeing the full context would be incredibly valuable to provide a more accurate recommendation. Once you've got the test spec passing, you can probably delete a few instances of your fixture.detectChanges(). The initial invocation triggers the ngOnInit behavior, which you need. However, any additional calls to fixture.detectChanges are only relevant if you intend to make assertions about the rendered HTML (change detection in test specs is off by default).

– ericksoen
Nov 14 '18 at 18:19













1 Answer
1






active

oldest

votes


















1














After hours of trying fakeAsync, providing mock class for the service, various tick() calls, and dozens of other posts and slighty different approaches, the culprit came down to adding one line: component.ngOnInit();.



Apparently, while fixture.detectChanges() certainly calls ngOnInit, it was somehow keeping the observable cold. When I would call fixture.detectChanges(), it would not go into the subscribe of the observable. As soon as I added component.ngOnInit(), the observable became hot, and the code inside the subscribe was executed, and I could see my console logs being printed. Oddly, this made the following fixture.detectChanges() calls also jump into the subscribe code for each subsequent call.



Here is a simplified version of my spec file, hopefully this aids anyone in the future with the same problem. fakeAsync and sync zones still passed the test, I had assumed I would have needed at least a tick() inside the fakeAsync zone, but it wasn't necessary.



describe('RecentActivityComponent', () => 
let component: RecentActivityComponent;
let fixture: ComponentFixture<RecentActivityComponent>;
let activityService: ActivityService;

beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [AccordionModule, FontAwesomeModule, HttpClientTestingModule],
declarations: [ RecentActivityComponent ],
providers: [AccordionConfig, ActivityService]
).compileComponents();
));

beforeEach(async () =>
fixture = TestBed.createComponent(RecentActivityComponent);
component = fixture.componentInstance;
activityService = TestBed.get(ActivityService);
);

it('should populate recent activities', fakeAsync( () =>
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));
component.ngOnInit();
expect(component.recentActivities.length).toBe(1);
));

it('should populate recent activities', () =>
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));
component.ngOnInit();
expect(component.recentActivities.length).toBe(1);
);


);






share|improve this answer

























  • I'm glad you were able to get something working. That's always the first step! There's something about your hot/cold observable conclusion that's unfamiliar to me (if you have a source for it, can you share?). I put together a fairly test harness using Angular StackBlitz to see if it is possible to trigger the ngOnInit lifecycle hook using fixture.detectChanges while also firing the subscribe block on an Observable.

    – ericksoen
    Nov 15 '18 at 4:03











Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53290899%2fangular-jasmine-test-not-firing-subscribe-inside-ngoninit%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














After hours of trying fakeAsync, providing mock class for the service, various tick() calls, and dozens of other posts and slighty different approaches, the culprit came down to adding one line: component.ngOnInit();.



Apparently, while fixture.detectChanges() certainly calls ngOnInit, it was somehow keeping the observable cold. When I would call fixture.detectChanges(), it would not go into the subscribe of the observable. As soon as I added component.ngOnInit(), the observable became hot, and the code inside the subscribe was executed, and I could see my console logs being printed. Oddly, this made the following fixture.detectChanges() calls also jump into the subscribe code for each subsequent call.



Here is a simplified version of my spec file, hopefully this aids anyone in the future with the same problem. fakeAsync and sync zones still passed the test, I had assumed I would have needed at least a tick() inside the fakeAsync zone, but it wasn't necessary.



describe('RecentActivityComponent', () => 
let component: RecentActivityComponent;
let fixture: ComponentFixture<RecentActivityComponent>;
let activityService: ActivityService;

beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [AccordionModule, FontAwesomeModule, HttpClientTestingModule],
declarations: [ RecentActivityComponent ],
providers: [AccordionConfig, ActivityService]
).compileComponents();
));

beforeEach(async () =>
fixture = TestBed.createComponent(RecentActivityComponent);
component = fixture.componentInstance;
activityService = TestBed.get(ActivityService);
);

it('should populate recent activities', fakeAsync( () =>
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));
component.ngOnInit();
expect(component.recentActivities.length).toBe(1);
));

it('should populate recent activities', () =>
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));
component.ngOnInit();
expect(component.recentActivities.length).toBe(1);
);


);






share|improve this answer

























  • I'm glad you were able to get something working. That's always the first step! There's something about your hot/cold observable conclusion that's unfamiliar to me (if you have a source for it, can you share?). I put together a fairly test harness using Angular StackBlitz to see if it is possible to trigger the ngOnInit lifecycle hook using fixture.detectChanges while also firing the subscribe block on an Observable.

    – ericksoen
    Nov 15 '18 at 4:03
















1














After hours of trying fakeAsync, providing mock class for the service, various tick() calls, and dozens of other posts and slighty different approaches, the culprit came down to adding one line: component.ngOnInit();.



Apparently, while fixture.detectChanges() certainly calls ngOnInit, it was somehow keeping the observable cold. When I would call fixture.detectChanges(), it would not go into the subscribe of the observable. As soon as I added component.ngOnInit(), the observable became hot, and the code inside the subscribe was executed, and I could see my console logs being printed. Oddly, this made the following fixture.detectChanges() calls also jump into the subscribe code for each subsequent call.



Here is a simplified version of my spec file, hopefully this aids anyone in the future with the same problem. fakeAsync and sync zones still passed the test, I had assumed I would have needed at least a tick() inside the fakeAsync zone, but it wasn't necessary.



describe('RecentActivityComponent', () => 
let component: RecentActivityComponent;
let fixture: ComponentFixture<RecentActivityComponent>;
let activityService: ActivityService;

beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [AccordionModule, FontAwesomeModule, HttpClientTestingModule],
declarations: [ RecentActivityComponent ],
providers: [AccordionConfig, ActivityService]
).compileComponents();
));

beforeEach(async () =>
fixture = TestBed.createComponent(RecentActivityComponent);
component = fixture.componentInstance;
activityService = TestBed.get(ActivityService);
);

it('should populate recent activities', fakeAsync( () =>
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));
component.ngOnInit();
expect(component.recentActivities.length).toBe(1);
));

it('should populate recent activities', () =>
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));
component.ngOnInit();
expect(component.recentActivities.length).toBe(1);
);


);






share|improve this answer

























  • I'm glad you were able to get something working. That's always the first step! There's something about your hot/cold observable conclusion that's unfamiliar to me (if you have a source for it, can you share?). I put together a fairly test harness using Angular StackBlitz to see if it is possible to trigger the ngOnInit lifecycle hook using fixture.detectChanges while also firing the subscribe block on an Observable.

    – ericksoen
    Nov 15 '18 at 4:03














1












1








1







After hours of trying fakeAsync, providing mock class for the service, various tick() calls, and dozens of other posts and slighty different approaches, the culprit came down to adding one line: component.ngOnInit();.



Apparently, while fixture.detectChanges() certainly calls ngOnInit, it was somehow keeping the observable cold. When I would call fixture.detectChanges(), it would not go into the subscribe of the observable. As soon as I added component.ngOnInit(), the observable became hot, and the code inside the subscribe was executed, and I could see my console logs being printed. Oddly, this made the following fixture.detectChanges() calls also jump into the subscribe code for each subsequent call.



Here is a simplified version of my spec file, hopefully this aids anyone in the future with the same problem. fakeAsync and sync zones still passed the test, I had assumed I would have needed at least a tick() inside the fakeAsync zone, but it wasn't necessary.



describe('RecentActivityComponent', () => 
let component: RecentActivityComponent;
let fixture: ComponentFixture<RecentActivityComponent>;
let activityService: ActivityService;

beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [AccordionModule, FontAwesomeModule, HttpClientTestingModule],
declarations: [ RecentActivityComponent ],
providers: [AccordionConfig, ActivityService]
).compileComponents();
));

beforeEach(async () =>
fixture = TestBed.createComponent(RecentActivityComponent);
component = fixture.componentInstance;
activityService = TestBed.get(ActivityService);
);

it('should populate recent activities', fakeAsync( () =>
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));
component.ngOnInit();
expect(component.recentActivities.length).toBe(1);
));

it('should populate recent activities', () =>
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));
component.ngOnInit();
expect(component.recentActivities.length).toBe(1);
);


);






share|improve this answer















After hours of trying fakeAsync, providing mock class for the service, various tick() calls, and dozens of other posts and slighty different approaches, the culprit came down to adding one line: component.ngOnInit();.



Apparently, while fixture.detectChanges() certainly calls ngOnInit, it was somehow keeping the observable cold. When I would call fixture.detectChanges(), it would not go into the subscribe of the observable. As soon as I added component.ngOnInit(), the observable became hot, and the code inside the subscribe was executed, and I could see my console logs being printed. Oddly, this made the following fixture.detectChanges() calls also jump into the subscribe code for each subsequent call.



Here is a simplified version of my spec file, hopefully this aids anyone in the future with the same problem. fakeAsync and sync zones still passed the test, I had assumed I would have needed at least a tick() inside the fakeAsync zone, but it wasn't necessary.



describe('RecentActivityComponent', () => 
let component: RecentActivityComponent;
let fixture: ComponentFixture<RecentActivityComponent>;
let activityService: ActivityService;

beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [AccordionModule, FontAwesomeModule, HttpClientTestingModule],
declarations: [ RecentActivityComponent ],
providers: [AccordionConfig, ActivityService]
).compileComponents();
));

beforeEach(async () =>
fixture = TestBed.createComponent(RecentActivityComponent);
component = fixture.componentInstance;
activityService = TestBed.get(ActivityService);
);

it('should populate recent activities', fakeAsync( () =>
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));
component.ngOnInit();
expect(component.recentActivities.length).toBe(1);
));

it('should populate recent activities', () =>
const activities = [new ActivityBuilder()
.withId('1').withRecentActivityActionId(RecentActivityActionType.Created).build()
];
spyOn(activityService, 'getActivities').and.returnValue(of(activities));
component.ngOnInit();
expect(component.recentActivities.length).toBe(1);
);


);







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 14 '18 at 18:49

























answered Nov 14 '18 at 18:44









develmatikdevelmatik

265




265












  • I'm glad you were able to get something working. That's always the first step! There's something about your hot/cold observable conclusion that's unfamiliar to me (if you have a source for it, can you share?). I put together a fairly test harness using Angular StackBlitz to see if it is possible to trigger the ngOnInit lifecycle hook using fixture.detectChanges while also firing the subscribe block on an Observable.

    – ericksoen
    Nov 15 '18 at 4:03


















  • I'm glad you were able to get something working. That's always the first step! There's something about your hot/cold observable conclusion that's unfamiliar to me (if you have a source for it, can you share?). I put together a fairly test harness using Angular StackBlitz to see if it is possible to trigger the ngOnInit lifecycle hook using fixture.detectChanges while also firing the subscribe block on an Observable.

    – ericksoen
    Nov 15 '18 at 4:03

















I'm glad you were able to get something working. That's always the first step! There's something about your hot/cold observable conclusion that's unfamiliar to me (if you have a source for it, can you share?). I put together a fairly test harness using Angular StackBlitz to see if it is possible to trigger the ngOnInit lifecycle hook using fixture.detectChanges while also firing the subscribe block on an Observable.

– ericksoen
Nov 15 '18 at 4:03






I'm glad you were able to get something working. That's always the first step! There's something about your hot/cold observable conclusion that's unfamiliar to me (if you have a source for it, can you share?). I put together a fairly test harness using Angular StackBlitz to see if it is possible to trigger the ngOnInit lifecycle hook using fixture.detectChanges while also firing the subscribe block on an Observable.

– ericksoen
Nov 15 '18 at 4:03


















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53290899%2fangular-jasmine-test-not-firing-subscribe-inside-ngoninit%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Barbados

How to read a connectionString WITH PROVIDER in .NET Core?

Node.js Script on GitHub Pages or Amazon S3