Testing CSS selectors in Firefox

CSS selectors are used frequently when writing jquery code. Recently I discovered Firefox provides a handy syntax for testing CSS selectors:

$$('CSS selector')

In the screenshot below, I’m looking at an <h3> element with the class ‘chapter-title’ using Firefox’s web developer tools.

firefox inspector

To test if the selector ‘h3.chapter-title’ returns the expected elements, enter $$('h3.chapter-title') in the console. The command returns a nodelist with two elements, one for each match. Hovering over the individual element in the console will highlight the corresponding element in the page.

testing css selector with $$

Solutions to Exercises: Learning JQuery – Chapter 2 Selecting Elements

After finishing the excellent Object Oriented Javascript, I’m now working my way through Learning jQuery 4th Edition by Chaffer and Swedberg. Here’s my solution to exercises found in the end of Chapter 2 Selecting Elements.

  1. Add a class of special to all of the <li> elements at the second level of the nested list.
    $('#selected-plays ul li').addClass('special')
  2. Add a class of year to all the table cells in the third column of a table.
    $('tr').find('td:eq(2)').addClass('year')
  3. Add the class special to the first table row that has the word Tragedy
    in it.

    $('td:contains(Tragedy)').first().parent().addClass('special')
  4. Challenge: Select all the list items (<li>s) containing
    a link (<a>). Add the class afterlink to the sibling list items that follow
    the ones selected.

    $('li a').not('[href^="mailto:"]').parent().nextAll().addClass('afterlink')
  5. Challenge: Add the class tragedy to the closest ancestor <ul> of
    any .pdf link.

    $('a[href$=".pdf"]').closest('ul').addClass('tragedy')

Node.js and learning JavaScript

I’m slowly working my way through Object-Oriented JavaScript by Stefan and Sharma. All the tutorials I’ve seen online suggest using the web console in browsers for typing and testing code. While this method is fine for one or two lines of code, it is not the most efficient way for larger programs.

This is where node.js comes in handy. According to its website, it is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications. For a JavaScript newbie, it means you can write your code in a text editor and run it outside a browser environment. All you have to do is

  1. open the node.js command prompt (via the windows menu)
  2. change to the directory where the JavaScript program is located
  3. type node filename.js

iOS 8 on an 8GB iPhone 5c: the mysterious case of missing memory

Ever since I upgraded my iphone 5c from iOS 7 to iOS 8, it was running very low on memory. I kept getting the low memory warning after taking 3-4 pictures. I deleted all the apps on the phone (except google maps), removed all the photos, music and video, and I still couldn’t get more than 300-400Mb. The phone was basically unusable. I knew iOS 8 had a larger memory footprint than iOS 7, but I didn’t expect it would be usuable on a 8GB phone. Especially iPhone 6 has just been released, so an iPhone 5 wasn’t that old!

I wanted to downgrade back to iOS7, but I was a day too late. Apple stopped signing iOS 7 on 29 Sept. Also jailbreaking wasn’t available for iOS 8 at the time. I was stuck with a more or less useless smart phone.

Then my 16GB iPad mini was also starting to run out of memory. However I had 1GB of photos synced from my old mac, so my first thought was to remove the photos. However, I no longer had the mac, and I couldn’t remove the photos with my windows iTunes installation. My only option was to reset my iPad mini.

With a fresh new installation of iOS 8, I noticed I had 11GB free on the iPad. It occurred to me immediately that I should have have a lot more memory on my phone instead of the 400MB I was struggling on. And indeed, after resetting the phone, I suddenly had 4GB.

I still don’t know what was eating up all the memory on my iDevices. (The lost memory wasn’t listed under Settings -> Usage). I am blaming the iOS 7 to iOS 8 upgrade being very poor, leaving a lot of temporary files behind on the devices.

Unit test Audit Logging Requirements with Mockito

During development of server-side software, I routinely encountered requirements to audit logging. This ranged from logging routine events such as system startup and shutdown, to information when errors occur. For example, a component I worked on was responsible for generating binary data structures and forwarding them to a distribution component. The data generator must limit the size of the structures to protect end devices from data packets that were too large to be processed within their resource constraints. The requirements stipulated that data attributes should be placed into the structure in ascending order, and an error message shall be logged in the audit log for any attributes that were not included in the structure. I have added verification on audit logging in the unit tests that test the handling of attribute omission. Since unit tests have been implemented to check the error handling already, it was not much more effort to include checks on the logging for the same conditions.

A naïve approach to unit test logging is to create the error within a unit test, write the log to a file, read the log file from disk, and then search the file for the expected error message. However, there is a simpler and more elegant way to assert logging behavior by using mock objects. By adding a mock Appender to the target Logger, all log requests to the target Logger are now also forwarded to the mock Appender. Logging events can then be verified directly with the mock Appender.

I use JUnit and Mockito for my unit testing. The following code snippet sets up a mock Appender for use in the unit test class.

@Mock private Appender appender;
private static final Logger AUDIT = Logger.getLogger("org.whileloop.org.data.generator");

@Before
public void setUp() {
  AUDIT.addAppender(appender);
}

@After
public void tearDown() {
  AUDIT.removeAppender(appender);
}

To assert that a log message is written during a unit test, I use Mockito’s verify on the mock Appender’s doAppend method:

verify(appender).doAppend((LoggingEvent) anyObject());

Obviously, this only checks for the existence of a log message when the unit test is run. I normally run our unit tests with logging at trace level to make sure logging calls at the lowest level are exercised. If a debug message is written during the unit test, the above verification will pass even when no error messages were written.

Mockito’s ArgumentCaptor can be used to check for a specific message at a specific logging level. The following code captures all the LoggingEvents that occur in a unit test. It then iterates over the list of captured events, checking their logging level and message content. If one of the log messages matches the expected level and keyword, then the test will pass the assert statement after the loop. Searching for an exact match in the message could lead to brittle tests. They will break if the log message is updated. Therefore I prefer searching for keywords like ‘error’, ‘exceeds’, ‘dropped’ instead.

verify(appender, atLeastOnce()).doAppend(argumentCaptor.capture());
List<LoggingEvent> loggingEvents = argumentCaptor.getAllValues();
for (LoggingEvent le : loggingEvents) {
  if (le.getLevel().equals(ERROR) &&
      le.getMessage().toString().contains(keyword) {
      matched = true;
  }
}
assertTrue("Cannot find error message [" + keyword + "] in audit log", matched);

Mock objects provide an easy way to test logging in unit tests. To do this I exploit the fact that a mock object remembers all its interactions. Logging can be verified by looking at interactions with the mock Appender’s doAppend method, instead of reading and parsing the log file on disk. By including logging in unit tests, I can verify that audit logging requirements are fulfilled. It also guards against future changes to the code from inadvertently breaking the logging requirement compliance. Problems with audit logging caused by refactoring can be caught during development automatically, removing the chance that the failure could reach testers or even clients.

This post was originally written and published in August 2013 for a newsletter.

Caching Password for Git HTTP/HTTPS connections

I got sick of entering my username and password every time I do a git operation. Luckily, git provides handy options for caching passwords. The safer option is probably to just cache the credentials in memory

git config --global credential.helper cache

This would keep the password in memory for 15 minutes. To permanently save the credentials on disk (in plain text format), use

git config --global credential.helper store

PS. I chose the later unsecure lazy option.