- In the previous section,
we had a simple component with some data
and it rendered a component HTML with a button.
When the user clicked the button,
it called an on click function in my component,
updated the data, redisplayed itself in the webpage.
In order to test that simple component,
we didn't actually test real interaction with the webpage,
we just simulated the event
by calling the event handler directly.
We basically said on our component,
call the click handler directly
as if the user had actually interacted
with the real webpage.
In full testing, you want to actually test
that the event handler does actually work properly, okay?
So in other words, you want to display the component
or effectively render your component in your test suite
and actually handle a real event from the button.
Okay, so that it, then it calls your event handler properly.
Your event handler updates the data in your component,
redisplays the result in the webpage
and then check the webpage to see
if it's been updated properly.
So in other words, this is full testing of the component.
Does the component interact properly
and fully with the DOM tree?
Does it handle events properly?
Does it update and redisplay content
in the DOM tree afterwards?
So in order to do this,
you've actually gotta run your component
in a kind of realistic environment
used in full data binding with Angular.
So we're gonna make use of a couple of classes
we've already seen actually.
TestBed, which enables us to kind of create the test model,
the Angular test framework we'll know about our components,
and then component fixture is like a wrapper
on top of our component.
It enables us to interact with the component
from our test.
So it's actually the same example
as we looked at in the previous video.
So in lesson 12, it's example one,
the demo application in there.
So here it is.
And then in the previous video,
we had a quick look at the toggle switch component.
What we're gonna do now is have a look
at the banner component instead, okay?
It's still quite a simple component.
It has some data which it displays,
and we're gonna check with a button
or with some event handlers.
And when the user clicks and triggers events,
we'll test that our code handles the events properly
and updates itself properly in the webpage, okay?
So here is the banner component.
It displays a message and that message
is in the title property and it's in Welsh.
So how is your Welsh today?
(speaking Welsh)
Do you speak Welsh?
Croeso pawb means welcome everybody.
Welcome everybody.
That's the title that my banner component is gonna display
and it'll display it either up uppercase or lowercase
based on this property.
So what's gonna happen
is initially it'll display that content,
but when the user clicks on the content,
I've got an on click handler
which toggles the upper case flag.
It makes it true instead of false or vice versa.
And then depending on the new state,
if we're now in uppercase mode,
it sets the title to uppercase.
Otherwise it sets the title to lowercase case.
(indistinct) has a very simple example,
some data and a handler to change that data.
Remember, whenever an event occurs in Angular
and a component event handler is fired,
Angular will call this event handler
and it'll automatically rebind in a webpage,
it'll automatically rebind and redisplay the HTML.
So the HTML for my banner component looks like this.
Is a really simple component.
It has a heading which displays the title.
So there's a bit of data binding there.
That title is that title up there.
Curly brackets, double curly brackets.
When my H1 click event occurs,
remember in Angular, you put events in parenthesis.
When somebody clicks on that H1,
it'll invoke this function up here, okay?
Which will change the title,
which will cause it to be redisplayed
automatically in the page.
So let's actually run it first of all, to see how it works.
If you wanna run this application,
go into lesson 12, example one, demo app,
open up a command window, do an NPM install
to install the libraries and then do an NG serve
to run the web server
and then open a browser, go to local host 4200.
And here it is.
Here, well, first of all,
there's the toggle switch that we looked at before.
Here is my banner component, croeso pawb,
welcome everybody.
If I click on it, the click event was handled.
It set the flag to be uppercase
and then it changed the title to be uppercase.
And then it automatically refreshed itself in the browser.
If I click again, it goes lowercase.
If I click again, it goes uppercase.
All right?
So it is actually working.
And well, obviously this banner component
is being rendered as part of my main application.
So I guess we should look at that as well, shouldn't we?
In my banner component, it's selector is at banner.
So if I wanna create it,
that's the element name that I need.
In my application component, app component,
my route component.
If you scroll down to line 354, would you believe?
There it displays the app component banner.
Each app banner, if I had several of these,
each one would be a different object.
Each one would be a different object
with its own internal state, okay?
It's just like having one instance of a bank account,
another instance of a bank account,
and another instance, they've each got their own values.
So I've got three banners now,
each has its own state and its own event handler.
I can click on any one of them, okay.
If I click on that one,
then just that one goes into uppercase.
If I click on that one and that one, okay?
So you can see, basically each component
has its own individual state and it knows what's going on.
That makes sense.
So I wanna test that now in my code.
So I'm gonna go into my banner component
and write some test code.
So in my banner folder, remember each component
goes into a separate folder in Angular.
So we have our banner component spec.
So in here, we're going to test what happens
when you click the initially what state
is my banner component in?
And then what happens when I click it once,
twice, three times.
So let's see what's going on here.
Right then.
So, first of all, here's my banner component spec.
You need to set up a test model
that knows about your component.
Set up a test module that knows about my banner component.
And that banner component has an HDML template.
That HDML template has to be compiled into pure JavaScript.
Okay, this is what happens when you normally
build an application.
In our test environment here,
load the banner component into the test module,
compile the HTML into JavaScript.
So my TestBed now knows about the banner component, okay?
So before each test,
we can ask the TestBed to create a new instance
of the banner component.
Fixture is a wrapper, remember.
Whenever you say create component,
it does create the component
but what it gives you back is a fixture.
That's the fixture available, okay.
Fixture.
And that fixture is a wrapper for the component.
It has a property component instance
and that actually is the component of interest, like that.
Okay?
So that's the component variable there.
The component variable is the actual component
that's been rendered.
So that component there will have some data,
it'll have data in there.
And remember what happens when you say detect changes?
When you call the detect changes function
basically it means do data binding.
From the fixture, go to the component,
whatever data is in here, basically update the HTML template
rebind the data in the component into the HTML.
That's what detect changes means.
Do data binding on the HTML, right.
So that's gonna happen before each test.
It's gonna basically set up a component
in pristine condition.
So initially the banner will be lowercase, croeso pawb!
Right, now here's a test.
Initially the heading should display this test,
"croeso pawb!"
Right.
So I need to remind you again, what's going on.
The fixture is a wrapper to the component
and the component has some HTML, okay?
And that HTML will be rendered.
When you say this fixture DOM native element,
what you're basically doing is you're saying,
okay, so this component here,
ultimately that component is gonna render a chunk of HTML.
A heading one or something.
This will give you back a reference to the HTML
that's actually been rendered by the component
because obviously that's what we want to test.
Give me back the actual HTML rendered
by the component as an HTML element.
This is just to keep the type script compiler happy, okay.
So this banner element here,
inside there there should be an H1
because my banner component renders H1.
Grab the H1 inside my banner component.
And that H1, it could be null,
so we have to be a bit careful,
the safe navigation operator.
If H1 isn't null, grab the text content for the heading,
it should be "croeso pawb!"
Here it is.
So grab the HTML rendered for the component.
In there there should be an H1.
Get the text content for the H1,
verify that it says croeso pawb!
Okay, so basically that was the text there,
but the HTML, the H1, there should be an H1
with text content that says croeso pawb!
That's what it should be.
Okay, so there we go.
Let's just run through the steps we've just done.
Great.
What about if the user clicked the button?
Well, this is how you simulate button events.
There's a new thing we haven't seen yet.
So from the top, grab the HTML that's been rendered.
So again, we had the fixed your object.
The fixed your object pointed to the component.
The component had an HTML template associated with it
which will render a certain chunk of HTML,
basically an H1 which I can click on.
So grab the H1 from this HTML.
So in here, grab the H1 from in there,
and on that H1, dispatch event.
Okay, so this is basically how you simulate events
using Jasmine.
You say, take the element and dispatch this event.
You create an event object and the name of the event.
It's basically simulating a click event on the H1, okay.
So if the user did click on the H1,
it should have called the on click handler in my component.
Okay and that click handler will have changed
the values in here, okay.
It'll have changed the value of the title to be upper case.
The thing is it doesn't automatically rerender.
When you're testing, it doesn't automatically
do data binding.
So even though, when we click the button
or when we click the head in,
it'll call the event handler,
the data inside my component will have changed
but it doesn't automatically refresh the HTML,
not in your test, it does doesn't.
In the regular angle application
when the event handler occurs,
it'll automatically reexecute data binding
to refresh the webpage but it doesn't do that automatically
in your test environment.
So even though we've clicked the event,
to dispatch the click event to H1,
we have to forcibly rebind, okay?
Always remember to do this.
This is what I forget.
When you change the data in the component in the test,
you have to detect changes.
The fixture basically detects the changes of the data
and it updates the rendered HTML.
So the HTML is now updated
and now the HTML should be in uppercase, CROESO PAWB!
So if I'd forgotten to do a detect changes,
the HTML wouldn't have changed.
The data inside my component would've changed,
but the HTML would not have been updated.
So remember to do this.
Whenever you change the component,
remember this statement here, really important.
Okay, so that's great.
So what we can do now is we can just run the tests.
So you could open up another command window
and then just do an NG test.
You can do this.
If your application contains lots of tests,
you can just tell it to run just one test file.
If you like, you say, entry test,
and then you say which test files to include.
The ** means like any sub directory.
In any subdirectory find the banner component spec
and only run that test
because you've probably got lots of components
and I just want to test this component, okay?
Is it gonna work?
Yes, it does.
So initially it displayed "croeso pawb!,
after one click event, it contained the text in uppercase.
I've also got another function.
You can have a look at the code if you like
to simulate two click events
in which case it should have revert it
back to lowercase again, okay?
So there we go.
That's a realistic example that we've just seen
of how to create the component, how to dispatch events
to cause your call back which will update the data.
Remember to say fixture detect changes
to rebind the HTML so that it's been updated properly.