-
Notifications
You must be signed in to change notification settings - Fork 26
Home
First, install shallow-render
:
npm install -D shallow-render
That's it, you're be ready to write a test!
Start by identifying the component you want to test, and the Angular module that component lives in.
For this example, let's say we have FooComponent
it lives in the FooModule
like so:
foo.component.ts
@Component({
selector: 'foo',
template: '<h1>{{label}}</h1>'
})
export class FooComponent {
@Input() label = 'FOO!!';
}
foo.module.ts
@NgModule({
declarations: [FooComponent],
exports: [FooComponent]
})
export class FooModule {}
We want to write tests to cover the functionality of the FooComponent
to make sure it renders the right thing.
foo.component.spec.ts
import { Shallow } from 'shallow-render';
import { FooComponent } from './foo.component';
import { FooModule } from './foo.module';
describe('FooComponent', () => {
let shallow: Shallow<FooComponent>;
beforeEach(() => {
shallow = new Shallow(FooComponent, FooModule);
});
it('displays a default when no label is set', async () => {
const {find} = await shallow.render(`<foo></foo>`);
expect(find('h1').nativeElement.textContent).toBe('FOO!!');
});
it('displays provided label', async () => {
const {find} = await shallow.render(`<foo label="My Label"></foo>`);
expect(find('h1').nativeElement.textContent).toBe('My Label');
});
});
Let's break this down starting with the shallow
variable:
let shallow: Shallow<FooComponent>;
This creates a closure that allows all of our specs access the shallow renderer.
Next, our beforeEach
fires before each test and sets up a fresh shallow renderer for every test. This means every script gets a clean renderer with fresh mocks.
beforeEach(() => {
shallow = new Shallow(FooComponent, FooModule);
});
Notice, we pass two items into the Shallow
constructor, first, the component we wish to test, in this case the FooComponent
. Next, we pass in the module that our test component lives in (the NgModule
we declare
our component to be a part of). We pass in the module because our Angular module should provide all the dependencies our component needs to render itself including providers, pipes, directives and other components that our component may need. Shallow
will mock any child providers and components so they stay out of our way while testing the FooComponent
.
Now let's look at one of the tests, take note of a few things:
it('displays provided label', async () => {
const {find} = await shallow.render(`<foo label="My Label"></foo>`);
expect(find('h1').nativeElement.textContent).toBe('My Label');
});
We use async
functions.
async () => {
When we render with Shallow
, part of the process involves compiling templates with TestBed
. This is an asynchronous process, so we use the async
keyword to allow us to use the easier-to-read syntax when dealing with promises.
Then we render our component:
const {find} = await shallow.render(`<foo label="My Label"></foo>`);
When we render with Shallow
, we use the exact same template HTML style that we would use when we write Angular HTML. You can even bind variables and events if you want. Notice we're setting the label
input to My Label
in the test.
If the const {find}
looks weird, it's another bit of ES6 syntactic sugar called destructuring. It's not necessary to destructure, but I like it so you can do it with Shallow
.
Once we're done rendering, we make our assertion:
expect(find('h1').nativeElement.textContent).toBe('My Label');
This is a pretty standard expectation, just make sure that our FooComponent
accepted and rendered our label value properly.
That's it! There are lots of examples for all kinds of scenarios.
You aren't required to use template HTML to render your components if you don't want to!
For example, the sample above:
const {find} = await shallow.render(`<foo label="My Label"></foo>`);
could be simplified as:
const {find} = await shallow.render({bind: {label: 'My Label'}});
In this case, Shallow
will force the bind
properties to match the names and types of the inputs for your component. If you want to use HTML templates, that's cool too. This is just an type-safe alternative.