How do I use the new `console.log()` output of Chrome? - google-chrome

Chrome 24 has a new way of outputting objects in console.log().
For example, console.log($("p")); on this jsFiddle example outputs this insanity:
▼[<p>, <p>, <p>, prevObject: jQuery.fn.jQuery.init[1], context: #document, selector: "p"]
► 0: <p>
► 1: <p>
► 2: <p>
► context: #document
length: 3
► prevObject: jQuery.fn.jQuery.init[1]
selector: "p"
► __proto__: Object[0]
I can see that it puts the collection of DOM elements at the beginning. But if you try to expand even a simple <p> tag that is mostly empty, it throws up all over you:
▼ 0: <p>
accessKey: ""
align: ""
► attributes: NamedNodeMap
...
[stopping here for sanity's sake]
So how do I use all this information? My first instinct is to tame it down to how it used to look, but on second thought, there really is a lot of info in there that I might want to have access to. But I'm having a hard time understanding what I'm looking at. Much of it looks like jQuery values. Is this a list of every jQuery value that the object has (or doesn't have)?
Then there's the whole issue of the ► context: thing and the ► __proto__: thing. Once you start drilling down in __proto__ you will never stop. I think it goes infinitely down!
How can I begin to learn how to use this new output?
EDIT:
I actually just realized that I'm still using Chrome 23, this isn't something that was introduced in 24. Someone in this thread said it was a Chrome 24 issue, but maybe it's new in 23? At any rate, I only just recently started noticing this on jQuery objects.
EDIT 2: If you're just looking for how to log the old way, try this: (hat tip)
console.log.apply(console, $("div"));

In your demo fiddle, you are logging NodeLists or HTMLCollections. Each of the elements within a NodeList is represented as a numeric index 0, 1, 2, etc. 0 being the first in the NodeList if any elements exist in it.
When you expand the Elements you see all available properties of an HTML Element as defined in DOM Core 3 specification. Refer here for more information about this http://domenlightenment.com/#3.2 and for a list of all properties and their purposes go here: https://developer.mozilla.org/en-US/docs/DOM/element. None of this is new in Chrome.
What is new in the latest Chrome version is the top level logged object, so if you just opened the console and typed:
console.log(window)
Which for me when I just did it logged a preview of what the expanded window object it provides when logging it. So for example, you should see something like:
Window {is_minor: 5, bmi_ie6: false, careers_adselector: "div.hireme, div#hireme"...}
Other NodeLists properties listed below the Elements of the list:
context - the context of the selection - http://domenlightenment.com/#4.4
length - the number of Elements in the HTMLCollection
selector - the selector used to select the Element or NodeList
__proto__ - An Object's __proto__ property references the same object as its internal [[Prototype]] (often referred to as "the prototype"), which may be an object or null (in the case of Object.prototype.__proto__). For more info on this refer to: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/proto
I modified the fiddle slightly and should show the preview of the objects when you view the console http://jsfiddle.net/jaredwilli/H3YWq/2/
You can't really get rid of any of these things either, they're a part of the DOM and will exist always otherwise the NodeType of what you're looking at will be something other than an ElementNode.

I'm just as annoyed as you are with this change. I know this isn't ideal, but it will hopefully help you a little bit.
console.log($('p')[0]);
You may have seen that solution before, and then found it didn't work if you were in a loop for instance:
$('p').each(function(){
console.log($(this)[0]);
});
That doesn't end up giving you the result you were used to either, so I had to use ['context'] instead of [0] like this:
$('p').each(function(){
console.log($(this)['context']);
});
Again, I'm looking for a better solution myself, but I thought I'd share with you what I've found.

You want first element so use [0]
As another option, check out Firebug in Firefox. I know, I love chrome too and use it every day, but Firebug is a great plugin and I've never had an issue with it.

Related

Parent node in react-testing-library

The component that I have testing renders something this:
<div>Text<span>span text</span></div>
As it turns out for testing the only reliable text that I have is the 'span text' but I want to get the 'Text' part of the <div>. Using Jest and react-testing-library I can
await screen.findByText(spanText)
This returns an HTMLElement but it seems limited as I don't have any of the context around the element. For example HTML methods like parentNode and previousSibling return null or undefined. Ideally I would like to get the text content of the parent <div>. Any idea how I can do this with either Jest or react-testing-library?
A good solution for this is the closest function.
In description of closest function is written: Returns the first (starting at element) including ancestor that matches selectors, and null otherwise.
The solution would look like this:
screen.getByText("span text").closest("div")
Admittedly, Testing Library doesn't communicate clearly how to do this. It includes an eslint rule no-direct-node-access that says "Avoid direct Node access. Prefer using the methods from Testing Library". This gives the impression that TL exposes a method for a situation like this, but at the moment it does not.
It could be you don't want to use .closest(), either because your project enforces that eslint rule, or because it is not always a reliable selector. I've found two alternative ways to tackle a situation like you describe.
within():
If your element is inside another element that is selectable by a Testing Library method (like a footer or an element with unique text), you can use within() like:
within(screen.getByRole('footer')).getByText('Text');
find() within the element with a custom function:
screen.getAllByText('Text').find(div => div.innerHTML.includes('span text'));
Doesn't look the prettiest, but you can pass any JS function you want so it's very flexible and controllable.
Ps. if you use my second option depending on your TypeScript config you may need to make an undefined check before asserting on the element with Testing Library's expect(...).toBeDefined().
But I have used HTML methods a lot and there was no problem yet. What was your problem with HTML methods?
You can try this code.
const spanElement = screen.getElementByText('span text');
const parentDiv = spanElement.parentElement as HTMLElement;
within(parentDiv).getElementByText('...');

Polymer databinding confusion with Object Properties

EDIT - THIS IS A COMPLETE RED HERRING. One of the user properties down the hierarchy had the readOnly property set for user. This was preventing it propagating.
I am struggling to understand databinding and how values propagate when the property changes I have a tree structured set of elements (the structure is spread across separate element definitions - not with <content> tags as possibly implied by the structure show below)
<my-app user="{{user}}">
<my-session user="{{user}}">
<my-login user="{{user}}"></my-login>
</my-session>
<template is="dom-if" if="[[user.name]]">
<my-pages user="{{user}}">
<iron-pages>
<my-menu user="{{user}}"></my-menu>
<my-reports user="{{user}}"></my-reports>
</iron-pages>
</my-pages>
</template>
</my-app>
Each of these elements at their different definitions define a property
user : {
type: Object,
notify: true
}
And all the elements are linked with two way data binding
<my-pages> is lazy loaded using importHref after the user has logged on (and therefore user.name is defined)
I have a property of user called keys which is used for access control. In particular both <my-menu> and a sub element of <my-reports> uses this to determine which menu items to display.
This all works fine on initial log on. But if I change the logged on user, then this change to the user property is apparently not propagating properly
What I can see is that from the debugger triggered during a page change from iron pagess I can see that the <my-app> 's user has the new logged on user value BUT <my-pages>'s user has the old user. For some reason data binding of user is not working down the tree structure, even though it appears to have successfully propagated up from <my-login> to <my-app>. .
I am assuming that possibly the "object" of user is not changing only the paths. I am getting confused about what I should be doing here. Can someone help.
Really cannot tell what's wrong with your code with the information that you have provided except for the syntax error where instead of closing my-pages you have started a new one, but here's a plunker emulating your code. I was able to successfully change the user for all the elements.

Unable to Access DIV element using Watir

Hi I am trying to access the DIV element using watir but I am unable to do that,I have tried in different ways but couldn't access it,may be I think it need to be access through some parent element can anyone help me out?
My system Configurations
IE-8
Windows 7
I tried with the below command
#ie.div(:text,'COMPOSE').click
the command gets execute with no errors but no action is performed on the UI
The best solution appears to be switching to Watir-Webdriver. With Watir-Webdriver, #ie.div(:text,'COMPOSE').click will work as expected.
Assuming that is not an option, there are a couple of reasons why that same command does not work with Watir(-Classic) v1.6.7:
The first problem is that #ie.div(:text,'COMPOSE').click will find the first div that contains this text. This would be one of the ancestors of the div you want. As a result, Watir will send the click event against the wrong element.
The second problem is that the div is not responding to the onclick event fired by Watir. I am not sure why this problem exists.
To solve the first problem, you will need to be more specific when locating the div. In this case, the "role" attribute can be used since none of the ancestor elements have this attribute. Watir-Classic does not support using the role attribute as a locator. As a result, you will need to create a custom locator using an element collection and the find method:
#ie.divs.find{ |div| div.attribute_value('role') == 'button' && div.text == 'COMPOSE' }
To solve the second problem, it turns out that double clicking does work. While newer versions of Watir-Classic have a double_click method implemented, it does not exist in 1.6.7. You can replicate the method by calling the fire_event method:
.fire_event('ondblclick')
Putting it all together, the following will click the compose button:
#ie.divs.find{ |div| div.attribute_value('role') == 'button' && div.text == 'COMPOSE' }.fire_event('ondblclick')
There may be more than one element on the page with the text 'COMPOSE', some may be hidden. Try:
#ie.divs(:text,'COMPOSE').size
That is divs with an s.
Then you can try something like the following and see if you get a change in the UI:
#ie.divs(:text,'COMPOSE').each { |b| b.fire_event('click') }
I remember that fire_event works better, but would recommend consulting the docs for the difference between .click and fire_event.

MVC Sitemap renders empty when the current action is not in the Mvc.sitemap file

Is it possible to force the sitemap control to render the menu when the current action is not listed in the MVC.sitemap file?
I have a simple top nav. When the current action is in the sitemap, the call to .Menu() will render the correct <ul><li>.. data. However, if I got to a page that is not in the sitemap such as /Home/Login, then it will not render any html at all (not even a comment, just empty space). This isn't an [authorize] issue; the menu is fine when i'm in '/Home/Index'.
It seems like it should render what was requested, but just not set the IsCurrentNode and IsNodeInPath properties. Here is the call I am making
<div id="main-nav">
#Html.MvcSiteMap().Menu(0, true, true, 1)
</div>
The Mvc.sitemap file:
<mvcSiteMapNode title="Home" controller="Home" action="Index">
<mvcSiteMapNode title="Form New Human" controller="Person" action="Create"/>
<!-- there is no mvcSiteMapNode for "Home" "Login" -->
</mvcSiteMapNode>
Found the way around it. It apparently isn't a built in extension method, or at least I couldn't find one. You could call Html.MvcSitemap().Menu(Html.MvcSiteMap.Provider.RootNode,...) but I didn't want to instantiate the helper twice.
<div id="main-nav">
#{
var sm = Html.MvcSiteMap();
#sm.Menu(sm.Provider.RootNode, true, true, 2); // 2 levels (home, plus main nav)
}
</div>
Looking around in the disassembly seems to show that it works a little like this:
You really need a starting node
If you don't give it one, it tries to find one based on the current node
plus restrictions (forward searching, depth restrictions, etc)
if you want nodes from level 1, you have to know what level you are on
Since that returns null, starting node is null, which means the helper writes an empty string
There may be a combination of tricks, or an overload or two, which can be finagled into doing this, but I can't find it right now. This works for my needs (simple top menu). There has to be a simpler way to do this, something with wild cards, or route based, with a closest match thing going on. I figured menus were a fairly standard part of a web app, and this would be covered :)

Any difference between .innerHTML and .set('html','') in mootools?

To set the html of elements on my site, I use mostly
$('elementId').innerHTML = "<p>text</p>";
Looking through the mootools docs, I found this example given:
$('myElement').set('html', '<div></div><p></p>');
Is there any difference between these? Should I go through and change .innerHTML to the mootools method, or doesn't it make a difference?
the reason why the first one works is because - as it stands - a $ selector (document.id) in mootools returns the actual element. this - in normal browsers - is identical to document.getElementById() and the element object exposes any and all of its attributes/properties for you to edit.
the problems with NOT using .set are:
when mootools 2.0 aka MILK gets released, it won't work as it will be wrapped like jQuery and the selector won't return the object (mootools is becoming AMD hence it won't modify native Types - Element, Array, Number, String, Function(maybe!) - prototypes).
you cannot chain this. with set you can: $('someid').set("html", "loading...").highlight();, for example.
set is overloaded - it can set either a single property or multiples by means of passing an object. eg, element.set({html: "hello", href: "#", events: boundObj});
look at https://github.com/mootools/mootools-core/blob/master/Source/Element/Element.js#L936-942 - you can pass an array as an argument and it will join it for you, this makes it easy to work with multi-line strings and ensures performance in IE
edit: the BBT fan has kind of opened a separate topic: should the framework try to block you / prevent you from doing things that break the browser?
if you want to, you can add disallowed elements by changing that setter Element.Properties.html.set = function() { var tag = this.get("tag"); ... check tag }; - isn't mootools great?
mootools - by default - will NOT try to prevent you from doing stupid shit [tm] - that's your responsibility :) try setting height on an element to a negative value in IE, for example. should the Fx class prevent you from doing that? No. Should the setter prevent you? No. The footprint of constant checks to see if you are not breaking means it will slow everything down in performance-critical cases like animations.