Getting to know fixture.debugElement : Angular Unit Testing
In the Angular world of Unit testing, we often overlook some concepts unless we actually need them to serve specific purpose. After answering a lot of questions on stackoverflow , one of such concept is related to accessing HTML elements using fixture
.
Before we begin, if you are new to unit testing then I would recommend you to start from the intro article. You can more article links below this link, which contain more use cases for unit testing in Angular.
In this article, I’ll discuss 3 ways to access an HTML element and how are they different. For below element with an id
as shan
:
<div id="shan">Hey there</div>
We can use below ways to get it in unit testing:
fixture.debugElement.query(By.css('#shan'))
fixture.debugElement.nativeElement.querySelector('#shan')
document.getElementById('#shan')
1. fixture.debugElement.query(By.css(‘#hello’))
It is used to get “DebugElement” for a DOM object. More detailed info can be found here on offical Angular doc.
In brief, you can pass id
as By.css('#shan')
, class
as By.css('.shan')
, or you can also elements with ways such as By.css('div')
or By.css('some-app-component')
DebugElement
is an Angular class that contains all kinds of references and methods relevant to investigate an element as well as component
fixture.debugElement.query(By.css('#shan'))
will return
DebugElement__PRE_R3__{listeners: [], parent: DebugElement__PRE_R3__{listeners: [], parent: null, debugContext: DebugContext{view: …, nodeIndex: …, nodeDef: …, elDef: …, elView: …}, nativeNode: Hey there, properties: Object{}, attributes: Object{ng-version: …}, classes: Object{}, styles: Object{}, childNodes: […], nativeElement: Hey there}, debugContext: DebugContext{view: Object{def: …, parent: …, viewContainerParent: …, parentNodeDef: …, context: …, component: …, nodes: …, state: …, root: …, renderer: …, oldValues: …, disposables: …, initIndex: …}, nodeIndex: 0, nodeDef: Object{nodeIndex: …, parent: …, renderParent: …, bindingIndex: …, outputIndex: …, checkIndex: …, flags: …, childFlags: …, directChildFlags: …, childMatchedQueries: …, matchedQueries: …, matchedQueryIds: …, references: …, ngContentIndex: …, childCount: …, bindings: …, bindingFlags: …, outputs: …, element: …, provider: …, text: …, query: …, ngContent: …}, elDef: Object{nodeIndex: …, parent: …, renderParent: …, bindingIndex: …, outputIndex: …, checkIndex: …, flags: …, childFlags: …, directChildFlags: …, childMatchedQueries: …, matchedQueries: …, matchedQueryIds: …, references: …, ngContentIndex: …, childCount: …, bindings: …, bindingFlags: …, outputs: …, element: …, provider: …, text: …, query: …, ngContent: …}, elView: Object{def: …, parent: …, viewContainerParent: …, parentNodeDef: …, context: …, component: …, nodes: …, state: …, root: …, renderer: …, oldValues: …, disposables: …, initIndex: …}}, nativeNode: Hey there, properties: Object{}, attributes: Object{id: ‘shan’}, classes: Object{}, styles: Object{}, childNodes:[DebugNode__PRE_R3__{listeners: …, parent: …, _debugContext: …, ..nativeNode: …}], nativeElement: Hey there, name: ‘div’}
2. fixture.debugElement.nativeElement.querySelector(‘#shan’)
nativeElement
returns a reference to the DOM element which can also come under debugElement
as stated above.You can use it do actions such as click()
event in test cases.
fixture.debugElement.nativeElement.querySelector('#shan').click(); // this will create a click event over this element.
It works for querying both class
something like (fixture.debugElement.nativeElement.querySelector('.shan'))
as well as id
.
fixture.debugElement.nativeElement.querySelector('#shan')
will return
<div _ngcontent-a-c0="" id="shan">Hey there</div>
3. document.getElementById(‘shan’)
This is our good old way to access an id
(not a class
). You can't access class
by doing something like
document.getElementById('.shan') // will return null
Also, note that you don’t need to pass #
in this function argument.
document.getElementById('#shan') // will return null
It should be avoided while working with angular
because angular has its own ChangeDetection
which requires it to be worked with fixtures
. By directly calling document
, you'll end up banging your head on the wall , trying to figure out why is the element coming as null
document.getElementById('shan')
will return
<div _ngcontent-a-c0="" id="shan">Hey there</div>
If you like this article, please 👏 clap 👏 few times & encourage me 🐼 to write more.