<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Dr Nic &#187; Greasemonkey</title>
	<atom:link href="http://drnicwilliams.com/category/greasemonkey/feed/" rel="self" type="application/rss+xml" />
	<link>http://drnicwilliams.com</link>
	<description>Ruby makes Rails, Javascript makes Ajax, Dr Nic makes Magic</description>
	<lastBuildDate>Sat, 12 Nov 2011 01:05:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Nifty Threaded IM Chat within Gtalk/Gmail Chat</title>
		<link>http://drnicwilliams.com/2009/07/04/nifty-threaded-im-chat-within-gtalkgmail-chat/</link>
		<comments>http://drnicwilliams.com/2009/07/04/nifty-threaded-im-chat-within-gtalkgmail-chat/#comments</comments>
		<pubDate>Fri, 03 Jul 2009 20:00:54 +0000</pubDate>
		<dc:creator>Dr Nic</dc:creator>
				<category><![CDATA[Announcement]]></category>
		<category><![CDATA[Greasemonkey]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Mocra]]></category>

		<guid isPermaLink="false">http://drnicwilliams.com/?p=550</guid>
		<description><![CDATA[Ever had IM chats where a conversation splits into multiple topics? You&#8217;ll be able to follow along, intelligently piecing together which-message-goes-with-which-topic, until the following scenario inevitably occurs: me: What's on this weekend? Going to the football? me: Are you and Jackie still seeing each other? you: Yes me: Eh? Yes - football or yes to [...]


Related posts:<ol><li><a href='http://drnicwilliams.com/2009/06/07/tdd-for-greasemonkey-scripts-and-introducing-ninja-search-js/' rel='bookmark' title='Permanent Link: TDD for Greasemonkey scripts; and introducing Ninja Search JS'>TDD for Greasemonkey scripts; and introducing Ninja Search JS</a> <small>&#8220;this article shows how I used test-driven development tools and...</small></li><li><a href='http://drnicwilliams.com/2006/09/11/prototype-call-dollar-on-string/' rel='bookmark' title='Permanent Link: Prototype: &#8220;element-id&#8221;.$() instead of $(&#8216;element-id&#8217;)'>Prototype: &#8220;element-id&#8221;.$() instead of $(&#8216;element-id&#8217;)</a> <small>The Prototype library gives us the $() operation for converting...</small></li><li><a href='http://drnicwilliams.com/2006/08/29/yehuda-katz-starts-a-blog/' rel='bookmark' title='Permanent Link: Yehuda Katz starts a blog'>Yehuda Katz starts a blog</a> <small>Yehuda is the creator of autoDB &#8211; the wonderful admin...</small></li></ol>]]></description>
			<content:encoded><![CDATA[<p>Ever had IM chats where a conversation splits into multiple topics? You&#8217;ll be able to follow along, intelligently piecing together which-message-goes-with-which-topic, until the following scenario inevitably occurs:</p>
<pre>
  me: What's on this weekend? Going to the football?
  me: Are you and Jackie still seeing each other?
  you: Yes
  me: Eh? Yes - football or yes to Jackie?
</pre>
<p>That is, eventually the messages become ambiguous as to which topic they go to.</p>
<h3 id="the_solution">The solution</h3>
<p><img alt="" src="http://img.skitch.com/20090703-js9ahnd44qmq6ue8ya8fdiryau.preview.jpg" title="Threaded example" class="alignright" width="265" height="311" /></p>
<p>A <a href="http://designbyelle.com/" target="_blank">designer friend of mine</a> and I discovered this problem every day as we talked about different projects and completely unrelated things. Ironically, this led to a new inline topic: <em>what if each thread/topic could be visually identifiable?</em></p>
<p>Perhaps we could just modify one of the HTML-based IM clients, such as Gmail Chat/Gtalk (same could be done for Facebook&#8217;s IM client I guess), and use twitter-esque #tags to identify threads (no fancy jabber protocol changes). If we did this we could prototype something, see if it was a useful way to solve the multi-threaded IM chat problem. <em>I mean, how hard could it be?</em></p>
<h3 id="prototype_greasemonkey_script_firefox_safari">Prototype: Greasemonkey Script (Firefox + Safari)</h3>
<p>Since I have a thing for <a href="https://addons.mozilla.org/en-US/firefox/addon/748">Greasemonkey</a> scripts at the moment (which also run on Safari/<a href="http://mailplaneapp.com/">Mailplane</a> using <a href="http://8-p.info/greasekit/">GreaseKit</a>), it immediately came to mind as a way to hack into Gmail&#8217;s Chat.</p>
<p>After installing Greasemonkey or GreaseKit, <a href="http://drnic.github.com/threaded-gtalk-gmscript/dist/threaded_gtalk.user.js">click to install the extension</a> for Gmail&#8217;s inline Jabber/Gtalk chat.</p>
<p>Restart Gmail, fire up a chat to someone (for example, complain of bugs to <a href="drnicwilliams@gmail.com">drnicwilliams@gmail.com</a>) and try the following:</p>
<pre>
  greasemonkey is fun
  gmailchat is very nifty and hackable
  its cool that I can annotate gmail chat with #greasemonkey
  no way, #gmailchat is colour highlighted
  sexy
</pre>
<p>Which will look something like the picture at the top.</p>
<p>Sadly, I&#8217;m talking to myself here. QA testing can be a lonely man&#8217;s sport.</p>
<h3 id="success">Success?</h3>
<p>Technically, yes. I mean, it works. You use a different #tag and it will be a different colour. </p>
<p>It was a prototype to determine if using #tags was a friendly, non-invasive way to identify threads. And it kind-of works, as long as you remember to use them. In IM, less-so than twitter, it seems unnatural to add #tags, or prefix a keyword with a # character. But, in time, I think you&#8217;d learn to do it to get the benefit.</p>
<p>The bigger issue is that I don&#8217;t want to use Gmail&#8217;s Chat for my IM client. I didn&#8217;t find the source to Apple&#8217;s iChat client lying around on github; and I really don&#8217;t want to go hacking Cocoa/Win32 apps just to try out an idea. A greasemonkey script is an awesome way to try out something like this.</p>
<p>Now, if everyone could just make this idea of #tagging intra-IM conversation threads/topics, then perhaps 5 years from now Apple will pick it up and implement it in iChat. Any of the more accessible, open source clients could implement this too. Probably a lot sooner.</p>
<h3 id="known_bugs">Known bugs</h3>
<p>In Mailplane (though not Safari), the 2nd+ threads aren&#8217;t coloured differently. I&#8217;m having trouble fixing this at the moment due to an <a href="http://github.com/relevance/blue-ridge/issues/#issue/13">issue</a> in <a href="http://github.com/relevance/blue-ridge">blue-ridge</a>&#8217;s setup on Safari.</p>
<p>It currently shares thread colouring across all open chat windows. Probably not a big issue. I forgot to consider multiple chat windows when I wrote the code.</p>
<p>When you use a new #tag, it only finds one previous message with &#8216;tag&#8217; in it. Really, once a word is #tagged, then any message containing &#8216;tagged&#8217; could be included in the thread.</p>
<h3 id="quirky_thing_i_learnt">Quirky thing I learned</h3>
<p>You can&#8217;t really use the <a href="http://docs.jquery.com/Plugins/livequery">jquery.livequery.js</a> plugin to watch for DOM changes in Greasemonkey scripts. It works by hooking into jQuery DOM modification calls, such as <code>append</code> and <code>prepend</code>, to know instantly that something has changed. Gmail, and many other websites, don&#8217;t use jQuery. So it doesn&#8217;t work. Even though your beautiful unit tests say it will. Use <code>setInterval</code> instead.</p>
<h3 id="project_status">Project status</h3>
<p>It&#8217;s finished. It was a prototype to try out an idea. It has unit tests, it works and if you want to use it for your own research project or &#8220;oh oh oh how cool would it be if&#8230;?&#8221; hackathon, go for gold with the code base. Rename it, abuse it. Have fun.</p>
<p>Source on github: <a href="http://github.com/drnic/threaded-gtalk-gmscript/">http://github.com/drnic/threaded-gtalk-gmscript/</a></p>
<h3 id="a_pleasant_word_from_my_sponsor">A pleasant word from my sponsor</h3>
<p>When I was hacking on Threaded Gtalk GMScript, I wasn&#8217;t doing something more productive at my firm <a href="http://mocra.com/">Mocra</a>. Ironically, you could reward my wayward efforts by considering us for your awesome new Rails or iPhone project. It will make you happy. Especially if its chock-full of JavaScript.</p>


<p>Related posts:<ol><li><a href='http://drnicwilliams.com/2009/06/07/tdd-for-greasemonkey-scripts-and-introducing-ninja-search-js/' rel='bookmark' title='Permanent Link: TDD for Greasemonkey scripts; and introducing Ninja Search JS'>TDD for Greasemonkey scripts; and introducing Ninja Search JS</a> <small>&#8220;this article shows how I used test-driven development tools and...</small></li><li><a href='http://drnicwilliams.com/2006/09/11/prototype-call-dollar-on-string/' rel='bookmark' title='Permanent Link: Prototype: &#8220;element-id&#8221;.$() instead of $(&#8216;element-id&#8217;)'>Prototype: &#8220;element-id&#8221;.$() instead of $(&#8216;element-id&#8217;)</a> <small>The Prototype library gives us the $() operation for converting...</small></li><li><a href='http://drnicwilliams.com/2006/08/29/yehuda-katz-starts-a-blog/' rel='bookmark' title='Permanent Link: Yehuda Katz starts a blog'>Yehuda Katz starts a blog</a> <small>Yehuda is the creator of autoDB &#8211; the wonderful admin...</small></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://drnicwilliams.com/2009/07/04/nifty-threaded-im-chat-within-gtalkgmail-chat/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>TDD for Greasemonkey scripts; and introducing Ninja Search JS</title>
		<link>http://drnicwilliams.com/2009/06/07/tdd-for-greasemonkey-scripts-and-introducing-ninja-search-js/</link>
		<comments>http://drnicwilliams.com/2009/06/07/tdd-for-greasemonkey-scripts-and-introducing-ninja-search-js/#comments</comments>
		<pubDate>Sat, 06 Jun 2009 23:00:40 +0000</pubDate>
		<dc:creator>Dr Nic</dc:creator>
				<category><![CDATA[Announcement]]></category>
		<category><![CDATA[Greasemonkey]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Mocra]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://drnicwilliams.com/?p=523</guid>
		<description><![CDATA[&#8220;this article shows how I used test-driven development tools and processes on a Greasemonkey script.&#8221; Though it also includes free ninjas. When I do online banking I need to select from a large list of other people&#8217;s bank accounts to which I might like to transfer money too. It is the massive drop down list [...]


Related posts:<ol><li><a href='http://drnicwilliams.com/2010/03/15/using-coffeescript-in-rails-and-even-on-heroku/' rel='bookmark' title='Permanent Link: Using CoffeeScript in Rails and even on Heroku'>Using CoffeeScript in Rails and even on Heroku</a> <small>I&#8217;m pretty excited about CoffeeScript as a clean-syntax replacement for...</small></li><li><a href='http://drnicwilliams.com/2009/11/12/dead-simple-javascript-unit-testing-in-rails/' rel='bookmark' title='Permanent Link: Dead simple JavaScript Unit Testing in Rails'>Dead simple JavaScript Unit Testing in Rails</a> <small> Formats: Video/Screencast (410 Mb, torrent) | Video only (vimeo)...</small></li><li><a href='http://drnicwilliams.com/2009/07/04/nifty-threaded-im-chat-within-gtalkgmail-chat/' rel='bookmark' title='Permanent Link: Nifty Threaded IM Chat within Gtalk/Gmail Chat'>Nifty Threaded IM Chat within Gtalk/Gmail Chat</a> <small>Ever had IM chats where a conversation splits into multiple...</small></li></ol>]]></description>
			<content:encoded><![CDATA[<p><em>&#8220;this article shows how I used test-driven development tools and processes on a Greasemonkey script.&#8221;</em> Though it also includes free ninjas.</p>
<div class="thumbnail"><a href="http://skitch.com/drnic/b19kn/1-long-drop-downs-hate-humans"><img style="width: 200px; float: right;" src="http://img.skitch.com/20090605-fjjyx32iidgw1jtq1kbys8tbr7.preview.jpg" alt="1. Long drop downs hate humans" /></a></div>
<p>When I do online banking I need to select from a large list of other people&#8217;s bank accounts to which I might like to transfer money too. It is the massive drop down list that I must scroll through that I wish to raise issue with today. The problem of having to give other people money is probably a different discussion.</p>
<p>And take those time-zone selector drop down lists, for example, the massively long list rendered by Rails&#8217; <code>time_zone_select</code> helper. Granted, I am thankful for you letting me choose my timezone in your web app. Though for those of us not living in the USA we must hunt for our closest city in the list. Dozens of locations, ordered by time zone and not the name of the city (see adjacent image). Unfortunately you can&#8217;t easily type a few letters of your current city to find it. Rather, you have to scroll. And if you live in the GMT+1000 time zone group (Eastern Australia), you have to scroll all the way to the bottom.</p>
<div class="thumbnail"><a href="http://skitch.com/drnic/b19kx/5-choose-from-a-small-list"><img style="width: 200px; float: right;" alt="5. Choose from a small list" src="http://img.skitch.com/20090605-t82418x1j76w4fm8s44cec9cr3.preview.jpg"/></a></div>
<p>So I got to thinking I&#8217;d like a <a href="http://www.greasespot.net/">Greasemonkey</a> (for Firefox) or <a href="http://8-p.info/greasekit/" title="GreaseKit - User Scripting for all WebKit applications">GreaseKit</a> (for Safari) script that automatically converted all ridiculously long HTML drop down lists into a sexy, autocompletion text field. You could then type in &#8220;bris&#8221; and be presented with &#8220;(GMT+1000) Brisbane&#8221;, or given the less amusing banking scenario then I could type &#8220;ATO&#8221; and get the bank account details for the Australian Tax Office.</p>
<p><strong>I mean, how hard could it be?</strong></p>
<p>This article is two things: an introduction to Ninja Search JS which gives a friendly ninja for every drop down field to solve the above problem. Mostly, the rest of this article shows how I used test-driven development tools and processes on a Greasemonkey script.</p>
<h2 id="introducing_ninja_search_js">Introducing Ninja Search JS</h2>
<div class="thumbnail"><a href="http://drnic.github.com/ninja-search-js/"><img src="http://img.skitch.com/20090606-xy454r3b8u29hsykjs1gfhu259.jpg" alt="Ninja Search JS banner" /></a></div>
<p>Click the banner to learn about and install the awesome Ninja Search JS. It includes free ninjas.</p>
<p>Currently it is a script for Greasemonkey (FireFox) or GreaseKit (Safari). It could be dynamically installed as necessary via a bookmarklet. I just haven&#8217;t done that yet. It could also be a FireFox extension so it didn&#8217;t have to fetch remote CSS and JS assets each time.</p>
<p>Ninja Search JS uses <a href="http://github.com/rmm5t/liquidmetal">liquidmetal</a> and <a href="http://rmm5t.github.com/jquery-flexselect">jquery-flexselect</a> projects created by <a href="http://www.emacsblog.org/">Ryan McGeary</a>.</p>
<p>Most importantly of all, I think, is that I wrote it all using TDD. That is, tests first. I don&#8217;t think this is an erroneous statement given the relatively ridiculous, and unimportant nature of Ninja Search JS itself.</p>
<h2 id="tdd_for_greasemonkey_scripts">TDD for Greasemonkey scripts</h2>
<p>I love the simple idea of Greasemonkey scripts: run a script on a subset of all websites you visit. You can&#8217;t easily do this on desktop apps, which is why web apps are so awesome &#8211; its just HTML inside <em>your</em> browser, and with Greasemoney or browser extensions you can hook into that HTML, add your own DOM, remove DOM, add events etc.</p>
<p>But what stops me writing more of them is that once you cobble together a script, you push it out into the wild and then bug reports start coming back. Or feature requests, preferably. I&#8217;d now have a code base without any test coverage, so each new change is likely to break something else. Its also difficult to isolate bugs across different browsers, or in different environments (running Ninja Search JS in a page that used <a href="http://www.prototypejs.org/">prototypejs</a> originally failed), without a test suite.</p>
<p>And the best way to get yourself a test suite is to write it before you write the code itself. I believe this to be true because I know it sucks writing tests <em>after</em> I&#8217;ve writing the code.</p>
<p>I mostly focused on unit testing this script rather than integration testing. With integration testing I&#8217;d need to install the script into Greasemonkey, then display some HTML, then run the tests. I&#8217;ve no idea how&#8217;d I&#8217;d do that.</p>
<div class="thumbnail"><a href="http://skitch.com/drnic/bunyt/testing-running"><img style="width: 200px; float: right;" src="http://img.skitch.com/20090606-d7usrgr8i1qjs3ji45xfkra3hs.preview.jpg" alt="testing running" /></a></div>
<p>But I do know how to unit test JavaScript, and if I can get good coverage of the core libraries, then I should be able to slap the Greasemonkey specific code on top and do manual QA testing after that. The Greasemonkey specific code shouldn&#8217;t ever change much (it just loads up CSS and more JS code dynamically) so I feel ok about this approach.</p>
<p>For this project I used <a href="http://github.com/nkallen/screw-unit/tree/master">Screw.Unit</a> for the first time (via a modified version of the <a href="http://github.com/relevance/blue-ridge/tree/master">blue-ridge rails plugin</a>) and it was pretty sweet. Especially being able to run single tests or groups of tests in isolation.</p>
<h3 id="project_structure">Project structure</h3>
<div class="thumbnail"><a href="http://skitch.com/drnic/bunbd/summary-of-project-structure"><img src="http://img.skitch.com/20090606-x7h9yhp9s3pt6y86r5q1mm1wf8.jpg" alt="summary of project structure" /></a></div>
<p>All the JavaScript source &#8211; including dependent libraries such as jquery and jquery-flexselect &#8211; was put into the <code>public</code> folder. This is because I needed to be able to load the files into the browser without using <code>file://</code> protocol (which was failing for me). So, I moved the entire project into my Sites folder, and added the project as a Passenger web app. I&#8217;m ahead of myself, but there is a reason I went with <code>public</code> for the JavaScript + assets folder.</p>
<p>In <code>vendor/plugins</code>, The blue-ridge rails plugin is a composite of several JavaScript libraries, including the test framework Screw.Unit, and a headless rake task to run all the tests without browser windows popping up everywhere. In my code base blue-ridge is slightly modified since my project doesn&#8217;t look like a rails app.</p>
<p>Our tests go in <code>spec</code>. In a Rails app using blue-ridge, they&#8217;d go in <code>spec/javascripts</code>, but since JavaScript is all we have in this project I&#8217;ve flattened the spec folder structure.</p>
<p>The <code>website</code> folder houses the github pages website (a git submodule to the gh-pages branch) and also the greasemonkey script and its runtime JavaScript, CSS, and ninja image assets.</p>
<h3 id="a_simple_first_test">A simple first test</h3>
<p>For the Ninja Search JS I wanted to add the little ninja icon next to every <code>&lt;select&gt;</code> element on every page I ever visited. When the icon is clicked, it would convert the corresponding <code>&lt;select&gt;</code> element into a text field with fantastical autocompletion support.</p>
<p>For Screw.Unit, the first thing we need is a <code>spec/ninja_search_spec.js</code> file for the tests, and an HTML fixture file that will be loaded into the browser. The HTML file&#8217;s name must match to the corresponding test name, so it must be <code>spec/fixtures/ninja_search.html</code>.</p>
<p>For our first test we want the cute ninja icon to appear next to <code>&lt;select&gt;</code> drop downs.</p>
<pre lang="javascript">
require("spec_helper.js");
require("../public/ninja_search.js"); // relative to spec folder

Screw.Unit(function(){
  describe("inline activation button", function(){
    it("should display NinjaSearch image button", function(){
      var button = $('a.ninja_search_activation');
      expect(button.size()).to(be_gte, 1);
    });
  });
});
</pre>
<p>The <a href="http://github.com/karnowski/blue-ridge-tmbundle/tree/master">Blue Ridge textmate bundle</a> makes it really easy to create the <code>describe</code> (<code>des</code>) and <code>it</code> (<code>it</code>) blocks, and <code>ex</code> expands into a useful <code>expects(...).to(matcher, ...)</code> snippet.</p>
<p>The two ellipses are values that are compared by a matcher. Matchers are available via global names such as <code>equals</code>, <code>be_gte</code> (greater than or equal) etc. See the <a href="http://github.com/nathansobo/screw-unit/blob/master/javascript/lib/screw/matchers.js">matchers.js</a> file for the default available matchers.</p>
<p>The HTML fixture file is important in that it includes the sample HTML upon which the tests are executed.</p>
<pre lang="html">
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;

&lt;head&gt;
  &lt;title&gt;Ninja Search | JavaScript Testing Results&lt;/title&gt;
  &lt;link rel="stylesheet" href="screw.css" type="text/css" charset="utf-8" /&gt;
  &lt;script src="../../vendor/plugins/blue-ridge/lib/blue-ridge.js"&gt;&lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;div&gt;
    &lt;label for="person_user_time_zone_id"&gt;Main drop down for tests&lt;/label&gt;
    &lt;select name="person[user][time_zone_id]" id="person_user_time_zone_id" style="display: inline;"&gt;
      &lt;option value="Hawaii"&gt;(GMT-10:00) Hawaii&lt;/option&gt;
      &lt;option value="Alaska"&gt;(GMT-09:00) Alaska&lt;/option&gt;
      &lt;option value="Pacific Time (US &amp; Canada)"&gt;(GMT-08:00) Pacific Time (US &#038; Canada)&lt;/option&gt;
      &lt;option value="Arizona"&gt;(GMT-07:00) Arizona&lt;/option&gt;
      &lt;option value="Mountain Time (US &amp; Canada)"&gt;(GMT-07:00) Mountain Time (US &#038; Canada)&lt;/option&gt;
      &lt;option value="Central Time (US &amp; Canada)"&gt;(GMT-06:00) Central Time (US &#038; Canada)&lt;/option&gt;
      &lt;option value="Eastern Time (US &amp; Canada)"&gt;(GMT-05:00) Eastern Time (US &#038; Canada)&lt;/option&gt;
    &lt;/select&gt;
  &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>In its header it loads the blue-ridge JavaScript library, which in turn loads Screw.Unit and ultimately our spec.js test file (based on corresponding file name), so <code>ninja_search.html</code> will cause a file <code>spec/ninja_search_spec.js</code> to be loaded.</p>
<p>To run our first test just load up the <code>spec/fixtures/ninja_search.html</code> file into your browser.</p>
<p>Your first test will fail. But that&#8217;s ok, that&#8217;s the point of TDD. <a href="http://en.wikipedia.org/wiki/Test-driven_development">Red, green, refactor</a>.</p>
<h3 id="simple_passing_code">Simple passing code</h3>
<p>So now we need some code to make the test pass.</p>
<p>Create a file <code>public/ninja_search.js</code> and something like the following should work:</p>
<pre lang="javascript">
(function($){
  $(function() {
    $('select').each(function(index) {
      var id = $(this).attr('id');

      // create the Ninja Search button, with rel attribute referencing corresponding &gt;select id="...">
      $('&gt; class="ninja_search_activation" rel="' + id + '">ninja search&gt;/a>')
      .insertAfter($(this));
    });
  });
})(jQuery);
</pre>
<p>Reload your test fixtures HTML file and the test should pass.</p>
<p>Now rinse and repeat. The final suite of <a href="http://github.com/drnic/ninja-search-js/tree/master/spec">tests and fixture files</a> for Ninja Search JS are on github.</p>
<h3 id="building_a_greasemonkey_script">Building a Greasemonkey script</h3>
<p>Typically Greasemonkey scripts are all-inclusive affairs. One JavaScript file, named <code>my_script.user.js</code>, typically does the trick.</p>
<p>I decided I wanted a thin Greasemonkey script that would dynamically load my <code>ninja-search.js</code>, and any stylesheets and dependent libraries. This would allow people to install the thin Greasemonkey script once, and I can deploy new versions of the actual code base over time without them having to re-install anything.</p>
<p>Ultimately in production, the stylesheets, images, and JavaScript code would be hosted on the intertubes somewhere. Though during development that would be long-winded and painful to push the code to a remote host just to run tests.</p>
<p>So I have three Greasemonkey scripts:</p>
<ul>
<li><code>public/ninja_search.dev.user.js</code> &#8211; loads each dependent library and asset from the local file system</li>
<li><code>public/ninja_search.local.user.js</code> &#8211; loads compressed library and asset from the local file system</li>
<li><code>public/ninja_search.user.js</code> &#8211; loads compressed library and assets from remote server</li>
</ul>
<p>Let&#8217;s ignore the optimisation of compressing dependent JavaScript libraries for the moment and just look at the <code>dev.user.js</code> and <code>user.js</code> files.</p>
<p>The two scripts differ in the target host from which they load assets and libraries. <a href="http://github.com/drnic/ninja-search-js/blob/master/public/ninja-search.dev.user.js">ninja_search.dev.user.js</a> loads them from the local machine and <a href="http://github.com/drnic/ninja-search-js/blob/master/public/ninja-search.user.js">ninja_search.user.js</a> loads them from a remote server.</p>
<p>For example <code>ninja_search.dev.user.js</code> loads local dependencies like this:</p>
<pre lang="javascript">
require("http://ninja-search-js.local/jquery.js");
require("http://ninja-search-js.local/ninja_search.js");
</pre>
<p>And <code>ninja_search.user.js</code> loads remote dependencies like this:</p>
<pre lang="javascript">
require("http://drnic.github.com/ninja-search-js/dist/jquery.js");
require("http://drnic.github.com/ninja-search-js/dist/ninja_search.js");
</pre>
<p>In the final version of <a href="http://github.com/drnic/ninja-search-js/blob/master/public/ninja-search.user.js">ninja_search.user.js</a> we load a simple, conpressed library containing jquery, our code, and other dependencies, called <a href="http://github.com/drnic/ninja-search-js/blob/master/public/ninja_search_complete.js">ninja_search_complete.js</a>.</p>
<h3 id="using_passenger_to_server_local_libraries">Using Passenger to server local libraries</h3>
<p>The problem with loading local JavaScript libraries using the <code>file://</code> protocol, inferred earlier, is that it doesn&#8217;t work. So if I can&#8217;t load libraries using <code>file://</code> then I must use the <code>http://</code> protocol. That means I must route the requests through Apache/Ningx.</p>
<p>Fortunately there is a very simple solution: use <a href="http://www.modrails.com/">Phusion Passenger</a> which serves a &#8220;web app&#8217;s&#8221; <code>public</code> folder automatically. That&#8217;s why all the javascript, CSS and image assets have been placed in a folder <code>public</code> instead of <code>src</code> or <code>lib</code> or <code>javascript</code>.</p>
<p>On my OS X machine, I moved the repository folder into my <code>Sites</code> folder and wired up the folder as a Passenger web app using <a href="http://github.com/alloy/passengerpane/tree/master">PassengerPane</a>. It took 2 minutes and now I had <a href="http://ninja-search.local">http://ninja-search.local</a> as a valid base URL to serve my JavaScript libraries to my Greasemonkey script.</p>
<h3 id="testing_the_greasemonkey_scripts">Testing the Greasemonkey scripts</h3>
<p>I can only have one of the three Greasemonkey scripts installed at a time, so I install the <code>ninja-search.dev.user.js</code> file to check that everything is basically working inside a browser on interesting, foreign sites (outside of the unit test HTML pages).</p>
<p>Once I&#8217;ve deployed the JavaScript files and assets to the remote server I can then install the <code>ninja-search.user.js</code> file (<a href="http://drnic.github.com/ninja-search-js/dist/ninja-search.user.js">so can you</a>) and double check that I haven&#8217;t screwed anything up.</p>
<h3 id="deploying_via_github_pages">Deploying via GitHub Pages</h3>
<p>The normal, community place to upload and share Greasemonkey scripts is <a href="http://userscripts.org/">userscripts.org</a>. This is great for one file scripts, though if your script includes CSS and image assets, let alone additional JavaScript libraries, then I don&#8217;t think its as helpful, which is a pity.</p>
<p>So I decided to deploy the ninja-search-js files into the project&#8217;s own GitHub Pages site.</p>
<p>After creating the GitHub Pages site using <a href="http://github.com/blog/277-pages-generator">Pages Generator</a>, I then pulled down the gh-pages branch, and then linked (via submodules) that branch into my master branch as <code>website</code> folder.</p>
<p>Something like:</p>
<pre><code>
git checkout origin/gh-pages -b gh-pages
git checkout master
git submodule add -b gh-pages git@github.com:drnic/ninja-search-js.git website
</code></pre>
<p>Now I can access the gh-pages branch from my master branch (where the code is).</p>
<p>Then to deploy our Greasemonkey script we just copy over all the <code>public</code> files into <code>website/dist</code>, and then commit and push the changes to the gh-pages branch.</p>
<pre><code>
mkdir -p website/dist
cp -R public/* website/dist/
cd website
git commit -a "latest script release"
git push origin gh-pages
cd ..
</code></pre>
<p>Then you wait very patiently for GitHub to deploy your latest website, which now contains your Greasemonkey script (<code>dist/ninja-search.user.js</code>) and all the libraries (our actual code), stylesheets and images.</p>
<h3 id="summary">Summary</h3>
<p>Greasemonkey scripts might seem like small little chunks of code. But all code starts small and grows. At some stage you&#8217;ll wish you had some test coverage. And later you&#8217;ll hate yourself for ever having release the bloody thing in the first place.</p>
<p>I wrote all this up to summarise how I&#8217;d done TDD for the <a href="http://drnic.github.com/ninja-search-js/">Ninja Search JS</a> project, which is slightly different from how I added test cases to _why&#8217;s <a href="http://github.com/drnic/8cpj/tree/master">the octocat&#8217;s pajamas</a> greasemonkey script when I first started hacking with unit testing Greasemonkey scripts. The next one will probably be slightly different again.</p>
<p>I feel good about the current project structure, I liked Screw.Unit and blue-ridge, and I&#8217;m amused by my use of GitHub Pages to deploy the application itself.</p>
<p>If anyone has any ideas on how this could be improved, or done radically differently, I&#8217;d love to hear them!</p>
<h3 id="polish_your_rails_project_with_mocra">Polish your Rails project with Mocra</h3>
<p>I want to help you, your business, your boss and your project reach delightful levels of wickedly awesomeness. I’m so proud of the small team of ace Rails developers here at Mocra and what I know we can do for you.</p>
<p>Send an email to <a href="mailto:&#x72;&#x61;&#x69;&#x6C;&#x73;&#x40;&#x6D;&#x6F;&#x63;&#x72;&#x61;&#x2E;&#x63;&#x6F;&#x6D;">rails@mocra.com</a> about your current/future projects. Dare us to be more awesome!</p>
<p>While you wait for a reply perhaps you&#8217;d like to learn more about <a href="http://mocra.com/how-we-do-it/">How we do it</a> at <a href="http://mocra.com/">Mocra</a>?</p>


<p>Related posts:<ol><li><a href='http://drnicwilliams.com/2010/03/15/using-coffeescript-in-rails-and-even-on-heroku/' rel='bookmark' title='Permanent Link: Using CoffeeScript in Rails and even on Heroku'>Using CoffeeScript in Rails and even on Heroku</a> <small>I&#8217;m pretty excited about CoffeeScript as a clean-syntax replacement for...</small></li><li><a href='http://drnicwilliams.com/2009/11/12/dead-simple-javascript-unit-testing-in-rails/' rel='bookmark' title='Permanent Link: Dead simple JavaScript Unit Testing in Rails'>Dead simple JavaScript Unit Testing in Rails</a> <small> Formats: Video/Screencast (410 Mb, torrent) | Video only (vimeo)...</small></li><li><a href='http://drnicwilliams.com/2009/07/04/nifty-threaded-im-chat-within-gtalkgmail-chat/' rel='bookmark' title='Permanent Link: Nifty Threaded IM Chat within Gtalk/Gmail Chat'>Nifty Threaded IM Chat within Gtalk/Gmail Chat</a> <small>Ever had IM chats where a conversation splits into multiple...</small></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://drnicwilliams.com/2009/06/07/tdd-for-greasemonkey-scripts-and-introducing-ninja-search-js/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

