[Pkg-javascript-commits] [node-mocks-http] 292/296: Imported Upstream version 1.4.3

Thorsten Alteholz alteholz at moszumanska.debian.org
Mon Feb 8 18:13:46 UTC 2016


This is an automated email from the git hooks/post-receive script.

alteholz pushed a commit to branch master
in repository node-mocks-http.

commit 5db8484aa646003beaa345652f18935a42f8dd94
Author: Thorsten Alteholz <debian at alteholz.de>
Date:   Mon Feb 8 16:46:27 2016 +0100

    Imported Upstream version 1.4.3
---
 .eslintrc                           |  82 ++++
 .gitignore                          |   6 +
 .travis.yml                         |  22 +
 CODE_OF_CONDUCT.md                  |  13 +
 CODING_RULES.md                     | 182 ++++++++
 CONTRIBUTING.md                     | 166 +++++++
 HISTORY.md                          |  90 ++++
 LICENSE                             |  21 +
 README.md                           | 183 ++++++++
 examples/express-route.js           |  61 +++
 examples/express-status-vs-json.js  |  51 +++
 gulpfile.js                         |  44 ++
 lib/http-mock.js                    |  14 +
 lib/mockEventEmitter.js             |  20 +
 lib/mockRequest.js                  | 296 +++++++++++++
 lib/mockResponse.js                 | 639 +++++++++++++++++++++++++++
 lib/mockWritableStream.js           |  25 ++
 lib/node/_http_server.js            |  61 +++
 lib/node/http.js                    |   5 +
 package.json                        |  60 +++
 test/.eslintrc                      |  10 +
 test/lib/http-mock.spec.js          |  21 +
 test/lib/mockEventEmitter.spec.js   |  61 +++
 test/lib/mockRequest.spec.js        | 528 ++++++++++++++++++++++
 test/lib/mockResponse.spec.js       | 859 ++++++++++++++++++++++++++++++++++++
 test/lib/mockWritableStream.spec.js |  41 ++
 test/mocha.opts                     |   3 +
 27 files changed, 3564 insertions(+)

diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..fa4a363
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,82 @@
+env:
+  node: true
+
+rules:
+  comma-dangle: 2
+  no-alert: 2
+  no-array-constructor: 2
+  no-caller: 2
+  no-catch-shadow: 2
+  no-control-regex: 2
+  no-debugger: 2
+  no-div-regex: 2
+  no-dupe-keys: 2
+  no-else-return: 2
+  no-empty: 2
+  no-empty-class: 2
+  no-eq-null: 2
+  no-eval: 2
+  no-ex-assign: 2
+  no-func-assign: 0
+  no-floating-decimal: 2
+  no-implied-eval: 2
+  no-with: 2
+  no-fallthrough: 2
+  no-unreachable: 2
+  no-undef: 2
+  no-undef-init: 2
+  no-unused-expressions: 2
+  no-octal: 2
+  no-octal-escape: 2
+  no-obj-calls: 2
+  no-multi-str: 2
+  no-new-wrappers: 2
+  no-new: 2
+  no-new-func: 2
+  no-native-reassign: 2
+  no-delete-var: 2
+  no-return-assign: 2
+  no-new-object: 2
+  no-label-var: 2
+  no-self-compare: 2
+  no-sync: 2
+  no-loop-func: 2
+  no-empty-label: 2
+  no-unused-vars: 1
+  no-script-url: 2
+  no-proto: 2
+  no-iterator: 2
+  no-mixed-requires:
+    - 0
+    - false
+  no-wrap-func: 2
+  no-shadow: 2
+  no-use-before-define: 2
+  no-redeclare: 2
+  no-regex-spaces: 2
+  no-mixed-spaces-and-tabs: 2
+  no-underscore-dangle: 0
+
+  brace-style: 2
+  camelcase: 2
+  consistent-this:
+    - 2
+    - self
+  curly: 2
+  dot-notation: 2
+  eqeqeq: 2
+  new-cap: 2
+  new-parens: 2
+  quotes:
+    - 2
+    - single
+  semi: 2
+  strict:
+    - 2
+    - global
+  use-isnan: 2
+  valid-typeof: 2
+  wrap-iife: 2
+  indent:
+    - 2
+    - indentSwitchCase: true
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dc945d8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+.project
+.settings
+coverage
+node_modules
+test/results
+npm-debug.log
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2e28e29
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,22 @@
+language: node_js
+node_js:
+  - "0.10"
+  - "0.12"
+
+notifications:
+  email:
+    - "howard.abrams at gmail.com"
+    - "johnny.estilles at agentia.asia"
+
+addons:
+  code_climate:
+    repo_token: 75dc20817d25bb52614e495f87d69b228edac0016fb096ccab2a75b624c68d4e
+
+before_script:
+  - npm install -g gulp
+  - npm install -g codeclimate-test-reporter
+  - gulp lint
+
+after_script:
+  - gulp coverage
+  - codeclimate < ./coverage/lcov.info
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..b3692be
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,13 @@
+# Contributor Code of Conduct
+
+As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
+
+We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
+
+Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
+
+This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
\ No newline at end of file
diff --git a/CODING_RULES.md b/CODING_RULES.md
new file mode 100644
index 0000000..b5445e0
--- /dev/null
+++ b/CODING_RULES.md
@@ -0,0 +1,182 @@
+# <a name="top"></a> Coding Rules
+For simplicity, we've divided our coding rules using the same categories as the ESLint documentation.
+
+- [Possible Errors](#errors)
+- [Best Practices](#best)
+- [Strict Mode](#strict)
+- [Variables](#variables)
+- [Node.js](#node)
+- [Stylistic Issues](#style)
+
+## <a name="errros"></a> Possible Errors
+The following rules point out areas where you might have made mistakes.
+
+* [comma-dangle] - enforce trailing commas
+* [no-control-regex] - disallow control characters in regular expressions
+* [no-debugger] - disallow use of debugger
+* [no-dupe-keys] - disallow duplicate keys when creating object literals
+* [no-empty] - disallow empty statements
+* [no-empty-class] - disallow the use of empty character classes in regular expressions
+* [no-ex-assign] - disallow assigning to the exception in a `catch block
+* [no-func-assign] - disallow overwriting functions written as function declarations
+* [no-unreachable] - disallow unreachable statements after a return, throw, continue, or break statement
+* [no-obj-calls] - disallow the use of object properties of the global object (`Math` and `JSON`) as functions
+* [no-regex-spaces] - disallow multiple spaces in a regular expression literal
+* [use-isnan] - disallow comparisons with the value `NaN`
+* [valid-typeof] - Ensure that the results of `typeof` are compared against a valid string
+
+[Back to Top](#top)
+
+## <a name="best"></a> Best Practices
+These are rules designed to prevent you from making mistakes.
+
+* [no-caller] - disallow use of `arguments.caller` or `arguments.callee`
+* [no-div-regex] - disallow division operators explicitly at beginning of regular expression
+* [no-else-return] - disallow `else` after a `return` in an `if`
+* [no-eq-null] - disallow comparisons to null without a type-checking operator
+* [no-eval] - disallow use of `eval()`
+* [no-floating-decimal] - disallow the use of leading or trailing decimal points in numeric literals
+* [no-implied-eval] - disallow use of `eval()`-like methods
+* [no-with] - disallow use of the `with` statement
+* [no-fallthrough] - disallow fallthrough of case statements
+* [no-unused-expressions] - disallow usage of expressions in statement position
+* [no-octal] - disallow use of octal literals
+* [no-octal-escape] - disallow use of octal escape sequences in string literals, such as `var foo = "Copyright \251";`
+* [no-multi-str] - disallow use of multiline strings
+* [no-new-wrappers] - disallows creating new instances of `String`, `Number`, and `Boolean`
+* [no-new] - disallow use of new operator when not part of the assignment or comparison
+* [no-new-func] - disallow use of new operator for `Function` object
+* [no-native-reassign] - disallow reassignments of native objects
+* [no-return-assign] - disallow use of assignment in return statement
+* [no-self-compare] - disallow comparisons where both sides are exactly the same
+* [no-loop-func] - disallow creation of functions within loops
+* [no-empty-label] - disallow use of labels for anything other then loops and switches
+* [no-script-url] - disallow use of javascript: urls.
+* [no-proto] - disallow usage of `__proto__` property
+* [no-iterator] - disallow usage of `__iterator__` property
+* [no-redeclare] - disallow declaring the same variable more then once
+* [curly] - specify curly brace conventions for all control statements
+* [dot-notation] - encourages use of dot notation whenever possible
+* [eqeqeq] - require the use of `===` and `!==`
+* [wrap-iife] - require immediate function invocation to be wrapped in parentheses
+
+[Back to Top](#top)
+
+## <a name="strict"></a> Strict Mode
+These rules relate to using strict mode.
+
+- [strict] - ensures all code is in strict mode and that there are no extraneous Use Strict Directives
+
+
+[Back to Top](#top)
+
+## <a name="variables"></a> Variables
+These rules have to do with variable declarations.
+
+* [no-catch-shadow] - disallow the catch clause parameter name being the same as a variable in the outer scope
+* [no-undef] - disallow use of undeclared variables unless mentioned in a `/*global */` block
+* [no-undef-init] - disallow use of undefined when initializing variables
+* [no-delete-var] - disallow deletion of variables
+* [no-label-var] - disallow labels that share a name with a variable
+* [no-unused-vars] - disallow declaration of variables that are not used in the code
+* [no-shadow] - disallow declaration of variables already declared in the outer scope
+* [no-use-before-define] - disallow use of variables before they are defined
+
+[Back to Top](#top)
+
+## <a name="node"></a> Node.js
+These rules are specific to JavaScript running on Node.js.
+
+* [no-sync] - disallow use of synchronous methods
+* [no-mixed-requires] - allow mixing regular variable and require declarations
+
+[Back to Top](#top)
+
+## <a name="style"></a> Stylistic Issues
+
+* [no-array-constructor] - disallow use of the `Array` `constructor
+* [no-new-object] - disallow use of the `Object constructor`
+* [no-wrap-func] - disallow wrapping of non-IIFE statements in parens
+* [brace-style] - enforce one true brace style
+* [camelcase] - require camel case names
+* [consistent-this] - enforces consistent naming when capturing the current execution context
+* [new-cap] - require a capital letter for constructors
+* [new-parens] - disallow the omission of parentheses when invoking a constructor with no arguments
+* [quotes] - specify whether double or single quotes should be used
+* [semi] - require use of semicolons instead of ASI
+* [no-mixed-spaces-and-tabs] - disallow mixed spaces and tabs for indentation
+* [indent] - 4 spaces indentation with enabled switch cases validation
+ 
+[Back to Top](#top)
+
+[comma-dangle]: http://eslint.org/docs/rules/comma-dangle.html
+[no-control-regex]: http://eslint.org/docs/rules/no-control-regex.html
+[no-debugger]: http://eslint.org/docs/rules/no-debugger.html
+[no-dupe-keys]: http://eslint.org/docs/rules/no-dupe-keys.html
+[no-empty]: http://eslint.org/docs/rules/no-empty.html
+[no-empty-class]: http://eslint.org/docs/rules/no-empty-class.html
+[no-ex-assign]: http://eslint.org/docs/rules/no-ex-assign.html
+[no-func-assign]: http://eslint.org/docs/rules/no-func-assign.html
+[no-unreachable]: http://eslint.org/docs/rules/no-unreachable.html
+[no-obj-calls]: http://eslint.org/docs/rules/no-obj-calls.html
+[no-regex-spaces]: http://eslint.org/docs/rules/no-regex-spaces.html
+[use-isnan]: http://eslint.org/docs/rules/use-isnan.html
+[valid-typeof]: http://eslint.org/docs/rules/valid-typeof.html
+
+[no-caller]: http://eslint.org/docs/rules/no-caller.html
+[no-div-regex]: http://eslint.org/docs/rules/no-div-regex.html
+[no-else-return]: http://eslint.org/docs/rules/no-else-return.html
+[no-eq-null]: http://eslint.org/docs/rules/no-eq-null.html
+[no-eval]: http://eslint.org/docs/rules/no-eval.html
+[no-floating-decimal]: http://eslint.org/docs/rules/no-floating-decimal.html
+[no-implied-eval]: http://eslint.org/docs/rules/no-implied-eval.html
+[no-with]: http://eslint.org/docs/rules/no-with.html
+[no-fallthrough]: http://eslint.org/docs/rules/no-fallthrough.html
+[no-unused-expressions]: http://eslint.org/docs/rules/no-unused-expressions.html
+[no-octal]: http://eslint.org/docs/rules/no-octal.html
+[no-octal-escape]: http://eslint.org/docs/rules/no-octal-escape.html
+[no-multi-str]: http://eslint.org/docs/rules/no-multi-str.html
+[no-new-wrappers]: http://eslint.org/docs/rules/no-new-wrappers.html
+[no-new]: http://eslint.org/docs/rules/no-new.html
+[no-new-func]: http://eslint.org/docs/rules/no-new-func.html
+[no-native-reassign]: http://eslint.org/docs/rules/no-native-reassign.html
+[no-return-assign]: http://eslint.org/docs/rules/no-return-assign.html
+[no-self-compare]: http://eslint.org/docs/rules/no-self-compare.html
+[no-loop-func]: http://eslint.org/docs/rules/no-loop-func.html
+[no-empty-label]: http://eslint.org/docs/rules/no-empty-label.html
+[no-script-url]: http://eslint.org/docs/rules/no-script-url.html
+[no-proto]: http://eslint.org/docs/rules/no-proto.html
+[no-iterator]: http://eslint.org/docs/rules/no-iterator.html
+[no-redeclare]: http://eslint.org/docs/rules/no-redeclare.html
+[curly]: http://eslint.org/docs/rules/curly.html
+[dot-notation]: http://eslint.org/docs/rules/dot-notation.html
+[eqeqeq]: http://eslint.org/docs/rules/eqeqeq.html
+[wrap-iife]: http://eslint.org/docs/rules/wrap-iife.html
+
+[strict]: http://eslint.org/docs/rules/strict.html
+
+[no-catch-shadow]: http://eslint.org/docs/rules/no-catch-shadow.html
+[no-undef]: http://eslint.org/docs/rules/no-undef.html
+[no-undef-init]: http://eslint.org/docs/rules/no-undef-init.html
+[no-delete-var]: http://eslint.org/docs/rules/no-delete-var.html
+[no-label-var]: http://eslint.org/docs/rules/no-label-var.html
+[no-unused-vars]: http://eslint.org/docs/rules/no-unused-vars.html
+[no-shadow]: http://eslint.org/docs/rules/no-shadow.html
+[no-use-before-define]: http://eslint.org/docs/rules/no-use-before-define.html
+
+[no-sync]: http://eslint.org/docs/rules/no-sync.html
+[no-mixed-requires]: http://eslint.org/docs/rules/no-mixed-requires.html
+
+[no-array-constructor]: http://eslint.org/docs/rules/no-array-constructor.html
+[no-new-object]: http://eslint.org/docs/rules/no-new-object.html
+[no-wrap-func]: http://eslint.org/docs/rules/no-wrap-func.html
+[brace-style]: http://eslint.org/docs/rules/brace-style.html
+[camelcase]: http://eslint.org/docs/rules/camelcase.html
+[consistent-this]: http://eslint.org/docs/rules/consistent-this.html
+[new-cap]: http://eslint.org/docs/rules/new-cap.html
+[new-parens]: http://eslint.org/docs/rules/new-parens.html
+[quotes]: http://eslint.org/docs/rules/quotes.html
+[semi]: http://eslint.org/docs/rules/semi.html
+[no-mixed-spaces-and-tabs]: http://eslint.org/docs/rules/no-mixed-spaces-and-tabs.html
+[indent]: http://eslint.org/docs/rules/indent.html
+[no-underscore-dangle]: http://eslint.org/docs/rules/no-underscore-dangle.html
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..0bfd090
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,166 @@
+# Contributing
+
+Contributions are always welcome, no matter how large or small. Here are the guidelines we ask our contributors to follow:
+
+ - [Code of Conduct](#coc)
+ - [Issues and Bugs](#issue)
+ - [Feature Requests](#feature)
+ - [Submission Guidelines](#submit)
+ - [Coding Rules](#rules)
+ - [Running Test Suite](#tests)
+ - [Contact Us](#contact)
+
+## <a name="coc"></a> Code of Conduct
+We want to keep our project open and inclusive. We ask that before you
+contribute, you read and follow our [Code of Conduct](CODE_OF_CONDUCT.md).
+
+## <a name="issue"></a> Found an Issue?
+We definitely want to hear from you!
+
+If you find a bug in the source code or a mistake in the docs, you can help us by
+submitting an issue to our [Repository][issues]. Make sure you search through our existing [open and closed issues][issues-archive] in order to avoid duplicate submissions.
+
+Want to contribute with a fix? Even better! Just submit a [Pull Request][pulls].
+
+**Please read the [Submission Guidelines](#submit) below**.
+
+## <a name="feature"></a> Want a Feature?
+Need a new feature no yet available on node-mocks-http? Submit a new feature to our [GitHub Repository][issues].  
+
+Think you can help us out by implementing the feature yourself? Go for it! Just craft and submit your [Pull Request][pulls].
+
+**Please read the [Submission Guidelines](#submit) below**.
+
+## <a name="submit"></a> Submission Guidelines
+
+### Submitting an Issue
+Before you submit your issue search the [archive][archive], maybe your question was already answered. Let's avoid duplicates.
+
+If you believe your issue is a bug, and you can't find a issue in the [archive][issues-archive], just open a new issue. 
+
+**Help us help you!**
+
+Provide the following information to help us identify and fix the issue in a timely manner:
+
+* **Overview** - describe the issue the best way you can, and if possible include a stack trace
+* **Use Case** - explain why you consider this a bug
+* **Version(s)** - tell us what version of node-mocks-http you're currently using
+* **Reproduce** - it would be awesome if you could provide a live example (using [Plunker][plunker] or
+  [JSFiddle][jsfiddle]), or at least a step-by-step description on how to reproduce it
+* **Suggestions** - if you have identified the lines of code or the commit responsible for the problem please include it as well
+
+### Submitting a Pull Request
+We are a *Pull Request-friendly* project!
+
+Your pull requests are always welcome. We only ask that  you adhere to the following guidelines before you submit your pull request:
+
+* Search [GitHub][pulls] for an open or closed Pull Request that may be similar to yours. Avoid duplicates!
+* Fork our [repo][repo] and create a local clone, if you haven't done so already.
+
+     ```shell
+     git clone https://github.com/YOUR-NAME/node-mocks-http.git
+     ```
+
+* If you had previously cloned the [repo][repo], make sure you sync it with the upstream repository.
+
+     ```shell
+     git remote add upstream https://github.com/howardabrams/node-mocks-http.git
+     git fetch upstream
+     git checkout master
+     git merge upstream/master
+	 ```
+
+* Create a new topic branch:
+
+     ```shell
+     git checkout -b my-awesome-fix master
+     ```
+
+* Now do your thing! Create your fix/patch, **including appropriate test cases**.
+* Follow our [Coding Rules](#rules).
+* Run our test suite, as described in [below](#tests),
+  and ensure that all tests pass.
+* Commit your changes using a descriptive commit message
+
+     ```shell
+     git commit -a
+     ```
+
+  Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
+
+* Push your branch to GitHub:
+
+    ```shell
+    git push origin my-awesome-fix
+    ```
+
+* In GitHub, send a pull request to `node-mocks-http`.
+* If we find any issues we may suggest that you:
+  * Make the required updates.
+  * Re-run the [test suite](#tests) to ensure tests are still passing.
+  * Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
+
+    ```shell
+    git rebase master -i
+    git push origin my-awesome-fix -f
+    ```
+
+That's it!
+
+#### Post merged cleanup
+
+After we merge your pull request, you can safely delete your branch and pull the changes from our main (upstream) repository:
+
+* Delete the remote branch on GitHub either through the GitHub web interface or your local shell as follows:
+
+    ```shell
+    git push origin --delete my-awesome-fix
+    ```
+
+* Check out the master branch:
+
+    ```shell
+    git checkout master -f
+    ```
+
+* Delete the local branch:
+
+    ```shell
+    git branch -D my-awesome-fix
+    ```
+
+* Update your master with the latest upstream version:
+
+    ```shell
+    git pull --ff upstream master
+    ```
+
+## <a name="rules"></a> Coding Rules
+
+For a detailed list our the conding conventions used in our project please read our [Coding Rules](CODING_RULES.md).
+
+## <a name="tests"></a> Running Test Suite
+
+Navigate to the project folder and run `npm install` to install the
+project's dependencies.
+
+Then simply run the tests.
+
+```bash
+npm test
+```
+
+## <a name="contact"></a> Contact Us
+[![Gitter chat](https://badges.gitter.im/howardabrams/node-mocks-http.png)](https://gitter.im/howardabrams/node-mocks-http)
+
+If you have any other questions or comments about **node-mocks-http** that do not fall under the category of [issues](#issue), [bugs](#issue), or [feature requests](#feature), feel free to join us on our [Gitter channel][gitter].
+
+
+[repo]: https://github.com/howardabrams/node-mocks-http
+[issues]: https://github.com/howardabrams/node-mocks-http/issues
+[issues-archive]: https://github.com/howardabrams/node-mocks-http/issues?q=is%3Aissue
+[pulls]: https://github.com/howardabrams/node-mocks-http/pulls
+[pulls-archive]: https://github.com/howardabrams/node-mocks-http/pulls?q=is%3Apr
+[gitter]: https://gitter.im/howardabrams/node-mocks-http
+[jsfiddle]: http://jsfiddle.net/
+[plunker]: http://plnkr.co/edit
diff --git a/HISTORY.md b/HISTORY.md
new file mode 100644
index 0000000..6bbe6c9
--- /dev/null
+++ b/HISTORY.md
@@ -0,0 +1,90 @@
+v 1.2.0
+---
+
+  * Adds a `.header` and `.get` method to the request.
+
+v 1.1.0
+---
+
+  * Adds a `.header`, `.set`, and `.get` method to the response.
+
+v 1.0.4
+---
+
+  * Adds the MIT license
+
+v 1.0.3
+---
+
+  * Merged changes by [invernizzie](https://github.com/invernizzie):
+    to address [#11](https://github.com/howardabrams/node-mocks-http/pull/11)
+
+  * Merged changes by [ericchaves](https://github.com/ericchaves):
+    > I extended your library a little but so it could also handle
+    > some structured responses. By doing so res.send now evaluate the
+    > data passed and search for either a statusCode or httpCode to be
+    > used, and also for a body to send as _data.
+    >
+    > It still working as expected (at least tests passed) for regular
+    > HTTP responses.
+    >
+    > Although I did it with node-restify in mind, it should work well
+    > for all other libs.
+
+v 1.0.2
+---
+
+  * Adds a `.json()` method to the response. (Thanks, diachedelic)
+  * Cleaned up all source files so ./run-tests passes.
+  * Cleaned up jshint issues.
+
+v 1.0.1
+---
+
+  * Adds support for response redirect and render
+
+v 0.0.9
+---
+
+  * Adds support for response cookies
+
+v 0.0.8
+---
+
+  * Adds support for request headers
+  * Fix wrong function name of set cookies
+
+v 0.0.7
+---
+
+  * Adds support for request cookies
+
+v 0.0.6
+---
+
+  * Adds support for request files
+
+v 0.0.5
+---
+
+  * Fixed a bug where `response.send()` can take two parameters, the status code and the data to send.
+
+v 0.0.4
+---
+
+  * Adds a `request.session` that can be set during construction (or via calling the `_setSessionVariable()` method, and read as an object.
+
+v 0.0.3
+---
+
+  * Adds a `request.query` that can be set during construction and read as an object.
+
+v 0.0.2
+---
+
+  * Code refactoring of the `Response` mock.
+
+v 0.0.1
+---
+
+  * Initial code banged out one late night...
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..fcf92f9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+This project is bound by the MIT License (MIT)
+
+Copyright (c) 2012-2014, Howard Abrams and other collaborators
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9b55848
--- /dev/null
+++ b/README.md
@@ -0,0 +1,183 @@
+[![node-mocks-http logo][nmh-logo]][nmh-url]
+---
+[![NPM version][npm-badge]][npm-url]
+[![Build Status][travis-badge]][travis-url]
+[![Gitter chat][gitter-badge]][gitter-url]
+
+
+Mock 'http' objects for testing [Express][express-url]
+routing functions, but could be used for testing any
+[Node.js][node-url] web server applications that have
+code that requires mockups of the `request` and `response` objects.
+
+## Installation
+
+This project is available as a
+[NPM package][npm-url].
+
+```bash
+$ npm install --save-dev node-mocks-http
+```
+
+> Our example includes `--save-dev` based on the assumption that **node-mocks-http** will be used as a development dependency..
+
+After installing the package include the following in your test files:
+
+```js
+var httpMocks = require('node-mocks-http');
+```
+
+## Usage
+
+Suppose you have the following Express route:
+
+```js
+app.get('/user/:id', routeHandler);
+```
+
+And you have created a function to handle that route's call:
+
+```js
+var routeHandler = function( request, response ) { ... };
+```
+
+You can easily test the `routeHandler` function with some code like
+this using the testing framework of your choice:
+
+```js
+exports['routeHandler - Simple testing'] = function(test) {
+
+    var request  = httpMocks.createRequest({
+        method: 'GET',
+        url: '/user/42',
+        params: {
+          id: 42
+        }
+    });
+
+    var response = httpMocks.createResponse();
+
+    routeHandler(request, response);
+
+    var data = JSON.parse( response._getData() );
+    test.equal("Bob Dog", data.name);
+    test.equal(42, data.age);
+    test.equal("bob at dog.com", data.email);
+
+    test.equal(200, response.statusCode );
+    test.ok( response._isEndCalled());
+    test.ok( response._isJSON());
+    test.ok( response._isUTF8());
+
+    test.done();
+
+};
+```
+
+## API
+### .createRequest()
+
+```
+httpMocks.createRequest(options)
+```
+
+Where options is an object hash with any of the following values:
+
+option | description | default value
+------ | ----------- | -------------
+`method`| request HTTP method | 'GET'
+`url` | request URL | ''
+`originalUrl` | request original URL | `url`
+`path` | request path | ''
+`params` | object hash with params | {}
+`session` | object hash with session values | `undefined`
+`cookies` | object hash with request cookies | {}
+`signedCookies` | object hash with signed cookies | `undefined`
+`headers` | object hash with request headers | {}
+`body` | object hash with body | {}
+`query` | object hash with query values | {}
+`files` | object hash with values | {}
+
+### .createResponse()
+
+```js
+httpMocks.createResponse(options)
+```
+
+Where options is an object hash with any of the following values:
+
+option | description | default value
+------ | ----------- | -------------
+`eventEmitter` | event emitter used by nmh | `mockEventEmitter`
+`writableStream`  | writable stream used by nmh | `mockWritableStream`
+
+## Design Decisions
+
+We wanted some simple mocks without a large framework.
+
+We also wanted the mocks to act like the original framework being
+mocked, but allow for setting of values before calling and inspecting
+of values after calling.
+
+## For Developers
+
+We are looking for more volunteers to bring value to this project,
+including the creation of more objects from the
+[HTTP module][node-http-module-url].
+
+This project doesn't address all features that must be
+mocked, but it is a good start. Feel free to send pull requests,
+and a member of the team will be timely in merging them.
+
+If you wish to contribute please read our [Contributing Guidelines](CONTRIBUTING.md).
+
+
+## Release Notes
+
+Most releases fix bugs with our mocks or add features similar to the
+actual `Request` and `Response` objects offered by Node.js and extended
+by Express.
+
+[Most Recent Release Notes][release-notes]
+
+* [v1.4.3][release-v1.4.3] - June 3, 2015
+* [v1.4.2][release-v1.4.2] - April 30, 2015
+* [v1.4.1][release-v1.4.1] - April 14, 2015
+* [v1.4.0][release-v1.4.0] - April 12, 2015
+* [v1.3.0][release-v1.3.0] - April 5, 2015
+* [v1.2.7][release-v1.2.7] - March 24, 2015
+* [v1.2.6][release-v1.2.6] - March 19, 2015
+* [v1.2.5][release-v1.2.5] - March 5, 2015
+
+
+License
+---
+
+Licensed under [MIT](https://github.com/howardabrams/node-mocks-http/blob/master/LICENSE).
+
+[nmh-logo]: https://raw.githubusercontent.com/wiki/howardabrams/node-mocks-http/images/nmh-logo-200x132.png
+[nmh-url]: https://github.com/howardabrams/node-mocks-http
+
+[npm-badge]: https://badge.fury.io/js/node-mocks-http.png
+[npm-url]: https://www.npmjs.com/package/node-mocks-http
+
+[travis-badge]: https://travis-ci.org/howardabrams/node-mocks-http.svg?branch=master
+[travis-url]: https://travis-ci.org/howardabrams/node-mocks-http
+
+[gitter-badge]: https://badges.gitter.im/howardabrams/node-mocks-http.png
+[gitter-url]: https://gitter.im/howardabrams/node-mocks-http
+
+[express-url]: http://expressjs.com/
+[node-url]: http://www.nodejs.org
+[node-http-module-url]: http://nodejs.org/docs/latest/api/http.html
+
+[release-notes]: https://github.com/howardabrams/node-mocks-http/releases
+
+[release-v1.4.3]: https://github.com/howardabrams/node-mocks-http/releases/tag/v1.4.3
+[release-v1.4.2]: https://github.com/howardabrams/node-mocks-http/releases/tag/v1.4.2
+[release-v1.4.1]: https://github.com/howardabrams/node-mocks-http/releases/tag/v1.4.1
+[release-v1.4.0]: https://github.com/howardabrams/node-mocks-http/releases/tag/v1.4.0
+[release-v1.3.0]: https://github.com/howardabrams/node-mocks-http/releases/tag/v1.3.0
+[release-v1.2.7]: https://github.com/howardabrams/node-mocks-http/releases/tag/v1.2.7
+[release-v1.2.6]: https://github.com/howardabrams/node-mocks-http/releases/tag/v1.2.6
+[release-v1.2.5]: https://github.com/howardabrams/node-mocks-http/releases/tag/v1.2.5
diff --git a/examples/express-route.js b/examples/express-route.js
new file mode 100644
index 0000000..d53dd31
--- /dev/null
+++ b/examples/express-route.js
@@ -0,0 +1,61 @@
+'use strict';
+
+var httpMocks = require('../lib/http-mock');
+
+// Suppose you have the following Express route:
+
+//     app.get('/user/:id', routeHandler);
+
+// And you have created a function to handle that route's call:
+
+var routeHandler = function(request, response) {
+
+    var id = request.params.id;
+
+    console.log('We have a \'%s\' request for %s (ID: %d)', request.method, request.url, id);
+
+    var body = {
+        name: 'Bob Dog',
+        age: 42,
+        email: 'bob at dog.com'
+    };
+
+    response.setHeader('Content-Type', 'application/json');
+    response.statusCode = 200;
+    response.send(JSON.stringify(body), 'utf8');
+    response.end();
+
+};
+
+// -----------------------------------------------------------------
+// In another file, you can easily test the routeHandler function
+// with some code like this using the testing framework of your choice:
+
+exports['routeHandler - Simple testing'] = function(test) {
+
+    var request = httpMocks.createRequest({
+        method: 'GET',
+        url: '/user/42',
+        params: {
+            id: 42
+        }
+    });
+
+    var response = httpMocks.createResponse();
+
+    routeHandler(request, response);
+
+    var data = JSON.parse(response._getData());
+
+    test.equal('Bob Dog', data.name);
+    test.equal(42, data.age);
+    test.equal('bob at dog.com', data.email);
+
+    test.equal(200, response.statusCode);
+    test.ok(response._isEndCalled());
+    test.ok(response._isJSON());
+    test.ok(response._isUTF8());
+
+    test.done();
+
+};
diff --git a/examples/express-status-vs-json.js b/examples/express-status-vs-json.js
new file mode 100644
index 0000000..6544bca
--- /dev/null
+++ b/examples/express-status-vs-json.js
@@ -0,0 +1,51 @@
+'use strict';
+
+var httpMocks = require('../lib/http-mock');
+
+// Suppose you have the following Express route:
+
+//     app.post('/users', routeHandler);
+
+// And you have created a function to handle that route's call:
+
+var routeHandler = function(request, response) {
+
+    console.log('We have a \'%s\' request for %s', request.method, request.url);
+
+    var body = {
+        name: 'Bob Dog',
+        age: 42,
+        email: 'bob at dog.com'
+    };
+
+    response.status(201).json(body);
+    response.end();
+};
+
+// -----------------------------------------------------------------
+// In another file, you can easily test the routeHandler function
+// with some code like this using the testing framework of your choice:
+
+exports['routeHandler - Simple testing of status() vs json()'] = function(test) {
+
+    var request = httpMocks.createRequest({
+        method: 'POST',
+        url: '/users'
+    });
+
+    var response = httpMocks.createResponse();
+
+    routeHandler(request, response);
+
+    var data = JSON.parse(response._getData());
+
+    test.equal('Bob Dog', data.name);
+    test.equal(42, data.age);
+    test.equal('bob at dog.com', data.email);
+
+    test.equal(201, response.statusCode);
+    test.ok(response._isJSON());
+
+    test.done();
+
+};
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 0000000..d4c5b08
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,44 @@
+'use strict';
+
+var gulp = require('gulp');
+var mocha = require('gulp-mocha');
+var istanbul = require('gulp-istanbul');
+var eslint = require('gulp-eslint');
+
+var files = {
+  src: ['./lib/**/*.js'],
+  test: ['./test/**/*.spec.js']
+};
+
+gulp.task('lint', function () {
+    return gulp.src(files.src.concat(files.test))
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failOnError());
+});
+
+gulp.task('test', function () {
+    return gulp.src(files.test, {read: false})
+      .pipe(mocha({reporter: 'dot'}));
+});
+
+gulp.task('spec', function () {
+    return gulp.src(files.test, {read: false})
+      .pipe(mocha({reporter: 'spec'}));
+});
+
+gulp.task('coverage', function (done) {
+    gulp.src(files.src)
+      .pipe(istanbul())
+      .pipe(istanbul.hookRequire())
+      .on('finish', function () {
+          gulp.src(files.test)
+              .pipe(mocha({reporter: 'dot'}))
+              .pipe(istanbul.writeReports({
+                  dir: './coverage',
+                  reporters: ['lcov', 'json', 'html'],
+                  reportOpts: { dir: './coverage' }
+                }))
+              .on('end', done);
+      });
+});
diff --git a/lib/http-mock.js b/lib/http-mock.js
new file mode 100644
index 0000000..196d794
--- /dev/null
+++ b/lib/http-mock.js
@@ -0,0 +1,14 @@
+'use strict';
+
+/**
+ * Module: http-mock
+ *
+ *   The interface for this entire module that just exposes the exported
+ *   functions from the other libraries.
+ */
+
+var request = require('./mockRequest');
+var response = require('./mockResponse');
+
+exports.createRequest = request.createRequest;
+exports.createResponse = response.createResponse;
diff --git a/lib/mockEventEmitter.js b/lib/mockEventEmitter.js
new file mode 100644
index 0000000..52075c9
--- /dev/null
+++ b/lib/mockEventEmitter.js
@@ -0,0 +1,20 @@
+'use strict';
+
+/*
+ * http://nodejs.org/api/events.html
+ */
+
+function EventEmitter() {}
+
+EventEmitter.prototype.addListener = function () {};
+EventEmitter.prototype.on = function () {};
+EventEmitter.prototype.once = function () {};
+EventEmitter.prototype.removeListener = function () {};
+EventEmitter.prototype.removeAllListeners = function () {};
+// EventEmitter.prototype.removeAllListeners = function([event])
+EventEmitter.prototype.setMaxListeners = function () {};
+EventEmitter.prototype.listeners = function () {};
+EventEmitter.prototype.emit = function () {};
+// EventEmitter.prototype.emit = function(event, [arg1], [arg2], [...]){}
+
+module.exports = EventEmitter;
diff --git a/lib/mockRequest.js b/lib/mockRequest.js
new file mode 100644
index 0000000..8a93677
--- /dev/null
+++ b/lib/mockRequest.js
@@ -0,0 +1,296 @@
+'use strict';
+
+/**
+ * File: mockRequest
+ *
+ * This file implements node.js's implementation of a 'request' object.
+ * This is actually closer to what Express offers the user, in that the
+ * body is really a parsed object of values.
+ *
+ * @author Howard Abrams <howard.abrams at gmail.com>
+ */
+
+/**
+ * Function: createRequest
+ *
+ *    Creates a new mock 'request' instance. All values are reset to the
+ *    defaults.
+ *
+ * Parameters:
+ *
+ *   options - An object of named parameters.
+ *
+ * Options:
+ *
+ *   method      - The method value, see <mockRequest._setMethod>
+ *   url         - The url value, see <mockRequest._setURL>
+ *   originalUrl - The originalUrl value, see <mockRequest._setOriginalUrl>
+ *   params      - The parameters, see <mockRequest._setParam>
+ *   body        - The body values, , see <mockRequest._setBody>
+ */
+
+var url = require('url');
+
+function convertKeysToLowerCase(map) {
+    var newMap = {};
+    for(var key in map) {
+        newMap[key.toLowerCase()] = map[key];
+    }
+    return newMap;
+}
+
+function createRequest(options) {
+
+    if (!options) {
+        options = {};
+    }
+
+    // creat mockRequest
+
+    var mockRequest = {};
+
+    mockRequest.method = (options.method) ? options.method : 'GET';
+    mockRequest.url = (options.url) ? options.url : '';
+    mockRequest.originalUrl = options.originalUrl || mockRequest.url;
+    mockRequest.path = (options.url) ? url.parse(options.url).pathname : '';
+    mockRequest.params = (options.params) ? options.params : {};
+    if (options.session) {
+        mockRequest.session = options.session;
+    }
+    mockRequest.cookies = (options.cookies) ? options.cookies : {};
+    if (options.signedCookies) {
+        mockRequest.signedCookies = options.signedCookies;
+    }
+    mockRequest.headers = (options.headers) ? convertKeysToLowerCase(options.headers) : {};
+    mockRequest.body = (options.body) ? options.body : {};
+    mockRequest.query = (options.query) ? options.query : {};
+    mockRequest.files = (options.files) ? options.files : {};
+
+    //parse query string from url to object
+    if (Object.keys(mockRequest.query).length === 0) {
+        mockRequest.query = require('querystring').parse(mockRequest.url.split('?')[1]);
+    }
+
+    /**
+     * Return request header.
+     *
+     * The `Referrer` header field is special-cased,
+     * both `Referrer` and `Referer` are interchangeable.
+     *
+     * Examples:
+     *
+     *     mockRequest.get('Content-Type');
+     *     // => "text/plain"
+     *
+     *     mockRequest.get('content-type');
+     *     // => "text/plain"
+     *
+     *     mockRequest.get('Something');
+     *     // => undefined
+     *
+     * Aliased as `mockRequest.header()`.
+     *
+     * @param {String} name
+     * @return {String}
+     * @api public
+     */
+
+    mockRequest.get =
+    mockRequest.header = function(name) {
+        name = name.toLowerCase();
+        switch (name) {
+            case 'referer':
+            case 'referrer':
+                return mockRequest.headers.referrer || mockRequest.headers.referer;
+            default:
+                return mockRequest.headers[name];
+        }
+    };
+
+    /**
+     * Function: param
+     *
+     *   Return the value of param name when present.
+     *   Lookup is performed in the following order:
+     *   - req.params
+     *   - req.body
+     *   - req.query
+     */
+    mockRequest.param = function(parameterName) {
+        if (mockRequest.params[parameterName]) {
+            return mockRequest.params[parameterName];
+        } else if (mockRequest.body[parameterName]) {
+            return mockRequest.body[parameterName];
+        } else if (mockRequest.query[parameterName]) {
+            return mockRequest.query[parameterName];
+        }
+        return null;
+    };
+
+    /**
+     * Function: _setParameter
+     *
+     *    Set parameters that the client can then get using the 'params'
+     *    key.
+     *
+     * Parameters:
+     *
+     *   key - The key. For instance, 'bob' would be accessed: request.params.bob
+     *   value - The value to return when accessed.
+     */
+    mockRequest._setParameter = function(key, value) {
+        mockRequest.params[key] = value;
+    };
+
+    /**
+     * Sets a variable that is stored in the session.
+     *
+     * @param variable The variable to store in the session
+     * @param value    The value associated with the variable
+     */
+    mockRequest._setSessionVariable = function(variable, value) {
+        if (typeof mockRequest.session !== 'object') {
+            mockRequest.session = {};
+        }
+        mockRequest.session[variable] = value;
+    };
+
+    /**
+     * Sets a variable that is stored in the cookies.
+     *
+     * @param variable The variable to store in the cookies
+     * @param value    The value associated with the variable
+     */
+    mockRequest._setCookiesVariable = function(variable, value) {
+        mockRequest.cookies[variable] = value;
+    };
+
+    /**
+     * Sets a variable that is stored in the signed cookies.
+     *
+     * @param variable The variable to store in the signed cookies
+     * @param value    The value associated with the variable
+     */
+    mockRequest._setSignedCookiesVariable = function(variable, value) {
+        if (typeof mockRequest.signedCookies !== 'object') {
+            mockRequest.signedCookies = {};
+        }
+        mockRequest.signedCookies[variable] = value;
+    };
+
+    /**
+     * Sets a variable that is stored in the headers.
+     *
+     * @param variable The variable to store in the headers
+     * @param value    The value associated with the variable
+     */
+    mockRequest._setHeadersVariable = function(variable, value) {
+        variable = variable.toLowerCase();
+        mockRequest.headers[variable] = value;
+    };
+
+    /**
+     * Sets a variable that is stored in the files.
+     *
+     * @param variable The variable to store in the files
+     * @param value    The value associated with the variable
+     */
+    mockRequest._setFilesVariable = function(variable, value) {
+        mockRequest.files[variable] = value;
+    };
+
+    /**
+     * Function: _setMethod
+     *
+     *    Sets the HTTP method that the client gets when the called the 'method'
+     *    property. This defaults to 'GET' if it is not set.
+     *
+     * Parameters:
+     *
+     *   method - The HTTP method, e.g. GET, POST, PUT, DELETE, etc.
+     *
+     * Note: We don't validate the string. We just return it.
+     */
+    mockRequest._setMethod = function(method) {
+        mockRequest.method = method;
+    };
+
+    /**
+     * Function: _setURL
+     *
+     *    Sets the URL value that the client gets when the called the 'url'
+     *    property.
+     *
+     * Parameters:
+     *
+     *   value - The request path, e.g. /my-route/452
+     *
+     * Note: We don't validate the string. We just return it. Typically, these
+     * do not include hostname, port or that part of the URL.
+     */
+    mockRequest._setURL = function(value) {
+        mockRequest.url = value;
+    };
+
+    /**
+     * Function: _setOriginalUrl
+     *
+     *    Sets the URL value that the client gets when the called the 'originalUrl'
+     *    property.
+     *
+     * Parameters:
+     *
+     *   value - The request path, e.g. /my-route/452
+     *
+     * Note: We don't validate the string. We just return it. Typically, these
+     * do not include hostname, port or that part of the URL.
+     */
+    mockRequest._setOriginalUrl = function(value) {
+        mockRequest.originalUrl = value;
+    };
+
+    /**
+     * Function: _setBody
+     *
+     *    Sets the body that the client gets when the called the 'body'
+     *    parameter. This defaults to 'GET' if it is not set.
+     *
+     * Parameters:
+     *
+     *   body - An object representing the body.
+     *
+     * If you expect the 'body' to come from a form, this typically means that
+     * it would be a flat object of properties and values, as in:
+     *
+     * > {  name: 'Howard Abrams',
+     * >    age: 522
+     * > }
+     *
+     * If the client is expecting a JSON object through a REST interface, then
+     * this object could be anything.
+     */
+    mockRequest._setBody = function(body) {
+        mockRequest.body = body;
+    };
+
+    /**
+     * Function: _addBody
+     *
+     *    Adds another body parameter the client gets when calling the 'body'
+     *    parameter with another property value, e.g. the name of a form element
+     *    that was passed in.
+     *
+     * Parameters:
+     *
+     *   key - The key. For instance, 'bob' would be accessed: request.params.bob
+     *   value - The value to return when accessed.
+     */
+    mockRequest._addBody = function(key, value) {
+        mockRequest.body[key] = value;
+    };
+
+    return mockRequest;
+
+}
+
+module.exports.createRequest = createRequest;
diff --git a/lib/mockResponse.js b/lib/mockResponse.js
new file mode 100644
index 0000000..bc49230
--- /dev/null
+++ b/lib/mockResponse.js
@@ -0,0 +1,639 @@
+'use strict';
+
+/**
+ * File: mockResponse
+ *
+ *  This file implements node.js's implementation of a 'response' object.
+ *  Like all good mocks, the response file that can be called and used in
+ *  place of a real HTTP response object.
+ *
+ * @author Howard Abrams <howard.abrams at gmail.com>
+ */
+
+/**
+ * Function: createResponse
+ *
+ *    Creates a new mock 'response' instance. All values are reset to the
+ *    defaults.
+ *
+ * Parameters:
+ *
+ *   options - An object of named parameters.
+ *
+ * Options:
+ *
+ *   encoding - The default encoding for the response
+ */
+
+var WritableStream = require('./mockWritableStream');
+var EventEmitter = require('./mockEventEmitter');
+var mime = require('mime');
+var http = require('./node/http');
+
+function createResponse(options) {
+
+    if (!options) {
+        options = {};
+    }
+
+    var _endCalled = false;
+    var _data = '';
+    var _encoding = options.encoding;
+
+    var _redirectUrl = '';
+    var _renderView = '';
+    var _renderData = {};
+
+    if (options.writableStream) {
+        WritableStream = options.writableStream;
+    }
+    if (options.eventEmitter) {
+        EventEmitter = options.eventEmitter;
+    }
+    var writableStream = new WritableStream();
+    var eventEmitter = new EventEmitter();
+
+    // create mockResponse
+
+    var mockResponse = {};
+
+    mockResponse._headers = {};
+
+    mockResponse.statusCode = 200;
+    mockResponse.cookies = {};
+
+    mockResponse.cookie = function(name, value, opt) {
+
+        mockResponse.cookies[name] = {
+            value: value,
+            options: opt
+        };
+
+    };
+
+    mockResponse.clearCookie = function(name) {
+        delete mockResponse.cookies[name];
+    };
+
+    mockResponse.status = function(code) {
+        mockResponse.statusCode = code;
+        return this;
+    };
+
+    /**
+     * Function: writeHead
+     *
+     *  The 'writeHead' function from node's HTTP API.
+     *
+     * Parameters:
+     *
+     *  statusCode - A number to send as a the HTTP status
+     *  headers    - An object of properties that will be used for
+     *               the HTTP headers.
+     */
+    mockResponse.writeHead = function(statusCode, phrase, headers) {
+
+        if (_endCalled) {
+            throw 'The end() method has already been called.';
+        }
+
+        mockResponse.statusCode = statusCode;
+
+        // Note: Not sure if the headers given in this function
+        //       overwrite any headers specified earlier.
+        if (headers) {
+            mockResponse._headers = headers;
+        } else {
+            mockResponse._headers = phrase;
+        }
+
+    };
+
+    /**
+     *  The 'send' function from node's HTTP API that returns data
+     *  to the client. Can be called multiple times.
+     *
+     * @param data The data to return. Must be a string.
+     */
+    mockResponse.send = function(a, b, c) {
+
+        var _formatData = function(data) {
+
+            if (typeof data === 'object') {
+
+                if (data.statusCode) {
+                    mockResponse.statusCode = data.statusCode;
+                } else if (data.httpCode) {
+                    mockResponse.statusCode = data.statusCode;
+                }
+
+                if (data.body) {
+                    _data = data.body;
+                } else {
+                    _data = data;
+                }
+
+            } else {
+                _data += data;
+            }
+
+        };
+
+        switch (arguments.length) {
+
+            case 1:
+
+                if (typeof a === 'number') {
+                    mockResponse.statusCode = a;
+                } else {
+                    _formatData(a);
+                }
+
+                break;
+
+            case 2:
+
+                if (typeof a === 'number') {
+                    _formatData(b);
+                    mockResponse.statusCode = a;
+                } else if (typeof b === 'number') {
+                    _formatData(a);
+                    mockResponse.statusCode = b;
+                    console.warn('WARNING: Called send() with deprecated parameter order');
+                } else {
+                    _formatData(a);
+                    _encoding = b;
+                }
+
+                break;
+
+            case 3:
+
+                _formatData(a);
+                mockResponse._headers = b;
+                mockResponse.statusCode = c;
+                console.warn('WARNING: Called send() with deprecated three parameters');
+
+                break;
+
+            default:
+                break;
+
+        }
+
+        mockResponse.emit('send');
+        mockResponse.emit('end');
+
+    };
+
+    /**
+     * Send given HTTP status code.
+     *
+     * Sets the response status to `statusCode` and the body of the
+     * response to the standard description from node's http.STATUS_CODES
+     * or the statusCode number if no description.
+     *
+     * Examples:
+     *
+     *     mockResponse.sendStatus(200);
+     *
+     * @param {number} statusCode
+     * @api public
+     */
+
+    mockResponse.sendStatus = function sendStatus(statusCode) {
+        var body = http.STATUS_CODES[statusCode] || String(statusCode);
+
+        mockResponse.statusCode = statusCode;
+        mockResponse.type('txt');
+
+        return mockResponse.send(body);
+    };
+
+
+    /**
+     * Function: json
+     *
+     *   The 'json' function from node's HTTP API that returns JSON
+     *   data to the client.
+     *
+     *  Parameters:
+     *
+     *   a - Either a statusCode or string containing JSON payload
+     *   b - Either a statusCode or string containing JSON payload
+     *
+     *  If not specified, the statusCode defaults to 200.
+     *  Second parameter is optional.
+     */
+    mockResponse.json = function(a, b) {
+
+        mockResponse.setHeader('Content-Type', 'application/json');
+        if (a) {
+            if (typeof a === 'number') {
+                mockResponse.statusCode = a;
+            } else {
+                _data += JSON.stringify(a);
+            }
+        }
+        if (b) {
+            if (typeof b === 'number') {
+                mockResponse.statusCode = b;
+            } else {
+                _data += JSON.stringify(b);
+            }
+        }
+
+        mockResponse.emit('send');
+        mockResponse.emit('end');
+
+    };
+
+    /**
+     * Set "Content-Type" response header with `type` through `mime.lookup()`
+     * when it does not contain "/", or set the Content-Type to `type` otherwise.
+     *
+     * Examples:
+     *
+     *     res.type('.html');
+     *     res.type('html');
+     *     res.type('json');
+     *     res.type('application/json');
+     *     res.type('png');
+     *
+     * @param {String} type
+     * @return {ServerResponse} for chaining
+     * @api public
+     */
+    mockResponse.contentType = mockResponse.type = function(type){
+        return mockResponse.set('Content-Type', type.indexOf('/') >= 0 ? type : mime.lookup(type));
+    };
+
+    /**
+     * Function: write
+     *
+     *    This function has the same behavior as the 'send' function.
+     *
+     * Parameters:
+     *
+     *  data - The data to return. Must be a string. Appended to
+     *         previous calls to data.
+     *  encoding - Optional encoding value.
+     */
+
+    mockResponse.write = function(data, encoding) {
+
+        _data += data;
+
+        if (encoding) {
+            _encoding = encoding;
+        }
+
+    };
+
+    /**
+     *  Function: end
+     *
+     *  The 'end' function from node's HTTP API that finishes
+     *  the connection request. This must be called.
+     *
+     * Parameters:
+     *
+     *  data - Optional data to return. Must be a string. Appended
+     *         to previous calls to <send>.
+     *  encoding - Optional encoding value.
+     */
+    mockResponse.end = function(data, encoding) {
+
+        _endCalled = true;
+
+        if (data) {
+            _data += data;
+        }
+
+        if (encoding) {
+            _encoding = encoding;
+        }
+
+        mockResponse.emit('end');
+
+    };
+
+   /**
+    * Set header `field` to `val`, or pass
+    * an object of header fields.
+    *
+    * Examples:
+    *
+    *    res.set('Foo', ['bar', 'baz']);
+    *    res.set('Accept', 'application/json');
+    *    res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });
+    *
+    * Aliased as `mockResponse.header()`.
+    *
+    * @param {String|Object|Array} field
+    * @param {String} val
+    * @return {ServerResponse} for chaining
+    * @api public
+    */
+    mockResponse.set = mockResponse.header = function header(field, val) {
+        if (arguments.length === 2) {
+            if (Array.isArray(val)) {
+                val = val.map(String);
+            } else {
+                val = String(val);
+            }
+            mockResponse.setHeader(field, val);
+        } else {
+            for (var key in field) {
+                mockResponse.setHeader(key, field[key]);
+            }
+        }
+        return mockResponse;
+    };
+
+    /**
+     * Function: getHeader
+     * Function: get
+     *
+     *   Returns a particular header by name.
+     */
+    mockResponse.get = mockResponse.getHeader = function(name) {
+        return mockResponse._headers[name];
+    };
+
+    /**
+     * Function: setHeader
+     * Function: set
+     *
+     *   Set a particular header by name.
+     */
+    mockResponse.setHeader = function(name, value) {
+        mockResponse._headers[name] = value;
+        return value;
+    };
+
+    /**
+     * Function: removeHeader
+     *
+     *   Removes an HTTP header by name.
+     */
+    mockResponse.removeHeader = function(name) {
+        delete mockResponse._headers[name];
+    };
+
+    /**
+     * Function: setEncoding
+     *
+     *    Sets the encoding for the data. Generally 'utf8'.
+     *
+     * Parameters:
+     *
+     *   encoding - The string representing the encoding value.
+     */
+    mockResponse.setEncoding = function(encoding) {
+        _encoding = encoding;
+    };
+
+    /**
+     * Function: redirect
+     *
+     *     Redirect to a url with response code
+     */
+    mockResponse.redirect = function(a, b) {
+
+        switch (arguments.length) {
+
+            case 1:
+
+                mockResponse.statusCode = 302;
+                _redirectUrl = a;
+                break;
+
+            case 2:
+
+                if (typeof a === 'number') {
+                    mockResponse.statusCode = a;
+                    _redirectUrl = b;
+                }
+
+                break;
+
+            default:
+                break;
+
+        }
+
+    };
+
+    /**
+     * Function: render
+     *
+     *     Render a view with a callback responding with the
+     *     rendered string.
+     */
+    mockResponse.render = function(a, b) {
+
+        _renderView = a;
+
+        switch (arguments.length) {
+
+            case 2:
+                _renderData = b;
+                break;
+
+            default:
+                break;
+
+        }
+
+        mockResponse.emit('render');
+        mockResponse.emit('end');
+
+    };
+
+    // WritableStream.writable is not a function
+    // mockResponse.writable = function() {
+    //     return writableStream.writable.apply(this, arguments);
+    // };
+
+    // mockResponse.end = function(){
+    //  return writableStream.end.apply(this, arguments);
+    // };
+
+    mockResponse.destroy = function() {
+        return writableStream.destroy.apply(this, arguments);
+    };
+
+    mockResponse.destroySoon = function() {
+        return writableStream.destroySoon.apply(this, arguments);
+    };
+
+    mockResponse.addListener = function() {
+        return eventEmitter.addListener.apply(this, arguments);
+    };
+
+    mockResponse.on = function() {
+        return eventEmitter.on.apply(this, arguments);
+    };
+
+    mockResponse.once = function() {
+        return eventEmitter.once.apply(this, arguments);
+    };
+
+    mockResponse.removeListener = function() {
+        return eventEmitter.removeListener.apply(this, arguments);
+    };
+
+    mockResponse.removeAllListeners = function() {
+        return eventEmitter.removeAllListeners.apply(this, arguments);
+    };
+
+    mockResponse.setMaxListeners = function() {
+        return eventEmitter.setMaxListeners.apply(this, arguments);
+    };
+
+    mockResponse.listeners = function() {
+        return eventEmitter.listeners.apply(this, arguments);
+    };
+
+    mockResponse.emit = function() {
+        return eventEmitter.emit.apply(this, arguments);
+    };
+
+    //This mock object stores some state as well
+    //as some test-analysis functions:
+
+    /**
+     * Function: _isEndCalled
+     *
+     *  Since the <end> function must be called, this function
+     *  returns true if it has been called. False otherwise.
+     */
+    mockResponse._isEndCalled = function() {
+        return _endCalled;
+    };
+
+    /**
+     * Function: _getHeaders
+     *
+     *  Returns all the headers that were set. This may be an
+     *  empty object, but probably will have "Content-Type" set.
+     */
+    mockResponse._getHeaders = function() {
+        return mockResponse._headers;
+    };
+
+    /**
+     * Function: _getData
+     *
+     *  The data sent to the user.
+     */
+    mockResponse._getData = function() {
+        return _data;
+    };
+
+    /**
+     * Function: _getStatusCode
+     *
+     *  The status code that was sent to the user.
+     */
+    mockResponse._getStatusCode = function() {
+        return mockResponse.statusCode;
+    };
+
+    /**
+     * Function: _isJSON
+     *
+     *  Returns true if the data sent was defined as JSON.
+     *  It doesn't validate the data that was sent.
+     */
+    mockResponse._isJSON = function() {
+        return (mockResponse._headers['Content-Type'] === 'application/json');
+    };
+
+    /**
+     * Function: _isUTF8
+     *
+     *    If the encoding was set, and it was set to UTF-8, then
+     *    this function return true. False otherwise.
+     *
+     * Returns:
+     *
+     *   False if the encoding wasn't set and wasn't set to "utf8".
+     */
+    mockResponse._isUTF8 = function() {
+
+        if (!_encoding) {
+            return false;
+        }
+
+        return (_encoding === 'utf8');
+
+    };
+
+    /**
+     * Function: _isDataLengthValid
+     *
+     *    If the Content-Length header was set, this will only
+     *    return true if the length is actually the length of the
+     *    data that was set.
+     *
+     * Returns:
+     *
+     *   True if the "Content-Length" header was not
+     *   set. Otherwise, it compares it.
+     */
+    mockResponse._isDataLengthValid = function() {
+
+        if (mockResponse._headers['Content-Length']) {
+            return (mockResponse._headers['Content-Length'].toString() === _data.length.toString());
+        }
+
+        return true;
+
+    };
+
+    /**
+     * Function: _getRedirectUrl
+     *
+     *     Return redirect url of redirect method
+     *
+     * Returns:
+     *
+     *     Redirect url
+     */
+    mockResponse._getRedirectUrl = function() {
+        return _redirectUrl;
+    };
+
+    /**
+     * Function: _getRenderView
+     *
+     *     Return render view of render method
+     *
+     * Returns:
+     *
+     *     render view
+     */
+    mockResponse._getRenderView = function() {
+        return _renderView;
+    };
+
+    /**
+     * Function: _getRenderData
+     *
+     *     Return render data of render method
+     *
+     * Returns:
+     *
+     *     render data
+     */
+    mockResponse._getRenderData = function() {
+        return _renderData;
+    };
+
+    return mockResponse;
+
+}
+
+module.exports.createResponse = createResponse;
diff --git a/lib/mockWritableStream.js b/lib/mockWritableStream.js
new file mode 100644
index 0000000..7d82644
--- /dev/null
+++ b/lib/mockWritableStream.js
@@ -0,0 +1,25 @@
+'use strict';
+
+/*
+ * http://nodejs.org/api/stream.html#stream_writable_stream
+ */
+
+function WritableStream() {}
+
+Object.defineProperty(WritableStream, 'writable', {
+    configurable: true,
+    enumerable: true,
+    get: function() {
+        return true;
+    }
+});
+
+// WritableStream.prototype.write = function(string, [encoding], [fd]){}
+// WritableStream.prototype.write = function(buffer){}
+WritableStream.prototype.end = function () {};
+// WritableStream.prototype.end = function(string, encoding){}
+// WritableStream.prototype.end = function(buffer){}
+WritableStream.prototype.destroy = function () {};
+WritableStream.prototype.destroySoon = function () {};
+
+module.exports = WritableStream;
diff --git a/lib/node/_http_server.js b/lib/node/_http_server.js
new file mode 100644
index 0000000..60c701f
--- /dev/null
+++ b/lib/node/_http_server.js
@@ -0,0 +1,61 @@
+'use strict';
+
+exports.STATUS_CODES = {
+  100: 'Continue',
+  101: 'Switching Protocols',
+  102: 'Processing',
+  200: 'OK',
+  201: 'Created',
+  202: 'Accepted',
+  203: 'Non-Authoritative Information',
+  204: 'No Content',
+  205: 'Reset Content',
+  206: 'Partial Content',
+  207: 'Multi-Status',
+  300: 'Multiple Choices',
+  301: 'Moved Permanently',
+  302: 'Moved Temporarily',
+  303: 'See Other',
+  304: 'Not Modified',
+  305: 'Use Proxy',
+  307: 'Temporary Redirect',
+  308: 'Permanent Redirect',
+  400: 'Bad Request',
+  401: 'Unauthorized',
+  402: 'Payment Required',
+  403: 'Forbidden',
+  404: 'Not Found',
+  405: 'Method Not Allowed',
+  406: 'Not Acceptable',
+  407: 'Proxy Authentication Required',
+  408: 'Request Time-out',
+  409: 'Conflict',
+  410: 'Gone',
+  411: 'Length Required',
+  412: 'Precondition Failed',
+  413: 'Request Entity Too Large',
+  414: 'Request-URI Too Large',
+  415: 'Unsupported Media Type',
+  416: 'Requested Range Not Satisfiable',
+  417: 'Expectation Failed',
+  418: 'I\'m a teapot',
+  422: 'Unprocessable Entity',
+  423: 'Locked',
+  424: 'Failed Dependency',
+  425: 'Unordered Collection',
+  426: 'Upgrade Required',
+  428: 'Precondition Required',
+  429: 'Too Many Requests',
+  431: 'Request Header Fields Too Large',
+  500: 'Internal Server Error',
+  501: 'Not Implemented',
+  502: 'Bad Gateway',
+  503: 'Service Unavailable',
+  504: 'Gateway Time-out',
+  505: 'HTTP Version Not Supported',
+  506: 'Variant Also Negotiates',
+  507: 'Insufficient Storage',
+  509: 'Bandwidth Limit Exceeded',
+  510: 'Not Extended',
+  511: 'Network Authentication Required'
+};
diff --git a/lib/node/http.js b/lib/node/http.js
new file mode 100644
index 0000000..5acea41
--- /dev/null
+++ b/lib/node/http.js
@@ -0,0 +1,5 @@
+'use strict';
+
+var server = require('./_http_server');
+
+exports.STATUS_CODES = server.STATUS_CODES;
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..d0e2d8e
--- /dev/null
+++ b/package.json
@@ -0,0 +1,60 @@
+{
+  "author": "Howard Abrams <howard.abrams at gmail.com> (http://www.github.com/howardabrams)",
+  "name": "node-mocks-http",
+  "description": "Mock 'http' objects for testing Express routing functions",
+  "version": "1.4.3",
+  "homepage": "https://github.com/howardabrams/node-mocks-http",
+  "bugs": {
+    "url": "https://github.com/howardabrams/node-mocks-http/issues"
+  },
+  "contributors": [
+    {
+      "name": "Howard Abrams",
+      "email": "howard.abrams at gmail.com",
+      "url": "https://github.com/howardabrams"
+    },
+    {
+      "name": "Johnny Estilles",
+      "email": "johnny.estilles at agentia.asia",
+      "url": "https://github.com/JohnnyEstilles"
+    }
+  ],
+  "license": "MIT",
+  "keywords": [
+    "mock",
+    "stub",
+    "dummy",
+    "nodejs",
+    "js",
+    "testing",
+    "test",
+    "http",
+    "http mock"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/howardabrams/node-mocks-http.git"
+  },
+  "main": "./lib/http-mock.js",
+  "engines": {
+    "node": ">=0.6"
+  },
+  "dependencies": {
+    "mime": "^1.3.4"
+  },
+  "devDependencies": {
+    "chai": "^2.2.0",
+    "eslint": "^0.22.1",
+    "gulp": "^3.8.11",
+    "gulp-eslint": "^0.12.0",
+    "gulp-istanbul": "^0.9.0",
+    "gulp-mocha": "^2.0.1",
+    "istanbul": "^0.3.13",
+    "mocha": "^2.2.4",
+    "sinon": "^1.14.1",
+    "sinon-chai": "^2.7.0"
+  },
+  "scripts": {
+    "test": "gulp spec"
+  }
+}
diff --git a/test/.eslintrc b/test/.eslintrc
new file mode 100644
index 0000000..34a7c62
--- /dev/null
+++ b/test/.eslintrc
@@ -0,0 +1,10 @@
+extends: ../.eslintrc
+
+env:
+  mocha: true
+
+rules:
+  no-unused-expressions: 0
+  indent:
+    - 2
+    - 2
diff --git a/test/lib/http-mock.spec.js b/test/lib/http-mock.spec.js
new file mode 100644
index 0000000..9939a80
--- /dev/null
+++ b/test/lib/http-mock.spec.js
@@ -0,0 +1,21 @@
+'use strict';
+
+var chai = require('chai');
+var expect = chai.expect;
+
+var httpMock;
+
+describe('http-mock', function() {
+  before(function() {
+    httpMock = require('../../lib/http-mock');
+  });
+
+  it('should export .createRequest()', function() {
+    expect(httpMock.createRequest).to.be.a('function');
+  });
+
+  it('should export .createResponse()', function() {
+    expect(httpMock.createResponse).to.be.a('function');
+  });
+
+});
diff --git a/test/lib/mockEventEmitter.spec.js b/test/lib/mockEventEmitter.spec.js
new file mode 100644
index 0000000..c113474
--- /dev/null
+++ b/test/lib/mockEventEmitter.spec.js
@@ -0,0 +1,61 @@
+'use strict';
+
+var chai = require('chai');
+var expect = chai.expect;
+
+var MockEventEmitter = require('../../lib/mockEventEmitter');
+var mockEventEmitter;
+
+describe('mockEventEmitter', function() {
+
+  before(function() {
+    mockEventEmitter = new MockEventEmitter();
+  });
+
+  it('should be a function', function() {
+    expect(MockEventEmitter).to.be.a('function');
+  });
+
+  it('should be an object factory', function() {
+    expect(mockEventEmitter).to.be.a('object');
+    expect(mockEventEmitter).to.be.an.instanceof(MockEventEmitter);
+  });
+
+  it('should expose "MockEventEmitter" prototype', function() {
+    expect(mockEventEmitter).to.have.property('addListener');
+    expect(mockEventEmitter.addListener).to.be.a('function');
+
+    expect(mockEventEmitter).to.have.property('on');
+    expect(mockEventEmitter.on).to.be.a('function');
+
+    expect(mockEventEmitter).to.have.property('once');
+    expect(mockEventEmitter.once).to.be.a('function');
+
+    expect(mockEventEmitter).to.have.property('removeListener');
+    expect(mockEventEmitter.removeListener).to.be.a('function');
+
+    expect(mockEventEmitter).to.have.property('removeAllListeners');
+    expect(mockEventEmitter.removeAllListeners).to.be.a('function');
+
+    expect(mockEventEmitter).to.have.property('setMaxListeners');
+    expect(mockEventEmitter.setMaxListeners).to.be.a('function');
+
+    expect(mockEventEmitter).to.have.property('listeners');
+    expect(mockEventEmitter.listeners).to.be.a('function');
+
+    expect(mockEventEmitter).to.have.property('emit');
+    expect(mockEventEmitter.emit).to.be.a('function');
+  });
+
+  it('should return undefined when methods called', function() {
+    expect(mockEventEmitter.addListener()).to.be.undefined;
+    expect(mockEventEmitter.on()).to.be.undefined;
+    expect(mockEventEmitter.once()).to.be.undefined;
+    expect(mockEventEmitter.removeListener()).to.be.undefined;
+    expect(mockEventEmitter.removeAllListeners()).to.be.undefined;
+    expect(mockEventEmitter.setMaxListeners()).to.be.undefined;
+    expect(mockEventEmitter.listeners()).to.be.undefined;
+    expect(mockEventEmitter.emit()).to.be.undefined;
+  });
+
+});
diff --git a/test/lib/mockRequest.spec.js b/test/lib/mockRequest.spec.js
new file mode 100644
index 0000000..a08c37d
--- /dev/null
+++ b/test/lib/mockRequest.spec.js
@@ -0,0 +1,528 @@
+'use strict';
+
+var chai = require('chai');
+var expect = chai.expect;
+var url = require('url');
+var querystring = require('querystring');
+
+var mockRequest = require('../../lib/mockRequest');
+
+describe('mockRequest', function() {
+
+  it('should expose .createRequest()', function() {
+    expect(mockRequest.createRequest).to.be.a('function');
+  });
+
+  describe('.createRequest()', function() {
+    var request;
+
+    describe('without options', function() {
+
+      before(function() {
+        request = mockRequest.createRequest();
+      });
+
+      it('should return an object', function() {
+        expect(request).to.be.an('object');
+      });
+
+      it('should expose Express Request object methods', function() {
+        expect(request).to.have.property('get');
+        expect(request.get).to.be.a('function');
+
+        expect(request).to.have.property('header');
+        expect(request.header).to.be.a('function');
+
+        expect(request).to.have.property('param');
+        expect(request.param).to.be.a('function');
+      });
+
+      it('shoud initialize with default options', function() {
+        expect(request.method).to.equal('GET');
+        expect(request.url).to.equal('');
+        expect(request.originalUrl).to.equal(request.url);
+        expect(request.path).to.equal('');
+        expect(request.params).to.deep.equal({});
+        expect(request.session).to.not.exist;
+        expect(request.cookies).to.deep.equal({});
+        expect(request.signedCookies).to.not.exist;
+        expect(request.headers).to.deep.equal({});
+        expect(request.body).to.deep.equal({});
+        expect(request.query).to.deep.equal({});
+        expect(request.files).to.deep.equal({});
+      });
+
+    });
+
+    describe('with options', function() {
+
+      afterEach(function() {
+        request = null;
+      });
+
+      it('should set .method to options.method', function() {
+        var options = {
+          method: 'POST'
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.method).to.equal(options.method);
+      });
+
+      it('should set .url to options.url', function() {
+        var options = {
+          url: '/this/is/a/url'
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.url).to.equal(options.url);
+        expect(request.originalUrl).to.equal(options.url);
+      });
+
+      it('should set .originalUrl to options.originalUrl', function() {
+        var options = {
+          originalUrl: '/this/is/a/url'
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.originalUrl).to.equal(options.originalUrl);
+      });
+
+      it('should set .path to pathname of options.url', function() {
+        var options = {
+          url: '/this/is/a/url'
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.path).to.equal(url.parse(options.url).pathname);
+      });
+
+      it('should set .params to options.params', function() {
+        var options = {
+          params: {
+            key1: 'value1',
+            key2: 'value2'
+          }
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.params).to.deep.equal(options.params);
+      });
+
+      it('should set .session to options.session', function() {
+        var options = {
+          session: {
+            key1: 'value1',
+            key2: 'value2'
+          }
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.session).to.deep.equal(options.session);
+      });
+
+      it('should set .cookies to options.cookies', function() {
+        var options = {
+          cookies: {
+            key1: 'value1',
+            key2: 'value2'
+          }
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.cookies).to.deep.equal(options.cookies);
+      });
+
+      it('should set .signedCookies to options.signedCookies', function() {
+        var options = {
+          signedCookies: {
+            key1: 'value1',
+            key2: 'value2'
+          }
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.signedCookies).to.deep.equal(options.signedCookies);
+      });
+
+      it('should set .headers to options.headers', function() {
+        var options = {
+          headers: {
+            key1: 'value1',
+            key2: 'value2'
+          }
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.headers).to.deep.equal(options.headers);
+      });
+
+      it('should set .headers to options.headers and be accessible via get() and header() case-insensitively', function() {
+        var options = {
+          headers: {
+            KEY1: 'value1',
+            Key2: 'value2'
+          }
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.header('KEY1')).to.equal('value1');
+        expect(request.get('KEY1')).to.equal('value1');
+        expect(request.header('KEY2')).to.equal('value2');
+        expect(request.get('KEY2')).to.equal('value2');
+      });
+
+      it('should set .body to options.body', function() {
+        var options = {
+          body: {
+            key1: 'value1',
+            key2: 'value2'
+          }
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.body).to.deep.equal(options.body);
+      });
+
+      it('should set .query to options.query', function() {
+        var options = {
+          query: {
+            key1: 'value1',
+            key2: 'value2'
+          }
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.query).to.deep.equal(options.query);
+      });
+
+      it('should set .files to options.files', function() {
+        var options = {
+          files: {
+            key1: 'value1',
+            key2: 'value2'
+          }
+        };
+
+        request = mockRequest.createRequest(options);
+        expect(request.files).to.deep.equal(options.files);
+      });
+
+      it('should set .query to url query params when options.query not set', function() {
+        var options = {
+          url: '/path/to/url?key1=value1&key2=value2'
+        };
+        var parsedOptions = querystring.parse(options.url.split('?')[1]);
+
+        request = mockRequest.createRequest(options);
+        expect(request.query).to.deep.equal(parsedOptions);
+      });
+
+    });
+
+  });
+
+  describe('.get()/.header()', function() {
+    var request;
+
+    afterEach(function() {
+      request = null;
+    });
+
+    it('should return header, when set', function() {
+      var options = {
+        headers: {
+          key: 'value'
+        }
+      };
+      request = mockRequest.createRequest(options);
+      expect(request.get('key')).to.equal('value');
+      expect(request.header('key')).to.equal('value');
+    });
+
+    it('should return referer, when request as referrer', function() {
+      var options = {
+        headers: {
+          referer: 'value'
+        }
+      };
+
+      request = mockRequest.createRequest(options);
+      expect(request.get('referrer')).to.equal('value');
+      expect(request.header('referrer')).to.equal('value');
+    });
+
+    it('should return referrer, when request as referer', function() {
+      var options = {
+        headers: {
+          referrer: 'value'
+        }
+      };
+
+      request = mockRequest.createRequest(options);
+      expect(request.get('referer')).to.equal('value');
+      expect(request.header('referer')).to.equal('value');
+    });
+
+    it('should not return header, when not set', function() {
+      request = mockRequest.createRequest();
+      expect(request.get('key')).to.not.exist;
+      expect(request.header('key')).to.not.exist;
+    });
+
+  });
+
+  describe('.param()', function() {
+    var request;
+
+    afterEach(function() {
+      request = null;
+    });
+
+    it('should return param, when found in params', function() {
+      var options = {
+        params: {
+          key: 'value'
+        }
+      };
+
+      request = mockRequest.createRequest(options);
+      expect(request.param('key')).to.equal('value');
+    });
+
+    it('should return param, when found in body', function() {
+      var options = {
+        body: {
+          key: 'value'
+        }
+      };
+
+      request = mockRequest.createRequest(options);
+      expect(request.param('key')).to.equal('value');
+    });
+
+    it('should return param, when found in query', function() {
+      var options = {
+        query: {
+          key: 'value'
+        }
+      };
+
+      request = mockRequest.createRequest(options);
+      expect(request.param('key')).to.equal('value');
+    });
+
+    it('should not return param, when not found in params/body/query', function() {
+      request = mockRequest.createRequest();
+      expect(request.get('key')).to.not.exist;
+      expect(request.header('key')).to.not.exist;
+    });
+
+  });
+
+  describe('helper functions', function() {
+    var request;
+
+    beforeEach(function() {
+      request = mockRequest.createRequest();
+    });
+
+    afterEach(function() {
+      request = null;
+    });
+
+    describe('._setParameter()', function() {
+
+      it('should set param, when called with key and value', function() {
+        request._setParameter('key', 'value');
+        expect(request.param('key')).to.equal('value');
+      });
+
+      it('should unset param, when called with key and no value', function() {
+        request._setParameter('key', 'value');
+        request._setParameter('key');
+        expect(request.param('key')).to.not.exist;
+      });
+
+      it('should throw an error, when called with no arguments', function () {
+        expect(request._setParameter).to.throw;
+      });
+
+    });
+
+    describe('._setSessionVariable()', function() {
+
+      it('should set session variable, when called with key and value', function() {
+        request._setSessionVariable('key', 'value');
+        expect(request.session.key).to.equal('value');
+      });
+
+      it('should unset session variable, when called with key and no value', function() {
+        request._setSessionVariable('key', 'value');
+        request._setSessionVariable('key');
+        expect(request.param('key')).to.not.exist;
+      });
+
+      it('should throw an error, when called with no arguments', function () {
+        expect(request._setSessionVariable).to.throw;
+      });
+
+    });
+
+    describe('._setCookiesVariable()', function() {
+
+      it('should set cookie, when called with key and value', function() {
+        request._setCookiesVariable('key', 'value');
+        expect(request.cookies.key).to.equal('value');
+      });
+
+      it('should unset cookie, when called with key and no value', function() {
+        request._setCookiesVariable('key', 'value');
+        request._setCookiesVariable('key');
+        expect(request.cookies.key).to.not.exist;
+      });
+
+      it('should throw an error, when called with no arguments', function () {
+        expect(request._setCookiesVariable).to.throw;
+      });
+
+    });
+
+    describe('._setSignedCookiesVariable()', function() {
+
+      it('should set signed cookie, when called with key and value', function() {
+        request._setSignedCookiesVariable('key', 'value');
+        expect(request.signedCookies.key).to.equal('value');
+      });
+
+      it('should unset signed cookie, when called with key and no value', function() {
+        request._setSignedCookiesVariable('key', 'value');
+        request._setSignedCookiesVariable('key');
+        expect(request.signedCookies.key).to.not.exist;
+      });
+
+      it('should throw an error, when called with no arguments', function () {
+        expect(request._setSignedCookiesVariable).to.throw;
+      });
+
+    });
+
+    describe('._setHeadersVariable()', function() {
+
+      it('should set header, when called with key and value', function() {
+        request._setHeadersVariable('key', 'value');
+        expect(request.get('key')).to.equal('value');
+        expect(request.header('key')).to.equal('value');
+      });
+
+      it('should throw an error, when called with missing arguments', function () {
+        expect(request._setHeadersVariable).to.throw;
+        expect(request._setHeadersVariable.bind(null, 'key')).to.throw;
+      });
+
+    });
+
+    describe('._setFilesVariable()', function() {
+
+      it('should set file, when called with key and value', function() {
+        request._setFilesVariable('key', 'value');
+        expect(request.files.key).to.equal('value');
+      });
+
+      it('should unset file, when called with key and no value', function() {
+        request._setFilesVariable('key', 'value');
+        request._setFilesVariable('key');
+        expect(request.files.key).to.not.exist;
+      });
+
+      it('should throw an error, when called with no arguments', function () {
+        expect(request._setFilesVariable).to.throw;
+      });
+
+    });
+
+    describe('._setMethod()', function() {
+
+      it('should set method, when called with value', function() {
+        var value = 'HEAD';
+        request._setMethod(value);
+        expect(request.method).to.equal(value);
+      });
+
+      it('should unset method, when called with no arguments', function() {
+        request._setMethod();
+        expect(request.method).to.not.exist;
+      });
+
+    });
+
+    describe('._setURL()', function() {
+
+      it('should set url, when called with value', function() {
+        var value = '/path/to/url';
+        request._setURL(value);
+        expect(request.url).to.equal(value);
+      });
+
+      it('should unset url, when called with no arguments', function() {
+        request._setURL();
+        expect(request.url).to.not.exist;
+      });
+
+    });
+
+    describe('._setOriginalUrl()', function() {
+
+      it('should set originalUrl, when called with value', function() {
+        var value = '/path/to/url';
+        request._setOriginalUrl(value);
+        expect(request.originalUrl).to.equal(value);
+      });
+
+      it('should unset originalUrl, when called with no arguments', function() {
+        request._setOriginalUrl();
+        expect(request.originalUrl).to.not.exist;
+      });
+
+    });
+
+    describe('._setBody()', function() {
+
+      it('should set body, when called with value', function() {
+        var value = {
+          key1: 'value1',
+          key2: 'value2'
+        };
+        request._setBody(value);
+        expect(request.body).to.deep.equal(value);
+      });
+
+      it('should unset body, when called with no arguments', function() {
+        request._setBody();
+        expect(request.body).to.not.exist;
+      });
+
+    });
+
+    describe('._addBody()', function() {
+
+      it('should add body variable, when called with key and value', function() {
+        request._addBody('key', 'value');
+        expect(request.body.key).to.equal('value');
+      });
+
+      it('should unset body variable, when called with key and no value', function() {
+        request._addBody('key', 'value');
+        request._addBody('key');
+        expect(request.body.key).to.not.exist;
+      });
+
+      it('should throw an error, when called with no arguments', function () {
+        expect(request._addBody).to.throw;
+      });
+
+    });
+
+  });
+
+});
diff --git a/test/lib/mockResponse.spec.js b/test/lib/mockResponse.spec.js
new file mode 100644
index 0000000..e68956f
--- /dev/null
+++ b/test/lib/mockResponse.spec.js
@@ -0,0 +1,859 @@
+'use strict';
+
+var chai = require('chai');
+var expect = chai.expect;
+var sinon = require('sinon');
+var sinonChai = require('sinon-chai');
+chai.use(sinonChai);
+
+var mockResponse = require('../../lib/mockResponse');
+
+describe('mockResponse', function() {
+
+  it('should expose .createResponse()', function() {
+    expect(mockResponse.createResponse).to.be.a('function');
+  });
+
+  describe('.createResponse()', function() {
+    var response;
+
+    before(function() {
+      response = mockResponse.createResponse();
+    });
+
+    it('should return an object', function() {
+      expect(response).to.be.an('object');
+    });
+
+    it('should expose Express Response methods', function() {
+      expect(response).to.have.property('cookie');
+      expect(response.cookie).to.be.a('function');
+
+      expect(response).to.have.property('clearCookie');
+      expect(response.clearCookie).to.be.a('function');
+
+      expect(response).to.have.property('status');
+      expect(response.status).to.be.a('function');
+
+      expect(response).to.have.property('send');
+      expect(response.send).to.be.a('function');
+
+      expect(response).to.have.property('sendStatus');
+      expect(response.sendStatus).to.be.a('function');
+
+      expect(response).to.have.property('json');
+      expect(response.json).to.be.a('function');
+
+      expect(response).to.have.property('contentType');
+      expect(response.contentType).to.be.a('function');
+
+      expect(response).to.have.property('type');
+      expect(response.type).to.be.a('function');
+
+      expect(response).to.have.property('set');
+      expect(response.set).to.be.a('function');
+
+      expect(response).to.have.property('header');
+      expect(response.header).to.be.a('function');
+
+      expect(response).to.have.property('get');
+      expect(response.get).to.be.a('function');
+
+      // TODO: check origin of setEnconding() method
+      expect(response).to.have.property('setEncoding');
+      expect(response.setEncoding).to.be.a('function');
+
+      expect(response).to.have.property('redirect');
+      expect(response.redirect).to.be.a('function');
+
+      expect(response).to.have.property('render');
+      expect(response.render).to.be.a('function');
+    });
+
+    it('should expose Node OutgoingMessage methods', function() {
+      expect(response).to.have.property('getHeader');
+      expect(response.getHeader).to.be.a('function');
+
+      expect(response).to.have.property('setHeader');
+      expect(response.setHeader).to.be.a('function');
+
+      expect(response).to.have.property('removeHeader');
+      expect(response.removeHeader).to.be.a('function');
+
+      expect(response).to.have.property('write');
+      expect(response.write).to.be.a('function');
+
+      expect(response).to.have.property('end');
+      expect(response.end).to.be.a('function');
+    });
+
+    it('should expose Node ServerResponse methods', function() {
+      expect(response).to.have.property('writeHead');
+      expect(response.writeHead).to.be.a('function');
+    });
+
+    it('should expose Node WritableStream methods', function() {
+
+      expect(response).to.have.property('destroy');
+      expect(response.destroy).to.be.a('function');
+
+      expect(response).to.have.property('destroySoon');
+      expect(response.destroySoon).to.be.a('function');
+    });
+
+    it('should expose Node EventEmitter methods', function() {
+      expect(response).to.have.property('addListener');
+      expect(response.addListener).to.be.a('function');
+
+      expect(response).to.have.property('on');
+      expect(response.on).to.be.a('function');
+
+      expect(response).to.have.property('once');
+      expect(response.once).to.be.a('function');
+
+      expect(response).to.have.property('removeListener');
+      expect(response.removeListener).to.be.a('function');
+
+      expect(response).to.have.property('removeAllListeners');
+      expect(response.removeAllListeners).to.be.a('function');
+
+      expect(response).to.have.property('setMaxListeners');
+      expect(response.setMaxListeners).to.be.a('function');
+
+      expect(response).to.have.property('listeners');
+      expect(response.listeners).to.be.a('function');
+
+      expect(response).to.have.property('emit');
+      expect(response.emit).to.be.a('function');
+    });
+
+    it('should expose heler methods', function() {
+      expect(response).to.have.property('_isEndCalled');
+      expect(response._isEndCalled).to.be.a('function');
+
+      expect(response).to.have.property('_getHeaders');
+      expect(response._getHeaders).to.be.a('function');
+
+      expect(response).to.have.property('_getData');
+      expect(response._getData).to.be.a('function');
+
+      expect(response).to.have.property('_getStatusCode');
+      expect(response._getStatusCode).to.be.a('function');
+
+      expect(response).to.have.property('_isJSON');
+      expect(response._isJSON).to.be.a('function');
+
+      expect(response).to.have.property('_isUTF8');
+      expect(response._isUTF8).to.be.a('function');
+
+      expect(response).to.have.property('_isDataLengthValid');
+      expect(response._isDataLengthValid).to.be.a('function');
+
+      expect(response).to.have.property('_getRedirectUrl');
+      expect(response._getRedirectUrl).to.be.a('function');
+
+      expect(response).to.have.property('_getRenderView');
+      expect(response._getRenderView).to.be.a('function');
+
+      expect(response).to.have.property('_getRenderData');
+      expect(response._getRenderData).to.be.a('function');
+    });
+
+    it('shoud initialize with default options', function() {
+      expect(response.statusCode).to.equal(200);
+      expect(response.cookies).to.deep.equal({});
+    });
+
+  });
+
+  describe('Express Response methods', function() {
+
+    describe('.cookie()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+      });
+
+      afterEach(function() {
+        response = null;
+      });
+
+      it('should set cookie, when called with, name and value', function() {
+        var cookie = {
+          value: 'value',
+          options: undefined
+        };
+        response.cookie('name', cookie.value);
+        expect(response.cookies.name).to.deep.equal(cookie);
+      });
+
+      it('should set cookie, when called with, name, value and options', function() {
+        var cookie = {
+          value: 'value',
+          options: {
+            domain: 'foo.bar.com',
+            path: '/cookie/path'
+          }
+        };
+        response.cookie('name', cookie.value, cookie.options);
+        expect(response.cookies.name).to.deep.equal(cookie);
+      });
+
+      it('should throw and error, when called without arguments', function() {
+        expect(response.cookie).to.throw;
+      });
+
+    });
+
+    describe('.clearCookie()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+      });
+
+      afterEach(function() {
+        response = null;
+      });
+
+      it('should remove cookie, when called with existing cookie', function() {
+        response.cookie('name', 'value');
+        response.clearCookie('name');
+        expect(response.cookies.name).not.to.exist;
+      });
+
+      it('should return silently, when called with non-existing cookie', function() {
+        expect(response.clearCookie.bind(null, 'invalid')).not.to.throw;
+      });
+
+    });
+
+    describe('.status()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+      });
+
+      afterEach(function() {
+        response = null;
+      });
+
+      it('should set cookie, when called with, name and value', function() {
+        response.status(404);
+        expect(response.statusCode).to.equal(404);
+      });
+
+      it('should statusCode to undefined, when called without arguments', function() {
+        response.status();
+        expect(response.statusCode).to.not.exist;
+      });
+
+    });
+
+    describe('.sendStatus()', function() {
+      var response;
+
+      before(function() {
+        response = mockResponse.createResponse();
+        sinon.spy(response, 'send');
+      });
+
+      after(function() {
+        response.send.restore();
+        response = null;
+      });
+
+      it('should set .statusCode, set .type to "text/plain", and call .send()', function() {
+        response.sendStatus(404);
+        expect(response.statusCode).to.equal(404);
+        expect(response.get('Content-Type')).to.equal('text/plain');
+        expect(response.send).to.have.been.calledOnce;
+      });
+    });
+
+    describe('.contentType()/.type()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+      });
+
+      it('should set "Content-Type"', function() {
+        response.type('html');
+        expect(response.get('Content-Type')).to.equal('text/html');
+        response.contentType('txt');
+        expect(response.get('Content-Type')).to.equal('text/plain');
+      });
+
+      it('should trow an error, when called without arguments', function() {
+        expect(response.type).to.throw;
+        expect(response.contentType).to.throw;
+      });
+
+    });
+
+    describe('.set()/.header()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+        sinon.spy(response, 'setHeader');
+      });
+
+      afterEach(function() {
+        response.setHeader.restore();
+        response = null;
+      });
+
+      it('should set header, when called with name and value strings', function() {
+        response.set('name1', 'value1');
+        expect(response.setHeader).to.have.been.calledWith('name1', 'value1');
+        expect(response.get('name1')).to.equal('value1');
+
+        response.header('name2', 'value2');
+        expect(response.setHeader).to.have.been.calledWith('name2', 'value2');
+        expect(response.get('name2')).to.equal('value2');
+      });
+
+      it('should conver value to string, when called with called with non-string value', function() {
+        var num = 1;
+        var obj = { key: 'value' };
+        var bool = false;
+
+        response.set('num', num);
+        expect(response.setHeader).to.have.been.calledWith('num', num.toString());
+        expect(response.get('num')).to.equal(num.toString());
+
+        response.set('obj', obj);
+        expect(response.setHeader).to.have.been.calledWith('obj', obj.toString());
+        expect(response.get('obj')).to.equal(obj.toString());
+
+        response.set('bool', bool);
+        expect(response.setHeader).to.have.been.calledWith('bool', bool.toString());
+        expect(response.get('bool')).to.equal(bool.toString());
+      });
+
+      it('should set headers, when called with a hash of key/values', function() {
+        var headers = {
+          name1: 'value1',
+          name2: 'value2'
+        };
+
+        response.set(headers);
+        expect(response.setHeader).to.have.been.calledTwice;
+        expect(response.setHeader).to.have.been.calledWith('name1', 'value1');
+        expect(response.setHeader).to.have.been.calledWith('name2', 'value2');
+
+        expect(response.get('name1')).to.equal('value1');
+        expect(response.get('name2')).to.equal('value2');
+      });
+
+      it('should throw an error when called without arguments', function() {
+        expect(response.set).to.throw;
+        expect(response.header).to.throw;
+      });
+
+    });
+
+    describe('.get()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+      });
+
+      afterEach(function() {
+        response = null;
+      });
+
+      it('should get header, when called existing header name', function() {
+        response.set('name1', 'value1');
+        expect(response.get('name1')).to.equal('value1');
+
+        response.header('name2', 'value2');
+        expect(response.get('name2')).to.equal('value2');
+      });
+
+      it('should throw and error, when called without arguments', function() {
+        expect(response.get).to.throw;
+        expect(response.getHeader).to.throw;
+      });
+
+    });
+
+    describe('.redirect()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+      });
+
+      afterEach(function() {
+        response = null;
+      });
+
+      it('should mimic Express Response.redirect()');
+
+      it('should redirect with status 302, when not specified', function() {
+        var url = '/path/to/redirect';
+
+        response.redirect(url);
+        expect(response.statusCode).to.equal(302);
+        expect(response._getRedirectUrl()).to.equal(url);
+      });
+
+      it('should redirect with status specified status', function() {
+        var statusCode = 301;
+        var url = '/path/to/redirect';
+
+        response.redirect(statusCode, url);
+        expect(response.statusCode).to.equal(statusCode);
+        expect(response._getRedirectUrl()).to.equal(url);
+      });
+
+    });
+
+    // TODO: fix in 2.0; method should mimic Express Response.render()
+    describe('.render()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+        sinon.spy(response, 'emit');
+      });
+
+      afterEach(function() {
+        response.emit.restore();
+        response = null;
+      });
+
+      it('should mimic Express Response.render()');
+
+      it('should accept view argument only', function() {
+        var view = 'view';
+
+        response.render(view);
+        expect(response._getRenderView()).to.equal(view);
+        expect(response._getRenderData()).to.deep.equal({});
+        expect(response.emit).to.have.been.calledTwice;
+        expect(response.emit).to.have.been.calledWith('render');
+        expect(response.emit).to.have.been.calledWith('end');
+      });
+
+      it('should accept view and data arguments', function() {
+        var view = 'view';
+        var data = { key: 'value' };
+
+        response.render(view, data);
+        expect(response._getRenderView()).to.equal(view);
+        expect(response._getRenderData()).to.deep.equal(data);
+        expect(response.emit).to.have.been.calledTwice;
+        expect(response.emit).to.have.been.calledWith('render');
+        expect(response.emit).to.have.been.calledWith('end');
+      });
+
+    });
+
+    // TODO: fix in 2.0; method should mimic Express Response.send()
+    describe('.send()', function() {
+
+      it('should mimic Express Response.send()');
+
+    });
+
+    // TODO: fix in 2.0; method should mimic Express Response.json()
+    describe('.json()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+        sinon.spy(response, 'emit');
+      });
+
+      afterEach(function() {
+        response.emit.restore();
+        response = null;
+      });
+
+      it('method should mimic Express Response.json()');
+
+      it('should emit send and end events', function() {
+        response.json({});
+        expect(response.emit).to.have.been.calledTwice;
+        expect(response.emit).to.have.been.calledWith('send');
+        expect(response.emit).to.have.been.calledWith('end');
+      });
+
+    });
+
+    // TODO: fix in 2.0; method should mimic Express Response.redirect()
+    describe('.redirect()', function() {
+
+      it('method should mimic Express Response.redirect()');
+
+    });
+
+  });
+
+  // TODO: fix in 2.0; methods should be inherited from Node ServerResponse
+  describe('Node ServerResponse methods', function() {
+
+    describe('.writeHead()', function() {
+
+      it('should inherit from ServerResponse.writeHead()');
+
+    });
+
+  });
+
+  // TODO: fix in 2.0; methods should be inherited from Node OutogingMessage
+  describe('Node OutogingMessage methods', function() {
+
+    describe('.setHeader()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+      });
+
+      afterEach(function() {
+        response = null;
+      });
+
+
+      it('should set header, when called with name and value strings', function() {
+        response.setHeader('name', 'value');
+        expect(response.getHeader('name')).to.equal('value');
+      });
+
+      it('should throw an error when called without arguments', function() {
+        expect(response.setHeader).to.throw;
+      });
+
+    });
+
+    describe('.getHeader()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+      });
+
+      afterEach(function() {
+        response = null;
+      });
+
+      it('should get header, when called existing header', function() {
+        response.set('name1', 'value1');
+        expect(response.getHeader('name1')).to.equal('value1');
+
+        response.header('name2', 'value2');
+        expect(response.getHeader('name2')).to.equal('value2');
+      });
+
+      it('should throw and error, when called without arguments', function() {
+        expect(response.getHeader).to.throw;
+      });
+
+    });
+
+    describe('.removeHeader()', function() {
+      var response;
+
+      beforeEach(function() {
+        response = mockResponse.createResponse();
+      });
+
+      afterEach(function() {
+        response = null;
+      });
+
+      it('should delete header, when with called existing header', function() {
+        response.set('namer1');
+        response.removeHeader('name1');
+        expect(response.getHeader('name1')).not.to.exist;
+      });
+
+      it('should exit silently, when with called non-existing header', function() {
+        expect(response.getHeader('name2')).not.to.exist;
+        response.removeHeader('name2');
+      });
+
+      it('should throw and error, when called without arguments', function() {
+        expect(response.removeHeader).to.throw;
+      });
+
+    });
+
+    describe('.write()', function() {
+
+      it('should inherit from Node OutogingMessage.write()');
+
+    });
+
+    describe('.end()', function() {
+
+      it('should inherit from Node OutogingMessage.end()');
+
+    });
+
+  });
+
+  // TODO: fix in 2.0; methods should be inherited from Node WritableStream
+  describe('node WritableStream methods', function() {
+
+    describe('.destroy()', function() {
+
+      it('should inherit from Node WritableStream.destroy()');
+
+    });
+
+    describe('.destroySoon()', function() {
+
+      it('should inherit from Node WritableStream.destroySoon()');
+
+    });
+
+  });
+
+  // TODO: fix in 2.0; methods should be inherited from Node EventEmitter
+  describe('node EventEmitter methods', function() {
+
+    describe('.addListener()', function() {
+
+      it('should inherit from Node EventEmitter.addListener()');
+
+    });
+
+    describe('.on()', function() {
+
+      it('should inherit from Node EventEmitter.on()');
+
+    });
+
+    describe('.once()', function() {
+
+      it('should inherit from Node EventEmitter.once()');
+
+    });
+
+    describe('.removeListener()', function() {
+
+      it('should inherit from Node EventEmitter.removeListener()');
+
+    });
+
+    describe('.removeAllListeners()', function() {
+
+      it('should inherit from Node EventEmitter.removeAllListeners()');
+
+    });
+
+    describe('.setMaxListeners()', function() {
+
+      it('should inherit from Node EventEmitter.setMaxListeners()');
+
+    });
+
+    describe('.listeners()', function() {
+
+      it('should inherit from Node EventEmitter.listeners()');
+
+    });
+
+    describe('.emit()', function() {
+
+      it('should inherit from Node EventEmitter.emit()');
+
+    });
+
+  });
+
+  // TODO: deprecate helper methods in 2.0
+  describe('helper methods', function() {
+    var response;
+
+    beforeEach(function() {
+      response = mockResponse.createResponse();
+    });
+
+    afterEach(function() {
+      response = null;
+    });
+
+    describe('._isEndCalled()', function() {
+
+      it('will be deprecated in 2.0');
+
+      it('should return false when .end() hasn\'t been called', function() {
+        expect(response._isEndCalled()).to.be.false;
+      });
+
+      it('should return true when .end() has been called', function() {
+        response.end();
+        expect(response._isEndCalled()).to.be.true;
+      });
+
+    });
+
+    describe('._getHeaders()', function() {
+
+      it('will be deprecated in 2.0');
+
+      it('should return empty object when no headers have been set', function() {
+        expect(response._getHeaders()).to.deep.equal({});
+      });
+
+      it('should return true when .end() has been called', function() {
+        var headers = {
+          'Content-Type': 'text/plain'
+        };
+        response.type('txt');
+        expect(response._getHeaders()).to.deep.equal(headers);
+      });
+
+    });
+
+    describe('._getData()', function() {
+
+      it('will be deprecated in 2.0');
+
+      it('should return empty string when no data has been sent', function() {
+        expect(response._getData()).to.equal('');
+      });
+
+      it('should return sent data', function() {
+        response.send('data');
+        expect(response._getData()).to.equal('data');
+      });
+
+    });
+
+    describe('._getStatusCode()', function() {
+
+      it('will be deprecated in 2.0');
+
+      it('should return default status code, when not set', function() {
+        expect(response._getStatusCode()).to.equal(200);
+      });
+
+      it('should return set status code', function() {
+        response.status(404);
+        expect(response._getStatusCode()).to.equal(404);
+      });
+
+    });
+
+    describe('._isJSON()', function() {
+
+      it('will be deprecated in 2.0');
+
+      it('should return true, when Content-Type is JSON', function() {
+        response.type('json');
+        expect(response._isJSON()).to.be.true;
+      });
+
+      it('should return false, when Content-Type is not JSON', function() {
+        response.type('html');
+        expect(response._isJSON()).to.be.false;
+      });
+
+    });
+
+    describe('._isUTF8()', function() {
+
+      it('will be deprecated in 2.0');
+
+      it('should return false, when enconding is not UTF-8', function() {
+        expect(response._isUTF8()).to.be.false;
+      });
+
+      it('should return true, when enconding is UTF-8', function() {
+        response.setEncoding('utf8');
+        expect(response._isUTF8()).to.be.true;
+      });
+
+    });
+
+    describe('._isDataLengthValid()', function() {
+
+      it('will be deprecated in 2.0');
+
+      it('should return true, when Content-Length not present', function() {
+        expect(response._isDataLengthValid()).to.be.true;
+      });
+
+      it('should return true, when Content-Length equals data size', function() {
+        response.send('data');
+        response.header('Content-Length', '4');
+        expect(response._isDataLengthValid()).to.be.true;
+      });
+
+      it('should return false, when Content-Length does not equal data size', function() {
+        response.send('data');
+        response.header('Content-Length', '5');
+        expect(response._isDataLengthValid()).to.be.false;
+      });
+
+    });
+
+    describe('._getRedirectUrl()', function() {
+
+      it('will be deprecated in 2.0');
+
+      it('should return empty string, when .redirect() not called', function() {
+        expect(response._getRedirectUrl()).to.equal('');
+      });
+
+      it('should return redirect url', function() {
+        var url = '/path/to/redirect';
+        response.redirect(url);
+        expect(response._getRedirectUrl()).to.equal(url);
+      });
+
+    });
+
+    describe('._getRenderView()', function() {
+
+      it('will be deprecated in 2.0');
+
+      it('should return empty string, when .render() not called', function() {
+        expect(response._getRenderView()).to.equal('');
+      });
+
+      it('should return name of rendered view', function() {
+        var view = 'view';
+        response.render(view);
+        expect(response._getRenderView()).to.equal(view);
+      });
+
+    });
+
+    describe('._getRenderData()', function() {
+
+      it('will be deprecated in 2.0');
+
+      it('should return empty object, when .render() not called', function() {
+        expect(response._getRenderData()).to.deep.equal({});
+      });
+
+      it('should return empty object, when .render() called without data', function() {
+        response.render('view');
+        expect(response._getRenderData()).to.deep.equal({});
+      });
+
+      it('should return data object, when .render() called with data', function() {
+        var data = {
+          key: 'value'
+        };
+        response.render('view', data);
+        expect(response._getRenderData()).to.deep.equal(data);
+      });
+
+    });
+
+  });
+
+});
diff --git a/test/lib/mockWritableStream.spec.js b/test/lib/mockWritableStream.spec.js
new file mode 100644
index 0000000..7909b13
--- /dev/null
+++ b/test/lib/mockWritableStream.spec.js
@@ -0,0 +1,41 @@
+'use strict';
+
+var chai = require('chai');
+var expect = chai.expect;
+
+var MockWritableStream = require('../../lib/mockWritableStream');
+var mockWritableStream;
+
+describe('mockWritableStream', function() {
+
+  before(function() {
+    mockWritableStream = new MockWritableStream();
+  });
+
+  it('should be a function', function() {
+    expect(MockWritableStream).to.be.a('function');
+  });
+
+  it('should be an object factory', function() {
+    expect(mockWritableStream).to.be.a('object');
+    expect(mockWritableStream).to.be.an.instanceof(MockWritableStream);
+  });
+
+  it('should expose "MockWritableStream" prototype', function() {
+    expect(mockWritableStream).to.have.property('end');
+    expect(mockWritableStream.end).to.be.a('function');
+
+    expect(mockWritableStream).to.have.property('destroy');
+    expect(mockWritableStream.destroy).to.be.a('function');
+
+    expect(mockWritableStream).to.have.property('destroySoon');
+    expect(mockWritableStream.destroySoon).to.be.a('function');
+  });
+
+  it('should return undefined when methods called', function() {
+    expect(mockWritableStream.end()).to.be.undefined;
+    expect(mockWritableStream.destroy()).to.be.undefined;
+    expect(mockWritableStream.destroySoon()).to.be.undefined;
+  });
+
+});
diff --git a/test/mocha.opts b/test/mocha.opts
new file mode 100644
index 0000000..727f2d7
--- /dev/null
+++ b/test/mocha.opts
@@ -0,0 +1,3 @@
+--recursive
+--reporter spec
+--ui bdd

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-mocks-http.git



More information about the Pkg-javascript-commits mailing list