Sunday, March 27, 2011

Quick Guide for Installing and Running CFSelenium

I've been playing around with CFSelenium this week in order to come up with an implementation that will let me easily replicate and run tests I've created with the Firefox Selenium IDE plugin on multiple browsers.  I've learned a few things along the way that are worth blogging about, but I thought I should start with a blog post on how to get CFSelenium up and running quickly.


Installating CFSelenium

  1. First, you need to have a computer that has either ColdFusion 7, ColdFusion 8, or ColdFusion 9 installed and running such that you can call and execute a .cfm page on the machine (example "http://localhost/myLocalSite/index.cfm"), and you'll need Firefox installed.
  2. Go to Bob Silverberg's CFSelenium GitHub site - https://github.com/bobsilverberg/CFSelenium - and click on the "Downloads" button.  In the pop-up window that appears, click one of the two buttons under "Download source" to download either a .tar.gz archive or a .zip archive, and download the file to your computer.
  3. Extract the files and folders from the downloaded file wherever you like to start with - let's say a folder called cfSeleniumFiles.
  4. Create a folder called CFSelenium within your webroot folder (usually "http" or "www").  Copy the following files and folder from your cfSeleniumFiles folder into the new CFSelenium folder (*updated in August 2012 to reflect additional files):
    • selenium.cfc
    • selenium_tags.cfc
    • server.cfc
    • CFSeleniumTestCase.cfc
    • CFSeleniumTestCase_Tags.cfc
    • test
  5. Create a folder called selenium somewhere on your hard drive that isn't too deep in your folder hierarchy. On my Windows machine, I created it at the root of the hard drive (C:/selenium), while on my Macintosh system I created it under my user account (/Users/Brian/selenium).
  6. In your cfSeleniumFiles folder, open the Selenium-RC folder and copy the .jar file (the Selenium Server file) within that directory to the selenium folder you created in the previous step.
  7. If you're running ColdFusion 8 or ColdFusion 9, you'll want to download and install the MXUnit ColdFusion unit test framework (if you're running ColdFusion 7, skip this step; you'll still be able to execute Selenium commands via CFSelenium but in a different way).  If you don't already have MXUnit installed:
    • Go to the MXUnit website - http://www.mxunit.org/ - and click the download link ("1. Download").
    • Once the .zip file is downloaded, unzip the files into an mxunit folder in your webroot (so you should now have a CFSelenium folder and mxunit folder in your webroot).
That's all you need to do to install what you need to try out CFSelenium. Now you're ready to issue commands to the Selenium Server via CFSelenium and see it in action:


Testing CFSelenium

  1. Any time you want to run Selenium tests through CFSelenium, you need to start the Selenium Server (previously called Selenium-RC):
    • Open up a command line interface. On a Mac, simply open up the Terminal application. If you're machine runs windows, click on the Start button, choose "Run" from the menu, type "cmd" in the input box that appears, and hit the Enter key.
    • Use the "cd" command to navigate to the selenium folder you created earlier (the one where you copied the .jar file).
    • Type in the following command and hit the Enter key:
         java -jar selenium-server-standalone-2.0b2.jar
    • The Selenium Server should start: it will output several lines of activity then stop. If the server does not start, you may need to install Java 1.5 or Java 1.6 on your computer:  if you go to http://www.java.com, the download link/button is front and center.
  2. Now the Selenium Server is ready to respond to commands issued through CFSelenium. What you do next depends on the version of ColdFusion you're running:
    • If you're running ColdFusion 9, run the seleniumTest.cfc MXUnit test in the CFSelenium/test/cf9 folder by calling it in the browser like so:
         http://localhost/CFSelenium/test/cf9/seleniumTest.cfc?method=runTestRemote
    • If you're running ColdFusion 8, run the seleniumTest_cf8.cfc MXUnit test in the CFSelenium/test/cf7_cf8 folder by calling it in the browser like so:
         http://localhost/CFSelenium/test/cf7_cf8/seleniumTest.cfc?method=runTestRemote
    • If you're running ColdFusion 7, run the seleniumTest_cf7.cfm file in the CFSelenium/test/cf7_cf8 folder like so (it mimics the MXUnit test for CF8 and CF9 without using MXUnit):
         http://localhost/CFSelenium/test/cf7_cf8/seleniumTest_cf7.cfm
  3. If everything works, you should observe the Selenium Server react to the commands issued by CFSelenium.  It should start up an instance of Firefox, run through the test routines, and shut down again, and you should be presented with the results of those test routines.
    • If you're on a Windows machine and the Selenium Server fails to launch Firefox, that probably means that Firefox is not defined in your system path, so the Selenium Server does not know the location of the Firefox executable and cannot start Firefox. You can fix this by doing the following:
      • Locate where your firefox.exe file is on your machine (example: C:\Program Files\firefox.exe).
      • Open the appropriate "seleniumTest" file (as listed above).
      • Do a search for " *firefox " (it should only appear once in the file). Add a space after " *firefox " and type in the path to the firefox.exe file, like so:
           *firefox C:\Program Files\firefox.exe
      • Save the file and try again: it should work this time.
  4. To shut down the Selenium Server when you're done, go back to your command window and hit Control-C on your keyboard to shut down the server.

Going Further

Now you have CFSelenium installed, know how to start the Selenium Server that receives the commands from CFSelenium, and have run through one of the included tests, hopefully you'll want to learn how to create your own tests. For that, you should download and install the Selenium IDE plugin for Firefox so that you can record your own browser behavior tests. The documentation for using Selenium IDE is quite thorough.  Pay particular attention to the "Adding Verifications and Asserts With the Context Menu" section:  verifications and asserts are key to actually doing browser behavior testing with Selenium/CFSelenium (I'll touch on that briefly in my next blog post).

Included in the CFSelenium download file is a plugin for the Selenium IDE (yes, a plugin for a plugin) that adds the ability to export the Selenium IDE recordings (test cases) as CFSelenium commands wrapped in an MXUnit test case.  To install it, double-click on the cfml-formatters-1.0.xpi file in the cfSeleniumFiles/formats folder you created out of the CFSelenium download file.  Even if you're running ColdFusion 7 and can't run the plugin output directly (as MXUnit isn't supported in ColdFusion 7), the plugin still saves you the step of translating the recorded steps into CFML cfscript statements.  If you are using ColdFusion 8 or 9 and can run CFSelenium via MXUnit tests, I would suggest checking out the MXUnit documentation, especially the "Testing Basics" section, so you know a bit about how MXUnit works.

After you've recorded a few tests, you'll probably want to run those tests on other browsers.  The Selenium Server supports a number of different browsers but sometimes you have to do some tweaking to get the Selenium Server and the browser working together:  that'll be the subject of another post.

Tuesday, March 22, 2011

CFSelenium Now Compatible With ColdFusion 7 and 8

A few weeks ago, Bob Silverberg released his latest open-source project, CFSelenium.  For those who don't know about the project, a little background:  Selenium is a tool suite for testing web pages.  The most well-known member of the Selenium product family is Selenium IDE, a Firefox plugin that lets you record the actions performed on a web page (or a series of connected web pages) and the results of those actions.  You can then use the recording (stored as a series of commands) to redo those steps whenever you need to test the page or pages after making changes.  Another member of the Selenium product family is Selenium Server (formerly called Selenium-RC), which is a small, Java-based server that can run scripts comprised of Selenium commands in multiple browsers, allowing you to conduct the same kinds of tests recorded by Selenium IDE in browsers other than Firefox:  a great way to test web page functionality across multiple browsers.

In creating CFSelenium, Bob made it possible (easy, in fact) to create and run Selenium Server scripts using ColdFusion 9, and created a plugin for Selenium IDE that would output the recording statements in CFSelenium format within MXUnit test case functions.

Bob wrote CFSelenium in ColdFusion 9-compatible cfscript, and after he announced the project a few folks inquired about the possibility of having a version written in tag-based CFML.  On somewhat of a whim, I decided to take on that task, and ended up with a tag-based version of Bob's original selenium.cfc file that is compatible with both ColdFusion 7 and ColdFusion 8, as well as a few test files that run against the tag-based version.

Bob has now incorporated my tag-based version and my test files into the CFSelenium project, and we've agreed that I will maintain the tag-based version while he maintains the CF9 script verison.  You can download CFSelenium from either RIAForge (http://cfselenium.riaforge.org/) or from GitHub (https://github.com/bobsilverberg/CFSelenium).  For more about Selenium in general, I'd suggest reading Bob's blog post announcing CFSelenium as well as the Selenium website.

So if you're a developer whose responsibilities include cross-browser testing of your web pages, you should really check out CFSelenium.

Wednesday, March 16, 2011

Things To Know About Creating Multiple jQuery UI Datepicker Widgets on the Fly

The first time I created a UI where users could create new jQuery UI Datepicker widgets on the web page as needed, I thought about blogging about some of the "gotchas" I ran into trying to do that, but never got around to it.

But after today, when I had to relearn those lessons, I figured I should write something down.  :)

Here's what I've observed about creating new (multiple) Datepicker widgets on the fly:

  • Cloning a text field that already has the Datepicker applied to it won't work.  You're better off either cloning a "plain" text input element (<input type="text">) or creating one from scratch when you need it.

  • If there's any chance that you're going to end up with multiple Datepicker widgets on the page, you need to make sure that each Datepicker-powered text element ends up with a unique value in the "id" attribute.  Otherwise, the user will click on a date on the pop-up calendar for the most recently-added Datepicker widget, but it'll change the text box value of the first Datepicker widget you added!

    One way to address this is to add a global numeric variable at the top of your Javascript block, increment it every time you want to add a new Datepicker, and combine the current value of that variable with some text and assign that as the id of the text element you're about to add as a Datepicker.

  • Do not invoke the datepicker() function (the function that turns the text field into a Datepicker widget) on the new text input element until after it has been added to the page:  clone or create your text input first, place it in the page using prepend(), append(), whatever, and then invoke the datepicker() function on it.

  • If you need to remove one of the Datepicker widgets, use the datepicker("destroy") method on it.

ColdFusion Builder 2 Extension That List Keyboard Shortcuts in an Eclipse View Panel

Last night, I posted a simple ColdFusion Builder 2 extension that, when activated, creates an Eclipse view that lists all of the defaut Builder-specific keyboard shortcuts in the current ColdFusion Builder 2 beta.  You can get it from RIAForge at http://cfbshortcutkeys.riaforge.org/.

I created this extension using Sagar Ganatra's list of CF Builder 2 keyboard shortcuts and by looking at how Ray Camden altered the VarScoper extension to display in an Eclipse view (see http://www.adobe.com/devnet/coldfusion/articles/cfb2-extensions.html).  The ability to display extension UIs in an Eclipse view (a movable windowed component, like the built-in Navigator or Outline views) rather than a modal window is a wonderful enhancement in Builder 2.

A few notes about the extension:

  • When you open the extension view, you have to click on either the Windows or Mac link to display the proper shortcut list (although the only difference in the shortcuts is that you use either the Ctrl key or the Cmd key).  If there's a way to detect the user's OS automatically, I haven't found it yet (cgi.http_user_agent wasn't useful in this regard).

  • It is a static list of the shortcut defaults as they are shipped in Builder 2.  If you change one of these shortcuts in your preferences, the change WILL NOT be reflected in the list.  I looked around to see if the default keyboard shorcuts were stored in a readable file somewhere that the extension could examine and parse, but it looks like that isn't the case:  user-defined and user-modified shortcuts are written to certain configuration files, but the default shortcuts are not exposed in that manner (if someone knows differently, speak up).

  • However, the advantage to it being a static list is that you can go ahead and customize the list in your copy of the extension.  If you pay attention to where the extension files are copied to when you install the extension, it's easy enough to go to that location, find the extension folder, and edit the index.cfm file in the extension.  It's a simple file, so it's easy to edit.

Hopefully this extension will be useful to folks who are trying to learn the new shortcuts, as you can use it to put the list right next to your editor window as you work.

UPDATE: per Sam Farmer's suggestion in the comments (thanks, Sam!), I've updated the shortcut to do OS detection using the os.name variable value in the server scope.

Monday, January 3, 2011

Small Update to My jQuery textCounting Plugin

I suspect there aren't too many users of my textCounting jQuery plugin, but if you do happen to use it, I wanted to point out a small update I made to it today.

Previously, the plugin was configured by default to look for the letter or word limit for your textarea control in an attribute called "maxLength."  That used to be a safe attribute name because browsers did not enforce the maxlength attribute on textrareas, only single-line text inputs.  But that's no longer the case with Safari:  if you put a maxlength attribute value of "100" on a textarea, Safari will prevent a user from entering more than 100 characters in that textarea.

So I changed the default attribute setting in the plugin to "maxTextLength" to avoid this issue.  To avoid this issue with Safari, you can either download the updated plugin files, or simply use the settings option in the previous version of the plugin to change the attribute name used by the plugin on a case-by-case basis.  In either case, you'll have to make sure you use "maxTextLength" instead of "maxLength" as an attribute in your textareas.

Saturday, December 11, 2010

Adding a Date Range Filter to a Master Table with the dataTables jQuery Plugin

This past week I was asked to build a simple suggestion box web app.  The people responsible for reviewing the suggestions wanted to be able to filter the suggestions by keyword and by date range.

Having used the dataTables jQuery plugin in previous projects, I knew that it could take care of the keyword filtering requirement, but I had never used it to filter out rows that didn't fall into a date range.

I did some research and found enough information to get it working, but since I didn't come across any single crystal-clear example or demo for it, I figured I'd throw one together to illustrate it.  You can check the source code to see what's going on under the hood. I also used the jQuery UI Datepicker plugin to make the date range boxes more user-friendly.  Here's the URL:

https://bcswartz.github.io/jQuery-dataTables-dateRange-demo/

Sunday, November 28, 2010

Technique For Managing Form Input in Model-Glue

I've been meaning to post about this technique I'm using in some of my Model-Glue applications, but I couldn't decide on the best way to explain what led me to develop it.  So I'm going to start with the code first rather than the explanation:

 

This collectFormDataAndTrim function lives in my main controller CFC in my Model-Glue appplications. I call it via a message broadcast any time I need to process typical form input.

Like many of the ColdFusion application frameworks, Model-Glue takes both the URL variables and any values submitted by an HTML form and puts them into one data structure for easy retrieval.  In the case of Model-Glue, that data structure is the event object. My function supports two different methods for retrieving the form values from the Model-Glue event object: it can use the list of form field names contained in the "fieldnames" variable created by ColdFusion, or it can process the event variables named in an argument called "propertyList" submitted in the message broadcast, like so...

<broadcasts>
    <message name="collectFormDataAndTrim">
        <argument name="propertyList" value="firstName,lastName,email,acceptTerms" />
    </message>
...

 

Two reasons for the propertyList option: specifying the form fields you expect to get prevents you from processing extra form fields a malevolent user might add to the form via JavaScript or some other means, and it allows you to name checkbox fields which would not be included in the formfields list if the user doesn't check them.

Once the form fields names are copied into the local propertyList variable, the function loops through the form variables, sanitizes them for further processing using Trim() and HTMLEditFormat(), and adds them to the loc.form struct variable.  I also submit the non-numeric form values to the removeMSWordChars function in my miscService bean to replace any Microsoft Word characters within the content with web-friendly equivalent values (my users have an annoying habit of copying and pasting text from Word into longer text fields).

Finally, the loc.form struct variable containing the santized form submissions is saved back into the Model-Glue event object to be utilized by subsequent message broadcasts (for the functions that will validate the form data and save it to the database).