Saturday 20 October 2012

Selenium Web Driver to test websites

In this post I will write how to use selenium web driver to test the websites.Selenium  web driver allows us to drive the browser from the code supporting many languages like java , python etc.While it takes a little setup for chrome and ie,it works with firefox without any setup.I am using java to drive firefox browser.

The main goal of this post is to share code on how to design the test suite to make the code most reusable and also to make the testing reliable irrespective of user's connection speed.On to the design now :

The basic approach to design a test suite should be to create methods which automate elementary tasks and then to use these methods from the testing class and assert the results.This way the code developed for automating elementary tasks can be used by any potential testing client.For example : for website testing, tasks like logging in,logout,using various features of site like create post in blogger etc. can be put in a common class.

The test suite I developed is to test a salesforce app , so I will provide methods which helps doing login,selecting apps from the top right,selecting tabs,asserting page title etc.

Also I have overridden the selenium web driver's default methods like findElement() and some others to wait them for given time for page to load before throwing element not found kind of exceptions resulting from incomplete page load.

Please set the variable TIMEOUT according to connection speed.The logic behind waiting till timeout is the recursive call of the methods each after 1 sec.The methods exit after TIMEOUT if the desired elements are not found.

Monday 3 September 2012

salesforce lead conversion


This application allows user to search leads based on a keyword and giving fields to search in. User can then go to details page of returned leads, can select multiple leads and then can convert selected leads by providing an account name.  The Outcome will be an account, a contact for each lead and an opportunity for each lead. After successful conversion user will be redirected to newly created account’s detail page.

Video Url:

you can install the unmanaged package from :

App uses one visual force page and one controller :

VisualForce Page :

    
    
     
      
           
         
         
            Enter Keyword
            
            
Search Fields
Lead Displayed as Name(Company) , Follow the link to go to lead's Details page Enter Account Name



Controller :

Salesforce Mashup with google maps

This app helps user to plot  sales on the google map.The sales to be plotted can be filtered based on various criteria like location,size,type,date etc.Clicking on a sale on the map redirects to the corresponding account.
Final application looks like this :
you can install the unmanaged apex package from  here :
https://login.salesforce.com/packaging/installPackage.apexp?p0=04t90000000Pyoa

Use the following doc for deployment instructions :
https://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnxteWZpbGVzOTF8Z3g6NTJkN2U5YWU4ZTA3ZDZlMA

Demo video:
https://sites.google.com/site/myfiles91/home/files/salesmap.swf?attredirects=0

The app uses only one visual force page and one controller

Visual Force page :


<apex:page sidebar="false" Controller="salesData" id="page">

    <apex:includeScript value="{!URLFOR($Resource.jquery, 'jquery-1.3.2.min.js')}"/>
    <apex:includeScript value="{!URLFOR($Resource.jquery, 'jquery-ui-1.7.2.custom.min.js')}"/>
    <apex:stylesheet value="{!URLFOR($Resource.jquery,'jquery-ui-1.7.2.custom.css')}"/>
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
    
    <script type="text/javascript">    
        //This will load as soon as the page is ready and will setup slider
        $(document).ready(function(){
               
                //to setup slider
                $("#slider-range").slider({ //This line creates a slider on the DIV specified, options are passed arguments,comma separated below
                range: true,
                min: 0, //Min value for slider
                max: 400, //Max value for slider
                values: [0,250], //initial values of slider
                slide: function(event, ui){ //function to execute on slide event
                
                  document.getElementById('{!$Component.page.form.block.values.size_low}').value = ui.values[0]; //hidden fields to pass slider values to controller 
                  document.getElementById('{!$Component.page.form.block.values.size_high}').value = ui.values[1];
                  $("#amountValue").html(ui.values[0] + ' - ' + ui.values[1]); //display slider value as text
                  
                }
                });
                
                //to display initial values of slider
                $("#amountValue").html($("#slider-range").slider("values", 0) + ' - ' + $("#slider-range").slider("values", 1));
                
        
        });
        
    </script>
    <style>
        #map_canvas {
        font-family: Arial;
        font-size:12px;
        line-height:normal !important;
        height:500px;
        width:1000px;
        background:transparent;
        }
    </style>
                
                
     <apex:form id="form">
         <apex:pageBlock mode="edit" id="block">
               <apex:pageMessages />
               
               <apex:pageBlockSection columns="7" id="values" >
                
                  <apex:pageBlockSectionItem >
                    <apex:outputlabel value="* Country"/>
                    <apex:selectList value="{!country}" multiselect="false" required="true" size="1">
                       <apex:selectOptions value="{!countries}"/>
                    </apex:selectList>
                 </apex:pageBlockSectionItem>
                  
                 <apex:pageBlockSectionItem >
                   <apex:outputlabel value="State"/>
                   <apex:inputtext value="{!state}"/> 
                 </apex:pageBlockSectionItem>
                  
                 <apex:pageBlockSectionItem >  
                   <apex:outputlabel value="City"/>
                   <apex:inputtext value="{!city}"/> 
                 </apex:pageBlockSectionItem>
                  
                 <apex:commandButton action="{! search}" value="Search" reRender="mymap" />  
                  
                 <!-- pass slider values -->
                 <apex:inputhidden value="{!size_low}" id="size_low" /> 
                 <apex:inputhidden value="{!size_high}" id="size_high" />
                 <!-- pass address of clicked marker -->
                 <apex:inputhidden value="{!addressParameter}" id="addressParameter" /> 
                  
               </apex:pageBlockSection>
               
               <apex:pageBlockSection title="Filter Results" columns="3">
                     
                     <apex:pageBlockSectionItem >
                        <apex:outputLabel value="Size"/>
                        <!-- This is where our slider will be -->
                        <div id="slider-range" style="font-size: 90%; margin-top: 0.5em;"></div>
                        <div id="amountValue" style="text-align: center;"></div>
                     </apex:pageBlockSectionItem>
                     
                     <apex:pageBlockSectionItem >
                        <apex:outputlabel value="Begining Year"/>
                        <apex:selectList value="{!b_year}" multiselect="false" required="true" size="1">
                           <apex:selectOptions value="{!years}"/>
                        </apex:selectList>
                     </apex:pageBlockSectionItem>
                     
                     <apex:pageBlockSectionItem >
                        <apex:outputlabel value="End Year"/>
                        <apex:selectList value="{!e_year}" multiselect="false" required="true" size="1">
                           <apex:selectOptions value="{!years}"/>
                        </apex:selectList>
                     </apex:pageBlockSectionItem>
                     
                     <apex:pageBlockSectionItem >
                        <apex:outputlabel value="Type"/>
                        <apex:selectCheckboxes value="{!type}">
                           <apex:selectOptions value="{!items}"/>
                        </apex:selectCheckboxes>
                     </apex:pageBlockSectionItem>
                     
               </apex:pageBlockSection>
               
          <apex:pageBlockSection columns="2">
                <apex:outputpanel id="mymap">
                  <div id="map_canvas"></div>
 
                  <script type="text/javascript">
                     
                     var myOptions = {
                            zoom:15,
                            mapTypeControl: false,
                            mapTypeId: google.maps.MapTypeId.ROADMAP
                         };
                     var geocoder = new google.maps.Geocoder();
                     
                    //create map
                     var map = new google.maps.Map(document.getElementById("map_canvas"),myOptions);
                 
                    function putmarker(map,address,geocoder){
                       geocoder.geocode( { address: address}, function(results, status) {
                        if (status == google.maps.GeocoderStatus.OK && results.length) {
                          if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
      
                              //center map
                                map.setCenter(results[0].geometry.location);
        
                             //create marker
                                var marker = new google.maps.Marker({
                                  position: results[0].geometry.location,
                                  map: map,
                                  title:address
                                });
                  
                             //add click listener on marker
                               google.maps.event.addListener(marker, 'click', function() {
                                  //change addressParameter on click
                                    document.getElementById('{!$Component.page.form.block.values.addressParameter}').value=marker.title;
                                    refreshData(); //to rerender rightpane containing sales data of a location(invokes action function)
                         
                               });
                           }
                        }
                       })
                     }
                  </script>
                
                  <apex:repeat value="{! salesAddress}" var="address">
                      <script> putmarker(map,"{!address}",geocoder);</script>
                  </apex:repeat>
               
                </apex:outputpanel>
                
                <apex:dataList value="{! Sales}" var="sale" id="dataView">
                    <!-- extract Record Id(15 character long from begining) to make link and Text to display(from 20th character to end of string) --> 
                    <!-- Instance is auto corrected by force.com if it is not ap1 -->
                        <apex:outputLink value="{!'https://ap1.salesforce.com/'+left(sale,15)}" target="_blank">
                            {!MID(sale,20,len(sale)-19)}
                        </apex:outputLink>
                 </apex:dataList>
                
          </apex:pageBlockSection>
          
         </apex:pageBlock>
               <!-- Rerender Right pane on marker click -->
               <apex:actionFunction name="refreshData" action="{!refreshData}" rerender="dataView"/>
          
     </apex:form>
                 
</apex:page>
Controller :

Monday 4 June 2012

Country database android app

we created this app for bitsmun . The app has database for many countries which includes various country details like area,population,military,politics,constitution taken from Cia-World factbook . This is an Html5 app created using phonegap. you may find the source code  at http://munappbits.appspot.com/ by viewing the source of webpage.

Android installer :  https://docs.google.com/open?id=0Bxag-fuMuJ3-RmNjMzlKcFZITUk

let me know in comments ,  if you want the source code of phonegap project and I will upload.

Sunday 29 April 2012

Dynamic SQL query when number of fields in where clause in not known

suppose we have a front end where user can select different filters to narrow down the query results.In this case it is not already known which all fields user will select.
A dynamic query for this case can be constructed using this trick:

here fieldNames is the array containing names of all filters and fields is the array containing values provided by user.


Saturday 28 April 2012

Force.com Eclipse plugin installation problem

Installation fails with error 'Md5 hash not as expected'
original error message :


An error occurred while collecting items to be installed session context was:(profile=SDKProfile, phase=org.eclipse.equinox.internal.p2.engine.phases.Collect, operand=, action=). Problems downloading artifact: osgi.bundle,com.salesforce.ide.api,23.0.2.201201091635. MD5 hash is not as expected. Expected: 97a6329f82c422a61e9b1bc28be7cace and found ef8b1c2b63c7d04acaa6bf41f4b8570c.


this happens due to corrupted download of jars by eclipse.To fix the problem follow these steps:
1. download all jars manually from
    http://www.adnsandbox.com/tools/ide/install/features/ and
    http://www.adnsandbox.com/tools/ide/install/plugins/
   you can use firefox plugin 'download them all' to download all links in one click.
2. put them in /features/ and /plugins/ directory of eclipse
3.run plugin installation again as you would do normally.It won't download the jars again and it will work without error.

original post:
http://stackoverflow.com/a/9823562/1219463