I'm new to unit testing in the context of an Angular 5 application. And right now, I'm trying to unit test a basic component.
The component is called CardComponent, and within the HTML of this component, I call the CheckboxComponent.
So here's the HTML of the CardComponent:
<div>
<p>Test</p>
<jg-checkbox [label]="'Test label'"></jg-checkbox>
</div>
As you can see, there's nothing complicated going on.
However, the CheckboxComponent does inject a service. For the sake of this question, I'll just call it TestService.
So when I unit test my CardComponent, here's my testbed:
TestBed.configureTestingModule({
declarations: [
CheckboxComponent
]
}).compileComponents();
Then I run this test:
it('should create', () => {
expect(component).toBeTruthy();
});
This is just the default test that gets created through the CLI.
But now, it complains that there's no provider for the TestService. Am I really supposed to inject (and mock/spy) that as well?
That seems a bit backwards because I only care about the CardComponent, I shouldn't have to care about the CheckboxComponent, right? That's the whole point of unit testing.
Otherwise, since Angular has hierarchical components, I might have to go down many levels deep as my app grows.
This can't be right.
Can someone please help with this issue? I appreciate the help!
This is the first spec of the test suite and tests to see if the component compiles correctly. The TestBed. createComponent() method is used to create an instance of the AppComponent. The spec then uses expect and matcher functions to see if the component produces the expected behavior.
SpyOn is a Jasmine feature that allows dynamically intercepting the calls to a function and change its result.
fixture is a wrapper for our component's environment so we can control things like change detection. To trigger change detection we call the function fixture.detectChanges() , now we can update our test spec to: Copy it('login button hidden when the user is authenticated', () => { expect(el. nativeElement.
You can create a component fixture with TestBed. createComponent . Fixtures have access to a debugElement , which will give you access to the internals of the component fixture. Change detection isn't done automatically, so you'll call detectChanges on a fixture to tell Angular to run change detection.
If there's no need to reference the CheckboxComponent
in the CardComponent
, there are two approaches:
CheckboxComponent
can be stubbedNO_ERRORS_SCHEMA
can be used in TestBed.configureTestingModule({})
The documentation has a section about Nested component tests
There is also an answer concerning Shallow component tests
Stubbing
Create a stub component in card.component.spec.ts
.
@Component({selector: 'jg-checkbox', template: ''})
class CheckboxStubComponent {}
Then declare this in TestBed.configureTestingModule({})
.
TestBed.configureTestingModule({
declarations: [
CardComponent,
CheckboxStubComponent
]
})
NO_ERRORS_SCHEMA
NO_ERRORS_SCHEMA
can be used instead of stubs.
TestBed.configureTestingModule({
declarations: [
CardComponent
],
schemas: [ NO_ERRORS_SCHEMA ]
})
The
NO_ERRORS_SCHEMA
tells the Angular compiler to ignore unrecognized elements and attributes.
Either approach is acceptable. However, the documentation has a warning about overusing NO_ERRORS_SCHEMA
.
The
NO_ERRORS_SCHEMA
also prevents the compiler from telling you about the missing components and attributes that you omitted inadvertently or misspelled. You could waste hours chasing phantom bugs that the compiler would have caught in an instant.
It also mentions that stubs have an additional advantage.
The stub component approach has another advantage. While the stubs in this example were empty, you could give them stripped-down templates and classes if your tests need to interact with them in some way.
It goes on further to show how to use both approaches together depending on the needs of the test.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With