I am unit testing a component in Angular, using Jasmine. My test
it('contacts should be passed to child component', fakeAsync(() => {
const newContact: Contact = {
id: 1,
name: 'Jason Pipemaker'
};
const contactsList: Array<Contact> = [newContact];
contactsComponent.contacts = contactsList;//change on parent component
tick()
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(childComponents()[0].contacts).toEqual(contactsComponent.contacts);//want to check if changed on child also
})
}));
I want to test if a change in the parent will reflect on the child, like happens in a real scenario.
I have tested that the values are equal when everything starts, but I want to test the scenario when one changes the parent value, and that should automatically reflect on the child.
it('contacts should be the same', () => {
expect(childComponents([0].contacts)
.toEqual(contactsComponent.contacts);
});
Error:
Expected $.length = 0 to equal 1. Expected $[0] = undefined to equal Object({ id: 1, name: 'Jason Pipemaker' }).
My interpretation: it is not waiting for the update to test.
Maybe it is not even a unit test? Since I want to test the binding, maybe it is an integration test.
Suggestions so far
Suggestion 1: I would try with contactsComponent.contacts = JSON.parse(JSON.stringify(contactsList))
comments: Thanks, it does not work. See that I have already tested at the beginning: everything passes. The question would be. Why did it work at the beginning/launching but not after started? I guess this is a problem of somehow making sure everything finishes before testing: an async issue, not JSON.stringify. I have no idea how to make that in code terms! In simple terms: I am changing something on the parent, and want to make sure the child receives the change, like it happens on real scenarios. Thanks for your participation! My HTML:
<app-contact-list [contacts]=contacts></app-contact-list>
PS. app-contact-list is the child:
export class ContactListComponent implements OnInit {
.......
@Input('contacts') contacts: Contact[];//the input for the component
Suggestion 2: I think you should test the component individually.
Comments: Regarding mocking the child, I am already mocking using ng-mock
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ContactsComponent,
MockComponent(ContactListComponent)],
}).compileComponents();
}));
Drawback: it came to me as private lessons that some organizations do not allow installing those packages, thus, one should mock manually, as suggested.
Suggestion 3: You can avoid it by leveraging the async/await syntax.
Comments: tried, but did not work, same problem as before. it seems the code is executing before test. I face the same problem with Jest, learnt a trick, that that never happened before. I guess I am missing something like that, something that makes sure the test waits for the final modifications before testing.
Codes: some suggested making the codes available. Here it goes: https://github.com/JorgeGuerraPires/testing-angular-applications/tree/master/website/src/app/contacts
Maybe someone could make a StackBlitz as suggested!
Final solution
In order to close this issue, I have decided to test in a simple case, as so the core idea under test would be the only concern. See the full simple application here before testing. And see the final testing file here.
I draw insights from both answers, and accepted the one that helped me the most, even the comments helped.
Thanks to everyone!