I'm developing projects using javascript (React). I'm using modular css which randomizes class name so I cannot have a hold on it using css selectors later in tests.
What are my options if I want to make referencing UI elements easier in tests (be it unit or selenium)?
I locate DOM elements by using special attributes I add to the HTML Element, which always follows a specific naming scheme.
Example (HTML): <div class="randomClass" data-testing-locator="test-locator-attr-example">
My locator: element(by.css('div[data-testing-locator="test-locator-attr-example"]'))
I avoid using class-based locators. We used to use them intensively in a large production application, and minor changes to the HTML (Like adding a new class name to an element) could break the locators. By swapping to the attribute look-up, our tests no longer broke when a designer did relatively minor changes. It really got annoying having to fix locators every second day or so.
Related
We are working on an enterprise web application, at the moment we hired an e2e test engineer to perform automation tests.
He asked us to assign IDs to every single element in pages.
Is there a tool or something to perform this action automatically and adds some random IDs to all elements in HTML files ?
we already have a bunch of files and it would take much time to add them manually.
According to the following question, A selector like body div:nth-of-type(4) ul li:nth-child(5) a to check a certain link is not only obviously ugly, but also prone to changes in the markup. A small change could break half of your testsuite.
Adding ID attribute to all HTML elements of a web application?
We are using: Angular v6 / Material v2 / Protractor / Jasmine
We have been working on a React project for which we are doing e2e testing using 'Mocha-Nightwatch'. As a UI automation tester I needed something to access the elements, there were following options for me:
1) Using the "CSS selector", which is ugly and long as you mentioned.
2) Using The "X-path" of the element, which is again long and much more confusing
3) The best of all the "Id's" for elements [because they are unique throughout the app]. But the problem was when we gave id an element, React web pack will append a alphas numeric string to the id each time you build the application,making a unique id every time. So again id's failed in this scenerio.
4) The thing which we settled for was "Classes" for the elements which we wanted to access in testing.
As far is going the id or classnames is concerned, there is no shortcut in doing it. You need to give meaningful names for the id/classnames, some tool [which may or may not exist] will add some random id to all the elements which is not at all needed, and just increases the space complexity of your application.
The better solution is take up module by module and add class or id's[id they are not made dynamic by Webpack in you case] names by yourself.
The approach we used was we taught the automation tested how to add class names or id's, and how to inspect in the chrome dev tools, if the id's/classes really exist or not. But the limitaion of this is, the tester may add some classes or id which may conflict with your functionality. to solve this you can use a proper naming convention, for e.g. we use .test-something-something or #test-something-somethig as our convention for naming the test id's and classes.
Here is a sample from your selectors file:
usernameInput: '.test--auth-username > input',
passwordInput: '.test--auth-password > input',
loginButton: '.test--auth-submit > button',
loginError: '.test--auth-error',
inputError: '.test--inputField-errorText',
Hope this helps,
Cheers
Just a minor comment, it might be smart to use data-test-id (a custom data element) in favor of using the "regular" html5 ID. this allows you to benefit from plugins like: https://github.com/mukeshsoni/babel-plugin-remove-data-test-id-attribute, which in turn cleans up your production output.
I am not aware of any libraries that automatically assign test-ids to your elements (and most probably you want to be in control of where the test ID is added in the first place)
I don't recommend to assign id to each element on page. For automation we can use CSS Selector and XPath to locate element from page, finding element by ID is not the only way.
And if you choose to use automatical ID, you have to make sure the same element will always get the same ID when you build the app each time, otherwise the automation script have to change for each app build.
I will recommend to add ID to key element on the whole page, for example, we have one page and we divide the page into 4 areas: head, left side bar, student table, footer. We can only add ID on the container element of the 4 areas, so only 4 IDs we need to add, rather than all elements. And add css class name in class attribute on sub elements.
With above approach, automation script can use findElement chain as below:
// find the container element of area firstly
WebElement headArea = driver.findElement(<By.id('id of head area')>);
// find sub element within container element
headArea.findElement(<By.css('css selector of sub element')>);
As a new web developer, I've been utilizing a lot of resources like StackOverflow to assist me in the learning and development process.
When using jQuery, all of the examples/responses that I've come across so far have only referenced classes, like so:
$('.yourClass')
as opposed to
$('#yourID')
Seeing that class referencing seems to be the trend (I honestly haven't found one author who writes a jQuery to an ID), are there any pitfalls I should be aware of for using ID's w/ jQuery or JS in general? Thanks!
EDIT 1: I'm aware that ID's are for single-items, classes are for accessing multiple items. I'm more interested in why I don't see any jQuery or JS examples referencing ID's. Thank you!
You would have to ask each author on a case-by-case basis, but generally when creating examples, the selector used doesn't matter; what's important is that you have a jQuery collection that you can call a method on.
By using a class selector in the example, you avoid newbie developers claiming that your plugin doesn't work when they try to use it on multiple elements with the same ID. Your example serves the purpose of showing how to use it on one or more elements, rather than just one.
People like to use classes because ids have to be unique across the whole page. When trying to make reusable, pluggable components, id's make this impossible to enforce.
Exception: the new web-components standard allows you to encapsulate ids to just your component.
An ID must be unique, you can have only one (like highlanders).
Classes are used to identify a "type" of object not a specific one.
An obligatory car analogy:
An ID is a license plate, unique to one specific thing #345-abc
The class relates to a whole category of things like .truck
Take note that a selector like $(".something") will actually be capable of producing a list of DOM elements; as it will select all DOM elements with the class of "something"
An ID selector $("#unique") will only ever return one element
Think of your HTML and CSS first.
Using Classes
If you have multiple HTML elements which all will look, feel and behave in the same way, then it is highly recommended to use a class to represent their style and behavior.
Example: rows or columns on a table, navigation buttons which animate in the exact same way, wrapper to images which have the same size throughout your website, etc.
Using ID's
However, if you have a unique HTML element which represents a particular thing or state or action in one of your pages, then that element should contain an id.
Example: pop up modal, a unique looking button, unique sections on your website which you can navigate to by their id, etc.
Then, you can use this behavior in your JavaScript and jQuery or whatever else you like to use.
Further reading
I know that you are fully aware of why we should use ID's or classes.
But the vast majority of answers that are given here, are thinking of a project context.
So, let's say editing a .js file that is linked to the scope of the entire project, the idea here is to be as reusable as possible, so that's why you'll see much more classes references than ID's. Is hard to maintain a project js file that makes reference to different ID's that are abroad the project.
Same thing will apply to css.
I hope the answer is enough, be free to post a comment or suggestions. :-)
The page I'm testing uses very few id's. All of my locators are these long xpaths. I'm wondering, would there be any advantages or disadvantages if I first execute some javascript to inject unique classNames for every element, and and then just locate by className?
EDIT
I am already using the page object model.
My question is simply, are there any advantages to locating an element by className eg "uniqueClass01" rather than by an xpath such as
"/html/body/div[13]/div/div/div/div/div/div/div[7]/div/div/div/div/div/div/div[2]/div/div[2]/div/div/div/div/div/div/div[6]/div/div/div/div/div[2]/a"
I have added unique classes to each element using the jsExecutor - that was easy. I'm just wondering if it's better to do it this way, or use xpaths like above.
If you find that you're repeating your locators (e.g. long xpaths) in your scripted code, that shows that there is a problem. You could inject a unique class name for each element and use that locator from then on; but your scripted code would still have to repeat the new locator (unique classname).
I'd recommend structuring your scripts using a Page Object model; that way, each locator would be defined just once. As long as the locator is defined only once, it doesn't matter whether it's a short class name or a long xpath; and it would make your scripts clearer to read.
I've had this happen to me three times now and I feel it's time I learned how to avoid this scenario.
Typically, I build the HTML. Once I'm content with the structure and visual design, I start using jQuery to wire up events and other things.
Thing is, sometimes the client wants a small change or even a medium change that requires me to change the HTML, and this causes my javascript code to break because it depends on HTML selectors that no longer exist.
How can I avoid digging myself into this hole every time I create a website? Any articles I should read?
Make your selectors less brittle.
Don't use a selector by index, next sibling, immediate child, or the like
Use classes so even if you have to change the tag name and the element's position in the HTML, the selector will still work
Don't use parent() or child() without specifying a selector. Make sure you look for a parent or child with a specific class
Sometimes, depending on the amount of rework, you'll have to update the script. Keep them as decoupled as possible, but there's always some coupling, it's the interface between script and HTML. It's like being able to change an implementation without having to change the interface. Sometimes you need new behavior that needs a new interface.
I think the best way to help you is for you to show a small sample of a change in the HTML that required a change to your jQuery code. We could then show you how to minimize changes to JS as you update the HTML
This is a follow-up question for In jQuery is it a bad idea to use name=X for all selectors?
I am using Backbone and decided that I wanted a way to differentiate between HTML elements that were bound and those that were not.
So I would write (in HAML):
.container
.title(name='title')
.separator
As you can see it's clear that the dynamic element is title.
The reason for this was so I could mess around with the style and rename classes without worrying about breaking the app. It also means in the template I can tell what the dynamic elements are without needing to go back and forth with the Backbone View.
My question now is, without using the [name] selector, does anyone have a code convention to keep track of which HTML elements are referenced from JS.
I have considering:
Using a common prefix on class names (e.g. class=bind-title)
Using some sort of custom HTML element (
Thanks!
FYI: I'm using CoffeeScript, Backbone and haml_coffee templates.
Updated jsperf to test all suggestions:
http://jsperf.com/class-or-name-attr-lookup/3
I would consider using a class to indicate that it is dynamic.
I'm not sure if you are aware of this but you can have multiple classes on one element. Like so:
.container
.dynamic.title(name='title')
.separator
This works in traditional HAML but I have not tried it with haml-coffee. If it doesn't work, you might have to specify the class like .title{:class => "dynamic"}(name='title').
I prefer this over a prefix on the class name because it's more semantically meaningful, which is how HTML should be used.
I am using data-view attribute on elements being set when rendering my Views.
This helps me to then show a tooltip in a browser window when I hover over View(s).