Overview:
One of the applications I had automated had some unique functionality! The application helped the users to connect with different service providers! Users would be entering their preference in the application. The application would show list of service providers. Users could pick one from them and and fill out a specific form for the service provider to get the better service.
To understand this better, assume an application like Dice.com where you search for list of openings based on your preferences in Dice which is Dice specific application fucntionality. Then when you try to apply for a job from the search results, you might have to provide some additional information in a company specific form which has posted the ad.
Challenges:
I had to automate one application like Dice in which the service providers forms are very complex. To imagine, there are forms in which we have more than 1000 elements! Yes it is Thousand! 100 dropdowns, 200 radio buttons, 300 text boxes etc. All these forms are not created at run time. They are created whenever a new service provider is added into our application. A new form is created for the provider as per the provider’s request. All the elements in the forms would have unique id/names. There would NOT be any relationship among the forms from different providers. So, no reuse!
Definitely I can not create page object with FindBy for 1000 elements and corresponding methods for filling out the form. I also can not spend too much time on automating the forms. I was looking for some approach which would save me a lot of time.
Sample Application:
As usual, to give you an idea, We are going to consider this form. Real form would be having a lot more elements than this.
Here the service provider is a doctor who seeks for patients medical history to give the patient better service. This is the page for which we need to come up with page object for filling out the form.
JSON Page Object Model:
In our scriptless framework approach, we would be creating page object in JSON format. We would be maintaining a separate JSON for each and every form/page. The Page object would be more or less as it is shown here for a page.
{
"element1-name":"value1",
"element2-name":"value2",
"element3-name":"value3",
...
}
We would be following the below process for each and every page for which you want the Page object to be in JSON format. To achieve that we would be injecting few scripts in the chrome console.
- Launch the form manually. [ Fill the form manually with appropriate inputs as it is shown here. It is not really required. We would NOT want our page object to have hard coded data. But we do this exercise now to get an idea to see how it works ]
- Launch chrome console and inject JQuery as it is shown here.
var jq = document.createElement('script');
jq.src = "//code.jquery.com/jquery-3.2.1.min.js";
document.getElementsByTagName('head')[0].appendChild(jq);
- Lets create an alias for JQuery. Run this command in the chrome console.
var $j = jQuery.noConflict();
- Run this below command in the chrome console which is used to extract the current input.
var eles = {};
var eleMap = {
'INPUT#checkbox': function(ele){
eles[ele.name] = eles[ele.name] || [];
if($j(ele).is(':checked')){
eles[ele.name].push(ele.value);
}
},
'INPUT#radio': function(ele){
if($j(ele).is(':checked')){
eles[ele.name] = ele.value;
}
},
'INPUT#text': function(ele){
eles[ele.name] = ele.value;
},
'SELECT#': function(ele){
eles[ele.name] = ele.value;
}
}
- Then run the below command in the chrome console which is responsible for creating the page object.
var pageObjectModel = function(root){
$j(root).find('input, select, textarea').filter(':enabled:visible:not([readonly])').each(function(){
let eleName = this.name;
let key = this.tagName + "#" + (this.getAttribute('type') || '');
var func = eleMap[key] || eleMap['INPUT#text'];
func(this);
});
console.log(JSON.stringify(eles, null, 4));
}
- Now chrome console is ready to create page object. We need to give the root element under which it has to find all the elements and create a page object. In our case, it is main document. So I run the below command to get the JSON object model.
pageObjectModel(document)
- That’s it. Our Page object for a complex form is ready within few seconds with all the inputs we had entered! You do not have to inject these scripts one by one. You could inject all of them at once.
- Copy the JSON output from the console and save it in a file. You could remove any fields from the JSON file which you do not want to include in automation.
{
"q71_patientGender":"Male",
"q45_patientName[first]":"test",
"q45_patientName[last]":"automation",
"q46_patientBirth[month]":"January",
"q46_patientBirth[day]":"6",
"q46_patientBirth[year]":"1960",
"q72_patientHeight72":"178",
"q73_patientWeight73":"72",
"q74_patientEmail":"test@gmail.com",
"q50_reasonFor50":"general check up",
"q51_pleaseList":"none",
"q52_haveYou52[]":[
"Anemia",
"Asthma",
"Arthritis",
"Diabetes",
"Emotional Disorder"
],
"q55_otherIllnesses":"none",
"q69_pleaseList69":"none",
"q68_pleaseList68":"none",
"q80_exercise":"1-2 days",
"q81_eatingFollowing":"I have a loose diet",
"q76_alcoholConsumption":"I don't drink",
"q77_caffeineConsumption77":"1-2 cups/day",
"q78_doYou":"No",
"q17_includeOther":"none"
}
Application Independence:
The above approach is NOT application dependent. I can use the same approach for a completely different application. I still get the Page Object in the console as shown here. So you should be able to use for your application as well.
Summary:
As you see, by injecting few scripts, we extract all the fields on a page or under specific element, we create a map of field names and values. This approach would be very useful in creating a page object for very complex page which contains hundreds of elements.
If you are still wondering – What am I supposed to do with this JSON? – No worries. I would explain that in the next article. Please continue reading – Part 2.
Happy Testing & Subscribe 🙂
Hi,
I was impressed with your blog post regarding scriptless automation. However, when I tried to inject those scripts in chrome console – I get an “undefined” error. Is there any setting that I should switch ON in chrome in order to allow the script to run without any problem?
Can you show the error you had received by uploading screenshot somewhere?
@Vinoth,
Sorry it was my mistake and I was able to getting it working.
Thanks
Krish
This is a very good Article Vinoth. How concisely you are integrating different aspects of available technologies to make the page object model for such huge pages a simpler task. Appreciate this solution.
Hi,
I was impressed with your web which appears to be at very higher level in the field. I like and appreciate it even I am one of new guys in field. I faced a problem.
When I tried to inject those scripts in chrome console, hit , then chose Patients gender, the below was what inside console
“var jq = document.createElement(‘script’);
jq.src = “//code.jquery.com/jquery-3.2.1.min.js”;
document.getElementsByTagName(‘head’)[0].appendChild(jq);
prototype.forms.js:280 Uncaught TypeError: Cannot read property ‘length’ of undefined
at Function.hasClassName (prototype.forms.js:280)
at addClassName (prototype.forms.js:280)
at HTMLLIElement._methodized [as addClassName] (prototype.forms.js:60)
at HTMLSelectElement. (jotform.forms.js?3.3.8310:756)
at HTMLSelectElement.responder (prototype.forms.js:569)
hasClassName @ prototype.forms.js:280
addClassName @ prototype.forms.js:280
_methodized @ prototype.forms.js:60
(anonymous) @ jotform.forms.js?3.3.8310:756
responder @ prototype.forms.js:569
prototype.forms.js:281 Uncaught TypeError: Cannot read property ‘replace’ of undefined
at removeClassName (prototype.forms.js:281)
at HTMLLIElement._methodized [as removeClassName] (prototype.forms.js:60)
at HTMLSelectElement. (jotform.forms.js?3.3.8310:757)
at HTMLSelectElement.responder (prototype.forms.js:569)
removeClassName @ prototype.forms.js:281
_methodized @ prototype.forms.js:60
(anonymous) @ jotform.forms.js?3.3.8310:757
responder @ prototype.forms.js:569
jotform.forms.js?3.3.8310:998 TypeError: inputContainer.select is not a function
at jotform.forms.js?3.3.8310:998
”
I need help
Mak
Hi,
here, Mak or ermao again
I keep following you, till “pageObjectModel(document)”. To my surprise, I got a right JSON output from the console. I don’t understand it.
Thank
Mak
Hi,
Can this be used for mobile automation by Appium .
You should be able to!
Hi Vinoth,
How to extract test from a page(
,<h1..6> lables) using this model
Can be done. But it requires a little bit of work. Also it is just an idea. you need to improvise this based on your requirements.