In angular unit testing using jasmine, we can test the view (html content) in two ways.
Getting the elements from DebugElement
fixture.debugElement.queryAll(By.css('.tableData.billStatus.text-center'))
Getting the elements from DOM.
fixture.debugElement.nativeElement.querySelectorAll('.tableData.billStatus.text-center')
My question is not related to queryAll vs querySelectorAll. It is DOM vs DebugElement. Because when I use either of them, they give me the correct result most of the time.
This question has some relation to this issue
They give a work around to look through DOM elements as opposed to DebugElement as a work around. So what makes these two differ from each other?
I have looked through several posts for the difference, before making this question. But I did not find anything appropriate to this.
debug element contains references and methods to a component or element whereas native element is a reference to the DOM element.
The Usage of DebugElement vs NativeElement depends on your scenario:
If you are going to run your tests only on the browser, then NativeElement is enough, since the tests will be run on the browser, the DOM will be available for NativeElement to do its operations.
If you are going to run your tests on server or some pipeline where the browser platform is not available, then you should use DebugElement, as it will wrap the native elements of the runtime platform, so that you can do query on non-browser supported platforms too.
Related
I'm studying how react currently works and am a bit confused how to access the functions that are hidden in the props with native javascript. I'm aware if I download the react extension I can view them in the google developer console but this is not what I need. I don't have access to the react components directly because I'm making a Google chrome extension.
For example in the Chrome Developer Console, I can type the following:
var elem = document.querySelector('.wrap-XdW9S1Ib');
Lets just say that this element is my element of interest and it has an onClick event within it's props that I would like to access to automate clicks for testing purposes.
Attached is a picture of the progress so far:
I can then type something like...
elem.__reactProps$63clhtkk874
Which shows the below:
Note you can see the onClick event and other functions that react creates.
Now... if you try to do this same thing via code. In particular the for(key in elem){console.log(key);} for some reason __reactFiber and __reactProps do not appear!
Note: Notice that align,title,lang etc... all show up but the __reactProps are not there now.
Note#2: My code is identical to what you see above in the pictures and works just fine printing out to console (as you can also see in the screenshot), except..., I just don't see the react events.
Why do these show up in the developer console and NOT in the same console via my code I write. In otherwords, when I type in the console prompt it not via non prompt (I.E, just regular .js file)
I found the solution to this question, it is indeed because the chrome extension is in isolated memory space compared to the DOM. To get access to that variable I first have to inject my script into the regular DOM and then use chrome messaging api to send a message to my injected script to THEN get the variables I'm looking for. Hopefully this helps someone else out. I can see why my question was initially closed now as a duplicate, but none the less I think this may help some people that get confused by this particular issue when it comes to react.
I'm just guessing over here. But judging from the underscores you are probably accessing elements from React's internal virtual DOM. Which may or may not be the same as the DOM. I've read that React was built for the purpose of abstracting away the imperative DOM manipulation that vanilla javascript uses.
Though sometimes interacting with the DOM cannot be avoided, so whenever I see DOM manipulation in React, I think of the useRef hook. By setting the useRef hook to a variable and linking it to a DOM element, you can console.log variable.current, and see the real DOM element and work with it in a useEffect hook for example. Hope this was at least a little helpful! All the best in your learning endeavors!
Use of Plain JavaScript ( syntax like getDocumentById) in angular5 project is good coding practice or not , or Should we use ElementRef , TemplateRef , ContainerRef for referring the DOM elements instead of Plain JavaScript.
It's not encouraged to use the DOM element manipulation directly .
This blog explains why it should be avoided
With Angular 6 last update by google they have started moving towards shadow dom and dom hierarchy tree it would help dev community to not worrying about actual dom elements manipulation
Use the framework, don't go direct to the DOM (which is what you mean by "plain JavaScript") unless you have no other choice. (Or don't use a framework at all.)
But note the warning in the ElementRef docs:
Permitting direct access to the DOM can make your application more vulnerable to XSS attacks. Carefully review any use of ElementRef in your code. For more detail, see the Security Guide.
If you can avoid using ElementRef (without going direct to the DOM), that's probably best.
In dealing with JS frameworks like AngularJS, Angular, and React, I've observed that directly interacting with the DOM is discouraged, and can often lead to bugs, if you ignore the warnings. When I say "interacting with the DOM" I mean using document.getElementById('myElement') and similar methods to do some manipulation or read values from the document.
My question is essentially Why?. Is this a virtual DOM problem, where React (for example) isn't tracking the actual DOM, and therefore will be caught off guard if you make a change "on your own" without notifying React and subsequently updating the virtual DOM? Would Angular have the same problem in such a case?
If someone has knowledge of only a specific framework, I would be very interested to read the answer to my question even if it is not generalized. Obviously, I'm going to go google this some more, but I didn't see a similar question here yet, so I figured I'd post for posterity. Thanks in advance for any insights!
#HDJEMAI linked to this article which I'll repeat, as it's good advice: https://www.reddit.com/r/javascript/comments/6btma7/whats_so_wrong_with_direct_dom_manipulation/
I'll expand on some of those reasons below:
Modern frameworks like Angular and React are designed to hide the DOM because they want to abstract the DOM away. By using the DOM directly you break the abstraction and make your code brittle to changes introduced in the framework.
There are many reasons to want to abstract-away the DOM, and the Reddit page linked-to mostly focuses on "state management" because your framework (Angular, React, etc) will likely make assumptions about the DOM's state that will be broken if you manipulate the DOM directly, for example:
function this_is_your_code() {
tell_angular_to_make_my_sidebar_500px_wide();
document.getElementById('mysidebar').style.width = 700px;
var sidebar_width = ask_angular_for_sidebar_width();
console.log( sidebar_width ); // will print "500px"
}
Another reason to abstract away the DOM is to ensure your code works with non-traditional DOMs besides the typical web-browser document/window DOM environment, for example "server-side Angular" is a thing, where some of the Angular code runs on the server to pre-render HTML to send to the client to minimize application startup delay or to allow web-browsers without JavaScript to access your webpages, in these situations the normal W3C DOM is no-longer available, but a "fake" DOM is available but it's provided by Angular - and it only works through Angular's abstractions - it won't work if you manipulate document directly, for example:
function this_is_your_code_that_runs_in_nodejs() {
tell_angular_to_make_my_sidebar_500px_wide(); // this works and Angular's built-in abstraction of the DOM makes the appropriate change to the rendered server-side HTML
document.getElementById('mysidebar').style.width = 500px; // fails because `document` is not available
}
Really good answer from #Dai above, I would like to add on top of that. For most cases, you should not manipulate the dom directly. There are cases where you have to and it's the right thing to do.
For example, React and Vue has a concept of ref. Which can be though like an id and gives you the access to the dom node. Let's say you are building a chat application where you fetch old chats when the user scroll to the top and you need to keep the last visible chat in focus.
This kind of situations are there and we need to access the dom. The good practice is to keep such code encapsulated and use the framework way of accessing something instead of reaching out for the document/dom.
When writing tests for React components, you have to render them into the DOM in order to make assertions about their correctness. For example, if you want to test that a certain class is added to a node given a certain state, you have to render into a DOM node, then inspect that DOM node via the normal DOM API.
The thing is, considering React maintains a virtual DOM into which it renders, why can't we just assert on the virtual DOM once the component is rendered? That seems to me like a very good reason to have something like the virtual DOM.
Have I missed something?
You haven't really missed anything. We're working on making this better. The virtual parts have always been very much an implementation detail of React, not exposed in any useful or reliable way for testing. We have some methods in our test helpers which wrap up the internal lookups which sometimes avoids looking at the actual DOM but we need more.
After answering this question I am left wondering why removeChild needs a parent element. After all, we could simply do
node.parentNode.removeChild(node);
As the parent node should be always directly available to the Javascript/DOM engine, it is not strictly necessary to supply the parent node of the node that is to be removed.
Of course I understand the principle that removeChild is a method of a DOM node, but why doesn't something like document.removeNode exist (that merely accepts an arbitrary node as parameter)?
EDIT: To be more clear, the question is: why does the JS engine need the parent node at all, if it already has the (unique) node that's to be removed?
I think it keeps the design simple. A node may exist in isolation but the more interesting case is the DOM tree. With removeChild, the node to be removed must be a child of the node on which the method was called.
Getting a list of all children and doing a manual comparison against each is not that expensive an operation. However, searching all descendants for a node that is to be removed is indeed expensive.
Edit: In response to your update, a browser is simply implementing the DOM spec, which defines a removeChild method on Node. The spec, in my opinion, has to be unambiguous and free of assumptions. It is similar to Dependency Injection from that perspective. The DOM Core spec models a tree using building blocks such as Node, Element, etc. Adding a lone method such as removeNode somewhere in these building blocks means the method has implicit knowledge about its environment - that it may be a child of some node, and it should be removed from there if it is.
The task of w3 is to make a very robust API which makes most things possible. They shouldn't worry about syntactic sugar as that can always be written around the native APIs if they are well written.
The confusion might be because you might think removing an element means something like killing or destroying it.
But in fact, the concept of removal basically means breaking the relationship between a child and its parent. It's just a detachment.
Therefore, removing a element which has no parent node makes no sense. And it's reasonable that, if you want to break that connection between a parent and a child, you need a reference to both.
That said, it's true that sometimes you just want to remove a child from its parent, without caring about that parent at all. That's why DOM Level 4 introduces the ChildNode interface, which provides the remove method.
That interface is implemented by DocumentType, Element and CharacterData, so you can use it on doctypes, elements and Text, Comment, and ProcessingInstruction nodes.
Assuming node is one of these, you can use
node.remove();
In case it already has no parent node, nothing happens.