Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Intro page and prettying

  • Loading branch information...
commit 85de751ce6904ee4d991b75e3c80e969a249a254 1 parent eea07f0
@ianb authored
View
2  .resources/build
@@ -7,7 +7,7 @@ mv .resources resources
echo "Updating files with template..."
-files="index.html examples/examples.html examples/examples-2.html"
+files="index.html tutorial.html reference.html"
python resources/retemplate.py $files
for file in $files ; do
View
20 .resources/doc.css
@@ -2,6 +2,24 @@ i, em {
font-family: serif;
}
+#contents ul {
+ margin-bottom: 0;
+ margin-top: 0;
+}
+
+#contents > ul {
+ padding-left: 0;
+}
+
+#contents li {
+ list-style: none;
+}
+
+#contents {
+ border-bottom: 1px solid #999;
+ padding-left: 1em;
+}
+
code {
color: #288;
}
@@ -11,7 +29,7 @@ aside code {
}
section:target h1, section:target h2, section:target h3, section:target h4,
-section:target h5, section:target h6 {
+section:target h5, section:target h6, h3:target, h4:target {
border-bottom: 3px solid #f90;
}
View
21 .resources/toc.js
@@ -1,10 +1,18 @@
function contentsOnLoad() {
+ if (contentsOnLoad.hasRun) {
+ return;
+ }
+ contentsOnLoad.hasRun = true;
var dest = document.getElementById('contents');
var toc = [document.createElement('ul')];
+ var generatedIds = [];
dest.appendChild(toc[0]);
var els = document.querySelectorAll('h3, h4, h5, h6');
for (var i=0; i<els.length; i++) {
var el = els[i];
+ if (el.className.indexOf('no-toc') != -1) {
+ continue;
+ }
var elDepth = ['H3', 'H4', 'H5', 'H6'].indexOf(el.tagName);
while (elDepth < toc.length-1) {
toc.splice(toc.length-1, 1);
@@ -16,8 +24,12 @@ function contentsOnLoad() {
toc[toc.length-1].appendChild(container);
toc.push(ul);
}
- var name = 'header-'+(i+1);
- el.setAttribute('id', name);
+ var name = el.getAttribute('id');
+ if (! name) {
+ name = 'header-'+(i+1);
+ generatedIds.push(name);
+ el.setAttribute('id', name);
+ }
var li = document.createElement('li');
var anchor = document.createElement('a');
if (el.getAttribute('href')) {
@@ -31,9 +43,10 @@ function contentsOnLoad() {
toc[toc.length-1].appendChild(li);
}
// Re-scroll:
- if (location.hash) {
+ if (location.hash && generatedIds.indexOf(location.hash.substr(1)) != -1) {
location.hash = location.hash;
}
}
-window.onload = contentsOnLoad;
+document.addEventListener("DOMContentLoaded", contentsOnLoad, false);
+window.addEventListener("load", contentsOnLoad, false);
View
208 index.html
@@ -0,0 +1,208 @@
+<!DOCTYPE html>
+<html class="no-js">
+ <head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="doctest.css">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <title>Doctest.js: the humane Javascript test framework</title>
+ <meta name="description" content="Doctest.js is a Javascript testing framework">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" href=".resources/boilerplate/css/normalize.min.css">
+ <link rel="stylesheet" href=".resources/boilerplate/css/main.css">
+ <link rel="stylesheet" href=".resources/doc.css">
+ <script src=".resources/boilerplate/js/vendor/modernizr-2.6.1.min.js"></script>
+ <script src="doctest.js"></script>
+ <!-- EXTRA_HEAD -->
+<script type="text/javascript" src="./.resources/toc.js"></script>
+<!-- /EXTRA_HEAD -->
+ </head>
+ <body class="autodoctest">
+
+ <a href="http://github.com/ianb/doctestjs"><img
+style="position: absolute; top: 0; right: 0; border: 0;"
+src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"
+alt="Fork me on GitHub"></a>
+
+ <div class="header-container">
+ <header class="wrapper clearfix">
+ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->A Humane Javascript Test Framework<!-- /TITLE --></h1>
+
+ <!--
+ <nav>
+ <ul>
+ <li><a href="#">nav ul li a</a></li>
+ <li><a href="#">nav ul li a</a></li>
+ <li><a href="#">nav ul li a</a></li>
+ </ul>
+ </nav>
+ -->
+
+ </header>
+ </div>
+
+ <div class="main-container">
+ <div class="main wrapper clearfix">
+
+
+ <!-- BODY -->
+
+
+<p><strong>Doctest.js</strong> is a test runner and testing framework for Javascript.</p>
+
+<p>Doctest uses a novel approach to testing: <em>example</em> and <em>expected result</em>. Each test is a chunk of code that prints out results and side effects, and then the expected result is matched against that to see if the test passed or failed.</p>
+
+<p>An example:
+
+<pre class="commenttest">
+function capitalize(words) {
+ return words.replace(/\b[a-z]/g, function (m) {
+ return m[0].toUpperCase();
+ });
+}
+
+print(capitalize('some words'));
+// => Some Words
+
+print(capitalize('some 4ward words'));
+// => Some 4ward Words
+</pre>
+</p>
+
+<p>This is similar to something like <code>assertEqual(capitalize('some words'), 'Some Words')</code> &mdash; there's a kind of "equal" check every time you print something. Instead of doing stuff then testing every detail of what happened or what was returned, testing almost happens for you &mdash; you print out what you are interested in, and you can even punt: you can start by simply exercising everything that matters, and then inspecting that what happens is what you expect, and copying those results into the test. For instance:
+
+<pre class="commenttest">
+function getProperties(obj) {
+ var result = [];
+ for (i in obj) {
+ result.push(i);
+ }
+ result.sort();
+ return result;
+}
+
+print(getProperties({b: 1, a: 2}));
+// =>
+
+print(getProperties("a"));
+// =>
+</pre>
+
+</p>
+
+<p>Look: the first example worked great, <code>["a", "b"]</code>. The second example though wasn't right at all. <code>"0"</code>? Once we have a better idea we can adjust those tests:
+
+<pre class="commenttest">
+function getProperties(obj) {
+ var result = [];
+ for (i in obj) {
+ if (obj.hasOwnProperty(i)) {
+ result.push(i);
+ }
+ }
+ result.sort();
+ return result;
+}
+
+print(getProperties({b: 1, a: 2}));
+// => ["a", "b"]
+
+print(getProperties("a"));
+// => []
+</pre>
+
+Well, that wasn't quite enough, but this kind of incremental development is exactly why doctest.js is so helpful: it shows you what you've done, it shows you both <em>presence</em> and <em>absence</em>. Most test frameworks only give you tools to test what <em>is</em> there, and not ensure that the things you don't want aren't there.</p>
+
+<h3>Async testing made easy!</h3>
+
+<p>The other <strong>great</strong> feature of doctest.js is how it lets you test async code.</p>
+
+<p>Async code is a bit tricky for all test runners. When you run the test, the <em>result</em> of the test won't be known until after you wait some time. Test runners might have ways to pause the test process while the test code completes. They also need ways to test that everything you wanted to happen will happen. Something that is often tricky in test code is to <em>make sure</em> that some callback was called &mdash; it's relatively easier to test that the callback was called correctly.</p>
+
+<p>Here doctest's ability to test both what's present and what's missing shines. And the test runner also gives you a great way to serialize your asynchronous tests.</p>
+
+<p>The core feature here is <code>wait()</code> &mdash; this lets you register a callback that will tell the test runner when this block of code is fully finished. An example:
+
+<pre class="commenttest">
+var now = Date.now();
+var done = false;
+
+setTimeout(function () {
+ done = true;
+ print('The timeout finished!', Date.now() - now);
+}, 300);
+
+wait(function () {return done;});
+// => The timeout finished! ...
+</pre>
+
+(Notice we use <code>...</code> to ignore the specific number that is printed: ellipsis act as a kind of wildcard)
+
+</p>
+
+<p>With Doctest you don't have to use fake <code>setTimeout</code> or fake async anywhere &mdash; you always use the real thing, and it's nearly as easy to test as async code. Frameworks that make this code synchronous are cheating you, because asynchronous code is the hardest of code and deserves to be tested accurately. But when a test framework makes synchronous easy and asynchronous hard, it's all too easy when in the depth of test development to take shortcuts.</p>
+
+<h3>Mocking with Spy</h3>
+
+<p>In addition there's a simply mocking framework in doctest with Spy. This lets you create a function that records over time it is called &mdash; and each time it is called it prints out how it is called. It also makes it easy to wait on the Spy to be called:
+
+<pre class="commenttest">
+var button = $('&lt;button>&lt;/button>');
+$('body').append(button);
+button.click(Spy('button.click'));
+button.click();
+Spy('button.click').wait();
+/* =>
+&lt;button />.button.click({...})
+*/
+</pre>
+
+You'll notice here that we also ignored the details of the object passed to the callback. We could use wildcards to match no part or any specific part of the argument called. Also note that the value of <code>this</code> is shown: people usually forget that <code>this</code> is a kind of implicit argument to many functions, but again doctest makes the implicit explicit. Also note that the <em>actual</em> output is always displayed, so you can use this to inspect aspects of the environment even if you don't want to test all fo them.
+</p>
+
+
+<h3>Lineage</h3>
+
+<p>Doctest is based on the Python <a href="http://docs.python.org/library/doctest.html">doctest module</a> originally written by Tim Peters. Spy was inspired some by Jasmine's <a href="http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Spy.html">Spy class</a>, and carries over ideas from <a href="http://pypi.python.org/pypi/MiniMock">MiniMock</a>.</p>
+
+
+<div style="display: none">
+ <div id="doctest-output"></div>
+</div>
+
+
+<!-- /BODY -->
+
+ </div> <!-- #main -->
+
+ </div> <!-- #main-container -->
+
+ <div class="footer-container">
+ <footer class="wrapper">
+ <h3>doctest.js is by <a href="http://ianbicking.org">Ian Bicking</a>.
+ It's on <a href="https://github.com/ianb/doctestjs">github</a>!</h3>
+ </footer>
+ </div>
+
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
+<script>
+window.jQuery || document.write('<script src=".resources/boilerplate/js/vendor/jquery-1.8.1.min.js"><\/script>')
+</script>
+
+<script src=".resources/boilerplate/js/main.js"></script>
+
+<script type="text/javascript">
+
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-34921728-1']);
+ _gaq.push(['_trackPageview']);
+
+ (function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+ })();
+
+</script>
+
+ </body>
+</html>
View
53 reference.html
@@ -27,15 +27,13 @@
<header class="wrapper clearfix">
<h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /TITLE --></h1>
- <!--
<nav>
<ul>
- <li><a href="#">nav ul li a</a></li>
- <li><a href="#">nav ul li a</a></li>
- <li><a href="#">nav ul li a</a></li>
+ <li><a href="https://github.com/ianb/doctestjs">Github</a></li>
+ <li><a href="/reference.html">Reference</a></li>
+ <li><a href="/tutorial.html">Tutorial</a></li>
</ul>
</nav>
- -->
</header>
</div>
@@ -54,11 +52,11 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
<div id="contents"></div>
-<h3>Format of test</h3>
+<h3 id="format">Format of test</h3>
<p>There are two formats that a doctest can take. You've probably seen the <code>commenttest</code> format, there is also the more traditional <code>doctest</code> format.</p>
-<h4><code>doctest</code> format</h4>
+<h4 id="format-doctest"><code>doctest</code> format</h4>
<p>This format is used like:
@@ -76,7 +74,7 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
<p>Note you can still have multiple statements using a continuation line. The only difference between two lines with <code>$</code> and one with a <code>$</code> followed by <code>></code> is that in the latter case the two lines are executed <em>together</em> and the output from both is combined into what is expected.</p>
-<h4><code>commenttest</code> format</h4>
+<h4 id="format-commenttest"><code>commenttest</code> format</h4>
<p>In this format the expected output is in a comment, like:
@@ -108,7 +106,7 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
<p>You can have one or more <code>=</code>'s. The text <code>A section header</code> will become a header. Each section header turns into a new <code>&lt;pre></code> element.</p>
-<h3>Printing/writing</h3>
+<h3 id="print">Printing/writing</h3>
<p>The <code>print()</code> function is pretty important, of course. (Note it also was called <code>writeln()</code>, a name which is still supported).</p>
@@ -153,13 +151,13 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
<p>Arrays and objects are displayed like you'd think. This might include objects that you might not think of as "plain" objects. Also the object prototype is not displayed. You'll have to use something like <code>print(o.constructor)</code> if you want to be specific about classes.</p>
-<h3><code>console.log()</code></h3>
+<h4 id="console"><code>console.log()</code></h3>
<p><code>console.log()</code> works a lot like <code>print()</code>. But unlike <code>print()</code> it doesn't make a test pass or fail, it's purely informative.</p>
<p>All the methods on console should work, like <code>console.warn()</code>. The underlying normal console function is called, but in addition on a test-by-test basis these are collected and displayed.</p>
-<h3>Output matching</h3>
+<h3 id="matching">Output matching</h3>
<p>The <em>expected</em> output is compared with the output you actually <em>got</em> (received).</p>
@@ -173,7 +171,7 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
<p>When you have a large expected text and got a lot of text, and that text differs just a bit, you'll see a line-by-line comparison of the two, to help you identify exactly where the problem is. Note if you use wildcards the line-by-line comparison might be very inaccurate.</p>
-<h3><code>wait()</code>, async code, and pausing the tests</h3>
+<h3 id="wait"><code>wait()</code>, async code, and pausing the tests</h3>
<p>Often you'll want to let code run for a while on its own before you are done with testing a section of code. I.e., you want to let all the requests complete, DOM elements update, and so forth.</p>
@@ -238,7 +236,7 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
<dd>This calls condition up until <code>timeout</code> milliseconds. You can use this to extend the timeout. The default timeout is 5 seconds (5000).</dd>
</dl>
-<h3>Spy, mocking, and watching functions</h3>
+<h3 id="spy">Spy, mocking, and watching functions</h3>
<p><code>Spy</code> is used to create a mock object/function that can be used to track calls and inspect call order and arguments.</p>
@@ -282,7 +280,7 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
<p>Note that your function can raise an exception, and the Spy will pass it through (though also note the exception using <code>console.log()</code>). You can use this to inspect how a library reacts to exceptions in callbacks.</p>
-<h4>Spy options</h4>
+<h4 id="spy-options">Spy options</h4>
<p>The options available:</p>
@@ -315,7 +313,7 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
<p>You can also change <code>Spy.defaultOptions</code> if you want to override one option by default, for instance to turn off printing or ignore <code>this</code>.</p>
-<h4>Spy methods</h4>
+<h4 id="spy-methods">Spy methods</h4>
<p>Several methods are available:</p>
@@ -369,7 +367,7 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
</dl>
-<h4>Spy attributes</h4>
+<h4 id="spy-attributes">Spy attributes</h4>
<p>Spies have several attributes to inspect how they have been called:</p>
@@ -383,7 +381,13 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
</dl>
-<h3>jshint</h3>
+<h3 id="abort">Aborting your tests</h3>
+
+<p>Tests often has prerequesites. Perhaps some browsers aren't supported. Maybe you need a server setup. Normally doctest will run through all the tests regardless of failures, but when basic prerequesites are missing this creates lots of chatter and failures with no purpose.</p>
+
+<p>To stop the tests from running call <code>Abort()</code>. This will still run the rest of the test block (up until the next <code>// =></code>).</p>
+
+<h3 id="jshint">jshint</h3>
<p>A helper is provided to help you run <a href="http://www.jshint.com/">JSHint</a> regularly on your code. Just do this:</p>
@@ -402,6 +406,19 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
</p>
+<h3 id="nosyxmlhttprequest"><code>NosyXMLHttpRequest</code></h3>
+
+<p>Sometimes you may want to watch the progress of XMLHttpRequest requests &mdash; both how the request is constructed and its result. You can use <code>NosyXMLHttpRequest</code> to wrap request objects.</p>
+
+<p>You probably want to use it like:
+
+<pre>
+XMLHttpRequest = NosyXMLHttpRequest.factory("request");
+</pre>
+</p>
+
+<p>The name will be used when showing output (e.g., <code>request.setRequestHeader('X-Something', 'value')</code>).</p>
+
<div style="display: none">
<div id="doctest-output"></div>
@@ -421,7 +438,7 @@ <h1 class="title"><a href="/">Doctest.js</a>: <!-- TITLE -->the reference<!-- /T
<div class="footer-container">
<footer class="wrapper">
- <h3>doctest.js is by <a href="http://ianbicking.org">Ian Bicking</a>.
+ <h3 class="no-toc">doctest.js is by <a href="http://ianbicking.org">Ian Bicking</a>.
It's on <a href="https://github.com/ianb/doctestjs">github</a>!</h3>
</footer>
</div>
View
30 tutorial.html
@@ -12,7 +12,9 @@
<link rel="stylesheet" href=".resources/boilerplate/css/main.css">
<link rel="stylesheet" href=".resources/doc.css">
<script src=".resources/boilerplate/js/vendor/modernizr-2.6.1.min.js"></script>
- <!-- EXTRA_HEAD --><!-- /EXTRA_HEAD -->
+ <!-- EXTRA_HEAD -->
+ <script type="text/javascript" src="./.resources/toc.js"></script>
+ <!-- /EXTRA_HEAD -->
</head>
<body class="autodoctest">
@@ -25,15 +27,13 @@
<header class="wrapper clearfix">
<h1 class="title">Doctest.js: <!-- TITLE -->A Tutorial <!-- /TITLE --></h1>
- <!--
<nav>
<ul>
- <li><a href="#">nav ul li a</a></li>
- <li><a href="#">nav ul li a</a></li>
- <li><a href="#">nav ul li a</a></li>
+ <li><a href="https://github.com/ianb/doctestjs">Github</a></li>
+ <li><a href="/reference.html">Reference</a></li>
+ <li><a href="/tutorial.html">Tutorial</a></li>
</ul>
</nav>
- -->
</header>
</div>
@@ -43,6 +43,8 @@ <h1 class="title">Doctest.js: <!-- TITLE -->A Tutorial <!-- /TITLE --></h1>
<!-- BODY -->
+<div id="contents"></div>
+
<article>
<section id="introduction">
<header>
@@ -156,6 +158,10 @@ <h1 class="title">Doctest.js: <!-- TITLE -->A Tutorial <!-- /TITLE --></h1>
<h3><code>print()</code> and output matching</h3>
</header>
+<aside>
+ <p>For more detail on printing see <a href="reference.html#print">the reference</a>.</p>
+</aside>
+
<p>
<code>print()</code> pretty-prints things. This is important, because you have to "expect" the same output that <code>print()</code> produces. You can give multiple arguments, like with <code>console.log</code>.
@@ -231,6 +237,10 @@ <h1 class="title">Doctest.js: <!-- TITLE -->A Tutorial <!-- /TITLE --></h1>
<h3>Testing async code</h3>
</header>
+<aside>
+ <p>For more on async and <code>wait</code> see <a href="reference.html#wait">the reference</a>.</p>
+</aside>
+
<p>
This is all well and good, but lots of code in Javascript is <em>asynchronous</em>, meaning that you don't just call a function that returns a value. Doctest.js has an answer to that too: a great answer!
@@ -296,6 +306,10 @@ <h1 class="title">Doctest.js: <!-- TITLE -->A Tutorial <!-- /TITLE --></h1>
<h3>The Spy</h3>
</header>
+<aside>
+ <p>For more information on <code>Spy</code> see <a href="reference.html#spy">the reference</a>.</p>
+</aside>
+
<p>
Note: the next example will use some jQuery, just for the heck of it, though there is no special support for jQuery or other frameworks in Doctest.
@@ -516,6 +530,10 @@ <h1 class="title">Doctest.js: <!-- TITLE -->A Tutorial <!-- /TITLE --></h1>
<h2>Setting Up Your HTML</h2>
</header>
+<aside>
+ <p>For more on the HTML setup see <a href="reference.html#format">the reference documentation</a>.</p>
+</aside>
+
<p>
I wanted to show you all the cool features of doctest first, but you can't actually use any of them unless you set up a test runner page. Luckily the page is pretty simple. Let's say you've put doctest.js into <code>doctest/</code>:
Please sign in to comment.
Something went wrong with that request. Please try again.