Skip to main content

jQuery, nth-child selector and Chrome or Safari Browsers

I’m in the middle of adding new functionality to the Wicked Text jQuery plugin and, to keep the code standard high, I have created a simple Unit Test page.

I had a problem with the nth-child selector in Chrome and Safari browsers and thought you might find my solution useful.  But not before I’ve done my usual rambling…

The Page

The page includes a series of tables where each row is a single unit test and with four columns – Test name, Wicked Text Input, Expected Output (HTML)and finally the Actual Output (also HTML).

The following example test the first two heading levels (you can see that the content of columns 2-4 are embedded in <pre/> tags):

Headings

Test Wicked Text Input Expected Output Actual Output
heading 1
= Hdng 1 =
<h1>Hdng 1</h1>
<h1>Hdng 1</h1>
heading 2
== Hdng 2 ==
<h2>Hdng 2</h2>
<h2>Hdng 2</h2>

The unit tests retrieves the Wicked Text Input and runs the Wicked Text plugin on it.  It then gets the Expected Output and compares the two – setting the background colour to green as shown if they are the same (red if not).  Finally, the Actual Output is inserted into the last column.

Once all the tests have run, the Test, Success and Fail counts are updated.

The Code

Here is the original code:


	function runTests()
	{
		//	Initialise variables.
		var countTests = 0;
		var countSuccess = 0;
		var countFail = 0;

		//	Iterate through each test row.
		$( "tr.test" ).each(
				function(index, element)
				{
					countTests++;

					//	get the source
					var aa = $( "td:nth-child(2)>pre", this );
					var bb = aa.text();
					var cc = $.trim( bb );
					var source = $( "td:nth-child(2)>pre", this ).text();

					//	get the expected output
					var dd = $( "td:nth-child(3)>pre", this );
					var ee = dd.text();
					var ff = $.trim( ee );
					var expected = $.trim( $( "td:nth-child(3)>pre", this )
							.text() );

					//	call wicked text to get output
					var result = $.trim( $.wickedText( source ) );

					var resultClass = "success";

					//	compare
					if( result === expected )
					{
						//		if same, increment success count - set success class
						countSuccess++;
					}
					else
					{
						//		if different, increment fail count - set fail class
						countFail++;
						resultClass = "fail";
					}

					//	Append actual result to final cell and set result class
					$( "td", this ).addClass( resultClass );
					$( "td:nth-child(4)", this ).append( $( "<pre></pre>" ).html( $.wickedText.safeText( result ) ) );
				} );

		// Finally, set the values in the summary table.
		$("#countTests").text( countTests );
		$("#countSuccess").text( countSuccess );
		$("#countFail").text( countFail );

		$( "#summary tbody td" ).addClass( countFail > 0 ? "fail" : "success" );
	}

	jQuery( document ).ready( function($)
	{
		$( "#no-js-warning" ).hide();
		runTests();
	} );

The Problem

I found that the tests run successfully on all the browsers on my laptop (IE 9, Firefox 10, Chrome 17 and Safari 5.1.2) but the last columns (Actual Output) was empty on Chrome and Safari.

This became a little stranger when I tried to debug the code – it worked intermittently – sometimes a whole row was correct and other times the previously successful test failed.

A colleague had a look and commented that he was aware of issues with the “nth-child” selector in jQuery and, following a quick Google, this was easily confirmed.  However, a fix for the problem was not immediately apparent.

The Solution (Finally)

Eventually, I added in a few extra bits of JavaScript and debugged them through – splitting the lines into smaller pieces and trying alternative approaches.

The solution turned out to be relatively simple: don’t use the “nth-child” selector.

Here is the modified code:


	function runTests()
	{
		//	Initialise variables.
		var countTests = 0;
		var countSuccess = 0;
		var countFail = 0;

		//	Iterate through each test row.
		$( "tr.test" ).each(
				function(index, element)
				{
					countTests++;
					var cells = $( "td", this );

					//	get the source
					var source = $( "pre", cells[1] ).text();;

					//	get the expected output
					var expected = $.trim( $( "pre", cells[2] ).text() );

					//	call wicked text to get output
					var result = $.trim( $.wickedText( source ) );

					var resultClass = "success";

					//	compare
					if( result === expected )
					{
						//		if same, increment success count - set success class
						countSuccess++;
					}
					else
					{
						//		if different, increment fail count - set fail class
						countFail++;
						resultClass = "fail";
					}

					//	Append actual result to final cell and set result class
					$( cells ).addClass( resultClass );
					$( cells[3] ).append( $( "<pre></pre>" ).html( $.wickedText.safeText( result ) ) );
				} );

		// Finally, set the values in the summary table.
		$("#countTests").text( countTests );
		$("#countSuccess").text( countSuccess );
		$("#countFail").text( countFail );
		
		$( "#summary tbody td" ).addClass( countFail > 0 ? "fail" : "success" );
	}

	jQuery( document ).ready( function($)
	{
		$( "#no-js-warning" ).hide();
		runTests();
	} );

That now works fine in all the browsers on my laptop – including Chrome and Safari.

Lets not mention IE 8 just now…

One comment on “jQuery, nth-child selector and Chrome or Safari Browsers”

  1. Kaila Haer says:

    I used to be very happy to find this net-site.I wanted to thanks for your time for this excellent read!! I definitely enjoying each little little bit of it and I’ve you bookmarked to take a look at new stuff you weblog post.

Leave a Reply

Your email address will not be published. Required fields are marked *

*