Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: StanAngeloff/lotte
base: 0.1.1
...
head fork: StanAngeloff/lotte
compare: 0.1.2
Checking mergeability… Don't worry, you can still create the pull request.
  • 6 commits
  • 8 files changed
  • 0 commit comments
  • 1 contributor
Commits on Nov 20, 2011
@StanAngeloff .{git,npm}ignore updated, #nfc. 25d3a56
@StanAngeloff Finish up documentation, hopefully everything is covered and easy to …
…follow.
d2c67f1
@StanAngeloff Final (hopefully) tweaks to the README. a6ac08f
Commits on Nov 24, 2011
@StanAngeloff Improve Node.js 0.6.x support.
- Remove tests where authentication fails, this now causes PhantomJS to
  hang with Node 0.6.2
- Use response.writeHead and response.end without a status code as both
  send headers causing Node 0.6.2 to spit endless screens of warnings
- Bump supported version in package & README
3a27fe4
@StanAngeloff Update `mktemp` command to work on Mac OS X.
On Linux, the options and template arguments are both optional.
On Mac OS X you must provide either a path or a template where
each 'X' is substituted with a random character (8 should do).
6a08b13
@StanAngeloff Bump version. 8c1a868
View
4 .gitignore
@@ -1,3 +1,7 @@
+~*
.*.pid
+lotte-*.tgz
node_modules
npm-*.log
+README.html
+Watchrfile
View
8 .npmignore
@@ -0,0 +1,8 @@
+~*
+.*.pid
+.*ignore
+lotte-*.tgz
+node_modules
+npm-*.log
+README.html
+Watchrfile
View
567 README.md
@@ -1,30 +1,25 @@
Lotte
=====
-Lotte is a work-in-progress, headless, automated testing framework built on top of [PhantomJS][phantom].
-Heavily inspired by [Ghostbuster][ghostbuster], it adds jQuery-like method chaining, more assertion logic and an extensible core.
+Lotte is a headless, automated testing framework built on top of [PhantomJS][phantom] and inspired by [Ghostbuster][ghostbuster].
+It adds jQuery-like methods and chaining, more assertion logic and an extensible core.
+Tests can be written in either JavaScript or [CoffeeScript][coffee].
-Tests can be written in JavaScript or [CoffeeScript][coffee] depending on your preference.
-New languages that can be [transpiled][transpile] to JavaScript can be added in the core if there is enough interest.
+Lotte comes with tools for accessing the DOM, evaluating arbitrary code, simulating mouse and keyboard input.
-Tests are ran asynchronously and independently of each other. Each task within a test is also ran asynchronously where possible.
-Blocking methods are provided to simulate dependencies and to control the flow of execution.
+Tests are sandboxed and run asynchronously. Blocking methods are available to simulate dependencies and to control the flow of execution.
-Lotte is written in JavaScript and can be extended easily by adding methods to built-in objects/classes.
-Most of the everyday testing needs, e.g., mouse and keyboard input, are available out of the box.
+This project is still highly experimental. Using it may cause your computer to blow up. [Seriously.][license]
-Lotte is highly experimental. Using this software may cause your computer to blow up. [Seriously.][license]
-
- [ghostbuster]: https://github.com/joshbuddy/ghostbuster
[phantom]: http://www.phantomjs.org/
+ [ghostbuster]: https://github.com/joshbuddy/ghostbuster
[coffee]: http://coffeescript.org/
- [transpile]: https://twitter.com/#!/scottdavis99/status/65579423335854080
[license]: https://github.com/StanAngeloff/lotte/blob/master/LICENSE.md
Prerequisites
-------------
-- [node.js][nodejs] **~0.4.10**
+- [node.js][nodejs] **>=0.4.10**
- [npm][npm] **~1.0**
- [PhantomJS][phantom] **~1.3.0**
@@ -32,191 +27,517 @@ Prerequisites
[nodejs]: http://nodejs.org/
[phantom]: http://www.phantomjs.org/
-### Optional dependencies:
+### Optional Dependencies
- [CoffeeScript][coffee]
-You must also have `mktemp` available which is installed by default on Mac OS and most Linux distributions as part of GNU [coreutils][coreutils].
-
[coffee]: http://coffeescript.org/
- [coreutils]: http://www.gnu.org/software/coreutils/
Installation
------------
-As there are no official releases available yet, your only option at present is to clone the Git repository and use [npm][npm] to link the project on your system:
+ $ npm -g install lotte
+
+`-g`lobal is preferred so you can run `lotte` from any directory.
-```shell
-$ git clone git://github.com/StanAngeloff/lotte.git
-$ cd lotte
-$ npm install
-$ npm link .
+Usage
+-----
+
+Create a new file `lotte_github.js` (preferably in an empty directory) and copy the following code:
+
+```javascript
+this.open('https://github.com', function() {
+ this.describe('Sign Up button', function() {
+ this.assert.ok(this.$('.signup-button').length, 'expects button to be in the DOM');
+ this.success();
+ });
+});
```
-If `npm install` fails to install one or more dependencies, remove the `node_modules` directory and re-run the command.
+Run `lotte` from within the directory and you should see the following output:
-`npm link` will make the `lotte` script available from any directory given you have configured the `npm` binary path (`/usr/local/bin` by default) to be on your system `$PATH`.
+```
+/tmp/lotte_github.js
+ @ https://github.com
+ ✓ Sign Up button
+```
- [npm]: http://npmjs.org/
+Command-Line Options
+--------------------
-Usage
------
+You can customise many aspects of Lotte's behaviour either on the command-line on through `Lottefile`s. The following options are available:
-When you run the `lotte` script from a terminal:
+```
+$ lotte --help
+Usage: lotte [OPTION...] PATH
-- The current working directory is scanned recursively for files matching the glob `lotte_*.js` (continue reading for details on how to configure this pattern)
-- Files are sorted and executed in order with at most 4 tests running at any given time
-- As individual tests complete, results are printed on-screen. Once all tests have finished, the `lotte` process exits either with a non-zero code if there was at least one failure or with a zero exit code if all tests passed
+Options:
+ --help, -h give this help page
+ --version, -v print program version
+ --concurrent, -c limit of files to run in parallel [default: 4]
+ --timeout, -t timeout for individual files (in milliseconds) [default: 30000]
+ --include, -I glob pattern to match files in PATH [string] [default: "**/lotte_*.js"]
+ --exclude, -E glob pattern to remove included files [string]
+ --lottefile, -f look for 'lottefile' in PATH [string] [default: "Lottefile"]
+ --verify verify PhantomJS version (expected ~1.3.0) [boolean] [default: true]
+ --phantom executable for PhantomJS [string] [default: "phantomjs"]
+ --coffee executable for CofeeScript [string] [default: "coffee"]
+ --mktemp executable to create unique temporary files [string] [default: "mktemp"]
+```
-Anatomy of a Test
------------------
+There are four key options you would want to customise while the rest should work with their defaults.
-A very basic test file looks like this:
+- **`--concurrent, -c`**
-```coffeescript
-@open 'http://local.dev/feature/action/page', 'optional description', ->
- @describe 'series of tests to verify XYZ', ->
- @$('h1').contains 'expects project name in heading', /\bLotte\b/
- @success()
+ If you have more than one test file in a directory, Lotte will attempt to run them in parallel (asynchronously).
+ You can specify how many tests can be running at any given time through this option.
+
+ If you want to run tests synchronously, specify a value of `1`.
+
+- **`--timeout, -t`**
+
+ Each test is expected to finish within a given period of time. If a test takes longer, it is interruped and recorded as failed.
+
+ The default value is `30` seconds, but you should consider reducing it.
+
+- **`--include, -I`
+ `--exclude, -E`**
+
+ When you run `lotte` from any directory the script collects a list of all files in the current directory and all sub-directories.
+ The list is reduced by running the `include` glob pattern and dropping any files that did not match.
+ The list is then reduced further by running the `exclude` glob pattern and dropping any files that did match.
+ The remaining list is sorted and considered final.
+
+ You can specify these arguments more than once to create an array of include/exclude patterns.
+
+### Lottefile
+
+In order to avoid having to type the full `lotte` command-line each time, you can use `Lottefile`s to store your settings per project.
+
+`Lottefile`s are regular JavaScript files where each global variable maps to a command-line option. For example, the following command:
+
+```
+$ lotte --include '**/*.coffee' --include '**/*.js' --concurrent 1 tests
```
-Note all Lotte functions are prefixed with `this.` (`@` in CoffeeScript).
+can be stored in a `Lottefile` as this:
-Each test file consists of:
+```javascript
+path = 'tests'
+include = ['**/*.coffee', '**/*.js']
+concurrent = 1
+```
-- one or many `@open` blocks to specify the target URL of nested test cases
-- one or many `@group` blocks to organise nested test cases
-- one or many `@describe` blocks to create test cases
-- one `@success` function call to mark the successful end of a test case
+Running `lotte` from the project directory will then read the `Lottefile` and scan the `tests` directory for all files matching `**/*.{coffee,js}`.
Writing Tests
-------------
-### Global Context
+Tests can be written in either JavaScript or CoffeeScript.
+In the sections below substitute `@` with `this.` if you are using JavaScript.
+Arguments wrapped in square brackets `[` and `]` are optional.
+Arguments ending in `...` can be used more than once.
-The following functions are defined in the global context:
+At the top-level, the following functions are available:
-- `@title(title)`
+- **`@title([name])`**
- Give the test file a meaningful title.
+ Gets or sets the test title.
+ This is useful for giving meaningful names to your tests.
- Example:
+ When called with zero arguments, returns the current title or `undefined`.
+ When called with one argument, sets the title.
- ```coffeescript
- @title 'Sign up page'
+ If you don't explicitly specify a title, the filename will be used instead.
- @open 'http://local.dev/signup', ->
- [...]
- ```
+- **`@base([uri])`**
-- `@base(uri)`
+ Gets or sets the absolute URI for all relative URIs in the test.
+ You can use this to specify the root URI for your project.
- When a URL is used anywhere in the test file without a protocol in it, the `uri` given will be prepended.
+ When called with zero arguments, returns the current URI or `undefined`.
+ When called with one argument, sets the URI.
- Example:
+ If you don't explicitly specify an absolute URI, all calls to `@open` will expect an absolute URI instead.
- ```coffeescript
- @base 'http://local.dev'
+- **`@open(uri, [message], [options], block)`**
+
+ Creates a new test.
+
+ `uri` can be either an absolute or relative URI (see above).
+ `message` is an optional description for the URI. If you don't specify it, Lotte will print the `uri` in the output instead.
+ `options` is an object hash to pass to PhantomJS. See [settings (object)][settings].
+ `block` is a function which is executed if the server returns a valid response (2xx or 3xx).
+
+ If the server returns a 4xx or 5xx HTTP code instead, the test is recorded as failed.
+
+ If you have more than one `@open` call at the top-level, they will be executed asynchronously.
- # The below URL does not contain a protocol and @base will be prepended.
- @open '/signup', ->
- [...]
+ [settings]: http://code.google.com/p/phantomjs/wiki/Interface#settings_(object)
+
+Putting it all together, a test file could look like this:
+
+```coffeescript
+@title 'Github'
+@base 'https://github.com'
+
+@open '/', 'the homepage', ->
+ # ...body of test...
+```
+
+### Cases & Grouping
+
+Once you have successfully requested an URI, you can start writing test cases against the page.
+
+The following functions are available:
+
+- **`@group(name, block)`**
+
+ Groups the nested test cases. This is mainly for structuring the output Lotte prints.
+
+ `name` is the name of the group.
+ `block` is a function which contains the nested test cases.
+
+- **`@describe(name, block)`**
+
+ Starts a new test case.
+
+ `name` is the name of the test case.
+ `block` is a function which is executed and is expected to contain assertion logic.
+
+Putting it all together a test file could now look like this:
+
+```coffeescript
+@title 'Github'
+@base 'https://github.com'
+
+@open '/', 'the homepage', ->
+ @describe 'counter shows number of repositories', ->
+ # ...assertion logic...
+ @group 'Sign Up button', ->
+ @describe 'is in place', ->
+ # ...assertion logic...
+ @describe 'takes you to /plans', ->
+ # ...assertion logic...
+```
+
+#### Flow of Execution
+
+Each test case is executed in the order in which it is defined:
+
+```coffeescript
+@describe 'I run first', ->
+@describe 'I run second', ->
+# etc.
+```
+
+If a test case contains an asynchronous function call, the next test case is executed without waiting for the function to finish:
+
+```coffeescript
+@describe 'I run first', ->
+@describe 'I run second', ->
+ setTimeout ( -> ), 2500
+@describe 'I run third in parallel with second still running', ->
+```
+
+Be 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.
+
+If a test case fails, any remaining test cases are skipped:
+
+```coffeescript
+@describe 'I run first', ->
+ throw 'Whoops!'
+@describe 'I should run second, but I never will', ->
+```
+
+To simulate dependencies and control the flow of execution, you can use the following functions:
+
+- **`@wait(name..., block)`**
+
+ Blocks the current test case until all dependencies have finished (either passed or failed).
+
+The earlier example can now be rewritten as follows to make it synchronous again:
+
+```coffeescript
+@describe 'I run first', ->
+@describe 'I run second', ->
+ setTimeout ( -> ), 2500
+@describe 'I run third', ->
+ @wait 'I run second', ->
+ # ...assertion logic...
+```
+
+### Environments
+
+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.
+
+Each test file runs in its own sandboxed environment. Each page you request also runs in a sandbox.
+You 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:
+
+```coffeescript
+@open 'https://github.com', ->
+ @describe 'Sandbox', ->
+ val = 'value'
+ # following line throws an exception
+ console.log(@page.evaluate( -> return val))
+ throw 'exit'
+```
- # The below URL contains a protocol and @base will be ignored.
- @open 'http://local-2.dev/login', ->
- [...]
+In the above code snippet `@page.evaluate` runs the function as if it were defined on the page you just requested, i.e, `github.com`.
+In order to do so, PhantomJS serializes the function, but it does not include the context in which it was defined.
+When the function is executed, `val` is missing in the new context causing it to throw an exception.
+
+Another limitation of PhantomJS is the fact you cannot return complex types from the page.
+Objects are serialized before they leave the page sandbox and unserialized back in the parent (test case) environment:
+
+```coffeescript
+@open 'https://github.com', ->
+ @describe 'serialize/unserialize', ->
+ h1 = @page.evaluate( -> return document.querySelector('h1'))
+ # prints 'H1' correctly
+ console.log h1.tagName
+ # prints 'undefined' as functions cannot be serialized/unserialized
+ console.log h1.focus
+ throw 'exit'
+```
+
+#### Document Queries
+
+To work around those limitations and to abstract the boilerplate needed to access the DOM of a page, Lotte comes with a jQuery-like query function:
+
+- **`@$(selector)`**
+
+ `selector` is a string containing a selector expression.
+
+ Returns a `DocumentQuery` object.
+
+The earlier example can now be rewritten as follows:
+
+```coffeescript
+@open 'https://github.com', ->
+ @describe 'Document Queries', ->
+ # prints 'H1' correctly
+ console.log @$('h1').tagName
+ # prints 'undefined'
+ console.log @$('h1').focus
+ throw 'exit'
+```
+
+##### Additional Methods
+
+A `DocumentQuery` object has the following methods to deal with the DOM:
+
+- **`DocumentQuery.prototype.attr([index], property)`**
+
+ Gets the value of `property` for the element at `index`.
+
+ The following code snippets are equivalent:
+
+ ```coffeescript
+ @$('h1').attr('tagName')
+ @$('h1').tagName
```
-- `@open(uri, [message], [options], block)`
+ The direct property access always returns the property value for the first matched element.
+
+ 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`.
- Creates a new request to `uri` and, if the server returns a valid response (2xx or 3xx), calls `block`.
+- **`DocumentQuery.prototype.click([index], [message], [block])`**
- `message` is optional and can be used to attach a meaningful description to the `uri`.
- `options` is optional and can contain a hash for Phantom. See [settings (object)][settings].
+ 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.
- Example:
+ `index` is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.
+ `message` is an optional message to display if something goes wrong, i.e., if no elements were matched.
+ `block` is an optional function to execute when the new page has loaded, i.e., when you follow an anchor.
```coffeescript
- @open 'http://local.dev/signup', 'Sign up without JavaScript', settings: javascriptEnabled: no, ->
- [...]
+ @open 'https://github.com', ->
+ @describe 'click(..)', ->
+ # prints https://github.com/
+ console.log('I am now on: ' + @page.evaluate( -> location.href))
+ @$('.signup-button').click ->
+ # prints https://github.com/plans
+ console.log('I am now on: ' + @page.evaluate( -> location.href))
+ throw 'exit'
```
-#### Example
+- **`DocumentQuery.prototype.input(value, [index], [message])`**
-The code below combines all functions:
+ Inputs `value` in the element at `index`. This method can be used to simulate keyboard input.
-```coffeescript
-@base 'http://local.dev'
-@title 'Sign up page'
+ `value` is a string to input as if it were keyboard input.
+ `index` is the position of the element in the matched selector collection. If you omit this argument, the first element is assumed.
+ `message` is an optional message to display if something goes wrong, i.e., if no elements were matched.
-@open '/signup', 'Sign up without JavaScript', settings: javascriptEnabled: no, ->
- [...]
-```
+ ```coffeescript
+ @open 'http://www.google.com', ->
+ @describe 'input(..)', ->
+ @$('[name="q"]').input 'meaning of life'
+ @$('input[type="submit"]').click ->
+ console.log @$('#res').attr('innerText')
+ throw 'exit'
+ ```
- [settings]: http://code.google.com/p/phantomjs/wiki/Interface#settings_(object)
+See **DOM Assertions** below for additional methods.
-------------------------------------------------------------------------------
+### Assertions
-This project is still a work-in-progress, please see the [test][test] directory for up-to-date examples.
+Lotte comes with two types of assertion logic:
- [test]: https://github.com/StanAngeloff/lotte/tree/master/test
+- Generic assertions
+- DOM assertions
-------------------------------------------------------------------------------
+#### Generic Assertions
-By default when you invoke the `lotte` script it will look for a `Lottefile` which could provide additional arguments before the script continues.
+If you have used Node's built-in [assert][assert] module, these functions will be familiar:
-The script then scans the given `PATH` for all files matching the configured `include` glob pattern.
-The list is filtered if an `exclude` glob pattern is present.
+- **`@assert.fail(actual, expected, message, operator)`**
-The resulting list is then considered final and tests are queued and executed in the order of their filenames.
-If concurrency is set to `1`, tests will run in a synchronous fashion.
-Otherwise a new process is started for each test, up to the configured concurrency. As processes exit, new ones are started until the queue is emptied.
+ Throws an exception that displays the values for `actual` and `expected` separated by the provided `operator`.
-Command-Line Options
---------------------
+- **`@assert.ok(value, message)`**
-Lotte can be configured either from the command-line or by using `Lottefile`s.
-See `--help` for available options:
+ Tests if `value` is a true value, it is equivalent to `@assert.equal(true, value, message)`.
-```shell
-$ lotte --help
+- **`@assert.equal(actual, expected, message)`**
-Usage: lotte [OPTION...] PATH
+ Tests shallow, coercive equality with the equal comparison operator `==`.
-Command-line arguments are evaluated before any included files.
+- **`@assert.notEqual(actual, expected, message)`**
-Report issues at https://github.com/StanAngeloff/lotte/issues.
+ Tests shallow, coercive non-equality with the not equal comparison operator `!=`.
-Options:
- --help, -h give this help page
- --version, -v print program version
- --concurrent, -c limit of files to run in parallel [default: 4]
- --timeout, -t timeout for individual files (in seconds) [default: 30000]
- --include, -I glob pattern to match files in PATH [string] [default: "**/lotte_*.js"]
- --exclude, -E glob pattern to remove included files [string]
- --lottefile, -f look for 'lottefile' in PATH [string] [default: "Lottefile"]
- --verify verify PhantomJS version (expected ~1.3.0) [boolean] [default: true]
- --phantom executable for PhantomJS [string] [default: "phantomjs"]
- --coffee executable for CofeeScript [string] [default: "coffee"]
- --mktemp executable to create unique temporary files [string] [default: "mktemp"]
+- **`@assert.deepEqual(actual, expected, message)`**
+
+ Tests for deep equality.
+
+- **`@assert.notDeepEqual(actual, expected, message)`**
+
+ Tests for any deep inequality.
+
+- **`@assert.strictEqual(actual, expected, message)`**
+
+ Tests strict equality, as determined by the strict equality operator `===`.
+
+- **`@assert.notStrictEqua(actual, expected, message)`**
+
+ Tests strict non-equality, as determined by the strict not equal operator `!==`.
+
+- **`@assert.throws(block, error, message)`**
+
+ Expects `block` to throw an error. `error` can be constructor, RegExp or validation function.
+
+- **`@assert.doesNotThrow(block, error, message)`**
+
+ Expects `block` not to throw an error, see `@assert.throws` for details.
+
+- **`@assert.contains(actual, expected, message)`**
+
+ Expects `actual` to contain `expected`. `expected` can be a string or a RegExp.
+
+ [assert]: http://nodejs.org/docs/v0.6.0/api/assert.html
+
+#### DOM Assertions
+
+`DocumentQuery` (see above) comes with additional methods to deal with assertions:
+
+- **`DocumentQuery.prototype.contains([message], pattern)`**
+
+ Expects at least one of the matched elements to contain `pattern`. `pattern` can be a string or a RegExp.
+
+- **`DocumentQuery.prototype.each([message], block)`**
+
+ Tests if calling `block` on each matched element as an argument returns a true value.
+
+- **`DocumentQuery.prototype.first([message], block)`**
+
+ Tests if calling `block` with the first matched element as an argument returns a true value.
+
+- **`DocumentQuery.prototype.last([message], block)`**
+
+ Tests if calling `block` with the last matched element as an argument returns a true value.
+
+- **`DocumentQuery.prototype.nth(index, [message], block)`**
+
+ Tests if calling `block` with the element at `index` as an argument returns a true value.
+
+A general note which applies to all functions above: you cannot access variables from scope within `block` (see **Environments**).
+
+An example test file that performs DOM assertions could look like this:
+
+```coffeescript
+@open 'https://github.com', ->
+ @describe 'Navigation and children have classes', ->
+ @$('.nav').first (element) -> element.classList.contains('logged_out')
+ @$('.nav li').each (element) -> !! element.className
+ throw 'exit'
```
-Any of the arguments listed above can also be configured from a `Lottefile`, either in the current working directory or inside the `PATH` argument passed to `lotte`.
+Passing Tests
+-------------
-Use `--phantom` if your `phantomjs` binary is not on `$PATH`.
+So far we have ended tests with `throw 'exit'`. To pass a test case, use the following functions:
-Use `--coffee` if your `coffee` binary is not on `$PATH`.
-Lotte does not come bundled with a compiler and it will shell-out to the system to generate the required JavaScript before a test is executed.
+- **`@success()`**
-Contributing
-------------
+ Marks the test case as passed. You must call this once within each `@describe` block.
+
+If 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.
-The goal of this project is to provide an awesome tool for web developers to test their websites/apps in their favourite language with minimum efforts.
+FAQs
+----
-As there are no releases made yet and things are still in a state of flux, a lot is likely to change before reaching a release milestone.
+- **Q**: How can I log in before requesting a page?
+
+ **A**: You can nest `@open(..)` functions to achieve this:
+
+ ```coffeescript
+ @base 'http://local.dev'
+ @open '/login', ->
+ @describe 'Log in', ->
+ @$('.username').input 'admin'
+ @$('.password').input 'password'
+ @$('input[type="submit"]').click ->
+ @success()
+ @open '/account', ->
+ @describe 'My Account', ->
+ # ...assertion logic...
+ @success()
+ ```
+
+- **Q**: Can I pass arguments to my tests?
+
+ **A**: Yes. Use `--` on the command-line followed by the arguments:
+
+ ```
+ $ lotte -- arg1 arg2
+ ```
+
+ Arguments will be available in your test files as `phantom.args[..]`.
+
+- **Q**: How can I see what PhantomJS 'sees'?
+
+ **A**: Within the context of a test case (`@describe`), you can refer to `@page` which is the PhantomJS [WebPage][webpage] object.
+
+ ```coffeescript
+ @describe 'snapshot', ->
+ @page.render 'home.png'
+ @success()
+ ```
+
+- **Q**: I don't have `phantomjs`, `coffee`, and/or `mktemp` on `$PATH`.
+
+ **A**: See `lotte --help` for information on how to specify a path to the missing binary. `mktemp` should be installed by default on Mac OS and most Linux distributions as part of GNU [coreutils][coreutils].
+
+ [webpage]: http://code.google.com/p/phantomjs/wiki/Interface#'_WebPage_'_Object
+ [coreutils]: http://www.gnu.org/software/coreutils/
+
+Contributing
+------------
-Commit and code reviews, ideas and wish-lists are welcomed.
+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.
+Commit and code reviews, ideas and documentation improvements are welcomed.
### Copyright
View
2  bin/cli.js
@@ -74,7 +74,7 @@ if (defaults.help) {
process.exit(0);
}
if (defaults.version) {
- console.log('%s %s', defaults.$0, '0.1.1');
+ console.log('%s %s', defaults.$0, '0.1.2');
process.exit(0);
}
View
4 lib/lotte.js
@@ -7,6 +7,8 @@ var childProcess = require('child_process'),
path = require('path'),
console = require('./console');
+var __basename = path.basename(__filename, '.js');
+
function exec(command, resume) {
childProcess.exec(command, function(e, stdout, stderr) {
if (e) {
@@ -21,7 +23,7 @@ function exec(command, resume) {
function mktemp(options, resume) {
options.garbage || (options.garbage = []);
- exec(options.mktemp || 'mktemp', function(e, stdout) {
+ exec((options.mktemp || 'mktemp') + ' -t ' + __basename + '.XXXXXX', function(e, stdout) {
if (e) {
return resume(e);
}
View
4 package.json
@@ -1,5 +1,5 @@
{ "name": "lotte",
- "version": "0.1.1",
+ "version": "0.1.2",
"description": "Headless, automated browser testing using PhantomJS",
"homepage": "https://github.com/StanAngeloff/lotte",
"bugs": "https://github.com/StanAngeloff/lotte/issues",
@@ -26,7 +26,7 @@
"express": "~2.5.0"
},
"engines": {
- "node": "~0.4.10"
+ "node": ">=0.4.10"
},
"preferGlobal": true
}
View
6 test/server.js
@@ -15,11 +15,11 @@ function basic_auth (request, response, next) {
return next();
}
}
- response.header('WWW-Authenticate', 'Basic realm="Secret"');
+ response.writeHead(401, { 'WWW-Authenticate': 'Basic realm="Secret"' });
if (request.headers.authorization) {
- response.end('Authentication required', 401);
+ response.end('Authentication required');
} else {
- response.send('Authentication required', 401);
+ response.end('Authentication required');
}
};
View
10 test/test_open.coffee
@@ -1,16 +1,6 @@
@base 'http://' + phantom.args[0] + ':' + phantom.args[1]
@title 'localhost.localdomain'
-@open '/secret', 'attempts without authentication details', ->
- @describe 'should fail', ->
- @assert.contains @page.content, 'Authentication required', 'expects authentication required response'
- @success()
-
-@open '/secret', 'attempts with wrong authentication details', settings: userName: 'wrong', password: 'password', ->
- @describe 'should fail', ->
- @assert.contains @page.content, 'Authentication required', 'expects authentication required response'
- @success()
-
@open '/secret', 'attempts with agreed authentication details', settings: userName: 'secret', password: 'password', ->
@describe 'should succeed', ->
@assert.contains @page.content, 'OK', 'expects authenticated response'

No commit comments for this range

Something went wrong with that request. Please try again.