{"_id":"lotte","_rev":"33-f60d620fc976f87ca6c2a9ea34ac513d","name":"lotte","description":"Headless, automated browser testing using PhantomJS","dist-tags":{"latest":"0.2.3"},"versions":{"0.1.0":{"name":"lotte","version":"0.1.0","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":{"name":"https://github.com/StanAngeloff/lotte/issues"},"author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["./bin","./lib/","./test/"],"bin":{"lotte":"./bin/cli.js"},"main":"./lib/lotte.js","repository":{"type":"git","url":"git://github.com/StanAngeloff/lotte.git"},"dependencies":{"findit":"~0.1.1","minimatch":"~0.0.4","naturalsort":"~0.0.1","optimist":"~0.2.8","semver":"~1.0.10"},"devDependencies":{"express":"~2.5.0"},"engines":{"node":"~0.4.10"},"preferGlobal":true,"_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"_id":"lotte@0.1.0","_engineSupported":true,"_npmVersion":"1.0.106","_nodeVersion":"v0.4.10","_defaultsLoaded":true,"dist":{"shasum":"53fcaa5382f2cd15599c680942f4b7e7603c14b9","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.1.0.tgz","integrity":"sha512-hsflpjRA6Ol0m1erE7rMiahDcoD+q5hfJtBWz6BGCr4cmI16azb3PNLvKRgbn8KIzt+MF/+XMlDrO+BRq+3/xg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEfwp9lUW6pkTJaQ6uJmbgf5H7WXuF3weOcAM3LUMUXZAiEAxXM+uM8dQdZAjMvlNxx0lugihTujBJTdFlzmiNgVsxo="}]},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}],"directories":{}},"0.1.1":{"name":"lotte","version":"0.1.1","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":{"name":"https://github.com/StanAngeloff/lotte/issues"},"author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["./bin","./lib/","./test/"],"bin":{"lotte":"./bin/cli.js"},"main":"./lib/lotte.js","repository":{"type":"git","url":"git://github.com/StanAngeloff/lotte.git"},"dependencies":{"findit":"~0.1.1","minimatch":"~0.0.4","naturalsort":"~0.0.1","optimist":"~0.2.8","semver":"~1.0.10"},"devDependencies":{"express":"~2.5.0"},"engines":{"node":"~0.4.10"},"preferGlobal":true,"_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"_id":"lotte@0.1.1","_engineSupported":true,"_npmVersion":"1.0.106","_nodeVersion":"v0.4.10","_defaultsLoaded":true,"dist":{"shasum":"86a93b9bca7a9aa9f205be5cc61e31663a5eba20","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.1.1.tgz","integrity":"sha512-6k37A399X0/iNstpoq4JOHZxjX2ACmonPbc7fIzJT/RB26wV4Js7csxccrjmLBE7L9oHmYw9L0wj8RRrw4r/uw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIALqFtcJcvcnURe2dwJHhPXvUHnJuSnAN615a4ec0FA0AiEA0eFrZjPEVrcQGo9+f4ScmkN0hlYw4MU1y46rnBsIC8s="}]},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}],"directories":{}},"0.1.2":{"name":"lotte","version":"0.1.2","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":{"name":"https://github.com/StanAngeloff/lotte/issues"},"author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["./bin","./lib/","./test/"],"bin":{"lotte":"./bin/cli.js"},"main":"./lib/lotte.js","repository":{"type":"git","url":"git://github.com/StanAngeloff/lotte.git"},"dependencies":{"findit":"~0.1.1","minimatch":"~0.0.4","naturalsort":"~0.0.1","optimist":"~0.2.8","semver":"~1.0.10"},"devDependencies":{"express":"~2.5.0"},"engines":{"node":">=0.4.10"},"preferGlobal":true,"_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"_id":"lotte@0.1.2","_engineSupported":true,"_npmVersion":"1.0.106","_nodeVersion":"v0.6.2","_defaultsLoaded":true,"dist":{"shasum":"2ec79631ecbcb90577ff1b4b0f09ddcda8d52eb5","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.1.2.tgz","integrity":"sha512-t4HQd5A9thQiv68Lq4C9tGvnBlw3bGPEnapnIwVEeWO6ZBtSPbkqJos+e/XhziNtlaNj4vvcUNXEgFvsq3HgFA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC3ARFPy5ELpNhEBe8w51kHUmefLWtEGW9tJ+77QZppIgIgFEkhda/BbQ/+rGYxKl7wPE1GzBLxwQi9JcqIYqYvbgY="}]},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}],"directories":{}},"0.1.2-1":{"name":"lotte","version":"0.1.2-1","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":{"name":"https://github.com/StanAngeloff/lotte/issues"},"author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["./bin","./lib/","./test/"],"bin":{"lotte":"./bin/cli.js"},"main":"./lib/lotte.js","repository":{"type":"git","url":"git://github.com/StanAngeloff/lotte.git"},"dependencies":{"findit":"~0.1.1","minimatch":"~0.0.4","naturalsort":"~0.0.1","optimist":"~0.2.8","semver":"~1.0.10"},"devDependencies":{"express":"~2.5.0"},"engines":{"node":">=0.4.10"},"preferGlobal":true,"_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"_id":"lotte@0.1.2-1","_engineSupported":true,"_npmVersion":"1.0.106","_nodeVersion":"v0.6.2","_defaultsLoaded":true,"dist":{"shasum":"3449589260ea1ba0762ba810b0cac4c91735c76f","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.1.2-1.tgz","integrity":"sha512-ct/3QYp8Sb8occ6wuY9KrbPZG1u3jTUVElcdT090warPIVbjd/3D5zrmrCqCm3GTjVV32bGWgeFIYglCQl2dMA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF7U6yKRtdmmw5kjQVDjbIjjDttZVZVGxp5/nkIcNTjEAiA9fY15O4xJzaVp9v0LOCKO16Ys2Tye2sHbOghoVBK/HQ=="}]},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}],"directories":{}},"0.1.2-2":{"name":"lotte","version":"0.1.2-2","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":{"name":"https://github.com/StanAngeloff/lotte/issues"},"author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["bin/","lib/","test/"],"bin":{"lotte":"bin/cli.js"},"main":"lib/lotte.js","repository":{"type":"git","url":"git://github.com/StanAngeloff/lotte.git"},"dependencies":{"findit":"~0.1.2","minimatch":"~0.0.4","naturalsort":"~0.0.1","optimist":"~0.3.0","semver":"~1.0.12","tmp":"~0.0.12"},"devDependencies":{"express":"~2.5.0"},"engines":{"node":">=0.4.10"},"preferGlobal":true,"_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"_id":"lotte@0.1.2-2","optionalDependencies":{},"_engineSupported":true,"_npmVersion":"1.1.16","_nodeVersion":"v0.6.15","_defaultsLoaded":true,"dist":{"shasum":"a3a086fd44bac993570e76288742c6e9079f616f","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.1.2-2.tgz","integrity":"sha512-whey3tOQ9xjx1QtaTb2tSpLRfYt3luRPDPAA9ZWyyNL6LW81VLdLF/tppqmUSD+IPsNKqga54jMOvRDNVw3r+Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFZw+UdAFEy7MRHFj0nH74Xzt2X4UWmO9rh/QPDn+13PAiAmncPs4FakoVSPTTfnqmu6/ms5fO7rS1RR/XjicCcDcw=="}]},"readme":"","maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}]},"0.2.0-1":{"name":"lotte","version":"0.2.0-1","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":"https://github.com/StanAngeloff/lotte/issues","author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["bin/","lib/","test/"],"bin":{"lotte":"bin/cli.js"},"main":"lib/lotte.js","repository":{"type":"git","url":"https://github.com/StanAngeloff/lotte"},"dependencies":{"minimatch":"~0.2.6","naturalsort":"~0.0.1","optimist":"~0.3.4","semver":"~1.0.14","tmp":"~0.0.14","walkdir":"~0.0.4"},"devDependencies":{"express":"~3.0.0"},"engines":{"node":">=0.8"},"preferGlobal":true,"readme":"<!doctype html>\n<html lang=en>\n<head>\n  <meta charset=utf-8>\n  <title>Lotte</title>\n</head>\n<body>\n\n<article id=page>\n<h1>Lotte</h1>\n\n<p>Lotte is a headless, automated testing framework built on top of <a href=\"http://www.phantomjs.org/\">PhantomJS</a> and inspired by <a href=\"https://github.com/joshbuddy/ghostbuster\">Ghostbuster</a>.\nIt adds jQuery-like methods and chaining, more assertion logic and an extensible core.\nTests can be written in either JavaScript or <a href=\"http://coffeescript.org/\">CoffeeScript</a>.</p>\n\n<p>Lotte comes with tools for accessing the DOM, evaluating arbitrary code, simulating mouse and keyboard input.</p>\n\n<p>Tests are sandboxed and run asynchronously. Blocking methods are available to simulate dependencies and to control the flow of execution.</p>\n\n<p>This project is still highly experimental. Using it may cause your computer to blow up. <a href=\"https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md\">Seriously.</a></p>\n\n<h2>Prerequisites</h2>\n\n<ul>\n<li><a href=\"http://nodejs.org/\">node.js</a> <strong>&gt;=0.4.10</strong></li>\n<li><a href=\"http://npmjs.org/\">npm</a> <strong>~1.0</strong></li>\n<li><a href=\"http://www.phantomjs.org/\">PhantomJS</a> <strong>~1.3.0</strong></li>\n</ul>\n\n<h3>Optional Dependencies</h3>\n\n<ul>\n<li><a href=\"http://coffeescript.org/\">CoffeeScript</a></li>\n</ul>\n\n<h2>Installation</h2>\n<div class=\"highlight\"><pre>$ npm -g install lotte\n</pre>\n</div>\n\n<p><code>-g</code>lobal is preferred so you can run <code>lotte</code> from any directory.</p>\n\n<h2>Usage</h2>\n\n<p>Create a new file <code>lotte_github.js</code> (preferably in an empty directory) and copy the following code:</p>\n<div class=\"highlight\"><pre><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">open</span><span class=\"p\">(</span><span class=\"s1\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"kd\">function</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">describe</span><span class=\"p\">(</span><span class=\"s1\">&#39;Sign Up button&#39;</span><span class=\"p\">,</span> <span class=\"kd\">function</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n    <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">assert</span><span class=\"p\">.</span><span class=\"nx\">ok</span><span class=\"p\">(</span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">$</span><span class=\"p\">(</span><span class=\"s1\">&#39;.signup-button&#39;</span><span class=\"p\">).</span><span class=\"nx\">length</span><span class=\"p\">,</span> <span class=\"s1\">&#39;expects button to be in the DOM&#39;</span><span class=\"p\">);</span>\n    <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">success</span><span class=\"p\">();</span>\n  <span class=\"p\">});</span>\n<span class=\"p\">});</span>\n</pre>\n</div>\n\n<p>Run <code>lotte</code> from within the directory and you should see the following output:</p>\n<div class=\"highlight\"><pre>/tmp/lotte_github.js\n  @ https://github.com\n      ✓ Sign Up button\n</pre>\n</div>\n\n<h2>Command-Line Options</h2>\n\n<p>You can customise many aspects of Lotte&#39;s behaviour either on the command-line on through <code>Lottefile</code>s. The following options are available:</p>\n<div class=\"highlight\"><pre>$ lotte --help\nUsage: lotte [OPTION...] PATH\n\nOptions:\n  --help, -h        give this help page\n  --version, -v     print program version\n  --concurrent, -c  limit of files to run in parallel                       [default: 4]\n  --timeout, -t     timeout for individual files (in milliseconds)          [default: 30000]\n  --include, -I     glob pattern to match files in PATH          [string]   [default: &quot;**/lotte_*.js&quot;]\n  --exclude, -E     glob pattern to remove included files        [string]\n  --lottefile, -f   look for &#39;lottefile&#39; in PATH                 [string]   [default: &quot;Lottefile&quot;]\n  --verify          verify PhantomJS version (expected ~1.3.0)   [boolean]  [default: true]\n  --phantom         executable for PhantomJS                     [string]   [default: &quot;phantomjs&quot;]\n  --coffee          executable for CofeeScript                   [string]   [default: &quot;coffee&quot;]\n</pre>\n</div>\n\n<p>There are four key options you would want to customise while the rest should work with their defaults.</p>\n\n<ul>\n<li><p><strong><code>--concurrent, -c</code></strong></p>\n\n<p>If you have more than one test file in a directory, Lotte will attempt to run them in parallel (asynchronously).\nYou can specify how many tests can be running at any given time through this option.</p>\n\n<p>If you want to run tests synchronously, specify a value of <code>1</code>.</p></li>\n<li><p><strong><code>--timeout, -t</code></strong></p>\n\n<p>Each test is expected to finish within a given period of time. If a test takes longer, it is interruped and recorded as failed.</p>\n\n<p>The default value is <code>30</code> seconds, but you should consider reducing it.</p></li>\n<li><p><strong><code>--include, -I</code><br>\n<code>--exclude, -E</code></strong></p>\n\n<p>When you run <code>lotte</code> from any directory the script collects a list of all files in the current directory and all sub-directories.\nThe list is reduced by running the <code>include</code> glob pattern and dropping any files that did not match.\nThe list is then reduced further by running the <code>exclude</code> glob pattern and dropping any files that did match.\nThe remaining list is sorted and considered final.</p>\n\n<p>You can specify these arguments more than once to create an array of include/exclude patterns.</p></li>\n</ul>\n\n<h3>Lottefile</h3>\n\n<p>In order to avoid having to type the full <code>lotte</code> command-line each time, you can use <code>Lottefile</code>s to store your settings per project.</p>\n\n<p><code>Lottefile</code>s are regular JavaScript files where each global variable maps to a command-line option. For example, the following command:</p>\n<div class=\"highlight\"><pre>$ lotte --include &#39;**/*.coffee&#39; --include &#39;**/*.js&#39; --concurrent 1 tests\n</pre>\n</div>\n\n<p>can be stored in a <code>Lottefile</code> as this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">path</span>       <span class=\"o\">=</span> <span class=\"s1\">&#39;tests&#39;</span>\n<span class=\"nx\">include</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;**/*.coffee&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;**/*.js&#39;</span><span class=\"p\">]</span>\n<span class=\"nx\">concurrent</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n</pre>\n</div>\n\n<p>Running <code>lotte</code> from the project directory will then read the <code>Lottefile</code> and scan the <code>tests</code> directory for all files matching <code>**/*.{coffee,js}</code>.</p>\n\n<h2>Writing Tests</h2>\n\n<p>Tests can be written in either JavaScript or CoffeeScript.\nIn the sections below substitute <code>@</code> with <code>this.</code> if you are using JavaScript.\nArguments wrapped in square brackets <code>[</code> and <code>]</code> are optional.\nArguments ending in <code>...</code> can be used more than once.</p>\n\n<p>At the top-level, the following functions are available:</p>\n\n<ul>\n<li><p><strong><code>@title([name])</code></strong></p>\n\n<p>Gets or sets the test title.\nThis is useful for giving meaningful names to your tests.</p>\n\n<p>When called with zero arguments, returns the current title or <code>undefined</code>.<br>\nWhen called with one argument, sets the title.</p>\n\n<p>If you don&#39;t explicitly specify a title, the filename will be used instead.</p></li>\n<li><p><strong><code>@base([uri])</code></strong></p>\n\n<p>Gets or sets the absolute URI for all relative URIs in the test.\nYou can use this to specify the root URI for your project.</p>\n\n<p>When called with zero arguments, returns the current URI or <code>undefined</code>.<br>\nWhen called with one argument, sets the URI.</p>\n\n<p>If you don&#39;t explicitly specify an absolute URI, all calls to <code>@open</code> will expect an absolute URI instead.</p></li>\n<li><p><strong><code>@open(uri, [message], [options], block)</code></strong></p>\n\n<p>Creates a new test.</p>\n\n<p><code>uri</code> can be either an absolute or relative URI (see above).<br>\n<code>message</code> is an optional description for the URI. If you don&#39;t specify it, Lotte will print the <code>uri</code> in the output instead.<br>\n<code>options</code> is an object hash to pass to PhantomJS. See <a href=\"http://code.google.com/p/phantomjs/wiki/Interface#settings_(object)\">settings (object)</a>.<br>\n<code>block</code> is a function which is executed if the server returns a valid response (2xx or 3xx).</p>\n\n<p>If the server returns a 4xx or 5xx HTTP code instead, the test is recorded as failed.</p>\n\n<p>If you have more than one <code>@open</code> call at the top-level, they will be executed asynchronously.</p></li>\n</ul>\n\n<p>Putting it all together, a test file could look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@title</span> <span class=\"s\">&#39;Github&#39;</span>\n<span class=\"nx\">@base</span>  <span class=\"s\">&#39;https://github.com&#39;</span>\n\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/&#39;</span><span class=\"p\">,</span> <span class=\"s\">&#39;the homepage&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"c1\"># ...body of test...</span>\n</pre>\n</div>\n\n<h3>Cases &amp; Grouping</h3>\n\n<p>Once you have successfully requested an URI, you can start writing test cases against the page.</p>\n\n<p>The following functions are available:</p>\n\n<ul>\n<li><p><strong><code>@group(name, block)</code></strong></p>\n\n<p>Groups the nested test cases. This is mainly for structuring the output Lotte prints.</p>\n\n<p><code>name</code> is the name of the group.<br>\n<code>block</code> is a function which contains the nested test cases.</p></li>\n<li><p><strong><code>@describe(name, block)</code></strong></p>\n\n<p>Starts a new test case.</p>\n\n<p><code>name</code> is the name of the test case.<br>\n<code>block</code> is a function which is executed and is expected to contain assertion logic.</p></li>\n</ul>\n\n<p>Putting it all together a test file could now look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@title</span> <span class=\"s\">&#39;Github&#39;</span>\n<span class=\"nx\">@base</span>  <span class=\"s\">&#39;https://github.com&#39;</span>\n\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/&#39;</span><span class=\"p\">,</span> <span class=\"s\">&#39;the homepage&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;counter shows number of repositories&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># ...assertion logic...</span>\n  <span class=\"nx\">@group</span> <span class=\"s\">&#39;Sign Up button&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@describe</span> <span class=\"s\">&#39;is in place&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># ...assertion logic...</span>\n    <span class=\"nx\">@describe</span> <span class=\"s\">&#39;takes you to /plans&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># ...assertion logic...</span>\n</pre>\n</div>\n\n<h4>Flow of Execution</h4>\n\n<p>Each test case is executed in the order in which it is defined:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"c1\"># etc.</span>\n</pre>\n</div>\n\n<p>If a test case contains an asynchronous function call, the next test case is executed without waiting for the function to finish:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">setTimeout</span> <span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"p\">),</span> <span class=\"mi\">2500</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run third in parallel with second still running&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n</pre>\n</div>\n\n<p>Be extremely careful when dealing with asynchronous function. For example, using <code>.click()</code> to follow an anchor could change the page while another test case is running.</p>\n\n<p>If a test case fails, any remaining test cases are skipped:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"k\">throw</span> <span class=\"s\">&#39;Whoops!&#39;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I should run second, but I never will&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n</pre>\n</div>\n\n<p>To simulate dependencies and control the flow of execution, you can use the following functions:</p>\n\n<ul>\n<li><p><strong><code>@wait(name..., block)</code></strong></p>\n\n<p>Blocks the current test case until all dependencies have finished (either passed or failed).</p></li>\n</ul>\n\n<p>The earlier example can now be rewritten as follows to make it synchronous again:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">setTimeout</span> <span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"p\">),</span> <span class=\"mi\">2500</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run third&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@wait</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># ...assertion logic...</span>\n</pre>\n</div>\n\n<h3>Environments</h3>\n\n<p>Lotte uses PhantomJS to execute tests. While you may be writing tests in JavaScript and expect to be able to access the DOM of a page directly, this is not the case.</p>\n\n<p>Each test file runs in its own sandboxed environment. Each page you request also runs in a sandbox.\nYou cannot access variables across environments, i.e., you cannot define a variable in your test file and access it within the page you have just requested:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Sandbox&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">val = </span><span class=\"s\">&#39;value&#39;</span>\n    <span class=\"c1\"># following line throws an exception</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"k\">return</span> <span class=\"nx\">val</span><span class=\"p\">))</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<p>In the above code snippet <code>@page.evaluate</code> runs the function as if it were defined on the page you just requested, i.e, <code>github.com</code>.\nIn order to do so, PhantomJS serializes the function, but it does not include the context in which it was defined.\nWhen the function is executed, <code>val</code> is missing in the new context causing it to throw an exception.</p>\n\n<p>Another limitation of PhantomJS is the fact you cannot return complex types from the page.\nObjects are serialized before they leave the page sandbox and unserialized back in the parent (test case) environment:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;serialize/unserialize&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">h1 = </span><span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"k\">return</span> <span class=\"nb\">document</span><span class=\"p\">.</span><span class=\"nx\">querySelector</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">))</span>\n    <span class=\"c1\"># prints &#39;H1&#39; correctly</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">h1</span><span class=\"p\">.</span><span class=\"nx\">tagName</span>\n    <span class=\"c1\"># prints &#39;undefined&#39; as functions cannot be serialized/unserialized</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">h1</span><span class=\"p\">.</span><span class=\"nx\">focus</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<p>Lotte comes with a workaround which allows you to pass variables to the PhantomJS environment.\nThis hack has the same limitations as outlined above (it uses <code>JSON.stringify</code> internally):</p>\n\n<ul>\n<li><p><strong><code>@using(hash, block)</code></strong></p>\n\n<p><code>hash</code> is a <code>key: value</code> object where:</p>\n\n<ul>\n<li><code>key</code> must be a valid identifier and defines the name of the variable within the PhantomJS environment</li>\n<li><code>value</code> must be serializable and contains the value of the variable</li>\n</ul>\n\n<p><code>block</code> is either a function or a string.</p>\n\n<p>Returns a <code>Function</code> string with all <code>key: value</code> pairs from <code>hash</code> as arguments.</p></li>\n</ul>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;@using(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">expected = </span><span class=\"s\">&#39;git&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h2&#39;</span><span class=\"p\">).</span><span class=\"nx\">first</span> <span class=\"nx\">@using</span> <span class=\"p\">{</span> <span class=\"nx\">expected</span> <span class=\"p\">},</span> <span class=\"nf\">(element) -&gt;</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">innerHTML</span><span class=\"p\">.</span><span class=\"nx\">indexOf</span><span class=\"p\">(</span><span class=\"nx\">expected</span><span class=\"p\">)</span> <span class=\"o\">is</span> <span class=\"mi\">0</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h4>Document Queries</h4>\n\n<p>There is a lot of boilerplate code required to access the DOM of a page.\nLotte comes with a jQuery-like query function to abstract some of the most common operations:</p>\n\n<ul>\n<li><p><strong><code>@$(selector)</code></strong></p>\n\n<p><code>selector</code> is a string containing a selector expression.</p>\n\n<p>Returns a <code>DocumentQuery</code> object.</p></li>\n</ul>\n\n<p>The earlier example can now be rewritten as follows:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Document Queries&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># prints &#39;H1&#39; correctly</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">tagName</span>\n    <span class=\"c1\"># prints &#39;undefined&#39;</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">focus</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h5>Additional Methods</h5>\n\n<p>A <code>DocumentQuery</code> object has the following methods to deal with the DOM:</p>\n\n<ul>\n<li><p><strong><code>DocumentQuery.prototype.attr([index], property)</code></strong></p>\n\n<p>Gets the value of <code>property</code> for the element at <code>index</code>.</p>\n\n<p>The following code snippets are equivalent:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">attr</span><span class=\"p\">(</span><span class=\"s\">&#39;tagName&#39;</span><span class=\"p\">)</span>\n<span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">tagName</span>\n</pre>\n</div>\n\n<p>The direct property access always returns the property value for the first matched element.</p>\n\n<p>While you can use <code>attr(..)</code> to access any property, the direct access will only work with the following pre-defined list of properties: <code>action</code>, <code>alt</code>, <code>checked</code>, <code>className</code>, <code>clientHeight</code>, <code>clientLeft</code>, <code>clientTop</code>, <code>clientWidth</code>, <code>disabled</code>, <code>enctype</code>, <code>height</code>, <code>href</code>, <code>id</code>, <code>innerHTML</code>, <code>length</code>, <code>maxLength</code>, <code>media</code>, <code>method</code>, <code>name</code>, <code>nodeName</code>, <code>nodeValue</code>, <code>offsetHeight</code>, <code>offsetLeft</code>, <code>offsetTop</code>, <code>offsetWidth</code>, <code>options</code>, <code>outerHTML</code>, <code>outerText</code>, <code>readOnly</code>, <code>rel</code>, <code>scrollHeight</code>, <code>scrollLeft</code>, <code>scrollTop</code>, <code>scrollWidth</code>, <code>selectedIndex</code>, <code>size</code>, <code>src</code>, <code>style</code>, <code>tagName</code>, <code>target</code>, <code>textContent</code>, <code>title</code>, <code>type</code>, <code>value</code>, <code>width</code>.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.click([index], [message], [block])</code></strong></p>\n\n<p>Clicks on the element at <code>index</code> and returns execution to the test case (i.e., asynchronous). This method can be used to simulate mouse input.</p>\n\n<p><code>index</code> is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.<br>\n<code>message</code> is an optional message to display if something goes wrong, i.e., if no elements were matched.<br>\n<code>block</code> is an optional function to execute when the new page has loaded, i.e., when you follow an anchor.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;click(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># prints https://github.com/</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"s\">&#39;I am now on: &#39;</span> <span class=\"o\">+</span> <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"nx\">location</span><span class=\"p\">.</span><span class=\"nx\">href</span><span class=\"p\">))</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.signup-button&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># prints https://github.com/plans</span>\n      <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"s\">&#39;I am now on: &#39;</span> <span class=\"o\">+</span> <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"nx\">location</span><span class=\"p\">.</span><span class=\"nx\">href</span><span class=\"p\">))</span>\n      <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div></li>\n<li><p><strong><code>DocumentQuery.prototype.input(value, [index], [message])</code></strong></p>\n\n<p>Inputs <code>value</code> in the element at <code>index</code>. This method can be used to simulate keyboard input.</p>\n\n<p><code>value</code> is a string to input as if it were keyboard input.<br>\n<code>index</code> is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.<br>\n<code>message</code> is an optional message to display if something goes wrong, i.e., if no elements were matched.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;http://www.google.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;input(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;[name=&quot;q&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;meaning of life&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;input[type=&quot;submit&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;#res&#39;</span><span class=\"p\">).</span><span class=\"nx\">attr</span><span class=\"p\">(</span><span class=\"s\">&#39;innerText&#39;</span><span class=\"p\">)</span>\n      <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div></li>\n</ul>\n\n<p>See <strong>DOM Assertions</strong> below for additional methods.</p>\n\n<h3>Assertions</h3>\n\n<p>Lotte comes with two types of assertion logic:</p>\n\n<ul>\n<li>Generic assertions</li>\n<li>DOM assertions</li>\n</ul>\n\n<h4>Generic Assertions</h4>\n\n<p>If you have used Node&#39;s built-in <a href=\"http://nodejs.org/docs/v0.6.0/api/assert.html\">assert</a> module, these functions will be familiar:</p>\n\n<ul>\n<li><p><strong><code>@assert.fail(actual, expected, message, operator)</code></strong></p>\n\n<p>Throws an exception that displays the values for <code>actual</code> and <code>expected</code> separated by the provided <code>operator</code>.</p></li>\n<li><p><strong><code>@assert.ok(value, message)</code></strong></p>\n\n<p>Tests if <code>value</code> is a true value, it is equivalent to <code>@assert.equal(true, value, message)</code>.</p></li>\n<li><p><strong><code>@assert.equal(actual, expected, message)</code></strong></p>\n\n<p>Tests shallow, coercive equality with the equal comparison operator <code>==</code>.</p></li>\n<li><p><strong><code>@assert.notEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests shallow, coercive non-equality with the not equal comparison operator <code>!=</code>.</p></li>\n<li><p><strong><code>@assert.deepEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests for deep equality.</p></li>\n<li><p><strong><code>@assert.notDeepEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests for any deep inequality.</p></li>\n<li><p><strong><code>@assert.strictEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests strict equality, as determined by the strict equality operator <code>===</code>.</p></li>\n<li><p><strong><code>@assert.notStrictEqua(actual, expected, message)</code></strong></p>\n\n<p>Tests strict non-equality, as determined by the strict not equal operator <code>!==</code>.</p></li>\n<li><p><strong><code>@assert.throws(block, error, message)</code></strong></p>\n\n<p>Expects <code>block</code> to throw an error. <code>error</code> can be constructor, RegExp or validation function.</p></li>\n<li><p><strong><code>@assert.doesNotThrow(block, error, message)</code></strong></p>\n\n<p>Expects <code>block</code> not to throw an error, see <code>@assert.throws</code> for details.</p></li>\n<li><p><strong><code>@assert.contains(actual, expected, message)</code></strong></p>\n\n<p>Expects <code>actual</code> to contain <code>expected</code>. <code>expected</code> can be a string or a RegExp.</p></li>\n</ul>\n\n<h4>DOM Assertions</h4>\n\n<p><code>DocumentQuery</code> (see above) comes with additional methods to deal with assertions:</p>\n\n<ul>\n<li><p><strong><code>DocumentQuery.prototype.contains([message], pattern)</code></strong></p>\n\n<p>Expects at least one of the matched elements to contain <code>pattern</code>. <code>pattern</code> can be a string or a RegExp.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.each([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> on each matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.first([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the first matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.last([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the last matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.nth(index, [message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the element at <code>index</code> as an argument returns a true value.</p></li>\n</ul>\n\n<p>A general note which applies to all functions above: you cannot access variables from scope within <code>block</code> (see <strong>Environments</strong>).</p>\n\n<p>An example test file that performs DOM assertions could look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Navigation and children have classes&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.nav&#39;</span><span class=\"p\">).</span><span class=\"nx\">first</span>   <span class=\"nf\">(element) -&gt;</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">classList</span><span class=\"p\">.</span><span class=\"nx\">contains</span><span class=\"p\">(</span><span class=\"s\">&#39;logged_out&#39;</span><span class=\"p\">)</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.nav li&#39;</span><span class=\"p\">).</span><span class=\"nx\">each</span> <span class=\"nf\">(element) -&gt;</span> <span class=\"o\">!!</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">className</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h2>Passing Tests</h2>\n\n<p>So far we have ended tests with <code>throw &#39;exit&#39;</code>. To pass a test case, use the following functions:</p>\n\n<ul>\n<li><p><strong><code>@success()</code></strong></p>\n\n<p>Marks the test case as passed. You must call this once within each <code>@describe</code> block.</p></li>\n</ul>\n\n<p>If you don&#39;t end a test case either by failing any of the asserts or calling <code>@success()</code>, the entire test file will hang until <code>timeout</code> is reached at which point it is recorded as failed.</p>\n\n<h2>FAQs</h2>\n\n<ul>\n<li><p><strong>Q</strong>: How can I log in before requesting a page?</p>\n\n<p><strong>A</strong>: You can nest <code>@open(..)</code> functions to achieve this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@base</span> <span class=\"s\">&#39;http://local.dev&#39;</span>\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/login&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Log in&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.username&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;admin&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.password&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;password&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;input[type=&quot;submit&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"nx\">@success</span><span class=\"p\">()</span>\n      <span class=\"nx\">@open</span> <span class=\"s\">&#39;/account&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n        <span class=\"nx\">@describe</span> <span class=\"s\">&#39;My Account&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n          <span class=\"c1\"># ...assertion logic...</span>\n          <span class=\"nx\">@success</span><span class=\"p\">()</span>\n</pre>\n</div></li>\n<li><p><strong>Q</strong>: Can I pass arguments to my tests?</p>\n\n<p><strong>A</strong>: Yes. Use <code>--</code> on the command-line followed by the arguments:</p>\n<div class=\"highlight\"><pre>$ lotte -- arg1 arg2\n</pre>\n</div>\n\n<p>Arguments will be available in your test files as <code>phantom.args[..]</code>.</p></li>\n<li><p><strong>Q</strong>: How can I see what PhantomJS &#39;sees&#39;?</p>\n\n<p><strong>A</strong>: Within the context of a test case (<code>@describe</code>), you can refer to <code>@page</code> which is the PhantomJS <a href=\"http://code.google.com/p/phantomjs/wiki/Interface#&#x27;_WebPage_&#x27;_Object\">WebPage</a> object.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;snapshot&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">render</span> <span class=\"s\">&#39;home.png&#39;</span>\n  <span class=\"nx\">@success</span><span class=\"p\">()</span>\n</pre>\n</div></li>\n<li><p><strong>Q</strong>: I don&#39;t have <code>phantomjs</code> and/or <code>coffee</code> on <code>$PATH</code>.</p>\n\n<p><strong>A</strong>: See <code>lotte --help</code> for information on how to specify a path to the missing binary.</p></li>\n</ul>\n\n<h2>Contributing</h2>\n\n<p>The goal of this project is to provide an awesome tool for developers to test their websites or apps in their favourite language with minimum effort.</p>\n\n<p>Commit and code reviews, ideas and documentation improvements are welcomed.</p>\n\n<h2>Changelog</h2>\n\n<h3>0.2</h3>\n\n<ul>\n<li><a href=\"https://github.com/StanAngeloff/lotte/commit/74aee9c\">74aee9c</a> - Drop &#39;findit&#39; and use &#39;walkdir&#39;, support Windows.</li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/commit/4ab5679\">4ab5679</a> - Bump dependencies versions in package.json and address deprecations.</li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/commit/8a49077\">8a49077</a> - Address deprecation &ldquo;<code>path.exists</code> is now called <code>fs.exists</code>.&rdquo;</li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/commit/1189ae6\">1189ae6</a> - Add (verified) support for PhantomJS 1.6.x.</li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/commit/4c9d441\">4c9d441</a> - Emit &#39;compile&#39; to allow hooks to modify the code before it&#39;s compiled.</li>\n</ul>\n\n<h3>Copyright</h3>\n\n<blockquote>\n<p>Copyright &copy; 2011 Stan Angeloff. See <a href=\"https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md\">LICENSE.md</a> for details.</p>\n</blockquote>\n\n</article>\n\n<style>/* normalize.css 2012-07-07T09:50 UTC - http://github.com/necolas/normalize.css */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:0.67em 0}h2{font-size:1.5em;margin:0.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:0.83em;margin:1.67em 0}h6{font-size:0.75em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:1em 40px}dfn{font-style:italic}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace, serif;_font-family:'courier new', monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:75%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,html input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=\"checkbox\"],input[type=\"radio\"]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=\"search\"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=\"search\"]::-webkit-search-cancel-button,input[type=\"search\"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}pre .hll,code .hll{background-color:#ffffcc}pre .c,code .c{color:#999988}pre .err,code .err{color:#a61717;background-color:#e3d2d2}pre .k,code .k{color:#000000}pre .o,code .o{color:#000000}pre .cm,code .cm{color:#999988}pre .cp,code .cp{color:#999999}pre .c1,code .c1{color:#999988}pre .cs,code .cs{color:#999999}pre .gd,code .gd{color:#000000;background-color:#ffdddd}pre .ge,code .ge{color:#000000}pre .gr,code .gr{color:#aa0000}pre .gh,code .gh{color:#999999}pre .gi,code .gi{color:#000000;background-color:#ddffdd}pre .go,code .go{color:#888888}pre .gp,code .gp{color:#555555}pre .gu,code .gu{color:#aaaaaa}pre .gt,code .gt{color:#aa0000}pre .kc,code .kc{color:#000000}pre .kd,code .kd{color:#000000}pre .kn,code .kn{color:#000000}pre .kp,code .kp{color:#000000}pre .kr,code .kr{color:#000000}pre .kt,code .kt{color:#445588}pre .m,code .m{color:#009999}pre .s,code .s{color:#d01040}pre .na,code .na{color:#008080}pre .nb,code .nb{color:#0086B3}pre .nc,code .nc{color:#445588}pre .no,code .no{color:#008080}pre .nd,code .nd{color:#3c5d5d}pre .ni,code .ni{color:#800080}pre .ne,code .ne{color:#990000}pre .nf,code .nf{color:#990000}pre .nl,code .nl{color:#990000}pre .nn,code .nn{color:#555555}pre .nt,code .nt{color:#000080}pre .nv,code .nv{color:#008080}pre .ow,code .ow{color:#000000}pre .w,code .w{color:#bbbbbb}pre .mf,code .mf{color:#009999}pre .mh,code .mh{color:#009999}pre .mi,code .mi{color:#009999}pre .mo,code .mo{color:#009999}pre .sb,code .sb{color:#d01040}pre .sc,code .sc{color:#d01040}pre .sd,code .sd{color:#d01040}pre .s2,code .s2{color:#d01040}pre .se,code .se{color:#d01040}pre .sh,code .sh{color:#d01040}pre .si,code .si{color:#d01040}pre .sx,code .sx{color:#d01040}pre .sr,code .sr{color:#009926}pre .s1,code .s1{color:#d01040}pre .ss,code .ss{color:#990073}pre .bp,code .bp{color:#999999}pre .vc,code .vc{color:#008080}pre .vg,code .vg{color:#008080}pre .vi,code .vi{color:#008080}pre .il,code .il{color:#009999}html{font-size:100%;line-height:1.4em}html,button,input,select,textarea{font-family:\"PT Sans\",\"Lucida Grande\",\"Lucida Sans Unicode\",\"Lucida Sans\",\"Droid Sans\",tahoma,verdana,arial,sans-serif}h1,h2,h3,h4,h5,h6{font-family:\"Palatino Linotype\",Palatino,\"Book Antiqua\",\"URW Palladio L\",Cambria,Georgia,\"Times New Roman\",times,serif}code,kbd,pre,samp{font-family:Inconsolata,Consolas,Menlo,\"Liberation Mono\",\"Courier New\",courier,monospace}html{background-color:#fff;color:#101010;height:100.1%;overflow-y:scroll}h1,h2,h3,h4,h5,h6{line-height:140%}small{color:#505050}pre{background-color:rgba(0,51,102,0.043);border:0.105em solid rgba(0,51,102,0.085);-webkit-border-radius:0.35em;-moz-border-radius:0.35em;-ms-border-radius:0.35em;-o-border-radius:0.35em;border-radius:0.35em;padding:0.7em;-webkit-box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17);-moz-box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17);box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17)}code{background-color:rgba(0,51,102,0.043);border:0.105em solid rgba(0,51,102,0.085);-webkit-border-radius:0.175em;-moz-border-radius:0.175em;-ms-border-radius:0.175em;-o-border-radius:0.175em;border-radius:0.175em;padding:0.105em 0.175em;-webkit-box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17);-moz-box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17);box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17)}pre code{background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0;padding:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}blockquote{margin-left:0;padding-left:1.05em;border-left:0.175em solid #e6e6e6;font-style:italic}#page{*zoom:1;max-width:60.5em;margin-left:auto;margin-right:auto;padding-left:1em;padding-right:1em;border-top:0.175em solid #404040;border-bottom:0.35em solid #404040;padding-bottom:1.4em}#page:after{content:\"\";display:table;clear:both}#page>header aside{float:right;margin-left:0.7em}#page>footer{text-align:right}#page>footer small{line-height:100%}.unstyled{list-style:none}.unstyled li{list-style-image:none;list-style-type:none;margin-left:0}.inline{margin:0;padding:0}.inline,.inline li{display:-moz-inline-stack;display:inline-block;vertical-align:middle;*vertical-align:auto;zoom:1;*display:inline}.inline a{border-bottom:0}.long{margin:0;padding:0}.long li{margin-bottom:0.7em}a{text-decoration:none;border-bottom:0.105em solid rgba(16,16,16,0.125)}#page .gist .gist-file{border:0}#page .gist .gist-file,#page .gist .gist-file .gist-data pre{font-family:Inconsolata,Consolas,Menlo,\"Liberation Mono\",\"Courier New\",courier,monospace}#page .gist .gist-file .gist-data pre{padding:0.7em !important;background-color:rgba(0,51,102,0.043) !important}#page .gist .gist-syntax{background-color:transparent;border-bottom:0}#page .gist .gist-syntax *{font-style:normal;font-weight:normal}#page .gist .gist-meta{background-color:transparent}#disqus_thread{margin-top:1.4em;margin-bottom:1.4em;font-family:\"PT Sans\",\"Lucida Grande\",\"Lucida Sans Unicode\",\"Lucida Sans\",\"Droid Sans\",tahoma,verdana,arial,sans-serif}</style>\n\n</body>\n</html>\n","_id":"lotte@0.2.0-1","dist":{"shasum":"dfff0728d4b1e783d93478108d59cd09d13214df","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.2.0-1.tgz","integrity":"sha512-uI4nxusKmDj3aJ0H1YJjuY4Ug1iEqA4uOtl6m5u3anZ5cyQ0zdKFhcxUFpJL8bvAED1ZAM+9PJCjO0PtpV283Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD+7APZdlUfqBooOmM003ULF95hh+gA3A8RDFCN+9pD+QIgGEE3jqnAY9xgO4KkNJ7shKydiCVKWkPeGVSDWRH5j1U="}]},"_npmVersion":"1.1.59","_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}]},"0.2.1":{"name":"lotte","version":"0.2.1","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":"https://github.com/StanAngeloff/lotte/issues","author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["bin/","lib/","test/"],"bin":{"lotte":"bin/cli.js"},"main":"lib/lotte.js","repository":{"type":"git","url":"https://github.com/StanAngeloff/lotte"},"dependencies":{"minimatch":"~0.2.6","naturalsort":"~0.0.1","optimist":"~0.3.4","semver":"~1.0.14","tmp":"~0.0.14","walkdir":"~0.0.4"},"devDependencies":{"express":"~3.0.0"},"engines":{"node":">=0.8"},"preferGlobal":true,"readme":"<!doctype html>\n<html lang=en>\n<head>\n  <meta charset=utf-8>\n  <title>Lotte</title>\n</head>\n<body>\n\n<article id=page>\n<h1>Lotte</h1>\n\n<p>Lotte is a headless, automated testing framework built on top of <a href=\"http://www.phantomjs.org/\">PhantomJS</a> and inspired by <a href=\"https://github.com/joshbuddy/ghostbuster\">Ghostbuster</a>.\nIt adds jQuery-like methods and chaining, more assertion logic and an extensible core.\nTests can be written in either JavaScript or <a href=\"http://coffeescript.org/\">CoffeeScript</a>.</p>\n\n<p>Lotte comes with tools for accessing the DOM, evaluating arbitrary code, simulating mouse and keyboard input.</p>\n\n<p>Tests are sandboxed and run asynchronously. Blocking methods are available to simulate dependencies and to control the flow of execution.</p>\n\n<p>This project is still highly experimental. Using it may cause your computer to blow up. <a href=\"https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md\">Seriously.</a></p>\n\n<h2>Prerequisites</h2>\n\n<ul>\n<li><a href=\"http://nodejs.org/\">node.js</a> <strong>&gt;=0.4.10</strong></li>\n<li><a href=\"http://npmjs.org/\">npm</a> <strong>~1.0</strong></li>\n<li><a href=\"http://www.phantomjs.org/\">PhantomJS</a> <strong>~1.3.0</strong></li>\n</ul>\n\n<h3>Optional Dependencies</h3>\n\n<ul>\n<li><a href=\"http://coffeescript.org/\">CoffeeScript</a></li>\n</ul>\n\n<h2>Installation</h2>\n<div class=\"highlight\"><pre>$ npm -g install lotte\n</pre>\n</div>\n\n<p><code>-g</code>lobal is preferred so you can run <code>lotte</code> from any directory.</p>\n\n<h2>Usage</h2>\n\n<p>Create a new file <code>lotte_github.js</code> (preferably in an empty directory) and copy the following code:</p>\n<div class=\"highlight\"><pre><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">open</span><span class=\"p\">(</span><span class=\"s1\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"kd\">function</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">describe</span><span class=\"p\">(</span><span class=\"s1\">&#39;Sign Up button&#39;</span><span class=\"p\">,</span> <span class=\"kd\">function</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n    <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">assert</span><span class=\"p\">.</span><span class=\"nx\">ok</span><span class=\"p\">(</span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">$</span><span class=\"p\">(</span><span class=\"s1\">&#39;.signup-button&#39;</span><span class=\"p\">).</span><span class=\"nx\">length</span><span class=\"p\">,</span> <span class=\"s1\">&#39;expects button to be in the DOM&#39;</span><span class=\"p\">);</span>\n    <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">success</span><span class=\"p\">();</span>\n  <span class=\"p\">});</span>\n<span class=\"p\">});</span>\n</pre>\n</div>\n\n<p>Run <code>lotte</code> from within the directory and you should see the following output:</p>\n<div class=\"highlight\"><pre>/tmp/lotte_github.js\n  @ https://github.com\n      ✓ Sign Up button\n</pre>\n</div>\n\n<h2>Command-Line Options</h2>\n\n<p>You can customise many aspects of Lotte&#39;s behaviour either on the command-line on through <code>Lottefile</code>s. The following options are available:</p>\n<div class=\"highlight\"><pre>$ lotte --help\nUsage: lotte [OPTION...] PATH\n\nOptions:\n  --help, -h        give this help page\n  --version, -v     print program version\n  --concurrent, -c  limit of files to run in parallel                       [default: 4]\n  --timeout, -t     timeout for individual files (in milliseconds)          [default: 30000]\n  --include, -I     glob pattern to match files in PATH          [string]   [default: &quot;**/lotte_*.js&quot;]\n  --exclude, -E     glob pattern to remove included files        [string]\n  --lottefile, -f   look for &#39;lottefile&#39; in PATH                 [string]   [default: &quot;Lottefile&quot;]\n  --verify          verify PhantomJS version (expected ~1.3.0)   [boolean]  [default: true]\n  --phantom         executable for PhantomJS                     [string]   [default: &quot;phantomjs&quot;]\n  --coffee          executable for CofeeScript                   [string]   [default: &quot;coffee&quot;]\n</pre>\n</div>\n\n<p>There are four key options you would want to customise while the rest should work with their defaults.</p>\n\n<ul>\n<li><p><strong><code>--concurrent, -c</code></strong></p>\n\n<p>If you have more than one test file in a directory, Lotte will attempt to run them in parallel (asynchronously).\nYou can specify how many tests can be running at any given time through this option.</p>\n\n<p>If you want to run tests synchronously, specify a value of <code>1</code>.</p></li>\n<li><p><strong><code>--timeout, -t</code></strong></p>\n\n<p>Each test is expected to finish within a given period of time. If a test takes longer, it is interruped and recorded as failed.</p>\n\n<p>The default value is <code>30</code> seconds, but you should consider reducing it.</p></li>\n<li><p><strong><code>--include, -I</code><br>\n<code>--exclude, -E</code></strong></p>\n\n<p>When you run <code>lotte</code> from any directory the script collects a list of all files in the current directory and all sub-directories.\nThe list is reduced by running the <code>include</code> glob pattern and dropping any files that did not match.\nThe list is then reduced further by running the <code>exclude</code> glob pattern and dropping any files that did match.\nThe remaining list is sorted and considered final.</p>\n\n<p>You can specify these arguments more than once to create an array of include/exclude patterns.</p></li>\n</ul>\n\n<h3>Lottefile</h3>\n\n<p>In order to avoid having to type the full <code>lotte</code> command-line each time, you can use <code>Lottefile</code>s to store your settings per project.</p>\n\n<p><code>Lottefile</code>s are regular JavaScript files where each global variable maps to a command-line option. For example, the following command:</p>\n<div class=\"highlight\"><pre>$ lotte --include &#39;**/*.coffee&#39; --include &#39;**/*.js&#39; --concurrent 1 tests\n</pre>\n</div>\n\n<p>can be stored in a <code>Lottefile</code> as this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">path</span>       <span class=\"o\">=</span> <span class=\"s1\">&#39;tests&#39;</span>\n<span class=\"nx\">include</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;**/*.coffee&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;**/*.js&#39;</span><span class=\"p\">]</span>\n<span class=\"nx\">concurrent</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n</pre>\n</div>\n\n<p>Running <code>lotte</code> from the project directory will then read the <code>Lottefile</code> and scan the <code>tests</code> directory for all files matching <code>**/*.{coffee,js}</code>.</p>\n\n<h2>Writing Tests</h2>\n\n<p>Tests can be written in either JavaScript or CoffeeScript.\nIn the sections below substitute <code>@</code> with <code>this.</code> if you are using JavaScript.\nArguments wrapped in square brackets <code>[</code> and <code>]</code> are optional.\nArguments ending in <code>...</code> can be used more than once.</p>\n\n<p>At the top-level, the following functions are available:</p>\n\n<ul>\n<li><p><strong><code>@title([name])</code></strong></p>\n\n<p>Gets or sets the test title.\nThis is useful for giving meaningful names to your tests.</p>\n\n<p>When called with zero arguments, returns the current title or <code>undefined</code>.<br>\nWhen called with one argument, sets the title.</p>\n\n<p>If you don&#39;t explicitly specify a title, the filename will be used instead.</p></li>\n<li><p><strong><code>@base([uri])</code></strong></p>\n\n<p>Gets or sets the absolute URI for all relative URIs in the test.\nYou can use this to specify the root URI for your project.</p>\n\n<p>When called with zero arguments, returns the current URI or <code>undefined</code>.<br>\nWhen called with one argument, sets the URI.</p>\n\n<p>If you don&#39;t explicitly specify an absolute URI, all calls to <code>@open</code> will expect an absolute URI instead.</p></li>\n<li><p><strong><code>@open(uri, [message], [options], block)</code></strong></p>\n\n<p>Creates a new test.</p>\n\n<p><code>uri</code> can be either an absolute or relative URI (see above).<br>\n<code>message</code> is an optional description for the URI. If you don&#39;t specify it, Lotte will print the <code>uri</code> in the output instead.<br>\n<code>options</code> is an object hash to pass to PhantomJS. See <a href=\"http://code.google.com/p/phantomjs/wiki/Interface#settings_(object)\">settings (object)</a>.<br>\n<code>block</code> is a function which is executed if the server returns a valid response (2xx or 3xx).</p>\n\n<p>If the server returns a 4xx or 5xx HTTP code instead, the test is recorded as failed.</p>\n\n<p>If you have more than one <code>@open</code> call at the top-level, they will be executed asynchronously.</p></li>\n</ul>\n\n<p>Putting it all together, a test file could look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@title</span> <span class=\"s\">&#39;Github&#39;</span>\n<span class=\"nx\">@base</span>  <span class=\"s\">&#39;https://github.com&#39;</span>\n\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/&#39;</span><span class=\"p\">,</span> <span class=\"s\">&#39;the homepage&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"c1\"># ...body of test...</span>\n</pre>\n</div>\n\n<h3>Cases &amp; Grouping</h3>\n\n<p>Once you have successfully requested an URI, you can start writing test cases against the page.</p>\n\n<p>The following functions are available:</p>\n\n<ul>\n<li><p><strong><code>@group(name, block)</code></strong></p>\n\n<p>Groups the nested test cases. This is mainly for structuring the output Lotte prints.</p>\n\n<p><code>name</code> is the name of the group.<br>\n<code>block</code> is a function which contains the nested test cases.</p></li>\n<li><p><strong><code>@describe(name, block)</code></strong></p>\n\n<p>Starts a new test case.</p>\n\n<p><code>name</code> is the name of the test case.<br>\n<code>block</code> is a function which is executed and is expected to contain assertion logic.</p></li>\n</ul>\n\n<p>Putting it all together a test file could now look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@title</span> <span class=\"s\">&#39;Github&#39;</span>\n<span class=\"nx\">@base</span>  <span class=\"s\">&#39;https://github.com&#39;</span>\n\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/&#39;</span><span class=\"p\">,</span> <span class=\"s\">&#39;the homepage&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;counter shows number of repositories&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># ...assertion logic...</span>\n  <span class=\"nx\">@group</span> <span class=\"s\">&#39;Sign Up button&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@describe</span> <span class=\"s\">&#39;is in place&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># ...assertion logic...</span>\n    <span class=\"nx\">@describe</span> <span class=\"s\">&#39;takes you to /plans&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># ...assertion logic...</span>\n</pre>\n</div>\n\n<h4>Flow of Execution</h4>\n\n<p>Each test case is executed in the order in which it is defined:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"c1\"># etc.</span>\n</pre>\n</div>\n\n<p>If a test case contains an asynchronous function call, the next test case is executed without waiting for the function to finish:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">setTimeout</span> <span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"p\">),</span> <span class=\"mi\">2500</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run third in parallel with second still running&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n</pre>\n</div>\n\n<p>Be extremely careful when dealing with asynchronous function. For example, using <code>.click()</code> to follow an anchor could change the page while another test case is running.</p>\n\n<p>If a test case fails, any remaining test cases are skipped:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"k\">throw</span> <span class=\"s\">&#39;Whoops!&#39;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I should run second, but I never will&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n</pre>\n</div>\n\n<p>To simulate dependencies and control the flow of execution, you can use the following functions:</p>\n\n<ul>\n<li><p><strong><code>@wait(name..., block)</code></strong></p>\n\n<p>Blocks the current test case until all dependencies have finished (either passed or failed).</p></li>\n</ul>\n\n<p>The earlier example can now be rewritten as follows to make it synchronous again:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">setTimeout</span> <span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"p\">),</span> <span class=\"mi\">2500</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run third&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@wait</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># ...assertion logic...</span>\n</pre>\n</div>\n\n<h3>Environments</h3>\n\n<p>Lotte uses PhantomJS to execute tests. While you may be writing tests in JavaScript and expect to be able to access the DOM of a page directly, this is not the case.</p>\n\n<p>Each test file runs in its own sandboxed environment. Each page you request also runs in a sandbox.\nYou cannot access variables across environments, i.e., you cannot define a variable in your test file and access it within the page you have just requested:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Sandbox&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">val = </span><span class=\"s\">&#39;value&#39;</span>\n    <span class=\"c1\"># following line throws an exception</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"k\">return</span> <span class=\"nx\">val</span><span class=\"p\">))</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<p>In the above code snippet <code>@page.evaluate</code> runs the function as if it were defined on the page you just requested, i.e, <code>github.com</code>.\nIn order to do so, PhantomJS serializes the function, but it does not include the context in which it was defined.\nWhen the function is executed, <code>val</code> is missing in the new context causing it to throw an exception.</p>\n\n<p>Another limitation of PhantomJS is the fact you cannot return complex types from the page.\nObjects are serialized before they leave the page sandbox and unserialized back in the parent (test case) environment:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;serialize/unserialize&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">h1 = </span><span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"k\">return</span> <span class=\"nb\">document</span><span class=\"p\">.</span><span class=\"nx\">querySelector</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">))</span>\n    <span class=\"c1\"># prints &#39;H1&#39; correctly</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">h1</span><span class=\"p\">.</span><span class=\"nx\">tagName</span>\n    <span class=\"c1\"># prints &#39;undefined&#39; as functions cannot be serialized/unserialized</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">h1</span><span class=\"p\">.</span><span class=\"nx\">focus</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<p>Lotte comes with a workaround which allows you to pass variables to the PhantomJS environment.\nThis hack has the same limitations as outlined above (it uses <code>JSON.stringify</code> internally):</p>\n\n<ul>\n<li><p><strong><code>@using(hash, block)</code></strong></p>\n\n<p><code>hash</code> is a <code>key: value</code> object where:</p>\n\n<ul>\n<li><code>key</code> must be a valid identifier and defines the name of the variable within the PhantomJS environment</li>\n<li><code>value</code> must be serializable and contains the value of the variable</li>\n</ul>\n\n<p><code>block</code> is either a function or a string.</p>\n\n<p>Returns a <code>Function</code> string with all <code>key: value</code> pairs from <code>hash</code> as arguments.</p></li>\n</ul>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;@using(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">expected = </span><span class=\"s\">&#39;git&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h2&#39;</span><span class=\"p\">).</span><span class=\"nx\">first</span> <span class=\"nx\">@using</span> <span class=\"p\">{</span> <span class=\"nx\">expected</span> <span class=\"p\">},</span> <span class=\"nf\">(element) -&gt;</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">innerHTML</span><span class=\"p\">.</span><span class=\"nx\">indexOf</span><span class=\"p\">(</span><span class=\"nx\">expected</span><span class=\"p\">)</span> <span class=\"o\">is</span> <span class=\"mi\">0</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h4>Document Queries</h4>\n\n<p>There is a lot of boilerplate code required to access the DOM of a page.\nLotte comes with a jQuery-like query function to abstract some of the most common operations:</p>\n\n<ul>\n<li><p><strong><code>@$(selector)</code></strong></p>\n\n<p><code>selector</code> is a string containing a selector expression.</p>\n\n<p>Returns a <code>DocumentQuery</code> object.</p></li>\n</ul>\n\n<p>The earlier example can now be rewritten as follows:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Document Queries&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># prints &#39;H1&#39; correctly</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">tagName</span>\n    <span class=\"c1\"># prints &#39;undefined&#39;</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">focus</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h5>Additional Methods</h5>\n\n<p>A <code>DocumentQuery</code> object has the following methods to deal with the DOM:</p>\n\n<ul>\n<li><p><strong><code>DocumentQuery.prototype.attr([index], property)</code></strong></p>\n\n<p>Gets the value of <code>property</code> for the element at <code>index</code>.</p>\n\n<p>The following code snippets are equivalent:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">attr</span><span class=\"p\">(</span><span class=\"s\">&#39;tagName&#39;</span><span class=\"p\">)</span>\n<span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">tagName</span>\n</pre>\n</div>\n\n<p>The direct property access always returns the property value for the first matched element.</p>\n\n<p>While you can use <code>attr(..)</code> to access any property, the direct access will only work with the following pre-defined list of properties: <code>action</code>, <code>alt</code>, <code>checked</code>, <code>className</code>, <code>clientHeight</code>, <code>clientLeft</code>, <code>clientTop</code>, <code>clientWidth</code>, <code>disabled</code>, <code>enctype</code>, <code>height</code>, <code>href</code>, <code>id</code>, <code>innerHTML</code>, <code>length</code>, <code>maxLength</code>, <code>media</code>, <code>method</code>, <code>name</code>, <code>nodeName</code>, <code>nodeValue</code>, <code>offsetHeight</code>, <code>offsetLeft</code>, <code>offsetTop</code>, <code>offsetWidth</code>, <code>options</code>, <code>outerHTML</code>, <code>outerText</code>, <code>readOnly</code>, <code>rel</code>, <code>scrollHeight</code>, <code>scrollLeft</code>, <code>scrollTop</code>, <code>scrollWidth</code>, <code>selectedIndex</code>, <code>size</code>, <code>src</code>, <code>style</code>, <code>tagName</code>, <code>target</code>, <code>textContent</code>, <code>title</code>, <code>type</code>, <code>value</code>, <code>width</code>.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.click([index], [message], [block])</code></strong></p>\n\n<p>Clicks on the element at <code>index</code> and returns execution to the test case (i.e., asynchronous). This method can be used to simulate mouse input.</p>\n\n<p><code>index</code> is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.<br>\n<code>message</code> is an optional message to display if something goes wrong, i.e., if no elements were matched.<br>\n<code>block</code> is an optional function to execute when the new page has loaded, i.e., when you follow an anchor.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;click(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># prints https://github.com/</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"s\">&#39;I am now on: &#39;</span> <span class=\"o\">+</span> <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"nx\">location</span><span class=\"p\">.</span><span class=\"nx\">href</span><span class=\"p\">))</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.signup-button&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># prints https://github.com/plans</span>\n      <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"s\">&#39;I am now on: &#39;</span> <span class=\"o\">+</span> <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"nx\">location</span><span class=\"p\">.</span><span class=\"nx\">href</span><span class=\"p\">))</span>\n      <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div></li>\n<li><p><strong><code>DocumentQuery.prototype.input(value, [index], [message])</code></strong></p>\n\n<p>Inputs <code>value</code> in the element at <code>index</code>. This method can be used to simulate keyboard input.</p>\n\n<p><code>value</code> is a string to input as if it were keyboard input.<br>\n<code>index</code> is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.<br>\n<code>message</code> is an optional message to display if something goes wrong, i.e., if no elements were matched.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;http://www.google.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;input(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;[name=&quot;q&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;meaning of life&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;input[type=&quot;submit&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;#res&#39;</span><span class=\"p\">).</span><span class=\"nx\">attr</span><span class=\"p\">(</span><span class=\"s\">&#39;innerText&#39;</span><span class=\"p\">)</span>\n      <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div></li>\n</ul>\n\n<p>See <strong>DOM Assertions</strong> below for additional methods.</p>\n\n<h3>Assertions</h3>\n\n<p>Lotte comes with two types of assertion logic:</p>\n\n<ul>\n<li>Generic assertions</li>\n<li>DOM assertions</li>\n</ul>\n\n<h4>Generic Assertions</h4>\n\n<p>If you have used Node&#39;s built-in <a href=\"http://nodejs.org/docs/v0.6.0/api/assert.html\">assert</a> module, these functions will be familiar:</p>\n\n<ul>\n<li><p><strong><code>@assert.fail(actual, expected, message, operator)</code></strong></p>\n\n<p>Throws an exception that displays the values for <code>actual</code> and <code>expected</code> separated by the provided <code>operator</code>.</p></li>\n<li><p><strong><code>@assert.ok(value, message)</code></strong></p>\n\n<p>Tests if <code>value</code> is a true value, it is equivalent to <code>@assert.equal(true, value, message)</code>.</p></li>\n<li><p><strong><code>@assert.equal(actual, expected, message)</code></strong></p>\n\n<p>Tests shallow, coercive equality with the equal comparison operator <code>==</code>.</p></li>\n<li><p><strong><code>@assert.notEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests shallow, coercive non-equality with the not equal comparison operator <code>!=</code>.</p></li>\n<li><p><strong><code>@assert.deepEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests for deep equality.</p></li>\n<li><p><strong><code>@assert.notDeepEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests for any deep inequality.</p></li>\n<li><p><strong><code>@assert.strictEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests strict equality, as determined by the strict equality operator <code>===</code>.</p></li>\n<li><p><strong><code>@assert.notStrictEqua(actual, expected, message)</code></strong></p>\n\n<p>Tests strict non-equality, as determined by the strict not equal operator <code>!==</code>.</p></li>\n<li><p><strong><code>@assert.throws(block, error, message)</code></strong></p>\n\n<p>Expects <code>block</code> to throw an error. <code>error</code> can be constructor, RegExp or validation function.</p></li>\n<li><p><strong><code>@assert.doesNotThrow(block, error, message)</code></strong></p>\n\n<p>Expects <code>block</code> not to throw an error, see <code>@assert.throws</code> for details.</p></li>\n<li><p><strong><code>@assert.contains(actual, expected, message)</code></strong></p>\n\n<p>Expects <code>actual</code> to contain <code>expected</code>. <code>expected</code> can be a string or a RegExp.</p></li>\n</ul>\n\n<h4>DOM Assertions</h4>\n\n<p><code>DocumentQuery</code> (see above) comes with additional methods to deal with assertions:</p>\n\n<ul>\n<li><p><strong><code>DocumentQuery.prototype.contains([message], pattern)</code></strong></p>\n\n<p>Expects at least one of the matched elements to contain <code>pattern</code>. <code>pattern</code> can be a string or a RegExp.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.each([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> on each matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.first([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the first matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.last([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the last matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.nth(index, [message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the element at <code>index</code> as an argument returns a true value.</p></li>\n</ul>\n\n<p>A general note which applies to all functions above: you cannot access variables from scope within <code>block</code> (see <strong>Environments</strong>).</p>\n\n<p>An example test file that performs DOM assertions could look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Navigation and children have classes&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.nav&#39;</span><span class=\"p\">).</span><span class=\"nx\">first</span>   <span class=\"nf\">(element) -&gt;</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">classList</span><span class=\"p\">.</span><span class=\"nx\">contains</span><span class=\"p\">(</span><span class=\"s\">&#39;logged_out&#39;</span><span class=\"p\">)</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.nav li&#39;</span><span class=\"p\">).</span><span class=\"nx\">each</span> <span class=\"nf\">(element) -&gt;</span> <span class=\"o\">!!</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">className</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h2>Passing Tests</h2>\n\n<p>So far we have ended tests with <code>throw &#39;exit&#39;</code>. To pass a test case, use the following functions:</p>\n\n<ul>\n<li><p><strong><code>@success()</code></strong></p>\n\n<p>Marks the test case as passed. You must call this once within each <code>@describe</code> block.</p></li>\n</ul>\n\n<p>If you don&#39;t end a test case either by failing any of the asserts or calling <code>@success()</code>, the entire test file will hang until <code>timeout</code> is reached at which point it is recorded as failed.</p>\n\n<h2>FAQs</h2>\n\n<ul>\n<li><p><strong>Q</strong>: How can I log in before requesting a page?</p>\n\n<p><strong>A</strong>: You can nest <code>@open(..)</code> functions to achieve this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@base</span> <span class=\"s\">&#39;http://local.dev&#39;</span>\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/login&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Log in&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.username&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;admin&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.password&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;password&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;input[type=&quot;submit&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"nx\">@success</span><span class=\"p\">()</span>\n      <span class=\"nx\">@open</span> <span class=\"s\">&#39;/account&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n        <span class=\"nx\">@describe</span> <span class=\"s\">&#39;My Account&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n          <span class=\"c1\"># ...assertion logic...</span>\n          <span class=\"nx\">@success</span><span class=\"p\">()</span>\n</pre>\n</div></li>\n<li><p><strong>Q</strong>: Can I pass arguments to my tests?</p>\n\n<p><strong>A</strong>: Yes. Use <code>--</code> on the command-line followed by the arguments:</p>\n<div class=\"highlight\"><pre>$ lotte -- arg1 arg2\n</pre>\n</div>\n\n<p>Arguments will be available in your test files as <code>phantom.args[..]</code>.</p></li>\n<li><p><strong>Q</strong>: How can I see what PhantomJS &#39;sees&#39;?</p>\n\n<p><strong>A</strong>: Within the context of a test case (<code>@describe</code>), you can refer to <code>@page</code> which is the PhantomJS <a href=\"http://code.google.com/p/phantomjs/wiki/Interface#&#x27;_WebPage_&#x27;_Object\">WebPage</a> object.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;snapshot&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">render</span> <span class=\"s\">&#39;home.png&#39;</span>\n  <span class=\"nx\">@success</span><span class=\"p\">()</span>\n</pre>\n</div></li>\n<li><p><strong>Q</strong>: I don&#39;t have <code>phantomjs</code> and/or <code>coffee</code> on <code>$PATH</code>.</p>\n\n<p><strong>A</strong>: See <code>lotte --help</code> for information on how to specify a path to the missing binary.</p></li>\n</ul>\n\n<h2>Contributing</h2>\n\n<p>The goal of this project is to provide an awesome tool for developers to test their websites or apps in their favourite language with minimum effort.</p>\n\n<p>Commit and code reviews, ideas and documentation improvements are welcomed.</p>\n\n<h2>Changelog</h2>\n\n<h3>0.2</h3>\n\n<ul>\n<li><a href=\"https://github.com/StanAngeloff/lotte/commit/74aee9c\">74aee9c</a> - Drop &#39;findit&#39; and use &#39;walkdir&#39;, support Windows.</li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/commit/4ab5679\">4ab5679</a> - Bump dependencies versions in package.json and address deprecations.</li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/commit/8a49077\">8a49077</a> - Address deprecation &ldquo;<code>path.exists</code> is now called <code>fs.exists</code>.&rdquo;</li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/commit/1189ae6\">1189ae6</a> - Add (verified) support for PhantomJS 1.6.x.</li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/commit/4c9d441\">4c9d441</a> - Emit &#39;compile&#39; to allow hooks to modify the code before it&#39;s compiled.</li>\n</ul>\n\n<h3>Copyright</h3>\n\n<blockquote>\n<p>Copyright &copy; 2011 Stan Angeloff. See <a href=\"https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md\">LICENSE.md</a> for details.</p>\n</blockquote>\n\n</article>\n\n<style>/* normalize.css 2012-07-07T09:50 UTC - http://github.com/necolas/normalize.css */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:0.67em 0}h2{font-size:1.5em;margin:0.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:0.83em;margin:1.67em 0}h6{font-size:0.75em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:1em 40px}dfn{font-style:italic}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace, serif;_font-family:'courier new', monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:75%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,html input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=\"checkbox\"],input[type=\"radio\"]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=\"search\"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=\"search\"]::-webkit-search-cancel-button,input[type=\"search\"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}pre .hll,code .hll{background-color:#ffffcc}pre .c,code .c{color:#999988}pre .err,code .err{color:#a61717;background-color:#e3d2d2}pre .k,code .k{color:#000000}pre .o,code .o{color:#000000}pre .cm,code .cm{color:#999988}pre .cp,code .cp{color:#999999}pre .c1,code .c1{color:#999988}pre .cs,code .cs{color:#999999}pre .gd,code .gd{color:#000000;background-color:#ffdddd}pre .ge,code .ge{color:#000000}pre .gr,code .gr{color:#aa0000}pre .gh,code .gh{color:#999999}pre .gi,code .gi{color:#000000;background-color:#ddffdd}pre .go,code .go{color:#888888}pre .gp,code .gp{color:#555555}pre .gu,code .gu{color:#aaaaaa}pre .gt,code .gt{color:#aa0000}pre .kc,code .kc{color:#000000}pre .kd,code .kd{color:#000000}pre .kn,code .kn{color:#000000}pre .kp,code .kp{color:#000000}pre .kr,code .kr{color:#000000}pre .kt,code .kt{color:#445588}pre .m,code .m{color:#009999}pre .s,code .s{color:#d01040}pre .na,code .na{color:#008080}pre .nb,code .nb{color:#0086B3}pre .nc,code .nc{color:#445588}pre .no,code .no{color:#008080}pre .nd,code .nd{color:#3c5d5d}pre .ni,code .ni{color:#800080}pre .ne,code .ne{color:#990000}pre .nf,code .nf{color:#990000}pre .nl,code .nl{color:#990000}pre .nn,code .nn{color:#555555}pre .nt,code .nt{color:#000080}pre .nv,code .nv{color:#008080}pre .ow,code .ow{color:#000000}pre .w,code .w{color:#bbbbbb}pre .mf,code .mf{color:#009999}pre .mh,code .mh{color:#009999}pre .mi,code .mi{color:#009999}pre .mo,code .mo{color:#009999}pre .sb,code .sb{color:#d01040}pre .sc,code .sc{color:#d01040}pre .sd,code .sd{color:#d01040}pre .s2,code .s2{color:#d01040}pre .se,code .se{color:#d01040}pre .sh,code .sh{color:#d01040}pre .si,code .si{color:#d01040}pre .sx,code .sx{color:#d01040}pre .sr,code .sr{color:#009926}pre .s1,code .s1{color:#d01040}pre .ss,code .ss{color:#990073}pre .bp,code .bp{color:#999999}pre .vc,code .vc{color:#008080}pre .vg,code .vg{color:#008080}pre .vi,code .vi{color:#008080}pre .il,code .il{color:#009999}html{font-size:100%;line-height:1.4em}html,button,input,select,textarea{font-family:\"PT Sans\",\"Lucida Grande\",\"Lucida Sans Unicode\",\"Lucida Sans\",\"Droid Sans\",tahoma,verdana,arial,sans-serif}h1,h2,h3,h4,h5,h6{font-family:\"Palatino Linotype\",Palatino,\"Book Antiqua\",\"URW Palladio L\",Cambria,Georgia,\"Times New Roman\",times,serif}code,kbd,pre,samp{font-family:Inconsolata,Consolas,Menlo,\"Liberation Mono\",\"Courier New\",courier,monospace}html{background-color:#fff;color:#101010;height:100.1%;overflow-y:scroll}h1,h2,h3,h4,h5,h6{line-height:140%}small{color:#505050}pre{background-color:rgba(0,51,102,0.043);border:0.105em solid rgba(0,51,102,0.085);-webkit-border-radius:0.35em;-moz-border-radius:0.35em;-ms-border-radius:0.35em;-o-border-radius:0.35em;border-radius:0.35em;padding:0.7em;-webkit-box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17);-moz-box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17);box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17)}code{background-color:rgba(0,51,102,0.043);border:0.105em solid rgba(0,51,102,0.085);-webkit-border-radius:0.175em;-moz-border-radius:0.175em;-ms-border-radius:0.175em;-o-border-radius:0.175em;border-radius:0.175em;padding:0.105em 0.175em;-webkit-box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17);-moz-box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17);box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17)}pre code{background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0;padding:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}blockquote{margin-left:0;padding-left:1.05em;border-left:0.175em solid #e6e6e6;font-style:italic}#page{*zoom:1;max-width:60.5em;margin-left:auto;margin-right:auto;padding-left:1em;padding-right:1em;border-top:0.175em solid #404040;border-bottom:0.35em solid #404040;padding-bottom:1.4em}#page:after{content:\"\";display:table;clear:both}#page>header aside{float:right;margin-left:0.7em}#page>footer{text-align:right}#page>footer small{line-height:100%}.unstyled{list-style:none}.unstyled li{list-style-image:none;list-style-type:none;margin-left:0}.inline{margin:0;padding:0}.inline,.inline li{display:-moz-inline-stack;display:inline-block;vertical-align:middle;*vertical-align:auto;zoom:1;*display:inline}.inline a{border-bottom:0}.long{margin:0;padding:0}.long li{margin-bottom:0.7em}a{text-decoration:none;border-bottom:0.105em solid rgba(16,16,16,0.125)}#page .gist .gist-file{border:0}#page .gist .gist-file,#page .gist .gist-file .gist-data pre{font-family:Inconsolata,Consolas,Menlo,\"Liberation Mono\",\"Courier New\",courier,monospace}#page .gist .gist-file .gist-data pre{padding:0.7em !important;background-color:rgba(0,51,102,0.043) !important}#page .gist .gist-syntax{background-color:transparent;border-bottom:0}#page .gist .gist-syntax *{font-style:normal;font-weight:normal}#page .gist .gist-meta{background-color:transparent}#disqus_thread{margin-top:1.4em;margin-bottom:1.4em;font-family:\"PT Sans\",\"Lucida Grande\",\"Lucida Sans Unicode\",\"Lucida Sans\",\"Droid Sans\",tahoma,verdana,arial,sans-serif}</style>\n\n</body>\n</html>\n","_id":"lotte@0.2.1","dist":{"shasum":"8f96488aa69fa3db7a543a27b0d45705444c1b08","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.2.1.tgz","integrity":"sha512-vAF+jHYMUESJZcuj1yP31ZDRawQGwlkX57B51SZiW++W+WrTEnSQkJ0krKYOacoxFpX3W37GRCePBf3WL+H9FA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEvwgMBDcrDZLaHhjJSRDoooRcNdIii21VyHFfekjZlJAiEA9MsfGUuPhJvwNMccor1HQzxIK269KhyPXZJS3gntAdI="}]},"_npmVersion":"1.1.59","_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}]},"0.2.2":{"name":"lotte","version":"0.2.2","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":"https://github.com/StanAngeloff/lotte/issues","author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["bin/","lib/","test/"],"bin":{"lotte":"bin/cli.js"},"main":"lib/lotte.js","repository":{"type":"git","url":"https://github.com/StanAngeloff/lotte"},"dependencies":{"minimatch":"~0.2.6","naturalsort":"~0.0.1","optimist":"~0.3.4","semver":"~1.0.14","tmp":"~0.0.14","walkdir":"~0.0.4"},"devDependencies":{"express":"~3.0.0"},"engines":{"node":">=0.8"},"preferGlobal":true,"readme":"<!doctype html>\n<html lang=en>\n<head>\n  <meta charset=utf-8>\n  <title>Lotte</title>\n</head>\n<body>\n\n<article id=page>\n<h1>Lotte</h1>\n\n<p>Lotte is a headless, automated testing framework built on top of <a href=\"http://www.phantomjs.org/\">PhantomJS</a> and inspired by <a href=\"https://github.com/joshbuddy/ghostbuster\">Ghostbuster</a>.\nIt adds jQuery-like methods and chaining, more assertion logic and an extensible core.\nTests can be written in either JavaScript or <a href=\"http://coffeescript.org/\">CoffeeScript</a>.</p>\n\n<p>Lotte comes with tools for accessing the DOM, evaluating arbitrary code, simulating mouse and keyboard input.</p>\n\n<p>Tests are sandboxed and run asynchronously. Blocking methods are available to simulate dependencies and to control the flow of execution.</p>\n\n<p>This project is still highly experimental. Using it may cause your computer to blow up. <a href=\"https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md\">Seriously.</a></p>\n\n<h2>Prerequisites</h2>\n\n<ul>\n<li><a href=\"http://nodejs.org/\">node.js</a> <strong>&gt;=0.8</strong></li>\n<li><a href=\"http://npmjs.org/\">npm</a> <strong>&gt;=1.0</strong></li>\n<li><a href=\"http://www.phantomjs.org/\">PhantomJS</a> <strong>&gt;=1.3.0 &lt;=1.6.x</strong></li>\n</ul>\n\n<h3>Optional Dependencies</h3>\n\n<ul>\n<li><a href=\"http://coffeescript.org/\">CoffeeScript</a></li>\n</ul>\n\n<h2>Installation</h2>\n<div class=\"highlight\"><pre>$ npm -g install lotte\n</pre>\n</div>\n\n<p><code>-g</code>lobal is preferred so you can run <code>lotte</code> from any directory.</p>\n\n<h2>Usage</h2>\n\n<p>Create a new file <code>lotte_github.js</code> (preferably in an empty directory) and copy the following code:</p>\n<div class=\"highlight\"><pre><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">open</span><span class=\"p\">(</span><span class=\"s1\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"kd\">function</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">describe</span><span class=\"p\">(</span><span class=\"s1\">&#39;Sign Up button&#39;</span><span class=\"p\">,</span> <span class=\"kd\">function</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n    <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">assert</span><span class=\"p\">.</span><span class=\"nx\">ok</span><span class=\"p\">(</span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">$</span><span class=\"p\">(</span><span class=\"s1\">&#39;.signup-button&#39;</span><span class=\"p\">).</span><span class=\"nx\">length</span><span class=\"p\">,</span> <span class=\"s1\">&#39;expects button to be in the DOM&#39;</span><span class=\"p\">);</span>\n    <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">success</span><span class=\"p\">();</span>\n  <span class=\"p\">});</span>\n<span class=\"p\">});</span>\n</pre>\n</div>\n\n<p>Run <code>lotte</code> from within the directory and you should see the following output:</p>\n<div class=\"highlight\"><pre>/tmp/lotte_github.js\n  @ https://github.com\n      ✓ Sign Up button\n</pre>\n</div>\n\n<h2>Command-Line Options</h2>\n\n<p>You can customise many aspects of Lotte&#39;s behaviour either on the command-line on through <code>Lottefile</code>s. The following options are available:</p>\n<div class=\"highlight\"><pre>$ lotte --help\nUsage: lotte [OPTION...] PATH\n\nOptions:\n  --help, -h        give this help page\n  --version, -v     print program version\n  --concurrent, -c  limit of files to run in parallel                       [default: 4]\n  --timeout, -t     timeout for individual files (in milliseconds)          [default: 30000]\n  --include, -I     glob pattern to match files in PATH          [string]   [default: &quot;**/lotte_*.js&quot;]\n  --exclude, -E     glob pattern to remove included files        [string]\n  --lottefile, -f   look for &#39;lottefile&#39; in PATH                 [string]   [default: &quot;Lottefile&quot;]\n  --verify          verify PhantomJS version (expected ~1.3.0)   [boolean]  [default: true]\n  --phantom         executable for PhantomJS                     [string]   [default: &quot;phantomjs&quot;]\n  --coffee          executable for CofeeScript                   [string]   [default: &quot;coffee&quot;]\n</pre>\n</div>\n\n<p>There are four key options you would want to customise while the rest should work with their defaults.</p>\n\n<ul>\n<li><p><strong><code>--concurrent, -c</code></strong></p>\n\n<p>If you have more than one test file in a directory, Lotte will attempt to run them in parallel (asynchronously).\nYou can specify how many tests can be running at any given time through this option.</p>\n\n<p>If you want to run tests synchronously, specify a value of <code>1</code>.</p></li>\n<li><p><strong><code>--timeout, -t</code></strong></p>\n\n<p>Each test is expected to finish within a given period of time. If a test takes longer, it is interruped and recorded as failed.</p>\n\n<p>The default value is <code>30</code> seconds, but you should consider reducing it.</p></li>\n<li><p><strong><code>--include, -I</code><br>\n<code>--exclude, -E</code></strong></p>\n\n<p>When you run <code>lotte</code> from any directory the script collects a list of all files in the current directory and all sub-directories.\nThe list is reduced by running the <code>include</code> glob pattern and dropping any files that did not match.\nThe list is then reduced further by running the <code>exclude</code> glob pattern and dropping any files that did match.\nThe remaining list is sorted and considered final.</p>\n\n<p>You can specify these arguments more than once to create an array of include/exclude patterns.</p></li>\n</ul>\n\n<h3>Lottefile</h3>\n\n<p>In order to avoid having to type the full <code>lotte</code> command-line each time, you can use <code>Lottefile</code>s to store your settings per project.</p>\n\n<p><code>Lottefile</code>s are regular JavaScript files where each global variable maps to a command-line option. For example, the following command:</p>\n<div class=\"highlight\"><pre>$ lotte --include &#39;**/*.coffee&#39; --include &#39;**/*.js&#39; --concurrent 1 tests\n</pre>\n</div>\n\n<p>can be stored in a <code>Lottefile</code> as this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">path</span>       <span class=\"o\">=</span> <span class=\"s1\">&#39;tests&#39;</span>\n<span class=\"nx\">include</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;**/*.coffee&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;**/*.js&#39;</span><span class=\"p\">]</span>\n<span class=\"nx\">concurrent</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n</pre>\n</div>\n\n<p>Running <code>lotte</code> from the project directory will then read the <code>Lottefile</code> and scan the <code>tests</code> directory for all files matching <code>**/*.{coffee,js}</code>.</p>\n\n<h2>Writing Tests</h2>\n\n<p>Tests can be written in either JavaScript or CoffeeScript.\nIn the sections below substitute <code>@</code> with <code>this.</code> if you are using JavaScript.\nArguments wrapped in square brackets <code>[</code> and <code>]</code> are optional.\nArguments ending in <code>...</code> can be used more than once.</p>\n\n<p>At the top-level, the following functions are available:</p>\n\n<ul>\n<li><p><strong><code>@title([name])</code></strong></p>\n\n<p>Gets or sets the test title.\nThis is useful for giving meaningful names to your tests.</p>\n\n<p>When called with zero arguments, returns the current title or <code>undefined</code>.<br>\nWhen called with one argument, sets the title.</p>\n\n<p>If you don&#39;t explicitly specify a title, the filename will be used instead.</p></li>\n<li><p><strong><code>@base([uri])</code></strong></p>\n\n<p>Gets or sets the absolute URI for all relative URIs in the test.\nYou can use this to specify the root URI for your project.</p>\n\n<p>When called with zero arguments, returns the current URI or <code>undefined</code>.<br>\nWhen called with one argument, sets the URI.</p>\n\n<p>If you don&#39;t explicitly specify an absolute URI, all calls to <code>@open</code> will expect an absolute URI instead.</p></li>\n<li><p><strong><code>@open(uri, [message], [options], block)</code></strong></p>\n\n<p>Creates a new test.</p>\n\n<p><code>uri</code> can be either an absolute or relative URI (see above).<br>\n<code>message</code> is an optional description for the URI. If you don&#39;t specify it, Lotte will print the <code>uri</code> in the output instead.<br>\n<code>options</code> is an object hash to pass to PhantomJS. See <a href=\"http://code.google.com/p/phantomjs/wiki/Interface#settings_(object)\">settings (object)</a>.<br>\n<code>block</code> is a function which is executed if the server returns a valid response (2xx or 3xx).</p>\n\n<p>If the server returns a 4xx or 5xx HTTP code instead, the test is recorded as failed.</p>\n\n<p>If you have more than one <code>@open</code> call at the top-level, they will be executed asynchronously.</p></li>\n</ul>\n\n<p>Putting it all together, a test file could look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@title</span> <span class=\"s\">&#39;Github&#39;</span>\n<span class=\"nx\">@base</span>  <span class=\"s\">&#39;https://github.com&#39;</span>\n\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/&#39;</span><span class=\"p\">,</span> <span class=\"s\">&#39;the homepage&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"c1\"># ...body of test...</span>\n</pre>\n</div>\n\n<h3>Cases &amp; Grouping</h3>\n\n<p>Once you have successfully requested an URI, you can start writing test cases against the page.</p>\n\n<p>The following functions are available:</p>\n\n<ul>\n<li><p><strong><code>@group(name, block)</code></strong></p>\n\n<p>Groups the nested test cases. This is mainly for structuring the output Lotte prints.</p>\n\n<p><code>name</code> is the name of the group.<br>\n<code>block</code> is a function which contains the nested test cases.</p></li>\n<li><p><strong><code>@describe(name, block)</code></strong></p>\n\n<p>Starts a new test case.</p>\n\n<p><code>name</code> is the name of the test case.<br>\n<code>block</code> is a function which is executed and is expected to contain assertion logic.</p></li>\n</ul>\n\n<p>Putting it all together a test file could now look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@title</span> <span class=\"s\">&#39;Github&#39;</span>\n<span class=\"nx\">@base</span>  <span class=\"s\">&#39;https://github.com&#39;</span>\n\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/&#39;</span><span class=\"p\">,</span> <span class=\"s\">&#39;the homepage&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;counter shows number of repositories&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># ...assertion logic...</span>\n  <span class=\"nx\">@group</span> <span class=\"s\">&#39;Sign Up button&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@describe</span> <span class=\"s\">&#39;is in place&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># ...assertion logic...</span>\n    <span class=\"nx\">@describe</span> <span class=\"s\">&#39;takes you to /plans&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># ...assertion logic...</span>\n</pre>\n</div>\n\n<h4>Flow of Execution</h4>\n\n<p>Each test case is executed in the order in which it is defined:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"c1\"># etc.</span>\n</pre>\n</div>\n\n<p>If a test case contains an asynchronous function call, the next test case is executed without waiting for the function to finish:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">setTimeout</span> <span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"p\">),</span> <span class=\"mi\">2500</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run third in parallel with second still running&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n</pre>\n</div>\n\n<p>Be extremely careful when dealing with asynchronous function. For example, using <code>.click()</code> to follow an anchor could change the page while another test case is running.</p>\n\n<p>If a test case fails, any remaining test cases are skipped:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"k\">throw</span> <span class=\"s\">&#39;Whoops!&#39;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I should run second, but I never will&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n</pre>\n</div>\n\n<p>To simulate dependencies and control the flow of execution, you can use the following functions:</p>\n\n<ul>\n<li><p><strong><code>@wait(name..., block)</code></strong></p>\n\n<p>Blocks the current test case until all dependencies have finished (either passed or failed).</p></li>\n</ul>\n\n<p>The earlier example can now be rewritten as follows to make it synchronous again:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">setTimeout</span> <span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"p\">),</span> <span class=\"mi\">2500</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run third&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@wait</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># ...assertion logic...</span>\n</pre>\n</div>\n\n<h3>Environments</h3>\n\n<p>Lotte uses PhantomJS to execute tests. While you may be writing tests in JavaScript and expect to be able to access the DOM of a page directly, this is not the case.</p>\n\n<p>Each test file runs in its own sandboxed environment. Each page you request also runs in a sandbox.\nYou cannot access variables across environments, i.e., you cannot define a variable in your test file and access it within the page you have just requested:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Sandbox&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">val = </span><span class=\"s\">&#39;value&#39;</span>\n    <span class=\"c1\"># following line throws an exception</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"k\">return</span> <span class=\"nx\">val</span><span class=\"p\">))</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<p>In the above code snippet <code>@page.evaluate</code> runs the function as if it were defined on the page you just requested, i.e, <code>github.com</code>.\nIn order to do so, PhantomJS serializes the function, but it does not include the context in which it was defined.\nWhen the function is executed, <code>val</code> is missing in the new context causing it to throw an exception.</p>\n\n<p>Another limitation of PhantomJS is the fact you cannot return complex types from the page.\nObjects are serialized before they leave the page sandbox and unserialized back in the parent (test case) environment:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;serialize/unserialize&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">h1 = </span><span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"k\">return</span> <span class=\"nb\">document</span><span class=\"p\">.</span><span class=\"nx\">querySelector</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">))</span>\n    <span class=\"c1\"># prints &#39;H1&#39; correctly</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">h1</span><span class=\"p\">.</span><span class=\"nx\">tagName</span>\n    <span class=\"c1\"># prints &#39;undefined&#39; as functions cannot be serialized/unserialized</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">h1</span><span class=\"p\">.</span><span class=\"nx\">focus</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<p>Lotte comes with a workaround which allows you to pass variables to the PhantomJS environment.\nThis hack has the same limitations as outlined above (it uses <code>JSON.stringify</code> internally):</p>\n\n<ul>\n<li><p><strong><code>@using(hash, block)</code></strong></p>\n\n<p><code>hash</code> is a <code>key: value</code> object where:</p>\n\n<ul>\n<li><code>key</code> must be a valid identifier and defines the name of the variable within the PhantomJS environment</li>\n<li><code>value</code> must be serializable and contains the value of the variable</li>\n</ul>\n\n<p><code>block</code> is either a function or a string.</p>\n\n<p>Returns a <code>Function</code> string with all <code>key: value</code> pairs from <code>hash</code> as arguments.</p></li>\n</ul>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;@using(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">expected = </span><span class=\"s\">&#39;git&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h2&#39;</span><span class=\"p\">).</span><span class=\"nx\">first</span> <span class=\"nx\">@using</span> <span class=\"p\">{</span> <span class=\"nx\">expected</span> <span class=\"p\">},</span> <span class=\"nf\">(element) -&gt;</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">innerHTML</span><span class=\"p\">.</span><span class=\"nx\">indexOf</span><span class=\"p\">(</span><span class=\"nx\">expected</span><span class=\"p\">)</span> <span class=\"o\">is</span> <span class=\"mi\">0</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h4>Document Queries</h4>\n\n<p>There is a lot of boilerplate code required to access the DOM of a page.\nLotte comes with a jQuery-like query function to abstract some of the most common operations:</p>\n\n<ul>\n<li><p><strong><code>@$(selector)</code></strong></p>\n\n<p><code>selector</code> is a string containing a selector expression.</p>\n\n<p>Returns a <code>DocumentQuery</code> object.</p></li>\n</ul>\n\n<p>The earlier example can now be rewritten as follows:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Document Queries&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># prints &#39;H1&#39; correctly</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">tagName</span>\n    <span class=\"c1\"># prints &#39;undefined&#39;</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">focus</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h5>Additional Methods</h5>\n\n<p>A <code>DocumentQuery</code> object has the following methods to deal with the DOM:</p>\n\n<ul>\n<li><p><strong><code>DocumentQuery.prototype.attr([index], property)</code></strong></p>\n\n<p>Gets the value of <code>property</code> for the element at <code>index</code>.</p>\n\n<p>The following code snippets are equivalent:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">attr</span><span class=\"p\">(</span><span class=\"s\">&#39;tagName&#39;</span><span class=\"p\">)</span>\n<span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">tagName</span>\n</pre>\n</div>\n\n<p>The direct property access always returns the property value for the first matched element.</p>\n\n<p>While you can use <code>attr(..)</code> to access any property, the direct access will only work with the following pre-defined list of properties: <code>action</code>, <code>alt</code>, <code>checked</code>, <code>className</code>, <code>clientHeight</code>, <code>clientLeft</code>, <code>clientTop</code>, <code>clientWidth</code>, <code>disabled</code>, <code>enctype</code>, <code>height</code>, <code>href</code>, <code>id</code>, <code>innerHTML</code>, <code>length</code>, <code>maxLength</code>, <code>media</code>, <code>method</code>, <code>name</code>, <code>nodeName</code>, <code>nodeValue</code>, <code>offsetHeight</code>, <code>offsetLeft</code>, <code>offsetTop</code>, <code>offsetWidth</code>, <code>options</code>, <code>outerHTML</code>, <code>outerText</code>, <code>readOnly</code>, <code>rel</code>, <code>scrollHeight</code>, <code>scrollLeft</code>, <code>scrollTop</code>, <code>scrollWidth</code>, <code>selectedIndex</code>, <code>size</code>, <code>src</code>, <code>style</code>, <code>tagName</code>, <code>target</code>, <code>textContent</code>, <code>title</code>, <code>type</code>, <code>value</code>, <code>width</code>.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.click([index], [message], [block])</code></strong></p>\n\n<p>Clicks on the element at <code>index</code> and returns execution to the test case (i.e., asynchronous). This method can be used to simulate mouse input.</p>\n\n<p><code>index</code> is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.<br>\n<code>message</code> is an optional message to display if something goes wrong, i.e., if no elements were matched.<br>\n<code>block</code> is an optional function to execute when the new page has loaded, i.e., when you follow an anchor.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;click(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># prints https://github.com/</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"s\">&#39;I am now on: &#39;</span> <span class=\"o\">+</span> <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"nx\">location</span><span class=\"p\">.</span><span class=\"nx\">href</span><span class=\"p\">))</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.signup-button&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># prints https://github.com/plans</span>\n      <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"s\">&#39;I am now on: &#39;</span> <span class=\"o\">+</span> <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"nx\">location</span><span class=\"p\">.</span><span class=\"nx\">href</span><span class=\"p\">))</span>\n      <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div></li>\n<li><p><strong><code>DocumentQuery.prototype.input(value, [index], [message])</code></strong></p>\n\n<p>Inputs <code>value</code> in the element at <code>index</code>. This method can be used to simulate keyboard input.</p>\n\n<p><code>value</code> is a string to input as if it were keyboard input.<br>\n<code>index</code> is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.<br>\n<code>message</code> is an optional message to display if something goes wrong, i.e., if no elements were matched.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;http://www.google.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;input(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;[name=&quot;q&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;meaning of life&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;input[type=&quot;submit&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;#res&#39;</span><span class=\"p\">).</span><span class=\"nx\">attr</span><span class=\"p\">(</span><span class=\"s\">&#39;innerText&#39;</span><span class=\"p\">)</span>\n      <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div></li>\n</ul>\n\n<p>See <strong>DOM Assertions</strong> below for additional methods.</p>\n\n<h3>Assertions</h3>\n\n<p>Lotte comes with two types of assertion logic:</p>\n\n<ul>\n<li>Generic assertions</li>\n<li>DOM assertions</li>\n</ul>\n\n<h4>Generic Assertions</h4>\n\n<p>If you have used Node&#39;s built-in <a href=\"http://nodejs.org/docs/v0.6.0/api/assert.html\">assert</a> module, these functions will be familiar:</p>\n\n<ul>\n<li><p><strong><code>@assert.fail(actual, expected, message, operator)</code></strong></p>\n\n<p>Throws an exception that displays the values for <code>actual</code> and <code>expected</code> separated by the provided <code>operator</code>.</p></li>\n<li><p><strong><code>@assert.ok(value, message)</code></strong></p>\n\n<p>Tests if <code>value</code> is a true value, it is equivalent to <code>@assert.equal(true, value, message)</code>.</p></li>\n<li><p><strong><code>@assert.equal(actual, expected, message)</code></strong></p>\n\n<p>Tests shallow, coercive equality with the equal comparison operator <code>==</code>.</p></li>\n<li><p><strong><code>@assert.notEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests shallow, coercive non-equality with the not equal comparison operator <code>!=</code>.</p></li>\n<li><p><strong><code>@assert.deepEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests for deep equality.</p></li>\n<li><p><strong><code>@assert.notDeepEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests for any deep inequality.</p></li>\n<li><p><strong><code>@assert.strictEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests strict equality, as determined by the strict equality operator <code>===</code>.</p></li>\n<li><p><strong><code>@assert.notStrictEqua(actual, expected, message)</code></strong></p>\n\n<p>Tests strict non-equality, as determined by the strict not equal operator <code>!==</code>.</p></li>\n<li><p><strong><code>@assert.throws(block, error, message)</code></strong></p>\n\n<p>Expects <code>block</code> to throw an error. <code>error</code> can be constructor, RegExp or validation function.</p></li>\n<li><p><strong><code>@assert.doesNotThrow(block, error, message)</code></strong></p>\n\n<p>Expects <code>block</code> not to throw an error, see <code>@assert.throws</code> for details.</p></li>\n<li><p><strong><code>@assert.contains(actual, expected, message)</code></strong></p>\n\n<p>Expects <code>actual</code> to contain <code>expected</code>. <code>expected</code> can be a string or a RegExp.</p></li>\n</ul>\n\n<h4>DOM Assertions</h4>\n\n<p><code>DocumentQuery</code> (see above) comes with additional methods to deal with assertions:</p>\n\n<ul>\n<li><p><strong><code>DocumentQuery.prototype.contains([message], pattern)</code></strong></p>\n\n<p>Expects at least one of the matched elements to contain <code>pattern</code>. <code>pattern</code> can be a string or a RegExp.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.each([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> on each matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.first([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the first matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.last([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the last matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.nth(index, [message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the element at <code>index</code> as an argument returns a true value.</p></li>\n</ul>\n\n<p>A general note which applies to all functions above: you cannot access variables from scope within <code>block</code> (see <strong>Environments</strong>).</p>\n\n<p>An example test file that performs DOM assertions could look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Navigation and children have classes&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.nav&#39;</span><span class=\"p\">).</span><span class=\"nx\">first</span>   <span class=\"nf\">(element) -&gt;</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">classList</span><span class=\"p\">.</span><span class=\"nx\">contains</span><span class=\"p\">(</span><span class=\"s\">&#39;logged_out&#39;</span><span class=\"p\">)</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.nav li&#39;</span><span class=\"p\">).</span><span class=\"nx\">each</span> <span class=\"nf\">(element) -&gt;</span> <span class=\"o\">!!</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">className</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h2>Passing Tests</h2>\n\n<p>So far we have ended tests with <code>throw &#39;exit&#39;</code>. To pass a test case, use the following functions:</p>\n\n<ul>\n<li><p><strong><code>@success()</code></strong></p>\n\n<p>Marks the test case as passed. You must call this once within each <code>@describe</code> block.</p></li>\n</ul>\n\n<p>If you don&#39;t end a test case either by failing any of the asserts or calling <code>@success()</code>, the entire test file will hang until <code>timeout</code> is reached at which point it is recorded as failed.</p>\n\n<h2>FAQs</h2>\n\n<ul>\n<li><p><strong>Q</strong>: How can I log in before requesting a page?</p>\n\n<p><strong>A</strong>: You can nest <code>@open(..)</code> functions to achieve this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@base</span> <span class=\"s\">&#39;http://local.dev&#39;</span>\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/login&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Log in&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.username&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;admin&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.password&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;password&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;input[type=&quot;submit&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"nx\">@success</span><span class=\"p\">()</span>\n      <span class=\"nx\">@open</span> <span class=\"s\">&#39;/account&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n        <span class=\"nx\">@describe</span> <span class=\"s\">&#39;My Account&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n          <span class=\"c1\"># ...assertion logic...</span>\n          <span class=\"nx\">@success</span><span class=\"p\">()</span>\n</pre>\n</div></li>\n<li><p><strong>Q</strong>: Can I pass arguments to my tests?</p>\n\n<p><strong>A</strong>: Yes. Use <code>--</code> on the command-line followed by the arguments:</p>\n<div class=\"highlight\"><pre>$ lotte -- arg1 arg2\n</pre>\n</div>\n\n<p>Arguments will be available in your test files as <code>phantom.args[..]</code>.</p></li>\n<li><p><strong>Q</strong>: How can I see what PhantomJS &#39;sees&#39;?</p>\n\n<p><strong>A</strong>: Within the context of a test case (<code>@describe</code>), you can refer to <code>@page</code> which is the PhantomJS <a href=\"http://code.google.com/p/phantomjs/wiki/Interface#&#x27;_WebPage_&#x27;_Object\">WebPage</a> object.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;snapshot&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">render</span> <span class=\"s\">&#39;home.png&#39;</span>\n  <span class=\"nx\">@success</span><span class=\"p\">()</span>\n</pre>\n</div></li>\n<li><p><strong>Q</strong>: I don&#39;t have <code>phantomjs</code> and/or <code>coffee</code> on <code>$PATH</code>.</p>\n\n<p><strong>A</strong>: See <code>lotte --help</code> for information on how to specify a path to the missing binary.</p></li>\n</ul>\n\n<h2>Contributing</h2>\n\n<p>The goal of this project is to provide an awesome tool for developers to test their websites or apps in their favourite language with minimum effort.</p>\n\n<p>Commit and code reviews, ideas and documentation improvements are welcomed.</p>\n\n<h2>Changelog</h2>\n\n<ul>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.1.1...0.1.2\">0.1.2</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.1.2...0.1.2-1\">0.1.2-1</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.1.2-1...0.1.2-2\">0.1.2-2</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.1.2-2...0.2.0\">0.2.0</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.2.0...0.2.0-1\">0.2.0-1</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.2.0-1...0.2.1\">0.2.1</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.2.1...0.2.2\">0.2.2</a></li>\n</ul>\n\n<h3>Copyright</h3>\n\n<blockquote>\n<p>Copyright &copy; 2011 Stan Angeloff. See <a href=\"https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md\">LICENSE.md</a> for details.</p>\n</blockquote>\n\n</article>\n\n<style>/* normalize.css 2012-07-07T09:50 UTC - http://github.com/necolas/normalize.css */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:0.67em 0}h2{font-size:1.5em;margin:0.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:0.83em;margin:1.67em 0}h6{font-size:0.75em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:1em 40px}dfn{font-style:italic}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace, serif;_font-family:'courier new', monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:75%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,html input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=\"checkbox\"],input[type=\"radio\"]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=\"search\"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=\"search\"]::-webkit-search-cancel-button,input[type=\"search\"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}pre .hll,code .hll{background-color:#ffffcc}pre .c,code .c{color:#999988}pre .err,code .err{color:#a61717;background-color:#e3d2d2}pre .k,code .k{color:#000000}pre .o,code .o{color:#000000}pre .cm,code .cm{color:#999988}pre .cp,code .cp{color:#999999}pre .c1,code .c1{color:#999988}pre .cs,code .cs{color:#999999}pre .gd,code .gd{color:#000000;background-color:#ffdddd}pre .ge,code .ge{color:#000000}pre .gr,code .gr{color:#aa0000}pre .gh,code .gh{color:#999999}pre .gi,code .gi{color:#000000;background-color:#ddffdd}pre .go,code .go{color:#888888}pre .gp,code .gp{color:#555555}pre .gu,code .gu{color:#aaaaaa}pre .gt,code .gt{color:#aa0000}pre .kc,code .kc{color:#000000}pre .kd,code .kd{color:#000000}pre .kn,code .kn{color:#000000}pre .kp,code .kp{color:#000000}pre .kr,code .kr{color:#000000}pre .kt,code .kt{color:#445588}pre .m,code .m{color:#009999}pre .s,code .s{color:#d01040}pre .na,code .na{color:#008080}pre .nb,code .nb{color:#0086B3}pre .nc,code .nc{color:#445588}pre .no,code .no{color:#008080}pre .nd,code .nd{color:#3c5d5d}pre .ni,code .ni{color:#800080}pre .ne,code .ne{color:#990000}pre .nf,code .nf{color:#990000}pre .nl,code .nl{color:#990000}pre .nn,code .nn{color:#555555}pre .nt,code .nt{color:#000080}pre .nv,code .nv{color:#008080}pre .ow,code .ow{color:#000000}pre .w,code .w{color:#bbbbbb}pre .mf,code .mf{color:#009999}pre .mh,code .mh{color:#009999}pre .mi,code .mi{color:#009999}pre .mo,code .mo{color:#009999}pre .sb,code .sb{color:#d01040}pre .sc,code .sc{color:#d01040}pre .sd,code .sd{color:#d01040}pre .s2,code .s2{color:#d01040}pre .se,code .se{color:#d01040}pre .sh,code .sh{color:#d01040}pre .si,code .si{color:#d01040}pre .sx,code .sx{color:#d01040}pre .sr,code .sr{color:#009926}pre .s1,code .s1{color:#d01040}pre .ss,code .ss{color:#990073}pre .bp,code .bp{color:#999999}pre .vc,code .vc{color:#008080}pre .vg,code .vg{color:#008080}pre .vi,code .vi{color:#008080}pre .il,code .il{color:#009999}html{font-size:100%;line-height:1.4em}html,button,input,select,textarea{font-family:\"PT Sans\",\"Lucida Grande\",\"Lucida Sans Unicode\",\"Lucida Sans\",\"Droid Sans\",tahoma,verdana,arial,sans-serif}h1,h2,h3,h4,h5,h6{font-family:\"Palatino Linotype\",Palatino,\"Book Antiqua\",\"URW Palladio L\",Cambria,Georgia,\"Times New Roman\",times,serif}code,kbd,pre,samp{font-family:Inconsolata,Consolas,Menlo,\"Liberation Mono\",\"Courier New\",courier,monospace}html{background-color:#fff;color:#101010;height:100.1%;overflow-y:scroll}h1,h2,h3,h4,h5,h6{line-height:140%}small{color:#505050}pre{background-color:rgba(0,51,102,0.043);border:0.105em solid rgba(0,51,102,0.085);-webkit-border-radius:0.35em;-moz-border-radius:0.35em;-ms-border-radius:0.35em;-o-border-radius:0.35em;border-radius:0.35em;padding:0.7em;-webkit-box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17);-moz-box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17);box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17)}code{background-color:rgba(0,51,102,0.043);border:0.105em solid rgba(0,51,102,0.085);-webkit-border-radius:0.175em;-moz-border-radius:0.175em;-ms-border-radius:0.175em;-o-border-radius:0.175em;border-radius:0.175em;padding:0.105em 0.175em;-webkit-box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17);-moz-box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17);box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17)}pre code{background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0;padding:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}blockquote{margin-left:0;padding-left:1.05em;border-left:0.175em solid #e6e6e6;font-style:italic}#page{*zoom:1;max-width:60.5em;margin-left:auto;margin-right:auto;padding-left:1em;padding-right:1em;border-top:0.175em solid #404040;border-bottom:0.35em solid #404040;padding-bottom:1.4em}#page:after{content:\"\";display:table;clear:both}#page>header aside{float:right;margin-left:0.7em}#page>footer{text-align:right}#page>footer small{line-height:100%}.unstyled{list-style:none}.unstyled li{list-style-image:none;list-style-type:none;margin-left:0}.inline{margin:0;padding:0}.inline,.inline li{display:-moz-inline-stack;display:inline-block;vertical-align:middle;*vertical-align:auto;zoom:1;*display:inline}.inline a{border-bottom:0}.long{margin:0;padding:0}.long li{margin-bottom:0.7em}a{text-decoration:none;border-bottom:0.105em solid rgba(16,16,16,0.125)}#page .gist .gist-file{border:0}#page .gist .gist-file,#page .gist .gist-file .gist-data pre{font-family:Inconsolata,Consolas,Menlo,\"Liberation Mono\",\"Courier New\",courier,monospace}#page .gist .gist-file .gist-data pre{padding:0.7em !important;background-color:rgba(0,51,102,0.043) !important}#page .gist .gist-syntax{background-color:transparent;border-bottom:0}#page .gist .gist-syntax *{font-style:normal;font-weight:normal}#page .gist .gist-meta{background-color:transparent}#disqus_thread{margin-top:1.4em;margin-bottom:1.4em;font-family:\"PT Sans\",\"Lucida Grande\",\"Lucida Sans Unicode\",\"Lucida Sans\",\"Droid Sans\",tahoma,verdana,arial,sans-serif}</style>\n\n</body>\n</html>\n","_id":"lotte@0.2.2","dist":{"shasum":"ad33aef55d16fb042ee1f54b6f446d354387cf20","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.2.2.tgz","integrity":"sha512-3dBQbhWeCVMlQ0LLZQgNkbXK1tzff+1E9s6uOOZz+/g4N40SHx7m/dMydROUmgxhjgKYR2D+3ixkU0w77KREbg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBfhXlJzeTq9S6X/ra4gH/5eL0rC7Tk8E3k6ZHDeL7liAiBuUNVkA7qypJJg20PUJ3sXR5cn4aTpxF0FsQPhrPExuQ=="}]},"_npmVersion":"1.1.59","_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}]},"0.2.2-1":{"name":"lotte","version":"0.2.2-1","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":"https://github.com/StanAngeloff/lotte/issues","author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["bin/","lib/","test/"],"bin":{"lotte":"bin/cli.js"},"main":"lib/lotte.js","repository":{"type":"git","url":"https://github.com/StanAngeloff/lotte"},"dependencies":{"minimatch":"~0.2.6","naturalsort":"~0.0.1","optimist":"~0.3.4","semver":"~1.0.14","tmp":"~0.0.14","walkdir":"~0.0.4"},"devDependencies":{"express":"~3.0.0"},"engines":{"node":">=0.8"},"preferGlobal":true,"readme":"<!doctype html>\n<html lang=en>\n<head>\n  <meta charset=utf-8>\n  <title>Lotte</title>\n</head>\n<body>\n\n<article id=page>\n<h1>Lotte</h1>\n\n<p>Lotte is a headless, automated testing framework built on top of <a href=\"http://www.phantomjs.org/\">PhantomJS</a> and inspired by <a href=\"https://github.com/joshbuddy/ghostbuster\">Ghostbuster</a>.\nIt adds jQuery-like methods and chaining, more assertion logic and an extensible core.\nTests can be written in either JavaScript or <a href=\"http://coffeescript.org/\">CoffeeScript</a>.</p>\n\n<p>Lotte comes with tools for accessing the DOM, evaluating arbitrary code, simulating mouse and keyboard input.</p>\n\n<p>Tests are sandboxed and run asynchronously. Blocking methods are available to simulate dependencies and to control the flow of execution.</p>\n\n<p>This project is still highly experimental. Using it may cause your computer to blow up. <a href=\"https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md\">Seriously.</a></p>\n\n<h2>Prerequisites</h2>\n\n<ul>\n<li><a href=\"http://nodejs.org/\">node.js</a> <strong>&gt;=0.8</strong></li>\n<li><a href=\"http://npmjs.org/\">npm</a> <strong>&gt;=1.0</strong></li>\n<li><a href=\"http://www.phantomjs.org/\">PhantomJS</a> <strong>&gt;=1.3.0 &lt;=1.6.x</strong></li>\n</ul>\n\n<h3>Optional Dependencies</h3>\n\n<ul>\n<li><a href=\"http://coffeescript.org/\">CoffeeScript</a></li>\n</ul>\n\n<h2>Installation</h2>\n<div class=\"highlight\"><pre>$ npm -g install lotte\n</pre>\n</div>\n\n<p><code>-g</code>lobal is preferred so you can run <code>lotte</code> from any directory.</p>\n\n<h2>Usage</h2>\n\n<p>Create a new file <code>lotte_github.js</code> (preferably in an empty directory) and copy the following code:</p>\n<div class=\"highlight\"><pre><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">open</span><span class=\"p\">(</span><span class=\"s1\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"kd\">function</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">describe</span><span class=\"p\">(</span><span class=\"s1\">&#39;Sign Up button&#39;</span><span class=\"p\">,</span> <span class=\"kd\">function</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n    <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">assert</span><span class=\"p\">.</span><span class=\"nx\">ok</span><span class=\"p\">(</span><span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">$</span><span class=\"p\">(</span><span class=\"s1\">&#39;.signup-button&#39;</span><span class=\"p\">).</span><span class=\"nx\">length</span><span class=\"p\">,</span> <span class=\"s1\">&#39;expects button to be in the DOM&#39;</span><span class=\"p\">);</span>\n    <span class=\"k\">this</span><span class=\"p\">.</span><span class=\"nx\">success</span><span class=\"p\">();</span>\n  <span class=\"p\">});</span>\n<span class=\"p\">});</span>\n</pre>\n</div>\n\n<p>Run <code>lotte</code> from within the directory and you should see the following output:</p>\n<div class=\"highlight\"><pre>/tmp/lotte_github.js\n  @ https://github.com\n      ✓ Sign Up button\n</pre>\n</div>\n\n<h2>Command-Line Options</h2>\n\n<p>You can customise many aspects of Lotte&#39;s behaviour either on the command-line on through <code>Lottefile</code>s. The following options are available:</p>\n<div class=\"highlight\"><pre>$ lotte --help\nUsage: lotte [OPTION...] PATH\n\nOptions:\n  --help, -h        give this help page\n  --version, -v     print program version\n  --concurrent, -c  limit of files to run in parallel                       [default: 4]\n  --timeout, -t     timeout for individual files (in milliseconds)          [default: 30000]\n  --include, -I     glob pattern to match files in PATH          [string]   [default: &quot;**/lotte_*.js&quot;]\n  --exclude, -E     glob pattern to remove included files        [string]\n  --lottefile, -f   look for &#39;lottefile&#39; in PATH                 [string]   [default: &quot;Lottefile&quot;]\n  --verify          verify PhantomJS version (expected ~1.3.0)   [boolean]  [default: true]\n  --phantom         executable for PhantomJS                     [string]   [default: &quot;phantomjs&quot;]\n  --coffee          executable for CofeeScript                   [string]   [default: &quot;coffee&quot;]\n</pre>\n</div>\n\n<p>There are four key options you would want to customise while the rest should work with their defaults.</p>\n\n<ul>\n<li><p><strong><code>--concurrent, -c</code></strong></p>\n\n<p>If you have more than one test file in a directory, Lotte will attempt to run them in parallel (asynchronously).\nYou can specify how many tests can be running at any given time through this option.</p>\n\n<p>If you want to run tests synchronously, specify a value of <code>1</code>.</p></li>\n<li><p><strong><code>--timeout, -t</code></strong></p>\n\n<p>Each test is expected to finish within a given period of time. If a test takes longer, it is interruped and recorded as failed.</p>\n\n<p>The default value is <code>30</code> seconds, but you should consider reducing it.</p></li>\n<li><p><strong><code>--include, -I</code><br>\n<code>--exclude, -E</code></strong></p>\n\n<p>When you run <code>lotte</code> from any directory the script collects a list of all files in the current directory and all sub-directories.\nThe list is reduced by running the <code>include</code> glob pattern and dropping any files that did not match.\nThe list is then reduced further by running the <code>exclude</code> glob pattern and dropping any files that did match.\nThe remaining list is sorted and considered final.</p>\n\n<p>You can specify these arguments more than once to create an array of include/exclude patterns.</p></li>\n</ul>\n\n<h3>Lottefile</h3>\n\n<p>In order to avoid having to type the full <code>lotte</code> command-line each time, you can use <code>Lottefile</code>s to store your settings per project.</p>\n\n<p><code>Lottefile</code>s are regular JavaScript files where each global variable maps to a command-line option. For example, the following command:</p>\n<div class=\"highlight\"><pre>$ lotte --include &#39;**/*.coffee&#39; --include &#39;**/*.js&#39; --concurrent 1 tests\n</pre>\n</div>\n\n<p>can be stored in a <code>Lottefile</code> as this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">path</span>       <span class=\"o\">=</span> <span class=\"s1\">&#39;tests&#39;</span>\n<span class=\"nx\">include</span>    <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;**/*.coffee&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;**/*.js&#39;</span><span class=\"p\">]</span>\n<span class=\"nx\">concurrent</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n</pre>\n</div>\n\n<p>Running <code>lotte</code> from the project directory will then read the <code>Lottefile</code> and scan the <code>tests</code> directory for all files matching <code>**/*.{coffee,js}</code>.</p>\n\n<h2>Writing Tests</h2>\n\n<p>Tests can be written in either JavaScript or CoffeeScript.\nIn the sections below substitute <code>@</code> with <code>this.</code> if you are using JavaScript.\nArguments wrapped in square brackets <code>[</code> and <code>]</code> are optional.\nArguments ending in <code>...</code> can be used more than once.</p>\n\n<p>At the top-level, the following functions are available:</p>\n\n<ul>\n<li><p><strong><code>@title([name])</code></strong></p>\n\n<p>Gets or sets the test title.\nThis is useful for giving meaningful names to your tests.</p>\n\n<p>When called with zero arguments, returns the current title or <code>undefined</code>.<br>\nWhen called with one argument, sets the title.</p>\n\n<p>If you don&#39;t explicitly specify a title, the filename will be used instead.</p></li>\n<li><p><strong><code>@base([uri])</code></strong></p>\n\n<p>Gets or sets the absolute URI for all relative URIs in the test.\nYou can use this to specify the root URI for your project.</p>\n\n<p>When called with zero arguments, returns the current URI or <code>undefined</code>.<br>\nWhen called with one argument, sets the URI.</p>\n\n<p>If you don&#39;t explicitly specify an absolute URI, all calls to <code>@open</code> will expect an absolute URI instead.</p></li>\n<li><p><strong><code>@open(uri, [message], [options], block)</code></strong></p>\n\n<p>Creates a new test.</p>\n\n<p><code>uri</code> can be either an absolute or relative URI (see above).<br>\n<code>message</code> is an optional description for the URI. If you don&#39;t specify it, Lotte will print the <code>uri</code> in the output instead.<br>\n<code>options</code> is an object hash to pass to PhantomJS. See <a href=\"http://code.google.com/p/phantomjs/wiki/Interface#settings_(object)\">settings (object)</a>.<br>\n<code>block</code> is a function which is executed if the server returns a valid response (2xx or 3xx).</p>\n\n<p>If the server returns a 4xx or 5xx HTTP code instead, the test is recorded as failed.</p>\n\n<p>If you have more than one <code>@open</code> call at the top-level, they will be executed asynchronously.</p></li>\n</ul>\n\n<p>Putting it all together, a test file could look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@title</span> <span class=\"s\">&#39;Github&#39;</span>\n<span class=\"nx\">@base</span>  <span class=\"s\">&#39;https://github.com&#39;</span>\n\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/&#39;</span><span class=\"p\">,</span> <span class=\"s\">&#39;the homepage&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"c1\"># ...body of test...</span>\n</pre>\n</div>\n\n<h3>Cases &amp; Grouping</h3>\n\n<p>Once you have successfully requested an URI, you can start writing test cases against the page.</p>\n\n<p>The following functions are available:</p>\n\n<ul>\n<li><p><strong><code>@group(name, block)</code></strong></p>\n\n<p>Groups the nested test cases. This is mainly for structuring the output Lotte prints.</p>\n\n<p><code>name</code> is the name of the group.<br>\n<code>block</code> is a function which contains the nested test cases.</p></li>\n<li><p><strong><code>@describe(name, block)</code></strong></p>\n\n<p>Starts a new test case.</p>\n\n<p><code>name</code> is the name of the test case.<br>\n<code>block</code> is a function which is executed and is expected to contain assertion logic.</p></li>\n</ul>\n\n<p>Putting it all together a test file could now look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@title</span> <span class=\"s\">&#39;Github&#39;</span>\n<span class=\"nx\">@base</span>  <span class=\"s\">&#39;https://github.com&#39;</span>\n\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/&#39;</span><span class=\"p\">,</span> <span class=\"s\">&#39;the homepage&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;counter shows number of repositories&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># ...assertion logic...</span>\n  <span class=\"nx\">@group</span> <span class=\"s\">&#39;Sign Up button&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@describe</span> <span class=\"s\">&#39;is in place&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># ...assertion logic...</span>\n    <span class=\"nx\">@describe</span> <span class=\"s\">&#39;takes you to /plans&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># ...assertion logic...</span>\n</pre>\n</div>\n\n<h4>Flow of Execution</h4>\n\n<p>Each test case is executed in the order in which it is defined:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"c1\"># etc.</span>\n</pre>\n</div>\n\n<p>If a test case contains an asynchronous function call, the next test case is executed without waiting for the function to finish:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">setTimeout</span> <span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"p\">),</span> <span class=\"mi\">2500</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run third in parallel with second still running&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n</pre>\n</div>\n\n<p>Be extremely careful when dealing with asynchronous function. For example, using <code>.click()</code> to follow an anchor could change the page while another test case is running.</p>\n\n<p>If a test case fails, any remaining test cases are skipped:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"k\">throw</span> <span class=\"s\">&#39;Whoops!&#39;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I should run second, but I never will&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n</pre>\n</div>\n\n<p>To simulate dependencies and control the flow of execution, you can use the following functions:</p>\n\n<ul>\n<li><p><strong><code>@wait(name..., block)</code></strong></p>\n\n<p>Blocks the current test case until all dependencies have finished (either passed or failed).</p></li>\n</ul>\n\n<p>The earlier example can now be rewritten as follows to make it synchronous again:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run first&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">setTimeout</span> <span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"p\">),</span> <span class=\"mi\">2500</span>\n<span class=\"nx\">@describe</span> <span class=\"s\">&#39;I run third&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@wait</span> <span class=\"s\">&#39;I run second&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># ...assertion logic...</span>\n</pre>\n</div>\n\n<h3>Environments</h3>\n\n<p>Lotte uses PhantomJS to execute tests. While you may be writing tests in JavaScript and expect to be able to access the DOM of a page directly, this is not the case.</p>\n\n<p>Each test file runs in its own sandboxed environment. Each page you request also runs in a sandbox.\nYou cannot access variables across environments, i.e., you cannot define a variable in your test file and access it within the page you have just requested:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Sandbox&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">val = </span><span class=\"s\">&#39;value&#39;</span>\n    <span class=\"c1\"># following line throws an exception</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"k\">return</span> <span class=\"nx\">val</span><span class=\"p\">))</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<p>In the above code snippet <code>@page.evaluate</code> runs the function as if it were defined on the page you just requested, i.e, <code>github.com</code>.\nIn order to do so, PhantomJS serializes the function, but it does not include the context in which it was defined.\nWhen the function is executed, <code>val</code> is missing in the new context causing it to throw an exception.</p>\n\n<p>Another limitation of PhantomJS is the fact you cannot return complex types from the page.\nObjects are serialized before they leave the page sandbox and unserialized back in the parent (test case) environment:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;serialize/unserialize&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">h1 = </span><span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"k\">return</span> <span class=\"nb\">document</span><span class=\"p\">.</span><span class=\"nx\">querySelector</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">))</span>\n    <span class=\"c1\"># prints &#39;H1&#39; correctly</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">h1</span><span class=\"p\">.</span><span class=\"nx\">tagName</span>\n    <span class=\"c1\"># prints &#39;undefined&#39; as functions cannot be serialized/unserialized</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">h1</span><span class=\"p\">.</span><span class=\"nx\">focus</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<p>Lotte comes with a workaround which allows you to pass variables to the PhantomJS environment.\nThis hack has the same limitations as outlined above (it uses <code>JSON.stringify</code> internally):</p>\n\n<ul>\n<li><p><strong><code>@using(hash, block)</code></strong></p>\n\n<p><code>hash</code> is a <code>key: value</code> object where:</p>\n\n<ul>\n<li><code>key</code> must be a valid identifier and defines the name of the variable within the PhantomJS environment</li>\n<li><code>value</code> must be serializable and contains the value of the variable</li>\n</ul>\n\n<p><code>block</code> is either a function or a string.</p>\n\n<p>Returns a <code>Function</code> string with all <code>key: value</code> pairs from <code>hash</code> as arguments.</p></li>\n</ul>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;@using(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nv\">expected = </span><span class=\"s\">&#39;git&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h2&#39;</span><span class=\"p\">).</span><span class=\"nx\">first</span> <span class=\"nx\">@using</span> <span class=\"p\">{</span> <span class=\"nx\">expected</span> <span class=\"p\">},</span> <span class=\"nf\">(element) -&gt;</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">innerHTML</span><span class=\"p\">.</span><span class=\"nx\">indexOf</span><span class=\"p\">(</span><span class=\"nx\">expected</span><span class=\"p\">)</span> <span class=\"o\">is</span> <span class=\"mi\">0</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h4>Document Queries</h4>\n\n<p>There is a lot of boilerplate code required to access the DOM of a page.\nLotte comes with a jQuery-like query function to abstract some of the most common operations:</p>\n\n<ul>\n<li><p><strong><code>@$(selector)</code></strong></p>\n\n<p><code>selector</code> is a string containing a selector expression.</p>\n\n<p>Returns a <code>DocumentQuery</code> object.</p></li>\n</ul>\n\n<p>The earlier example can now be rewritten as follows:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Document Queries&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># prints &#39;H1&#39; correctly</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">tagName</span>\n    <span class=\"c1\"># prints &#39;undefined&#39;</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">focus</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h5>Additional Methods</h5>\n\n<p>A <code>DocumentQuery</code> object has the following methods to deal with the DOM:</p>\n\n<ul>\n<li><p><strong><code>DocumentQuery.prototype.attr([index], property)</code></strong></p>\n\n<p>Gets the value of <code>property</code> for the element at <code>index</code>.</p>\n\n<p>The following code snippets are equivalent:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">attr</span><span class=\"p\">(</span><span class=\"s\">&#39;tagName&#39;</span><span class=\"p\">)</span>\n<span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;h1&#39;</span><span class=\"p\">).</span><span class=\"nx\">tagName</span>\n</pre>\n</div>\n\n<p>The direct property access always returns the property value for the first matched element.</p>\n\n<p>While you can use <code>attr(..)</code> to access any property, the direct access will only work with the following pre-defined list of properties: <code>action</code>, <code>alt</code>, <code>checked</code>, <code>className</code>, <code>clientHeight</code>, <code>clientLeft</code>, <code>clientTop</code>, <code>clientWidth</code>, <code>disabled</code>, <code>enctype</code>, <code>height</code>, <code>href</code>, <code>id</code>, <code>innerHTML</code>, <code>length</code>, <code>maxLength</code>, <code>media</code>, <code>method</code>, <code>name</code>, <code>nodeName</code>, <code>nodeValue</code>, <code>offsetHeight</code>, <code>offsetLeft</code>, <code>offsetTop</code>, <code>offsetWidth</code>, <code>options</code>, <code>outerHTML</code>, <code>outerText</code>, <code>readOnly</code>, <code>rel</code>, <code>scrollHeight</code>, <code>scrollLeft</code>, <code>scrollTop</code>, <code>scrollWidth</code>, <code>selectedIndex</code>, <code>size</code>, <code>src</code>, <code>style</code>, <code>tagName</code>, <code>target</code>, <code>textContent</code>, <code>title</code>, <code>type</code>, <code>value</code>, <code>width</code>.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.click([index], [message], [block])</code></strong></p>\n\n<p>Clicks on the element at <code>index</code> and returns execution to the test case (i.e., asynchronous). This method can be used to simulate mouse input.</p>\n\n<p><code>index</code> is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.<br>\n<code>message</code> is an optional message to display if something goes wrong, i.e., if no elements were matched.<br>\n<code>block</code> is an optional function to execute when the new page has loaded, i.e., when you follow an anchor.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;click(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"c1\"># prints https://github.com/</span>\n    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"s\">&#39;I am now on: &#39;</span> <span class=\"o\">+</span> <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"nx\">location</span><span class=\"p\">.</span><span class=\"nx\">href</span><span class=\"p\">))</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.signup-button&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"c1\"># prints https://github.com/plans</span>\n      <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"s\">&#39;I am now on: &#39;</span> <span class=\"o\">+</span> <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">evaluate</span><span class=\"p\">(</span> <span class=\"o\">-&gt;</span> <span class=\"nx\">location</span><span class=\"p\">.</span><span class=\"nx\">href</span><span class=\"p\">))</span>\n      <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div></li>\n<li><p><strong><code>DocumentQuery.prototype.input(value, [index], [message])</code></strong></p>\n\n<p>Inputs <code>value</code> in the element at <code>index</code>. This method can be used to simulate keyboard input.</p>\n\n<p><code>value</code> is a string to input as if it were keyboard input.<br>\n<code>index</code> is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.<br>\n<code>message</code> is an optional message to display if something goes wrong, i.e., if no elements were matched.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;http://www.google.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;input(..)&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;[name=&quot;q&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;meaning of life&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;input[type=&quot;submit&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span> <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;#res&#39;</span><span class=\"p\">).</span><span class=\"nx\">attr</span><span class=\"p\">(</span><span class=\"s\">&#39;innerText&#39;</span><span class=\"p\">)</span>\n      <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div></li>\n</ul>\n\n<p>See <strong>DOM Assertions</strong> below for additional methods.</p>\n\n<h3>Assertions</h3>\n\n<p>Lotte comes with two types of assertion logic:</p>\n\n<ul>\n<li>Generic assertions</li>\n<li>DOM assertions</li>\n</ul>\n\n<h4>Generic Assertions</h4>\n\n<p>If you have used Node&#39;s built-in <a href=\"http://nodejs.org/docs/v0.6.0/api/assert.html\">assert</a> module, these functions will be familiar:</p>\n\n<ul>\n<li><p><strong><code>@assert.fail(actual, expected, message, operator)</code></strong></p>\n\n<p>Throws an exception that displays the values for <code>actual</code> and <code>expected</code> separated by the provided <code>operator</code>.</p></li>\n<li><p><strong><code>@assert.ok(value, message)</code></strong></p>\n\n<p>Tests if <code>value</code> is a true value, it is equivalent to <code>@assert.equal(true, value, message)</code>.</p></li>\n<li><p><strong><code>@assert.equal(actual, expected, message)</code></strong></p>\n\n<p>Tests shallow, coercive equality with the equal comparison operator <code>==</code>.</p></li>\n<li><p><strong><code>@assert.notEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests shallow, coercive non-equality with the not equal comparison operator <code>!=</code>.</p></li>\n<li><p><strong><code>@assert.deepEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests for deep equality.</p></li>\n<li><p><strong><code>@assert.notDeepEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests for any deep inequality.</p></li>\n<li><p><strong><code>@assert.strictEqual(actual, expected, message)</code></strong></p>\n\n<p>Tests strict equality, as determined by the strict equality operator <code>===</code>.</p></li>\n<li><p><strong><code>@assert.notStrictEqua(actual, expected, message)</code></strong></p>\n\n<p>Tests strict non-equality, as determined by the strict not equal operator <code>!==</code>.</p></li>\n<li><p><strong><code>@assert.throws(block, error, message)</code></strong></p>\n\n<p>Expects <code>block</code> to throw an error. <code>error</code> can be constructor, RegExp or validation function.</p></li>\n<li><p><strong><code>@assert.doesNotThrow(block, error, message)</code></strong></p>\n\n<p>Expects <code>block</code> not to throw an error, see <code>@assert.throws</code> for details.</p></li>\n<li><p><strong><code>@assert.contains(actual, expected, message)</code></strong></p>\n\n<p>Expects <code>actual</code> to contain <code>expected</code>. <code>expected</code> can be a string or a RegExp.</p></li>\n</ul>\n\n<h4>DOM Assertions</h4>\n\n<p><code>DocumentQuery</code> (see above) comes with additional methods to deal with assertions:</p>\n\n<ul>\n<li><p><strong><code>DocumentQuery.prototype.contains([message], pattern)</code></strong></p>\n\n<p>Expects at least one of the matched elements to contain <code>pattern</code>. <code>pattern</code> can be a string or a RegExp.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.each([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> on each matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.first([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the first matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.last([message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the last matched element as an argument returns a true value.</p></li>\n<li><p><strong><code>DocumentQuery.prototype.nth(index, [message], block)</code></strong></p>\n\n<p>Tests if calling <code>block</code> with the element at <code>index</code> as an argument returns a true value.</p></li>\n</ul>\n\n<p>A general note which applies to all functions above: you cannot access variables from scope within <code>block</code> (see <strong>Environments</strong>).</p>\n\n<p>An example test file that performs DOM assertions could look like this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@open</span> <span class=\"s\">&#39;https://github.com&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Navigation and children have classes&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.nav&#39;</span><span class=\"p\">).</span><span class=\"nx\">first</span>   <span class=\"nf\">(element) -&gt;</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">classList</span><span class=\"p\">.</span><span class=\"nx\">contains</span><span class=\"p\">(</span><span class=\"s\">&#39;logged_out&#39;</span><span class=\"p\">)</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.nav li&#39;</span><span class=\"p\">).</span><span class=\"nx\">each</span> <span class=\"nf\">(element) -&gt;</span> <span class=\"o\">!!</span> <span class=\"nx\">element</span><span class=\"p\">.</span><span class=\"nx\">className</span>\n    <span class=\"k\">throw</span> <span class=\"s\">&#39;exit&#39;</span>\n</pre>\n</div>\n\n<h2>Passing Tests</h2>\n\n<p>So far we have ended tests with <code>throw &#39;exit&#39;</code>. To pass a test case, use the following functions:</p>\n\n<ul>\n<li><p><strong><code>@success()</code></strong></p>\n\n<p>Marks the test case as passed. You must call this once within each <code>@describe</code> block.</p></li>\n</ul>\n\n<p>If you don&#39;t end a test case either by failing any of the asserts or calling <code>@success()</code>, the entire test file will hang until <code>timeout</code> is reached at which point it is recorded as failed.</p>\n\n<h2>FAQs</h2>\n\n<ul>\n<li><p><strong>Q</strong>: How can I log in before requesting a page?</p>\n\n<p><strong>A</strong>: You can nest <code>@open(..)</code> functions to achieve this:</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@base</span> <span class=\"s\">&#39;http://local.dev&#39;</span>\n<span class=\"nx\">@open</span> <span class=\"s\">&#39;/login&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@describe</span> <span class=\"s\">&#39;Log in&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.username&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;admin&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;.password&#39;</span><span class=\"p\">).</span><span class=\"nx\">input</span> <span class=\"s\">&#39;password&#39;</span>\n    <span class=\"nx\">@$</span><span class=\"p\">(</span><span class=\"s\">&#39;input[type=&quot;submit&quot;]&#39;</span><span class=\"p\">).</span><span class=\"nx\">click</span> <span class=\"o\">-&gt;</span>\n      <span class=\"nx\">@success</span><span class=\"p\">()</span>\n      <span class=\"nx\">@open</span> <span class=\"s\">&#39;/account&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n        <span class=\"nx\">@describe</span> <span class=\"s\">&#39;My Account&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n          <span class=\"c1\"># ...assertion logic...</span>\n          <span class=\"nx\">@success</span><span class=\"p\">()</span>\n</pre>\n</div></li>\n<li><p><strong>Q</strong>: Can I pass arguments to my tests?</p>\n\n<p><strong>A</strong>: Yes. Use <code>--</code> on the command-line followed by the arguments:</p>\n<div class=\"highlight\"><pre>$ lotte -- arg1 arg2\n</pre>\n</div>\n\n<p>Arguments will be available in your test files as <code>phantom.args[..]</code>.</p></li>\n<li><p><strong>Q</strong>: How can I see what PhantomJS &#39;sees&#39;?</p>\n\n<p><strong>A</strong>: Within the context of a test case (<code>@describe</code>), you can refer to <code>@page</code> which is the PhantomJS <a href=\"http://code.google.com/p/phantomjs/wiki/Interface#&#x27;_WebPage_&#x27;_Object\">WebPage</a> object.</p>\n<div class=\"highlight\"><pre><span class=\"nx\">@describe</span> <span class=\"s\">&#39;snapshot&#39;</span><span class=\"p\">,</span> <span class=\"o\">-&gt;</span>\n  <span class=\"nx\">@page</span><span class=\"p\">.</span><span class=\"nx\">render</span> <span class=\"s\">&#39;home.png&#39;</span>\n  <span class=\"nx\">@success</span><span class=\"p\">()</span>\n</pre>\n</div></li>\n<li><p><strong>Q</strong>: I don&#39;t have <code>phantomjs</code> and/or <code>coffee</code> on <code>$PATH</code>.</p>\n\n<p><strong>A</strong>: See <code>lotte --help</code> for information on how to specify a path to the missing binary.</p></li>\n</ul>\n\n<h2>Contributing</h2>\n\n<p>The goal of this project is to provide an awesome tool for developers to test their websites or apps in their favourite language with minimum effort.</p>\n\n<p>Commit and code reviews, ideas and documentation improvements are welcomed.</p>\n\n<h2>Changelog</h2>\n\n<ul>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.1.1...0.1.2\">0.1.2</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.1.2...0.1.2-1\">0.1.2-1</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.1.2-1...0.1.2-2\">0.1.2-2</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.1.2-2...0.2.0\">0.2.0</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.2.0...0.2.0-1\">0.2.0-1</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.2.0-1...0.2.1\">0.2.1</a></li>\n<li><a href=\"https://github.com/StanAngeloff/lotte/compare/0.2.1...0.2.2\">0.2.2</a></li>\n</ul>\n\n<h3>Copyright</h3>\n\n<blockquote>\n<p>Copyright &copy; 2011 Stan Angeloff. See <a href=\"https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md\">LICENSE.md</a> for details.</p>\n</blockquote>\n\n</article>\n\n<style>/* normalize.css 2012-07-07T09:50 UTC - http://github.com/necolas/normalize.css */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:0.67em 0}h2{font-size:1.5em;margin:0.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:0.83em;margin:1.67em 0}h6{font-size:0.75em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:1em 40px}dfn{font-style:italic}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace, serif;_font-family:'courier new', monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:75%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,html input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=\"checkbox\"],input[type=\"radio\"]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=\"search\"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=\"search\"]::-webkit-search-cancel-button,input[type=\"search\"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}pre .hll,code .hll{background-color:#ffffcc}pre .c,code .c{color:#999988}pre .err,code .err{color:#a61717;background-color:#e3d2d2}pre .k,code .k{color:#000000}pre .o,code .o{color:#000000}pre .cm,code .cm{color:#999988}pre .cp,code .cp{color:#999999}pre .c1,code .c1{color:#999988}pre .cs,code .cs{color:#999999}pre .gd,code .gd{color:#000000;background-color:#ffdddd}pre .ge,code .ge{color:#000000}pre .gr,code .gr{color:#aa0000}pre .gh,code .gh{color:#999999}pre .gi,code .gi{color:#000000;background-color:#ddffdd}pre .go,code .go{color:#888888}pre .gp,code .gp{color:#555555}pre .gu,code .gu{color:#aaaaaa}pre .gt,code .gt{color:#aa0000}pre .kc,code .kc{color:#000000}pre .kd,code .kd{color:#000000}pre .kn,code .kn{color:#000000}pre .kp,code .kp{color:#000000}pre .kr,code .kr{color:#000000}pre .kt,code .kt{color:#445588}pre .m,code .m{color:#009999}pre .s,code .s{color:#d01040}pre .na,code .na{color:#008080}pre .nb,code .nb{color:#0086B3}pre .nc,code .nc{color:#445588}pre .no,code .no{color:#008080}pre .nd,code .nd{color:#3c5d5d}pre .ni,code .ni{color:#800080}pre .ne,code .ne{color:#990000}pre .nf,code .nf{color:#990000}pre .nl,code .nl{color:#990000}pre .nn,code .nn{color:#555555}pre .nt,code .nt{color:#000080}pre .nv,code .nv{color:#008080}pre .ow,code .ow{color:#000000}pre .w,code .w{color:#bbbbbb}pre .mf,code .mf{color:#009999}pre .mh,code .mh{color:#009999}pre .mi,code .mi{color:#009999}pre .mo,code .mo{color:#009999}pre .sb,code .sb{color:#d01040}pre .sc,code .sc{color:#d01040}pre .sd,code .sd{color:#d01040}pre .s2,code .s2{color:#d01040}pre .se,code .se{color:#d01040}pre .sh,code .sh{color:#d01040}pre .si,code .si{color:#d01040}pre .sx,code .sx{color:#d01040}pre .sr,code .sr{color:#009926}pre .s1,code .s1{color:#d01040}pre .ss,code .ss{color:#990073}pre .bp,code .bp{color:#999999}pre .vc,code .vc{color:#008080}pre .vg,code .vg{color:#008080}pre .vi,code .vi{color:#008080}pre .il,code .il{color:#009999}html{font-size:100%;line-height:1.4em}html,button,input,select,textarea{font-family:\"PT Sans\",\"Lucida Grande\",\"Lucida Sans Unicode\",\"Lucida Sans\",\"Droid Sans\",tahoma,verdana,arial,sans-serif}h1,h2,h3,h4,h5,h6{font-family:\"Palatino Linotype\",Palatino,\"Book Antiqua\",\"URW Palladio L\",Cambria,Georgia,\"Times New Roman\",times,serif}code,kbd,pre,samp{font-family:Inconsolata,Consolas,Menlo,\"Liberation Mono\",\"Courier New\",courier,monospace}html{background-color:#fff;color:#101010;height:100.1%;overflow-y:scroll}h1,h2,h3,h4,h5,h6{line-height:140%}small{color:#505050}pre{background-color:rgba(0,51,102,0.043);border:0.105em solid rgba(0,51,102,0.085);-webkit-border-radius:0.35em;-moz-border-radius:0.35em;-ms-border-radius:0.35em;-o-border-radius:0.35em;border-radius:0.35em;padding:0.7em;-webkit-box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17);-moz-box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17);box-shadow:inset 0 0 0.455em rgba(0,51,102,0.17)}code{background-color:rgba(0,51,102,0.043);border:0.105em solid rgba(0,51,102,0.085);-webkit-border-radius:0.175em;-moz-border-radius:0.175em;-ms-border-radius:0.175em;-o-border-radius:0.175em;border-radius:0.175em;padding:0.105em 0.175em;-webkit-box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17);-moz-box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17);box-shadow:inset 0 0 0.175em rgba(0,51,102,0.17)}pre code{background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0;padding:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}blockquote{margin-left:0;padding-left:1.05em;border-left:0.175em solid #e6e6e6;font-style:italic}#page{*zoom:1;max-width:60.5em;margin-left:auto;margin-right:auto;padding-left:1em;padding-right:1em;border-top:0.175em solid #404040;border-bottom:0.35em solid #404040;padding-bottom:1.4em}#page:after{content:\"\";display:table;clear:both}#page>header aside{float:right;margin-left:0.7em}#page>footer{text-align:right}#page>footer small{line-height:100%}.unstyled{list-style:none}.unstyled li{list-style-image:none;list-style-type:none;margin-left:0}.inline{margin:0;padding:0}.inline,.inline li{display:-moz-inline-stack;display:inline-block;vertical-align:middle;*vertical-align:auto;zoom:1;*display:inline}.inline a{border-bottom:0}.long{margin:0;padding:0}.long li{margin-bottom:0.7em}a{text-decoration:none;border-bottom:0.105em solid rgba(16,16,16,0.125)}#page .gist .gist-file{border:0}#page .gist .gist-file,#page .gist .gist-file .gist-data pre{font-family:Inconsolata,Consolas,Menlo,\"Liberation Mono\",\"Courier New\",courier,monospace}#page .gist .gist-file .gist-data pre{padding:0.7em !important;background-color:rgba(0,51,102,0.043) !important}#page .gist .gist-syntax{background-color:transparent;border-bottom:0}#page .gist .gist-syntax *{font-style:normal;font-weight:normal}#page .gist .gist-meta{background-color:transparent}#disqus_thread{margin-top:1.4em;margin-bottom:1.4em;font-family:\"PT Sans\",\"Lucida Grande\",\"Lucida Sans Unicode\",\"Lucida Sans\",\"Droid Sans\",tahoma,verdana,arial,sans-serif}</style>\n\n</body>\n</html>\n","_id":"lotte@0.2.2-1","dist":{"shasum":"d2d48c64640bbe63466f8dac526480cc62058a0f","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.2.2-1.tgz","integrity":"sha512-Y+rAXl0bdJLEiTu/TDESVgChPm/rDDfoD6nxp6uuyY4dQrVlWiHnnzL32HqPk7Uy+S9grOIiiOeXpYpIEIqa3A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD+f4ixGs5E8DwPN6QjlyiXGtqizUDZayjhLKuljtN7sQIgMiBvJrTdOkYQ6WBLx/+tTYyv50ruliApvwSCzJYkHWs="}]},"_npmVersion":"1.1.59","_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}]},"0.2.2-2":{"name":"lotte","version":"0.2.2-2","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":"https://github.com/StanAngeloff/lotte/issues","author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["bin/","lib/","test/"],"bin":{"lotte":"bin/cli.js"},"main":"lib/lotte.js","repository":{"type":"git","url":"https://github.com/StanAngeloff/lotte"},"dependencies":{"minimatch":"~0.2.6","naturalsort":"~0.0.1","optimist":"~0.3.4","semver":"~1.0.14","tmp":"~0.0.14","walkdir":"~0.0.4"},"devDependencies":{"express":"~3.0.0"},"engines":{"node":">=0.8"},"preferGlobal":true,"readme":"Lotte\n=====\n\nLotte is a headless, automated testing framework built on top of [PhantomJS][phantom] and inspired by [Ghostbuster][ghostbuster].\nIt adds jQuery-like methods and chaining, more assertion logic and an extensible core.\nTests can be written in either JavaScript or [CoffeeScript][coffee].\n\nLotte comes with tools for accessing the DOM, evaluating arbitrary code, simulating mouse and keyboard input.\n\nTests are sandboxed and run asynchronously. Blocking methods are available to simulate dependencies and to control the flow of execution.\n\nThis project is still highly experimental. Using it may cause your computer to blow up. [Seriously.][license]\n\n  [phantom]:     http://www.phantomjs.org/\n  [ghostbuster]: https://github.com/joshbuddy/ghostbuster\n  [coffee]:      http://coffeescript.org/\n  [license]:     https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md\n\nPrerequisites\n-------------\n\n- [node.js][nodejs] **>=0.8**\n- [npm][npm] **>=1.0**\n- [PhantomJS][phantom] **>=1.3.0 <=1.6.x**\n\n  [npm]:       http://npmjs.org/\n  [nodejs]:    http://nodejs.org/\n  [phantom]:   http://www.phantomjs.org/\n\n### Optional Dependencies\n\n- [CoffeeScript][coffee]\n\n  [coffee]:    http://coffeescript.org/\n\nInstallation\n------------\n\n    $ npm -g install lotte\n\n`-g`lobal is preferred so you can run `lotte` from any directory.\n\nUsage\n-----\n\nCreate a new file `lotte_github.js` (preferably in an empty directory) and copy the following code:\n\n```javascript\nthis.open('https://github.com', function() {\n  this.describe('Sign Up button', function() {\n    this.assert.ok(this.$('.signup-button').length, 'expects button to be in the DOM');\n    this.success();\n  });\n});\n```\n\nRun `lotte` from within the directory and you should see the following output:\n\n```\n/tmp/lotte_github.js\n  @ https://github.com\n      ✓ Sign Up button\n```\n\nCommand-Line Options\n--------------------\n\nYou can customise many aspects of Lotte's behaviour either on the command-line on through `Lottefile`s. The following options are available:\n\n```\n$ lotte --help\nUsage: lotte [OPTION...] PATH\n\nOptions:\n  --help, -h        give this help page\n  --version, -v     print program version\n  --concurrent, -c  limit of files to run in parallel                       [default: 4]\n  --timeout, -t     timeout for individual files (in milliseconds)          [default: 30000]\n  --include, -I     glob pattern to match files in PATH          [string]   [default: \"**/lotte_*.js\"]\n  --exclude, -E     glob pattern to remove included files        [string]\n  --lottefile, -f   look for 'lottefile' in PATH                 [string]   [default: \"Lottefile\"]\n  --verify          verify PhantomJS version (expected ~1.3.0)   [boolean]  [default: true]\n  --phantom         executable for PhantomJS                     [string]   [default: \"phantomjs\"]\n  --coffee          executable for CofeeScript                   [string]   [default: \"coffee\"]\n```\n\nThere are four key options you would want to customise while the rest should work with their defaults.\n\n- **`--concurrent, -c`**\n\n    If you have more than one test file in a directory, Lotte will attempt to run them in parallel (asynchronously).\n    You can specify how many tests can be running at any given time through this option.\n\n    If you want to run tests synchronously, specify a value of `1`.\n\n- **`--timeout, -t`**\n\n    Each test is expected to finish within a given period of time. If a test takes longer, it is interruped and recorded as failed.\n\n    The default value is `30` seconds, but you should consider reducing it.\n\n- **`--include, -I`  \n  `--exclude, -E`**\n\n    When you run `lotte` from any directory the script collects a list of all files in the current directory and all sub-directories.\n    The list is reduced by running the `include` glob pattern and dropping any files that did not match.\n    The list is then reduced further by running the `exclude` glob pattern and dropping any files that did match.\n    The remaining list is sorted and considered final.\n\n    You can specify these arguments more than once to create an array of include/exclude patterns.\n\n### Lottefile\n\nIn order to avoid having to type the full `lotte` command-line each time, you can use `Lottefile`s to store your settings per project.\n\n`Lottefile`s are regular JavaScript files where each global variable maps to a command-line option. For example, the following command:\n\n```\n$ lotte --include '**/*.coffee' --include '**/*.js' --concurrent 1 tests\n```\n\ncan be stored in a `Lottefile` as this:\n\n```javascript\npath       = 'tests'\ninclude    = ['**/*.coffee', '**/*.js']\nconcurrent = 1\n```\n\nRunning `lotte` from the project directory will then read the `Lottefile` and scan the `tests` directory for all files matching `**/*.{coffee,js}`.\n\nWriting Tests\n-------------\n\nTests can be written in either JavaScript or CoffeeScript.\nIn the sections below substitute `@` with `this.` if you are using JavaScript.\nArguments wrapped in square brackets `[` and `]` are optional.\nArguments ending in `...` can be used more than once.\n\nAt the top-level, the following functions are available:\n\n- **`@title([name])`**\n\n    Gets or sets the test title.\n    This is useful for giving meaningful names to your tests.\n\n    When called with zero arguments, returns the current title or `undefined`.  \n    When called with one argument, sets the title.\n\n    If you don't explicitly specify a title, the filename will be used instead.\n\n- **`@base([uri])`**\n\n    Gets or sets the absolute URI for all relative URIs in the test.\n    You can use this to specify the root URI for your project.\n\n    When called with zero arguments, returns the current URI or `undefined`.  \n    When called with one argument, sets the URI.\n\n    If you don't explicitly specify an absolute URI, all calls to `@open` will expect an absolute URI instead.\n\n- **`@open(uri, [message], [options], block)`**\n\n    Creates a new test.\n\n    `uri` can be either an absolute or relative URI (see above).  \n    `message` is an optional description for the URI. If you don't specify it, Lotte will print the `uri` in the output instead.  \n    `options` is an object hash to pass to PhantomJS. See [settings (object)][settings].  \n    `block` is a function which is executed if the server returns a valid response (2xx or 3xx).\n\n    If the server returns a 4xx or 5xx HTTP code instead, the test is recorded as failed.\n\n    If you have more than one `@open` call at the top-level, they will be executed asynchronously.\n\n  [settings]: http://code.google.com/p/phantomjs/wiki/Interface#settings_(object)\n\nPutting it all together, a test file could look like this:\n\n```coffeescript\n@title 'Github'\n@base  'https://github.com'\n\n@open '/', 'the homepage', ->\n  # ...body of test...\n```\n\n### Cases & Grouping\n\nOnce you have successfully requested an URI, you can start writing test cases against the page.\n\nThe following functions are available:\n\n- **`@group(name, block)`**\n\n    Groups the nested test cases. This is mainly for structuring the output Lotte prints.\n\n    `name` is the name of the group.  \n    `block` is a function which contains the nested test cases.\n\n- **`@describe(name, block)`**\n\n    Starts a new test case.\n\n    `name` is the name of the test case.  \n    `block` is a function which is executed and is expected to contain assertion logic.\n\nPutting it all together a test file could now look like this:\n\n```coffeescript\n@title 'Github'\n@base  'https://github.com'\n\n@open '/', 'the homepage', ->\n  @describe 'counter shows number of repositories', ->\n    # ...assertion logic...\n  @group 'Sign Up button', ->\n    @describe 'is in place', ->\n      # ...assertion logic...\n    @describe 'takes you to /plans', ->\n      # ...assertion logic...\n```\n\n#### Flow of Execution\n\nEach test case is executed in the order in which it is defined:\n\n```coffeescript\n@describe 'I run first', ->\n@describe 'I run second', ->\n# etc.\n```\n\nIf a test case contains an asynchronous function call, the next test case is executed without waiting for the function to finish:\n\n```coffeescript\n@describe 'I run first', ->\n@describe 'I run second', ->\n  setTimeout ( -> ), 2500\n@describe 'I run third in parallel with second still running', ->\n```\n\nBe extremely careful when dealing with asynchronous function. For example, using `.click()` to follow an anchor could change the page while another test case is running.\n\nIf a test case fails, any remaining test cases are skipped:\n\n```coffeescript\n@describe 'I run first', ->\n  throw 'Whoops!'\n@describe 'I should run second, but I never will', ->\n```\n\nTo simulate dependencies and control the flow of execution, you can use the following functions:\n\n- **`@wait(name..., block)`**\n\n    Blocks the current test case until all dependencies have finished (either passed or failed).\n\nThe earlier example can now be rewritten as follows to make it synchronous again:\n\n```coffeescript\n@describe 'I run first', ->\n@describe 'I run second', ->\n  setTimeout ( -> ), 2500\n@describe 'I run third', ->\n  @wait 'I run second', ->\n    # ...assertion logic...\n```\n\n### Environments\n\nLotte uses PhantomJS to execute tests. While you may be writing tests in JavaScript and expect to be able to access the DOM of a page directly, this is not the case.\n\nEach test file runs in its own sandboxed environment. Each page you request also runs in a sandbox.\nYou cannot access variables across environments, i.e., you cannot define a variable in your test file and access it within the page you have just requested:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'Sandbox', ->\n    val = 'value'\n    # following line throws an exception\n    console.log(@page.evaluate( -> return val))\n    throw 'exit'\n```\n\nIn the above code snippet `@page.evaluate` runs the function as if it were defined on the page you just requested, i.e, `github.com`.\nIn order to do so, PhantomJS serializes the function, but it does not include the context in which it was defined.\nWhen the function is executed, `val` is missing in the new context causing it to throw an exception.\n\nAnother limitation of PhantomJS is the fact you cannot return complex types from the page.\nObjects are serialized before they leave the page sandbox and unserialized back in the parent (test case) environment:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'serialize/unserialize', ->\n    h1 = @page.evaluate( -> return document.querySelector('h1'))\n    # prints 'H1' correctly\n    console.log h1.tagName\n    # prints 'undefined' as functions cannot be serialized/unserialized\n    console.log h1.focus\n    throw 'exit'\n```\n\nLotte comes with a workaround which allows you to pass variables to the PhantomJS environment.\nThis hack has the same limitations as outlined above (it uses `JSON.stringify` internally):\n\n- **`@using(hash, block)`**\n\n    `hash` is a `key: value` object where:\n\n      - `key` must be a valid identifier and defines the name of the variable within the PhantomJS environment\n      - `value` must be serializable and contains the value of the variable\n\n    `block` is either a function or a string.\n\n    Returns a `Function` string with all `key: value` pairs from `hash` as arguments.\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe '@using(..)', ->\n    expected = 'git'\n    @$('h2').first @using { expected }, (element) -> element.innerHTML.indexOf(expected) is 0\n    throw 'exit'\n```\n\n#### Document Queries\n\nThere is a lot of boilerplate code required to access the DOM of a page.\nLotte comes with a jQuery-like query function to abstract some of the most common operations:\n\n- **`@$(selector)`**\n\n    `selector` is a string containing a selector expression.\n\n    Returns a `DocumentQuery` object.\n\nThe earlier example can now be rewritten as follows:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'Document Queries', ->\n    # prints 'H1' correctly\n    console.log @$('h1').tagName\n    # prints 'undefined'\n    console.log @$('h1').focus\n    throw 'exit'\n```\n\n##### Additional Methods\n\nA `DocumentQuery` object has the following methods to deal with the DOM:\n\n- **`DocumentQuery.prototype.attr([index], property)`**\n\n    Gets the value of `property` for the element at `index`.\n\n    The following code snippets are equivalent:\n\n    ```coffeescript\n    @$('h1').attr('tagName')\n    @$('h1').tagName\n    ```\n\n    The direct property access always returns the property value for the first matched element.\n\n    While you can use `attr(..)` to access any property, the direct access will only work with the following pre-defined list of properties: `action`, `alt`, `checked`, `className`, `clientHeight`, `clientLeft`, `clientTop`, `clientWidth`, `disabled`, `enctype`, `height`, `href`, `id`, `innerHTML`, `length`, `maxLength`, `media`, `method`, `name`, `nodeName`, `nodeValue`, `offsetHeight`, `offsetLeft`, `offsetTop`, `offsetWidth`, `options`, `outerHTML`, `outerText`, `readOnly`, `rel`, `scrollHeight`, `scrollLeft`, `scrollTop`, `scrollWidth`, `selectedIndex`, `size`, `src`, `style`, `tagName`, `target`, `textContent`, `title`, `type`, `value`, `width`.\n\n- **`DocumentQuery.prototype.click([index], [message], [block])`**\n\n    Clicks on the element at `index` and returns execution to the test case (i.e., asynchronous). This method can be used to simulate mouse input.\n\n    `index` is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.  \n    `message` is an optional message to display if something goes wrong, i.e., if no elements were matched.  \n    `block` is an optional function to execute when the new page has loaded, i.e., when you follow an anchor.\n\n    ```coffeescript\n    @open 'https://github.com', ->\n      @describe 'click(..)', ->\n        # prints https://github.com/\n        console.log('I am now on: ' + @page.evaluate( -> location.href))\n        @$('.signup-button').click ->\n          # prints https://github.com/plans\n          console.log('I am now on: ' + @page.evaluate( -> location.href))\n          throw 'exit'\n    ```\n\n- **`DocumentQuery.prototype.input(value, [index], [message])`**\n\n    Inputs `value` in the element at `index`. This method can be used to simulate keyboard input.\n\n    `value` is a string to input as if it were keyboard input.  \n    `index` is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.  \n    `message` is an optional message to display if something goes wrong, i.e., if no elements were matched.\n\n    ```coffeescript\n    @open 'http://www.google.com', ->\n      @describe 'input(..)', ->\n        @$('[name=\"q\"]').input 'meaning of life'\n        @$('input[type=\"submit\"]').click ->\n          console.log @$('#res').attr('innerText')\n          throw 'exit'\n    ```\n\nSee **DOM Assertions** below for additional methods.\n\n### Assertions\n\nLotte comes with two types of assertion logic:\n\n- Generic assertions\n- DOM assertions\n\n#### Generic Assertions\n\nIf you have used Node's built-in [assert][assert] module, these functions will be familiar:\n\n- **`@assert.fail(actual, expected, message, operator)`**\n\n    Throws an exception that displays the values for `actual` and `expected` separated by the provided `operator`.\n\n- **`@assert.ok(value, message)`**\n\n    Tests if `value` is a true value, it is equivalent to `@assert.equal(true, value, message)`.\n\n- **`@assert.equal(actual, expected, message)`**\n\n    Tests shallow, coercive equality with the equal comparison operator `==`.\n\n- **`@assert.notEqual(actual, expected, message)`**\n\n    Tests shallow, coercive non-equality with the not equal comparison operator `!=`.\n\n- **`@assert.deepEqual(actual, expected, message)`**\n\n    Tests for deep equality.\n\n- **`@assert.notDeepEqual(actual, expected, message)`**\n\n    Tests for any deep inequality.\n\n- **`@assert.strictEqual(actual, expected, message)`**\n\n    Tests strict equality, as determined by the strict equality operator `===`.\n\n- **`@assert.notStrictEqua(actual, expected, message)`**\n\n    Tests strict non-equality, as determined by the strict not equal operator `!==`.\n\n- **`@assert.throws(block, error, message)`**\n\n    Expects `block` to throw an error. `error` can be constructor, RegExp or validation function.\n\n- **`@assert.doesNotThrow(block, error, message)`**\n\n    Expects `block` not to throw an error, see `@assert.throws` for details.\n\n- **`@assert.contains(actual, expected, message)`**\n\n    Expects `actual` to contain `expected`. `expected` can be a string or a RegExp.\n\n  [assert]: http://nodejs.org/docs/v0.6.0/api/assert.html\n\n#### DOM Assertions\n\n`DocumentQuery` (see above) comes with additional methods to deal with assertions:\n\n- **`DocumentQuery.prototype.contains([message], pattern)`**\n\n    Expects at least one of the matched elements to contain `pattern`. `pattern` can be a string or a RegExp.\n\n- **`DocumentQuery.prototype.each([message], block)`**\n\n    Tests if calling `block` on each matched element as an argument returns a true value.\n\n- **`DocumentQuery.prototype.first([message], block)`**\n\n    Tests if calling `block` with the first matched element as an argument returns a true value.\n\n- **`DocumentQuery.prototype.last([message], block)`**\n\n    Tests if calling `block` with the last matched element as an argument returns a true value.\n\n- **`DocumentQuery.prototype.nth(index, [message], block)`**\n\n    Tests if calling `block` with the element at `index` as an argument returns a true value.\n\nA general note which applies to all functions above: you cannot access variables from scope within `block` (see **Environments**).\n\nAn example test file that performs DOM assertions could look like this:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'Navigation and children have classes', ->\n    @$('.nav').first   (element) -> element.classList.contains('logged_out')\n    @$('.nav li').each (element) -> !! element.className\n    throw 'exit'\n```\n\nPassing Tests\n-------------\n\nSo far we have ended tests with `throw 'exit'`. To pass a test case, use the following functions:\n\n- **`@success()`**\n\n    Marks the test case as passed. You must call this once within each `@describe` block.\n\nIf you don't end a test case either by failing any of the asserts or calling `@success()`, the entire test file will hang until `timeout` is reached at which point it is recorded as failed.\n\nFAQs\n----\n\n- **Q**: How can I log in before requesting a page?\n\n    **A**: You can nest `@open(..)` functions to achieve this:\n\n    ```coffeescript\n    @base 'http://local.dev'\n    @open '/login', ->\n      @describe 'Log in', ->\n        @$('.username').input 'admin'\n        @$('.password').input 'password'\n        @$('input[type=\"submit\"]').click ->\n          @success()\n          @open '/account', ->\n            @describe 'My Account', ->\n              # ...assertion logic...\n              @success()\n    ```\n\n- **Q**: Can I pass arguments to my tests?\n\n    **A**: Yes. Use `--` on the command-line followed by the arguments:\n\n    ```\n    $ lotte -- arg1 arg2\n    ```\n\n    Arguments will be available in your test files as `phantom.args[..]`.\n\n- **Q**: How can I see what PhantomJS 'sees'?\n\n    **A**: Within the context of a test case (`@describe`), you can refer to `@page` which is the PhantomJS [WebPage][webpage] object.\n\n    ```coffeescript\n    @describe 'snapshot', ->\n      @page.render 'home.png'\n      @success()\n    ```\n\n- **Q**: I don't have `phantomjs` and/or `coffee` on `$PATH`.\n\n    **A**: See `lotte --help` for information on how to specify a path to the missing binary.\n\n  [webpage]:   http://code.google.com/p/phantomjs/wiki/Interface#'_WebPage_'_Object\n\nContributing\n------------\n\nThe goal of this project is to provide an awesome tool for developers to test their websites or apps in their favourite language with minimum effort.\n\nCommit and code reviews, ideas and documentation improvements are welcomed.\n\nChangelog\n---------\n\n- [0.1.2](https://github.com/StanAngeloff/lotte/compare/0.1.1...0.1.2)\n- [0.1.2-1](https://github.com/StanAngeloff/lotte/compare/0.1.2...0.1.2-1)\n- [0.1.2-2](https://github.com/StanAngeloff/lotte/compare/0.1.2-1...0.1.2-2)\n- [0.2.0](https://github.com/StanAngeloff/lotte/compare/0.1.2-2...0.2.0)\n- [0.2.0-1](https://github.com/StanAngeloff/lotte/compare/0.2.0...0.2.0-1)\n- [0.2.1](https://github.com/StanAngeloff/lotte/compare/0.2.0-1...0.2.1)\n- [0.2.2](https://github.com/StanAngeloff/lotte/compare/0.2.1...0.2.2)\n- [0.2.2-1](https://github.com/StanAngeloff/lotte/compare/0.2.2...0.2.2-1)\n\n### Copyright\n\n> Copyright (c) 2011 Stan Angeloff. See [LICENSE.md](https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md) for details.\n","_id":"lotte@0.2.2-2","dist":{"shasum":"eea49bd8abc04a330186f21ef536fc94da9022a6","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.2.2-2.tgz","integrity":"sha512-+zovf9UqrKXgHzLWf7AcLtZA4n2MHqddHOxwuBcWLhv5ee6w3aJpVvPXTh4AbGZjGLxTAsA7VWyGrNHTdRn1JQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAPp1S4n2qfgN86QAIupMlWqp9sgOcpxi255WNtElYBuAiEAu//v/OWNkOzpWH5I+dNQTHtTnuSqNFcOaV2nmroMomg="}]},"_npmVersion":"1.1.59","_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}]},"0.2.2-3":{"name":"lotte","version":"0.2.2-3","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":"https://github.com/StanAngeloff/lotte/issues","author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["bin/","lib/","test/"],"bin":{"lotte":"bin/cli.js"},"main":"lib/lotte.js","repository":{"type":"git","url":"https://github.com/StanAngeloff/lotte"},"dependencies":{"minimatch":"~0.2.6","naturalsort":"~0.0.1","optimist":"~0.3.4","semver":"~1.0.14","tmp":"~0.0.14","walkdir":"~0.0.4"},"devDependencies":{"express":"~3.0.0"},"engines":{"node":">=0.8"},"preferGlobal":true,"readme":"Lotte\n=====\n\nLotte is a headless, automated testing framework built on top of [PhantomJS][phantom] and inspired by [Ghostbuster][ghostbuster].\nIt adds jQuery-like methods and chaining, more assertion logic and an extensible core.\nTests can be written in either JavaScript or [CoffeeScript][coffee].\n\nLotte comes with tools for accessing the DOM, evaluating arbitrary code, simulating mouse and keyboard input.\n\nTests are sandboxed and run asynchronously. Blocking methods are available to simulate dependencies and to control the flow of execution.\n\nThis project is still highly experimental. Using it may cause your computer to blow up. [Seriously.][license]\n\n  [phantom]:     http://www.phantomjs.org/\n  [ghostbuster]: https://github.com/joshbuddy/ghostbuster\n  [coffee]:      http://coffeescript.org/\n  [license]:     https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md\n\nPrerequisites\n-------------\n\n- [node.js][nodejs] **>=0.8**\n- [npm][npm] **>=1.0**\n- [PhantomJS][phantom] **<2.0.0**\n\n  [npm]:       http://npmjs.org/\n  [nodejs]:    http://nodejs.org/\n  [phantom]:   http://www.phantomjs.org/\n\n### Optional Dependencies\n\n- [CoffeeScript][coffee]\n\n  [coffee]:    http://coffeescript.org/\n\nInstallation\n------------\n\n    $ npm -g install lotte\n\n`-g`lobal is preferred so you can run `lotte` from any directory.\n\nUsage\n-----\n\nCreate a new file `lotte_github.js` (preferably in an empty directory) and copy the following code:\n\n```javascript\nthis.open('https://github.com', function() {\n  this.describe('Sign Up button', function() {\n    this.assert.ok(this.$('.signup-button').length, 'expects button to be in the DOM');\n    this.success();\n  });\n});\n```\n\nRun `lotte` from within the directory and you should see the following output:\n\n```\n/tmp/lotte_github.js\n  @ https://github.com\n      ✓ Sign Up button\n```\n\nCommand-Line Options\n--------------------\n\nYou can customise many aspects of Lotte's behaviour either on the command-line on through `Lottefile`s. The following options are available:\n\n```\n$ lotte --help\nUsage: lotte [OPTION...] PATH\n\nOptions:\n  --help, -h        give this help page\n  --version, -v     print program version\n  --concurrent, -c  limit of files to run in parallel                       [default: 4]\n  --timeout, -t     timeout for individual files (in milliseconds)          [default: 30000]\n  --include, -I     glob pattern to match files in PATH          [string]   [default: \"**/lotte_*.js\"]\n  --exclude, -E     glob pattern to remove included files        [string]\n  --lottefile, -f   look for 'lottefile' in PATH                 [string]   [default: \"Lottefile\"]\n  --verify          verify PhantomJS version (expected <2.0.0)   [boolean]  [default: true]\n  --phantom         executable for PhantomJS                     [string]   [default: \"phantomjs\"]\n  --coffee          executable for CofeeScript                   [string]   [default: \"coffee\"]\n```\n\nThere are four key options you would want to customise while the rest should work with their defaults.\n\n- **`--concurrent, -c`**\n\n    If you have more than one test file in a directory, Lotte will attempt to run them in parallel (asynchronously).\n    You can specify how many tests can be running at any given time through this option.\n\n    If you want to run tests synchronously, specify a value of `1`.\n\n- **`--timeout, -t`**\n\n    Each test is expected to finish within a given period of time. If a test takes longer, it is interruped and recorded as failed.\n\n    The default value is `30` seconds, but you should consider reducing it.\n\n- **`--include, -I`  \n  `--exclude, -E`**\n\n    When you run `lotte` from any directory the script collects a list of all files in the current directory and all sub-directories.\n    The list is reduced by running the `include` glob pattern and dropping any files that did not match.\n    The list is then reduced further by running the `exclude` glob pattern and dropping any files that did match.\n    The remaining list is sorted and considered final.\n\n    You can specify these arguments more than once to create an array of include/exclude patterns.\n\n### Lottefile\n\nIn order to avoid having to type the full `lotte` command-line each time, you can use `Lottefile`s to store your settings per project.\n\n`Lottefile`s are regular JavaScript files where each global variable maps to a command-line option. For example, the following command:\n\n```\n$ lotte --include '**/*.coffee' --include '**/*.js' --concurrent 1 tests\n```\n\ncan be stored in a `Lottefile` as this:\n\n```javascript\npath       = 'tests'\ninclude    = ['**/*.coffee', '**/*.js']\nconcurrent = 1\n```\n\nRunning `lotte` from the project directory will then read the `Lottefile` and scan the `tests` directory for all files matching `**/*.{coffee,js}`.\n\nWriting Tests\n-------------\n\nTests can be written in either JavaScript or CoffeeScript.\nIn the sections below substitute `@` with `this.` if you are using JavaScript.\nArguments wrapped in square brackets `[` and `]` are optional.\nArguments ending in `...` can be used more than once.\n\nAt the top-level, the following functions are available:\n\n- **`@title([name])`**\n\n    Gets or sets the test title.\n    This is useful for giving meaningful names to your tests.\n\n    When called with zero arguments, returns the current title or `undefined`.  \n    When called with one argument, sets the title.\n\n    If you don't explicitly specify a title, the filename will be used instead.\n\n- **`@base([uri])`**\n\n    Gets or sets the absolute URI for all relative URIs in the test.\n    You can use this to specify the root URI for your project.\n\n    When called with zero arguments, returns the current URI or `undefined`.  \n    When called with one argument, sets the URI.\n\n    If you don't explicitly specify an absolute URI, all calls to `@open` will expect an absolute URI instead.\n\n- **`@open(uri, [message], [options], block)`**\n\n    Creates a new test.\n\n    `uri` can be either an absolute or relative URI (see above).  \n    `message` is an optional description for the URI. If you don't specify it, Lotte will print the `uri` in the output instead.  \n    `options` is an object hash to pass to PhantomJS. See [settings (object)][settings].  \n    `block` is a function which is executed if the server returns a valid response (2xx or 3xx).\n\n    If the server returns a 4xx or 5xx HTTP code instead, the test is recorded as failed.\n\n    If you have more than one `@open` call at the top-level, they will be executed asynchronously.\n\n  [settings]: http://code.google.com/p/phantomjs/wiki/Interface#settings_(object)\n\nPutting it all together, a test file could look like this:\n\n```coffeescript\n@title 'Github'\n@base  'https://github.com'\n\n@open '/', 'the homepage', ->\n  # ...body of test...\n```\n\n### Cases & Grouping\n\nOnce you have successfully requested an URI, you can start writing test cases against the page.\n\nThe following functions are available:\n\n- **`@group(name, block)`**\n\n    Groups the nested test cases. This is mainly for structuring the output Lotte prints.\n\n    `name` is the name of the group.  \n    `block` is a function which contains the nested test cases.\n\n- **`@describe(name, block)`**\n\n    Starts a new test case.\n\n    `name` is the name of the test case.  \n    `block` is a function which is executed and is expected to contain assertion logic.\n\nPutting it all together a test file could now look like this:\n\n```coffeescript\n@title 'Github'\n@base  'https://github.com'\n\n@open '/', 'the homepage', ->\n  @describe 'counter shows number of repositories', ->\n    # ...assertion logic...\n  @group 'Sign Up button', ->\n    @describe 'is in place', ->\n      # ...assertion logic...\n    @describe 'takes you to /plans', ->\n      # ...assertion logic...\n```\n\n#### Flow of Execution\n\nEach test case is executed in the order in which it is defined:\n\n```coffeescript\n@describe 'I run first', ->\n@describe 'I run second', ->\n# etc.\n```\n\nIf a test case contains an asynchronous function call, the next test case is executed without waiting for the function to finish:\n\n```coffeescript\n@describe 'I run first', ->\n@describe 'I run second', ->\n  setTimeout ( -> ), 2500\n@describe 'I run third in parallel with second still running', ->\n```\n\nBe extremely careful when dealing with asynchronous function. For example, using `.click()` to follow an anchor could change the page while another test case is running.\n\nIf a test case fails, any remaining test cases are skipped:\n\n```coffeescript\n@describe 'I run first', ->\n  throw 'Whoops!'\n@describe 'I should run second, but I never will', ->\n```\n\nTo simulate dependencies and control the flow of execution, you can use the following functions:\n\n- **`@wait(name..., block)`**\n\n    Blocks the current test case until all dependencies have finished (either passed or failed).\n\nThe earlier example can now be rewritten as follows to make it synchronous again:\n\n```coffeescript\n@describe 'I run first', ->\n@describe 'I run second', ->\n  setTimeout ( -> ), 2500\n@describe 'I run third', ->\n  @wait 'I run second', ->\n    # ...assertion logic...\n```\n\n### Environments\n\nLotte uses PhantomJS to execute tests. While you may be writing tests in JavaScript and expect to be able to access the DOM of a page directly, this is not the case.\n\nEach test file runs in its own sandboxed environment. Each page you request also runs in a sandbox.\nYou cannot access variables across environments, i.e., you cannot define a variable in your test file and access it within the page you have just requested:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'Sandbox', ->\n    val = 'value'\n    # following line throws an exception\n    console.log(@page.evaluate( -> return val))\n    throw 'exit'\n```\n\nIn the above code snippet `@page.evaluate` runs the function as if it were defined on the page you just requested, i.e, `github.com`.\nIn order to do so, PhantomJS serializes the function, but it does not include the context in which it was defined.\nWhen the function is executed, `val` is missing in the new context causing it to throw an exception.\n\nAnother limitation of PhantomJS is the fact you cannot return complex types from the page.\nObjects are serialized before they leave the page sandbox and unserialized back in the parent (test case) environment:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'serialize/unserialize', ->\n    h1 = @page.evaluate( -> return document.querySelector('h1'))\n    # prints 'H1' correctly\n    console.log h1.tagName\n    # prints 'undefined' as functions cannot be serialized/unserialized\n    console.log h1.focus\n    throw 'exit'\n```\n\nLotte comes with a workaround which allows you to pass variables to the PhantomJS environment.\nThis hack has the same limitations as outlined above (it uses `JSON.stringify` internally):\n\n- **`@using(hash, block)`**\n\n    `hash` is a `key: value` object where:\n\n      - `key` must be a valid identifier and defines the name of the variable within the PhantomJS environment\n      - `value` must be serializable and contains the value of the variable\n\n    `block` is either a function or a string.\n\n    Returns a `Function` string with all `key: value` pairs from `hash` as arguments.\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe '@using(..)', ->\n    expected = 'git'\n    @$('h2').first @using { expected }, (element) -> element.innerHTML.indexOf(expected) is 0\n    throw 'exit'\n```\n\n#### Document Queries\n\nThere is a lot of boilerplate code required to access the DOM of a page.\nLotte comes with a jQuery-like query function to abstract some of the most common operations:\n\n- **`@$(selector)`**\n\n    `selector` is a string containing a selector expression.\n\n    Returns a `DocumentQuery` object.\n\nThe earlier example can now be rewritten as follows:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'Document Queries', ->\n    # prints 'H1' correctly\n    console.log @$('h1').tagName\n    # prints 'undefined'\n    console.log @$('h1').focus\n    throw 'exit'\n```\n\n##### Additional Methods\n\nA `DocumentQuery` object has the following methods to deal with the DOM:\n\n- **`DocumentQuery.prototype.attr([index], property)`**\n\n    Gets the value of `property` for the element at `index`.\n\n    The following code snippets are equivalent:\n\n    ```coffeescript\n    @$('h1').attr('tagName')\n    @$('h1').tagName\n    ```\n\n    The direct property access always returns the property value for the first matched element.\n\n    While you can use `attr(..)` to access any property, the direct access will only work with the following pre-defined list of properties: `action`, `alt`, `checked`, `className`, `clientHeight`, `clientLeft`, `clientTop`, `clientWidth`, `disabled`, `enctype`, `height`, `href`, `id`, `innerHTML`, `length`, `maxLength`, `media`, `method`, `name`, `nodeName`, `nodeValue`, `offsetHeight`, `offsetLeft`, `offsetTop`, `offsetWidth`, `options`, `outerHTML`, `outerText`, `readOnly`, `rel`, `scrollHeight`, `scrollLeft`, `scrollTop`, `scrollWidth`, `selectedIndex`, `size`, `src`, `style`, `tagName`, `target`, `textContent`, `title`, `type`, `value`, `width`.\n\n- **`DocumentQuery.prototype.click([index], [message], [block])`**\n\n    Clicks on the element at `index` and returns execution to the test case (i.e., asynchronous). This method can be used to simulate mouse input.\n\n    `index` is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.  \n    `message` is an optional message to display if something goes wrong, i.e., if no elements were matched.  \n    `block` is an optional function to execute when the new page has loaded, i.e., when you follow an anchor.\n\n    ```coffeescript\n    @open 'https://github.com', ->\n      @describe 'click(..)', ->\n        # prints https://github.com/\n        console.log('I am now on: ' + @page.evaluate( -> location.href))\n        @$('.signup-button').click ->\n          # prints https://github.com/plans\n          console.log('I am now on: ' + @page.evaluate( -> location.href))\n          throw 'exit'\n    ```\n\n- **`DocumentQuery.prototype.input(value, [index], [message])`**\n\n    Inputs `value` in the element at `index`. This method can be used to simulate keyboard input.\n\n    `value` is a string to input as if it were keyboard input.  \n    `index` is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.  \n    `message` is an optional message to display if something goes wrong, i.e., if no elements were matched.\n\n    ```coffeescript\n    @open 'http://www.google.com', ->\n      @describe 'input(..)', ->\n        @$('[name=\"q\"]').input 'meaning of life'\n        @$('input[type=\"submit\"]').click ->\n          console.log @$('#res').attr('innerText')\n          throw 'exit'\n    ```\n\nSee **DOM Assertions** below for additional methods.\n\n### Assertions\n\nLotte comes with two types of assertion logic:\n\n- Generic assertions\n- DOM assertions\n\n#### Generic Assertions\n\nIf you have used Node's built-in [assert][assert] module, these functions will be familiar:\n\n- **`@assert.fail(actual, expected, message, operator)`**\n\n    Throws an exception that displays the values for `actual` and `expected` separated by the provided `operator`.\n\n- **`@assert.ok(value, message)`**\n\n    Tests if `value` is a true value, it is equivalent to `@assert.equal(true, value, message)`.\n\n- **`@assert.equal(actual, expected, message)`**\n\n    Tests shallow, coercive equality with the equal comparison operator `==`.\n\n- **`@assert.notEqual(actual, expected, message)`**\n\n    Tests shallow, coercive non-equality with the not equal comparison operator `!=`.\n\n- **`@assert.deepEqual(actual, expected, message)`**\n\n    Tests for deep equality.\n\n- **`@assert.notDeepEqual(actual, expected, message)`**\n\n    Tests for any deep inequality.\n\n- **`@assert.strictEqual(actual, expected, message)`**\n\n    Tests strict equality, as determined by the strict equality operator `===`.\n\n- **`@assert.notStrictEqua(actual, expected, message)`**\n\n    Tests strict non-equality, as determined by the strict not equal operator `!==`.\n\n- **`@assert.throws(block, error, message)`**\n\n    Expects `block` to throw an error. `error` can be constructor, RegExp or validation function.\n\n- **`@assert.doesNotThrow(block, error, message)`**\n\n    Expects `block` not to throw an error, see `@assert.throws` for details.\n\n- **`@assert.contains(actual, expected, message)`**\n\n    Expects `actual` to contain `expected`. `expected` can be a string or a RegExp.\n\n  [assert]: http://nodejs.org/docs/v0.6.0/api/assert.html\n\n#### DOM Assertions\n\n`DocumentQuery` (see above) comes with additional methods to deal with assertions:\n\n- **`DocumentQuery.prototype.contains([message], pattern)`**\n\n    Expects at least one of the matched elements to contain `pattern`. `pattern` can be a string or a RegExp.\n\n- **`DocumentQuery.prototype.each([message], block)`**\n\n    Tests if calling `block` on each matched element as an argument returns a true value.\n\n- **`DocumentQuery.prototype.first([message], block)`**\n\n    Tests if calling `block` with the first matched element as an argument returns a true value.\n\n- **`DocumentQuery.prototype.last([message], block)`**\n\n    Tests if calling `block` with the last matched element as an argument returns a true value.\n\n- **`DocumentQuery.prototype.nth(index, [message], block)`**\n\n    Tests if calling `block` with the element at `index` as an argument returns a true value.\n\nA general note which applies to all functions above: you cannot access variables from scope within `block` (see **Environments**).\n\nAn example test file that performs DOM assertions could look like this:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'Navigation and children have classes', ->\n    @$('.nav').first   (element) -> element.classList.contains('logged_out')\n    @$('.nav li').each (element) -> !! element.className\n    throw 'exit'\n```\n\nPassing Tests\n-------------\n\nSo far we have ended tests with `throw 'exit'`. To pass a test case, use the following functions:\n\n- **`@success()`**\n\n    Marks the test case as passed. You must call this once within each `@describe` block.\n\nIf you don't end a test case either by failing any of the asserts or calling `@success()`, the entire test file will hang until `timeout` is reached at which point it is recorded as failed.\n\nFAQs\n----\n\n- **Q**: How can I log in before requesting a page?\n\n    **A**: You can nest `@open(..)` functions to achieve this:\n\n    ```coffeescript\n    @base 'http://local.dev'\n    @open '/login', ->\n      @describe 'Log in', ->\n        @$('.username').input 'admin'\n        @$('.password').input 'password'\n        @$('input[type=\"submit\"]').click ->\n          @success()\n          @open '/account', ->\n            @describe 'My Account', ->\n              # ...assertion logic...\n              @success()\n    ```\n\n- **Q**: Can I pass arguments to my tests?\n\n    **A**: Yes. Use `--` on the command-line followed by the arguments:\n\n    ```\n    $ lotte -- arg1 arg2\n    ```\n\n    Arguments will be available in your test files as `phantom.args[..]`.\n\n- **Q**: How can I see what PhantomJS 'sees'?\n\n    **A**: Within the context of a test case (`@describe`), you can refer to `@page` which is the PhantomJS [WebPage][webpage] object.\n\n    ```coffeescript\n    @describe 'snapshot', ->\n      @page.render 'home.png'\n      @success()\n    ```\n\n- **Q**: I don't have `phantomjs` and/or `coffee` on `$PATH`.\n\n    **A**: See `lotte --help` for information on how to specify a path to the missing binary.\n\n  [webpage]:   http://code.google.com/p/phantomjs/wiki/Interface#'_WebPage_'_Object\n\nContributing\n------------\n\nThe goal of this project is to provide an awesome tool for developers to test their websites or apps in their favourite language with minimum effort.\n\nCommit and code reviews, ideas and documentation improvements are welcomed.\n\nChangelog\n---------\n\n- [0.1.2](https://github.com/StanAngeloff/lotte/compare/0.1.1...0.1.2)\n- [0.1.2-1](https://github.com/StanAngeloff/lotte/compare/0.1.2...0.1.2-1)\n- [0.1.2-2](https://github.com/StanAngeloff/lotte/compare/0.1.2-1...0.1.2-2)\n- [0.2.0](https://github.com/StanAngeloff/lotte/compare/0.1.2-2...0.2.0)\n- [0.2.0-1](https://github.com/StanAngeloff/lotte/compare/0.2.0...0.2.0-1)\n- [0.2.1](https://github.com/StanAngeloff/lotte/compare/0.2.0-1...0.2.1)\n- [0.2.2](https://github.com/StanAngeloff/lotte/compare/0.2.1...0.2.2)\n- [0.2.2-1](https://github.com/StanAngeloff/lotte/compare/0.2.2...0.2.2-1)\n- [0.2.2-2](https://github.com/StanAngeloff/lotte/compare/0.2.2-1...0.2.2-2)\n- [0.2.2-3](https://github.com/StanAngeloff/lotte/compare/0.2.2-2...0.2.2-3)\n\n### Copyright\n\n> Copyright (c) 2011 Stan Angeloff. See [LICENSE.md](https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md) for details.\n","readmeFilename":"README.md","_id":"lotte@0.2.2-3","dist":{"shasum":"cf8cacc59bbeb8ba9da340379316c0f369c0b9f1","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.2.2-3.tgz","integrity":"sha512-lXB9hKZGTetlNgUFLqUNKO5VvZfi24cFX9hbM7S8shfJZUZohViAMy9U+y5WESuatm7f0tJg1Ewsi3/Oafol8A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCnYb8ArL+YvZKZwOOcxeK+RPCdi8gRtrdIiGdTr6fncgIgXVlZugJkFKJ0ND0LLkUXFSWJCiWM0jPM1s/i1QeQQJ0="}]},"_from":".","_npmVersion":"1.2.15","_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}]},"0.2.3":{"name":"lotte","version":"0.2.3","description":"Headless, automated browser testing using PhantomJS","homepage":"https://github.com/StanAngeloff/lotte","bugs":{"url":"https://github.com/StanAngeloff/lotte/issues"},"author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"files":["bin/","lib/","test/"],"bin":{"lotte":"bin/cli.js"},"main":"lib/lotte.js","repository":{"type":"git","url":"https://github.com/StanAngeloff/lotte"},"dependencies":{"minimatch":"~0.2.6","naturalsort":"~0.0.1","optimist":"~0.3.4","semver":"~1.0.14","tmp":"~0.0.14","walkdir":"~0.0.4"},"devDependencies":{"express":"~3.0.0"},"engines":{"node":">=0.8"},"preferGlobal":true,"readme":"Lotte\n=====\n\nLotte is a headless, automated testing framework built on top of [PhantomJS][phantom] and inspired by [Ghostbuster][ghostbuster].\nIt adds jQuery-like methods and chaining, more assertion logic and an extensible core.\nTests can be written in either JavaScript or [CoffeeScript][coffee].\n\nLotte comes with tools for accessing the DOM, evaluating arbitrary code, simulating mouse and keyboard input.\n\nTests are sandboxed and run asynchronously. Blocking methods are available to simulate dependencies and to control the flow of execution.\n\nThis project is still highly experimental. Using it may cause your computer to blow up. [Seriously.][license]\n\n  [phantom]:     http://www.phantomjs.org/\n  [ghostbuster]: https://github.com/joshbuddy/ghostbuster\n  [coffee]:      http://coffeescript.org/\n  [license]:     https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md\n\nPrerequisites\n-------------\n\n- [node.js][nodejs] **>=0.8**\n- [npm][npm] **>=1.0**\n- [PhantomJS][phantom] **<2.0.0**\n\n  [npm]:       http://npmjs.org/\n  [nodejs]:    http://nodejs.org/\n  [phantom]:   http://www.phantomjs.org/\n\n### Optional Dependencies\n\n- [CoffeeScript][coffee]\n\n  [coffee]:    http://coffeescript.org/\n\nInstallation\n------------\n\n    $ npm -g install lotte\n\n`-g`lobal is preferred so you can run `lotte` from any directory.\n\nUsage\n-----\n\nCreate a new file `lotte_github.js` (preferably in an empty directory) and copy the following code:\n\n```javascript\nthis.open('https://github.com', function() {\n  this.describe('Sign Up button', function() {\n    this.assert.ok(this.$('.signup-button').length, 'expects button to be in the DOM');\n    this.success();\n  });\n});\n```\n\nRun `lotte` from within the directory and you should see the following output:\n\n```\n/tmp/lotte_github.js\n  @ https://github.com\n      ✓ Sign Up button\n```\n\nCommand-Line Options\n--------------------\n\nYou can customise many aspects of Lotte's behaviour either on the command-line on through `Lottefile`s. The following options are available:\n\n```\n$ lotte --help\nUsage: lotte [OPTION...] PATH\n\nOptions:\n  --help, -h        give this help page\n  --version, -v     print program version\n  --concurrent, -c  limit of files to run in parallel                       [default: 4]\n  --timeout, -t     timeout for individual files (in milliseconds)          [default: 30000]\n  --include, -I     glob pattern to match files in PATH          [string]   [default: \"**/lotte_*.js\"]\n  --exclude, -E     glob pattern to remove included files        [string]\n  --lottefile, -f   look for 'lottefile' in PATH                 [string]   [default: \"Lottefile\"]\n  --verify          verify PhantomJS version (expected <2.0.0)   [boolean]  [default: true]\n  --phantom         executable for PhantomJS                     [string]\n  --coffee          executable for CofeeScript                   [string]\n```\n\nThere are four key options you would want to customise while the rest should work with their defaults.\n\n- **`--concurrent, -c`**\n\n    If you have more than one test file in a directory, Lotte will attempt to run them in parallel (asynchronously).\n    You can specify how many tests can be running at any given time through this option.\n\n    If you want to run tests synchronously, specify a value of `1`.\n\n- **`--timeout, -t`**\n\n    Each test is expected to finish within a given period of time. If a test takes longer, it is interruped and recorded as failed.\n\n    The default value is `30` seconds, but you should consider reducing it.\n\n- **`--include, -I`  \n  `--exclude, -E`**\n\n    When you run `lotte` from any directory the script collects a list of all files in the current directory and all sub-directories.\n    The list is reduced by running the `include` glob pattern and dropping any files that did not match.\n    The list is then reduced further by running the `exclude` glob pattern and dropping any files that did match.\n    The remaining list is sorted and considered final.\n\n    You can specify these arguments more than once to create an array of include/exclude patterns.\n\n### Lottefile\n\nIn order to avoid having to type the full `lotte` command-line each time, you can use `Lottefile`s to store your settings per project.\n\n`Lottefile`s are regular JavaScript files where each global variable maps to a command-line option. For example, the following command:\n\n```\n$ lotte --include '**/*.coffee' --include '**/*.js' --concurrent 1 tests\n```\n\ncan be stored in a `Lottefile` as this:\n\n```javascript\npath       = 'tests'\ninclude    = ['**/*.coffee', '**/*.js']\nconcurrent = 1\n```\n\nRunning `lotte` from the project directory will then read the `Lottefile` and scan the `tests` directory for all files matching `**/*.{coffee,js}`.\n\nWriting Tests\n-------------\n\nTests can be written in either JavaScript or CoffeeScript.\nIn the sections below substitute `@` with `this.` if you are using JavaScript.\nArguments wrapped in square brackets `[` and `]` are optional.\nArguments ending in `...` can be used more than once.\n\nAt the top-level, the following functions are available:\n\n- **`@title([name])`**\n\n    Gets or sets the test title.\n    This is useful for giving meaningful names to your tests.\n\n    When called with zero arguments, returns the current title or `undefined`.  \n    When called with one argument, sets the title.\n\n    If you don't explicitly specify a title, the filename will be used instead.\n\n- **`@base([uri])`**\n\n    Gets or sets the absolute URI for all relative URIs in the test.\n    You can use this to specify the root URI for your project.\n\n    When called with zero arguments, returns the current URI or `undefined`.  \n    When called with one argument, sets the URI.\n\n    If you don't explicitly specify an absolute URI, all calls to `@open` will expect an absolute URI instead.\n\n- **`@open(uri, [message], [options], block)`**\n\n    Creates a new test.\n\n    `uri` can be either an absolute or relative URI (see above).  \n    `message` is an optional description for the URI. If you don't specify it, Lotte will print the `uri` in the output instead.  \n    `options` is an object hash to pass to PhantomJS. See [settings (object)][settings].  \n    `block` is a function which is executed if the server returns a valid response (2xx or 3xx).\n\n    If the server returns a 4xx or 5xx HTTP code instead, the test is recorded as failed.\n\n    If you have more than one `@open` call at the top-level, they will be executed asynchronously.\n\n  [settings]: http://code.google.com/p/phantomjs/wiki/Interface#settings_(object)\n\nPutting it all together, a test file could look like this:\n\n```coffeescript\n@title 'Github'\n@base  'https://github.com'\n\n@open '/', 'the homepage', ->\n  # ...body of test...\n```\n\n### Cases & Grouping\n\nOnce you have successfully requested an URI, you can start writing test cases against the page.\n\nThe following functions are available:\n\n- **`@group(name, block)`**\n\n    Groups the nested test cases. This is mainly for structuring the output Lotte prints.\n\n    `name` is the name of the group.  \n    `block` is a function which contains the nested test cases.\n\n- **`@describe(name, block)`**\n\n    Starts a new test case.\n\n    `name` is the name of the test case.  \n    `block` is a function which is executed and is expected to contain assertion logic.\n\nPutting it all together a test file could now look like this:\n\n```coffeescript\n@title 'Github'\n@base  'https://github.com'\n\n@open '/', 'the homepage', ->\n  @describe 'counter shows number of repositories', ->\n    # ...assertion logic...\n  @group 'Sign Up button', ->\n    @describe 'is in place', ->\n      # ...assertion logic...\n    @describe 'takes you to /plans', ->\n      # ...assertion logic...\n```\n\n#### Flow of Execution\n\nEach test case is executed in the order in which it is defined:\n\n```coffeescript\n@describe 'I run first', ->\n@describe 'I run second', ->\n# etc.\n```\n\nIf a test case contains an asynchronous function call, the next test case is executed without waiting for the function to finish:\n\n```coffeescript\n@describe 'I run first', ->\n@describe 'I run second', ->\n  setTimeout ( -> ), 2500\n@describe 'I run third in parallel with second still running', ->\n```\n\nBe extremely careful when dealing with asynchronous function. For example, using `.click()` to follow an anchor could change the page while another test case is running.\n\nIf a test case fails, any remaining test cases are skipped:\n\n```coffeescript\n@describe 'I run first', ->\n  throw 'Whoops!'\n@describe 'I should run second, but I never will', ->\n```\n\nTo simulate dependencies and control the flow of execution, you can use the following functions:\n\n- **`@wait(name..., block)`**\n\n    Blocks the current test case until all dependencies have finished (either passed or failed).\n\nThe earlier example can now be rewritten as follows to make it synchronous again:\n\n```coffeescript\n@describe 'I run first', ->\n@describe 'I run second', ->\n  setTimeout ( -> ), 2500\n@describe 'I run third', ->\n  @wait 'I run second', ->\n    # ...assertion logic...\n```\n\n### Environments\n\nLotte uses PhantomJS to execute tests. While you may be writing tests in JavaScript and expect to be able to access the DOM of a page directly, this is not the case.\n\nEach test file runs in its own sandboxed environment. Each page you request also runs in a sandbox.\nYou cannot access variables across environments, i.e., you cannot define a variable in your test file and access it within the page you have just requested:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'Sandbox', ->\n    val = 'value'\n    # following line throws an exception\n    console.log(@page.evaluate( -> return val))\n    throw 'exit'\n```\n\nIn the above code snippet `@page.evaluate` runs the function as if it were defined on the page you just requested, i.e, `github.com`.\nIn order to do so, PhantomJS serializes the function, but it does not include the context in which it was defined.\nWhen the function is executed, `val` is missing in the new context causing it to throw an exception.\n\nAnother limitation of PhantomJS is the fact you cannot return complex types from the page.\nObjects are serialized before they leave the page sandbox and unserialized back in the parent (test case) environment:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'serialize/unserialize', ->\n    h1 = @page.evaluate( -> return document.querySelector('h1'))\n    # prints 'H1' correctly\n    console.log h1.tagName\n    # prints 'undefined' as functions cannot be serialized/unserialized\n    console.log h1.focus\n    throw 'exit'\n```\n\nLotte comes with a workaround which allows you to pass variables to the PhantomJS environment.\nThis hack has the same limitations as outlined above (it uses `JSON.stringify` internally):\n\n- **`@using(hash, block)`**\n\n    `hash` is a `key: value` object where:\n\n      - `key` must be a valid identifier and defines the name of the variable within the PhantomJS environment\n      - `value` must be serializable and contains the value of the variable\n\n    `block` is either a function or a string.\n\n    Returns a `Function` string with all `key: value` pairs from `hash` as arguments.\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe '@using(..)', ->\n    expected = 'git'\n    @$('h2').first @using { expected }, (element) -> element.innerHTML.indexOf(expected) is 0\n    throw 'exit'\n```\n\n#### Document Queries\n\nThere is a lot of boilerplate code required to access the DOM of a page.\nLotte comes with a jQuery-like query function to abstract some of the most common operations:\n\n- **`@$(selector)`**\n\n    `selector` is a string containing a selector expression.\n\n    Returns a `DocumentQuery` object.\n\nThe earlier example can now be rewritten as follows:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'Document Queries', ->\n    # prints 'H1' correctly\n    console.log @$('h1').tagName\n    # prints 'undefined'\n    console.log @$('h1').focus\n    throw 'exit'\n```\n\n##### Additional Methods\n\nA `DocumentQuery` object has the following methods to deal with the DOM:\n\n- **`DocumentQuery.prototype.attr([index], property)`**\n\n    Gets the value of `property` for the element at `index`.\n\n    The following code snippets are equivalent:\n\n    ```coffeescript\n    @$('h1').attr('tagName')\n    @$('h1').tagName\n    ```\n\n    The direct property access always returns the property value for the first matched element.\n\n    While you can use `attr(..)` to access any property, the direct access will only work with the following pre-defined list of properties: `action`, `alt`, `checked`, `className`, `clientHeight`, `clientLeft`, `clientTop`, `clientWidth`, `disabled`, `enctype`, `height`, `href`, `id`, `innerHTML`, `length`, `maxLength`, `media`, `method`, `name`, `nodeName`, `nodeValue`, `offsetHeight`, `offsetLeft`, `offsetTop`, `offsetWidth`, `options`, `outerHTML`, `outerText`, `readOnly`, `rel`, `scrollHeight`, `scrollLeft`, `scrollTop`, `scrollWidth`, `selectedIndex`, `size`, `src`, `style`, `tagName`, `target`, `textContent`, `title`, `type`, `value`, `width`.\n\n- **`DocumentQuery.prototype.click([index], [message], [block])`**\n\n    Clicks on the element at `index` and returns execution to the test case (i.e., asynchronous). This method can be used to simulate mouse input.\n\n    `index` is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.  \n    `message` is an optional message to display if something goes wrong, i.e., if no elements were matched.  \n    `block` is an optional function to execute when the new page has loaded, i.e., when you follow an anchor.\n\n    ```coffeescript\n    @open 'https://github.com', ->\n      @describe 'click(..)', ->\n        # prints https://github.com/\n        console.log('I am now on: ' + @page.evaluate( -> location.href))\n        @$('.signup-button').click ->\n          # prints https://github.com/plans\n          console.log('I am now on: ' + @page.evaluate( -> location.href))\n          throw 'exit'\n    ```\n\n- **`DocumentQuery.prototype.input(value, [index], [message])`**\n\n    Inputs `value` in the element at `index`. This method can be used to simulate keyboard input.\n\n    `value` is a string to input as if it were keyboard input.  \n    `index` is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.  \n    `message` is an optional message to display if something goes wrong, i.e., if no elements were matched.\n\n    ```coffeescript\n    @open 'http://www.google.com', ->\n      @describe 'input(..)', ->\n        @$('[name=\"q\"]').input 'meaning of life'\n        @$('input[type=\"submit\"]').click ->\n          console.log @$('#res').attr('innerText')\n          throw 'exit'\n    ```\n\nSee **DOM Assertions** below for additional methods.\n\n### Assertions\n\nLotte comes with two types of assertion logic:\n\n- Generic assertions\n- DOM assertions\n\n#### Generic Assertions\n\nIf you have used Node's built-in [assert][assert] module, these functions will be familiar:\n\n- **`@assert.fail(actual, expected, message, operator)`**\n\n    Throws an exception that displays the values for `actual` and `expected` separated by the provided `operator`.\n\n- **`@assert.ok(value, message)`**\n\n    Tests if `value` is a true value, it is equivalent to `@assert.equal(true, value, message)`.\n\n- **`@assert.equal(actual, expected, message)`**\n\n    Tests shallow, coercive equality with the equal comparison operator `==`.\n\n- **`@assert.notEqual(actual, expected, message)`**\n\n    Tests shallow, coercive non-equality with the not equal comparison operator `!=`.\n\n- **`@assert.deepEqual(actual, expected, message)`**\n\n    Tests for deep equality.\n\n- **`@assert.notDeepEqual(actual, expected, message)`**\n\n    Tests for any deep inequality.\n\n- **`@assert.strictEqual(actual, expected, message)`**\n\n    Tests strict equality, as determined by the strict equality operator `===`.\n\n- **`@assert.notStrictEqua(actual, expected, message)`**\n\n    Tests strict non-equality, as determined by the strict not equal operator `!==`.\n\n- **`@assert.throws(block, error, message)`**\n\n    Expects `block` to throw an error. `error` can be constructor, RegExp or validation function.\n\n- **`@assert.doesNotThrow(block, error, message)`**\n\n    Expects `block` not to throw an error, see `@assert.throws` for details.\n\n- **`@assert.contains(actual, expected, message)`**\n\n    Expects `actual` to contain `expected`. `expected` can be a string or a RegExp.\n\n  [assert]: http://nodejs.org/docs/v0.6.0/api/assert.html\n\n#### DOM Assertions\n\n`DocumentQuery` (see above) comes with additional methods to deal with assertions:\n\n- **`DocumentQuery.prototype.contains([message], pattern)`**\n\n    Expects at least one of the matched elements to contain `pattern`. `pattern` can be a string or a RegExp.\n\n- **`DocumentQuery.prototype.each([message], block)`**\n\n    Tests if calling `block` on each matched element as an argument returns a true value.\n\n- **`DocumentQuery.prototype.first([message], block)`**\n\n    Tests if calling `block` with the first matched element as an argument returns a true value.\n\n- **`DocumentQuery.prototype.last([message], block)`**\n\n    Tests if calling `block` with the last matched element as an argument returns a true value.\n\n- **`DocumentQuery.prototype.nth(index, [message], block)`**\n\n    Tests if calling `block` with the element at `index` as an argument returns a true value.\n\nA general note which applies to all functions above: you cannot access variables from scope within `block` (see **Environments**).\n\nAn example test file that performs DOM assertions could look like this:\n\n```coffeescript\n@open 'https://github.com', ->\n  @describe 'Navigation and children have classes', ->\n    @$('.nav').first   (element) -> element.classList.contains('logged_out')\n    @$('.nav li').each (element) -> !! element.className\n    throw 'exit'\n```\n\nPassing Tests\n-------------\n\nSo far we have ended tests with `throw 'exit'`. To pass a test case, use the following functions:\n\n- **`@success()`**\n\n    Marks the test case as passed. You must call this once within each `@describe` block.\n\nIf you don't end a test case either by failing any of the asserts or calling `@success()`, the entire test file will hang until `timeout` is reached at which point it is recorded as failed.\n\nFAQs\n----\n\n- **Q**: How can I log in before requesting a page?\n\n    **A**: You can nest `@open(..)` functions to achieve this:\n\n    ```coffeescript\n    @base 'http://local.dev'\n    @open '/login', ->\n      @describe 'Log in', ->\n        @$('.username').input 'admin'\n        @$('.password').input 'password'\n        @$('input[type=\"submit\"]').click ->\n          @success()\n          @open '/account', ->\n            @describe 'My Account', ->\n              # ...assertion logic...\n              @success()\n    ```\n\n- **Q**: Can I pass arguments to my tests?\n\n    **A**: Yes. Use `--` on the command-line followed by the arguments:\n\n    ```\n    $ lotte -- arg1 arg2\n    ```\n\n    Arguments will be available in your test files as `phantom.args[..]`.\n\n- **Q**: How can I see what PhantomJS 'sees'?\n\n    **A**: Within the context of a test case (`@describe`), you can refer to `@page` which is the PhantomJS [WebPage][webpage] object.\n\n    ```coffeescript\n    @describe 'snapshot', ->\n      @page.render 'home.png'\n      @success()\n    ```\n\n- **Q**: I don't have `phantomjs` and/or `coffee` on `$PATH`.\n\n    **A**: See `lotte --help` for information on how to specify a path to the missing binary.\n\n    Optionally, you can install the corresponding [NPM] modules [coffee-script] and [phantomjs] in your project.\n\n\n  [webpage]:   http://code.google.com/p/phantomjs/wiki/Interface#'_WebPage_'_Object\n  [NPM]: https://npmjs.org/\n  [coffee-script]: https://npmjs.org/package/coffee-script\n  [phantomjs]: https://npmjs.org/package/phantomjs\n\nContributing\n------------\n\nThe goal of this project is to provide an awesome tool for developers to test their websites or apps in their favourite language with minimum effort.\n\nCommit and code reviews, ideas and documentation improvements are welcomed.\n\nChangelog\n---------\n\n- [0.1.2](https://github.com/StanAngeloff/lotte/compare/0.1.1...0.1.2)\n- [0.1.2-1](https://github.com/StanAngeloff/lotte/compare/0.1.2...0.1.2-1)\n- [0.1.2-2](https://github.com/StanAngeloff/lotte/compare/0.1.2-1...0.1.2-2)\n- [0.2.0](https://github.com/StanAngeloff/lotte/compare/0.1.2-2...0.2.0)\n- [0.2.0-1](https://github.com/StanAngeloff/lotte/compare/0.2.0...0.2.0-1)\n- [0.2.1](https://github.com/StanAngeloff/lotte/compare/0.2.0-1...0.2.1)\n- [0.2.2](https://github.com/StanAngeloff/lotte/compare/0.2.1...0.2.2)\n- [0.2.2-1](https://github.com/StanAngeloff/lotte/compare/0.2.2...0.2.2-1)\n- [0.2.2-2](https://github.com/StanAngeloff/lotte/compare/0.2.2-1...0.2.2-2)\n- [0.2.2-3](https://github.com/StanAngeloff/lotte/compare/0.2.2-2...0.2.2-3)\n- [0.2.3](https://github.com/StanAngeloff/lotte/compare/0.2.2-3...0.2.3)\n\n### Copyright\n\n> Copyright (c) 2011 Stan Angeloff. See [LICENSE.md](https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md) for details.\n","readmeFilename":"README.md","_id":"lotte@0.2.3","dist":{"shasum":"189a0e98349026a8704ecf47c0260efb9abf8341","tarball":"https://registry.npmjs.org/lotte/-/lotte-0.2.3.tgz","integrity":"sha512-5up512v4VD1ssMFJCHkRLZkyd4Snmtod5tJAtt/X0Uj9Lcc64e0T1aH7XEvdiDCpBCGZ7bjwruI3JnPGepBigw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCEzJhjGk/1MDK5bT+9sYzX9VtVW7jDBH7avfsgZuLofgIhAMfqYEuuvolyMYhJ1BMgDDsKZwUVsOfF/ppu49Qt0Xsq"}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"stanangeloff","email":"stanimir@angeloff.name"},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}]}},"maintainers":[{"name":"stanangeloff","email":"stanimir@angeloff.name"}],"time":{"modified":"2022-06-19T14:22:30.592Z","created":"2011-11-20T10:53:33.300Z","0.1.0":"2011-11-20T10:55:56.693Z","0.1.1":"2011-11-20T14:39:43.274Z","0.1.2":"2011-11-24T09:21:29.527Z","0.1.2-1":"2011-11-24T16:24:02.440Z","0.1.2-2":"2012-04-25T12:59:06.232Z","0.2.0-1":"2012-09-07T11:14:29.391Z","0.2.1":"2012-09-07T11:24:34.148Z","0.2.2":"2012-09-07T13:51:57.801Z","0.2.2-1":"2012-09-07T13:56:06.695Z","0.2.2-2":"2012-09-25T08:36:09.526Z","0.2.2-3":"2013-04-03T15:25:59.578Z","0.2.3":"2013-09-23T07:01:45.639Z"},"author":{"name":"Stan Angeloff","email":"stanimir@angeloff.name","url":"http://blog.angeloff.name"},"repository":{"type":"git","url":"https://github.com/StanAngeloff/lotte"},"users":{}}