[Pkg-javascript-commits] [node-js-cookie] 01/02: Import Upstream version 2.2.0

Daniel Ring techwolf-guest at moszumanska.debian.org
Wed Jan 3 01:56:18 UTC 2018


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

techwolf-guest pushed a commit to branch master
in repository node-js-cookie.

commit 51eda5a26505672499e034b904ecb4e3b01dee84
Author: Daniel Ring <dring at wolfishly.me>
Date:   Tue Jan 2 04:15:41 2018 -0800

    Import Upstream version 2.2.0
---
 .gitignore                             |   4 +
 .jshintignore                          |   2 +
 .jshintrc                              |  14 +
 .tm_properties                         |  11 +
 .travis.yml                            |  12 +
 CONTRIBUTING.md                        |  79 +++++
 Gruntfile.js                           | 244 +++++++++++++
 LICENSE                                |  20 ++
 README.md                              | 304 ++++++++++++++++
 SERVER_SIDE.md                         | 107 ++++++
 bower.json                             |  18 +
 package.json                           |  49 +++
 src/.jshintrc                          |  13 +
 src/js.cookie.js                       | 165 +++++++++
 test/.jshintrc                         |  18 +
 test/amd-config.js                     |   9 +
 test/amd.html                          |  15 +
 test/amd.js                            |  14 +
 test/encoding.html                     |  18 +
 test/encoding.js                       | 628 +++++++++++++++++++++++++++++++++
 test/environment-with-amd-and-umd.html |  15 +
 test/environment-with-amd-and-umd.js   |  28 ++
 test/index.html                        |  18 +
 test/malformed_cookie.html             |  17 +
 test/missing_semicolon.html            |  24 ++
 test/node.js                           |  29 ++
 test/polyfill.js                       |  11 +
 test/tests.js                          | 476 +++++++++++++++++++++++++
 test/utils.js                          | 126 +++++++
 travis.sh                              |   6 +
 30 files changed, 2494 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..15812b0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+build
+.sizecache.json
+*.log*
diff --git a/.jshintignore b/.jshintignore
new file mode 100644
index 0000000..e3fbd98
--- /dev/null
+++ b/.jshintignore
@@ -0,0 +1,2 @@
+build
+node_modules
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..46377ea
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,14 @@
+{
+	"curly": true,
+	"eqeqeq": true,
+	"expr": true,
+	"newcap": true,
+	"noarg": true,
+	"nonbsp": true,
+	"trailing": true,
+	"undef": true,
+	"unused": true,
+	"globals": {
+		"Cookies": true
+	}
+}
diff --git a/.tm_properties b/.tm_properties
new file mode 100644
index 0000000..6fd361d
--- /dev/null
+++ b/.tm_properties
@@ -0,0 +1,11 @@
+softTabs = false
+tabSize  = 2
+
+[ text.plain ]
+softWrap   = true
+wrapColumn = "Use Window Frame"
+softTabs   = true
+tabSize    = 4
+
+[ "*.md" ]
+fileType = "text.plain"
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..879912b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+language: node_js
+node_js:
+  - '6'
+# Only use grunt-ci for commits pushed to this repo. Fall back to regular test
+# for pull requests (as secure variables won't be exposed there).
+script:
+  - ./travis.sh
+env:
+  # Encrypted SAUCE_USERNAME and SAUCE_ACCESS_KEY used by travis
+  global:
+    - secure: IkMOa/8r4sWyzUMxecsfqoPzZyIqVAMwPkQ6/HxXPbT8X7UnvqAdaicAMeHEKtOnOac+rx6pGB9HQvC8P/ZzkEBtsKLP4nEh9vsAInZvb3pXg+qbIgIK6/19X0kU4UkpDqVdWmBuFTamJvMDMstUTgEaM3869bB5vGp9taBgfVo=
+    - secure: DKrQplF0CBiBh+cbQ8D7EKebCeklUWEELblIJdU4475Occ4G9b8ZFYO9HFwl1B8F/XapB7CsMyxbJCWor030FySeqn8bhJs9NoAVoYGg+MtWniv1EOHuZLWuOGfgQDv7qj5U0Af9Y655MmUpXSN2aDlCmQweWnYdpFTM9Dfsdd8=
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..a3bd083
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,79 @@
+## Issues
+
+- Report issues or feature requests on [GitHub Issues](https://github.com/js-cookie/js-cookie/issues).
+- If reporting a bug, please add a [simplified example](http://sscce.org/).
+
+## Pull requests
+- Create a new topic branch for every separate change you make.
+- Create a test case if you are fixing a bug or implementing an important feature.
+- Make sure the build runs successfully.
+
+## Development
+
+### Tools
+We use the following tools for development:
+
+- [Qunit](http://qunitjs.com/) for tests.
+- [NodeJS](http://nodejs.org/download/) required to run grunt.
+- [Grunt](http://gruntjs.com/getting-started) for task management.
+
+### Getting started 
+Install [NodeJS](http://nodejs.org/).  
+Install globally grunt-cli using the following command:
+
+    $ npm install -g grunt-cli
+
+Browse to the project root directory and install the dev dependencies:
+
+    $ npm install -d
+
+To execute the build and tests run the following command in the root of the project:
+
+    $ grunt
+
+You should see a green message in the console:
+
+    Done, without errors.
+
+### Tests
+You can also run the tests in the browser.  
+Start a test server from the project root:
+
+    $ grunt connect:tests
+
+This will automatically open the test suite at http://127.0.0.1:10000 in the default browser, with livereload enabled.
+
+_Note: we recommend cleaning all the browser cookies before running the tests, that can avoid false positive failures._
+
+### Automatic build
+You can build automatically after a file change using the following command:
+
+    $ grunt watch
+
+## Integration with server-side
+
+js-cookie allows integrating the encoding test suite with solutions written in other server-side languages. To integrate successfully, the server-side solution need to execute the `test/encoding.html` file in it's integration testing routine with a web automation tool, like [Selenium](http://www.seleniumhq.org/). js-cookie test suite exposes an API to make this happen.
+
+### ?integration_baseurl
+
+Specify the base url to pass the cookies into the server through a query string. If `integration_baseurl` query is not present, then js-cookie will assume there's no server.
+
+### window.global_test_results
+
+After the test suite has finished, js-cookie exposes the global `window.global_test_results` property containing an Object Literal that represents the [QUnit's details](http://api.qunitjs.com/QUnit.done/). js-cookie also adds an additional property representing an Array containing the tests data.
+
+### Handling requests
+
+When js-cookie encoding tests are executed, it will request a url in the server through an iframe representing each test being run. js-cookie expects the server to handle the input and return the proper `Set-Cookie` headers in the response. js-cookie will then read the response and verify if the encoding is consistent with js-cookie default encoding mechanism
+
+js-cookie will send some requests to the server from the baseurl in the format `/encoding?name=<cookie>`, where `<cookie>` represents the cookie-name to be read from the request.
+
+The server should handle those requests, internally parsing the cookie from the request and writing it again. It must set an `application/json` content type containing an object literal in the content body with `name` and `value` keys, each representing the cookie-name and cookie-value decoded by the server-side implementation.
+
+If the server fails to respond with this specification in any request, the related QUnit test will fail. This is to make sure the server-side implementation will always be in sync with js-cookie encoding tests for maximum compatibility.
+
+### Projects using it
+
+This hook is being used in the following projects:
+
+* [Java Cookie](https://github.com/js-cookie/java-cookie).
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..b3789ec
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,244 @@
+/*jshint node:true */
+'use strict';
+
+module.exports = function (grunt) {
+
+	function encodingMiddleware(request, response, next) {
+		var url = require('url').parse(request.url, true, true);
+		var query = url.query;
+		var pathname = url.pathname;
+
+		if (pathname !== '/encoding') {
+			next();
+			return;
+		}
+
+		var cookieName = query.name;
+		var cookieValue = query.value;
+
+		response.setHeader('content-type', 'application/json');
+		response.end(JSON.stringify({
+			name: cookieName,
+			value: cookieValue
+		}));
+	}
+
+	grunt.initConfig({
+		pkg: grunt.file.readJSON('package.json'),
+		qunit: {
+			all: {
+				options: {
+					urls: [
+						'http://127.0.0.1:9998/',
+						'http://127.0.0.1:9998/amd.html',
+						'http://127.0.0.1:9998/environment-with-amd-and-umd.html',
+						'http://127.0.0.1:9998/encoding.html?integration_baseurl=http://127.0.0.1:9998/'
+					]
+				}
+			},
+		},
+		nodeunit: {
+			all: 'test/node.js'
+		},
+		jshint: {
+			options: {
+				jshintrc: true
+			},
+			grunt: 'Gruntfile.js',
+			source: 'src/**/*.js',
+			tests: ['test/**/*.js', '!test/polyfill.js']
+		},
+		jscs: {
+			options: {
+				requireCommaBeforeLineBreak: true,
+				requireLineFeedAtFileEnd: true,
+				requireSemicolons: true,
+				requireSpaceBeforeKeywords: ['else', 'while', 'catch'],
+				requireSpaceAfterKeywords: true,
+				requireSpaceAfterLineComment: true,
+				requireSpaceBeforeBlockStatements: true,
+				requireSpaceBeforeObjectValues: true,
+				validateIndentation: '\t',
+				validateLineBreaks: 'LF',
+				validateQuoteMarks: true,
+				disallowSpacesInsideArrayBrackets: 'all',
+				disallowSpacesInsideParentheses: true,
+				disallowTrailingWhitespace: true
+			},
+			grunt: 'Gruntfile.js',
+			source: 'src/**/*.js',
+			tests: ['test/**/*.js', '!test/polyfill.js']
+		},
+		uglify: {
+			options: {
+				compress: {
+					unsafe: true
+				},
+				screwIE8: false,
+				banner: '/*! <%= pkg.name %> v<%= pkg.version %> | <%= pkg.license %> */\n'
+			},
+			build: {
+				files: {
+					'build/js.cookie.min.js': 'src/js.cookie.js',
+					'build/js.cookie-<%= pkg.version %>.min.js': 'src/js.cookie.js'
+				}
+			}
+		},
+		watch: {
+			options: {
+				livereload: true
+			},
+			files: '{src,test}/**/*.js',
+			tasks: 'default'
+		},
+		compare_size: {
+			files: [
+				'build/js.cookie-<%= pkg.version %>.min.js',
+				'src/js.cookie.js'
+			],
+			options: {
+				compress: {
+					gz: function (fileContents) {
+						return require('gzip-js').zip(fileContents, {}).length;
+					}
+				}
+			}
+		},
+		connect: {
+			'build-qunit': {
+				options: {
+					port: 9998,
+					base: ['.', 'test'],
+					middleware: function (connect, options, middlewares) {
+						middlewares.unshift(encodingMiddleware);
+						return middlewares;
+					}
+				}
+			},
+			'build-sauce': {
+				options: {
+					port: 9999,
+					base: ['.', 'test']
+				}
+			},
+			tests: {
+				options: {
+					port: 10000,
+					base: ['.', 'test'],
+					open: 'http://127.0.0.1:10000',
+					keepalive: true,
+					livereload: true,
+					middleware: function (connect, options, middlewares) {
+						middlewares.unshift(encodingMiddleware);
+						return middlewares;
+					}
+				}
+			}
+		},
+		'saucelabs-qunit': {
+			all: {
+				options: {
+					urls: ['http://127.0.0.1:9999'],
+					testname: 'Sauce Test for js-cookie',
+					build: process.env.TRAVIS_JOB_ID,
+					pollInterval: 10000,
+					statusCheckAttempts: 90,
+					throttled: 3,
+					browsers: (function () {
+						var browsers = {
+							'iOS': [{
+								browserName: 'iphone',
+								platform: 'OS X 10.10',
+								version: '8.2',
+								deviceName: 'iPhone Simulator'
+							}, {
+								browserName: 'iphone',
+								platform: 'OS X 10.10',
+								version: '8.2',
+								deviceName: 'iPad Simulator'
+							}],
+							'android': [{
+								browserName: 'android',
+								platform: 'Linux',
+								version: '5.1',
+								deviceName: 'Android Emulator'
+							}],
+							'mac': [{
+								browserName: 'safari',
+								platform: 'OS X 10.10',
+								version: '8.0'
+							}, {
+								browserName: 'safari',
+								platform: 'OS X 10.11',
+								version: '9.0'
+							}, {
+								browserName: 'safari',
+								platform: 'OS X 10.11',
+								version: '10.0'
+							}, {
+								browserName: 'safari',
+								platform: 'OS X 10.12',
+								version: '11.0'
+							}, {
+								browserName: 'firefox',
+								platform: 'OS X 10.11',
+								version: '56.0'
+							}, {
+								browserName: 'chrome',
+								platform: 'OS X 10.10',
+								version: '61.0'
+							}],
+							'windows7': [{
+								browserName: 'internet explorer',
+								platform: 'Windows 7',
+								version: '11.0'
+							}, {
+								browserName: 'internet explorer',
+								platform: 'Windows 7',
+								version: '10.0'
+							}, {
+								browserName: 'internet explorer',
+								platform: 'Windows 7',
+								version: '9.0'
+							}, {
+								browserName: 'internet explorer',
+								platform: 'Windows 7',
+								version: '8.0'
+							}],
+							'linux': [{
+								browserName: 'firefox',
+								platform: 'Linux',
+								version: '45.0'
+							}, {
+								browserName: 'chrome',
+								platform: 'Linux',
+								version: '48.0'
+							}]
+						};
+
+						var matrix = [];
+						for (var os in browsers) {
+							matrix = matrix.concat(browsers[os]);
+						}
+						return matrix;
+					}())
+				}
+			}
+		}
+	});
+
+	// Loading dependencies
+	for (var key in grunt.file.readJSON('package.json').devDependencies) {
+		if (key !== 'grunt' && key.indexOf('grunt') === 0) {
+			grunt.loadNpmTasks(key);
+		}
+	}
+
+	grunt.registerTask('saucelabs', ['connect:build-sauce', 'saucelabs-qunit']);
+	grunt.registerTask('test', ['uglify', 'jshint', 'jscs', 'connect:build-qunit', 'qunit', 'nodeunit']);
+
+	grunt.registerTask('dev', ['test', 'compare_size']);
+	grunt.registerTask('ci', ['test', 'saucelabs']);
+
+	grunt.registerTask('default', 'dev');
+};
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7a631e8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright 2014 Klaus Hartl
+
+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..7101453
--- /dev/null
+++ b/README.md
@@ -0,0 +1,304 @@
+<p align="center">
+  <img src="https://cloud.githubusercontent.com/assets/835857/14581711/ba623018-0436-11e6-8fce-d2ccd4d379c9.gif">
+</p>
+
+# JavaScript Cookie [![Build Status](https://travis-ci.org/js-cookie/js-cookie.svg?branch=master)](https://travis-ci.org/js-cookie/js-cookie) [![Code Climate](https://codeclimate.com/github/js-cookie/js-cookie.svg)](https://codeclimate.com/github/js-cookie/js-cookie) [![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/js-cookie/badge?style=rounded)](https://www.jsdelivr.com/package/npm/js-cookie)
+
+A simple, lightweight JavaScript API for handling cookies
+
+* Works in [all](https://saucelabs.com/u/js-cookie) browsers
+* Accepts [any](#encoding) character
+* [Heavily](test) tested
+* No dependency
+* [Unobtrusive](#json) JSON support
+* Supports AMD/CommonJS
+* [RFC 6265](https://tools.ietf.org/html/rfc6265) compliant
+* Useful [Wiki](https://github.com/js-cookie/js-cookie/wiki)
+* Enable [custom encoding/decoding](#converters)
+* **~900 bytes** gzipped!
+
+**If you're viewing this at https://github.com/js-cookie/js-cookie, you're reading the documentation for the master branch.
+[View documentation for the latest release.](https://github.com/js-cookie/js-cookie/tree/latest#readme)**
+
+## Build Status Matrix
+
+[![Selenium Test Status](https://saucelabs.com/browser-matrix/js-cookie.svg)](https://saucelabs.com/u/js-cookie)
+
+## Installation
+
+### Direct download
+
+Download the script [here](https://github.com/js-cookie/js-cookie/blob/latest/src/js.cookie.js) and include it (unless you are packaging scripts somehow else):
+
+```html
+<script src="/path/to/js.cookie.js"></script>
+```
+
+Or include it via [jsDelivr CDN](https://www.jsdelivr.com/package/npm/js-cookie):
+
+```html
+<script src="https://cdn.jsdelivr.net/npm/js-cookie@2/src/js.cookie.min.js"></script>
+```
+
+**Do not include the script directly from GitHub (http://raw.github.com/...).** The file is being served as text/plain and as such being blocked
+in Internet Explorer on Windows 7 for instance (because of the wrong MIME type). Bottom line: GitHub is not a CDN.
+
+### Package Managers
+
+JavaScript Cookie supports [npm](https://www.npmjs.com/package/js-cookie) and [Bower](http://bower.io/search/?q=js-cookie) under the name `js-cookie`.
+
+### Module Loaders
+
+JavaScript Cookie can also be loaded as an AMD, CommonJS or [ES6](https://github.com/js-cookie/js-cookie/issues/233#issuecomment-233187386) module.
+
+## Basic Usage
+
+Create a cookie, valid across the entire site:
+
+```javascript
+Cookies.set('name', 'value');
+```
+
+Create a cookie that expires 7 days from now, valid across the entire site:
+
+```javascript
+Cookies.set('name', 'value', { expires: 7 });
+```
+
+Create an expiring cookie, valid to the path of the current page:
+
+```javascript
+Cookies.set('name', 'value', { expires: 7, path: '' });
+```
+
+Read cookie:
+
+```javascript
+Cookies.get('name'); // => 'value'
+Cookies.get('nothing'); // => undefined
+```
+
+Read all visible cookies:
+
+```javascript
+Cookies.get(); // => { name: 'value' }
+```
+
+Delete cookie:
+
+```javascript
+Cookies.remove('name');
+```
+
+Delete a cookie valid to the path of the current page:
+
+```javascript
+Cookies.set('name', 'value', { path: '' });
+Cookies.remove('name'); // fail!
+Cookies.remove('name', { path: '' }); // removed!
+```
+
+*IMPORTANT! when deleting a cookie, you must pass the exact same path and domain attributes that was used to set the cookie, unless you're relying on the [default attributes](#cookie-attributes).*
+
+*Note: Removing unexisting cookie does not raise any exception nor return any value*
+
+## Namespace conflicts
+
+If there is any danger of a conflict with the namespace `Cookies`, the `noConflict` method will allow you to define a new namespace and preserve the original one. This is especially useful when running the script on third party sites e.g. as part of a widget or SDK.
+
+```javascript
+// Assign the js-cookie api to a different variable and restore the original "window.Cookies"
+var Cookies2 = Cookies.noConflict();
+Cookies2.set('name', 'value');
+```
+
+*Note: The `.noConflict` method is not necessary when using AMD or CommonJS, thus it is not exposed in those environments.*
+
+## JSON
+
+js-cookie provides unobtrusive JSON storage for cookies.
+
+When creating a cookie you can pass an Array or Object Literal instead of a string in the value. If you do so, js-cookie will store the string representation of the object according to `JSON.stringify`:
+
+```javascript
+Cookies.set('name', { foo: 'bar' });
+```
+
+When reading a cookie with the default `Cookies.get` api, you receive the string representation stored in the cookie:
+
+```javascript
+Cookies.get('name'); // => '{"foo":"bar"}'
+```
+
+```javascript
+Cookies.get(); // => { name: '{"foo":"bar"}' }
+```
+
+When reading a cookie with the `Cookies.getJSON` api, you receive the parsed representation of the string stored in the cookie according to `JSON.parse`:
+
+```javascript
+Cookies.getJSON('name'); // => { foo: 'bar' }
+```
+
+```javascript
+Cookies.getJSON(); // => { name: { foo: 'bar' } }
+```
+
+*Note: To support IE6-7 ([and IE 8 compatibility mode](http://stackoverflow.com/questions/4715373/json-object-undefined-in-internet-explorer-8)) you need to include the JSON-js polyfill: https://github.com/douglascrockford/JSON-js*
+
+## Encoding
+
+This project is [RFC 6265](http://tools.ietf.org/html/rfc6265#section-4.1.1) compliant. All special characters that are not allowed in the cookie-name or cookie-value are encoded with each one's UTF-8 Hex equivalent using [percent-encoding](http://en.wikipedia.org/wiki/Percent-encoding).  
+The only character in cookie-name or cookie-value that is allowed and still encoded is the percent `%` character, it is escaped in order to interpret percent input as literal.  
+Please note that the default encoding/decoding strategy is meant to be interoperable [only between cookies that are read/written by js-cookie](https://github.com/js-cookie/js-cookie/pull/200#discussion_r63270778). To override the default encoding/decoding strategy you need to use a [converter](#converters).
+
+## Cookie Attributes
+
+Cookie attributes defaults can be set globally by setting properties of the `Cookies.defaults` object or individually for each call to `Cookies.set(...)` by passing a plain object in the last argument. Per-call attributes override the default attributes.
+
+### expires
+
+Define when the cookie will be removed. Value can be a [`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) which will be interpreted as days from time of creation or a [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) instance. If omitted, the cookie becomes a session cookie.
+
+To create a cookie that expires in less than a day, you can check the [FAQ on the Wiki](https://github.com/js-cookie/js-cookie/wiki/Frequently-Asked-Questions#expire-cookies-in-less-than-a-day).
+
+**Default:** Cookie is removed when the user closes the browser.
+
+**Examples:**
+
+```javascript
+Cookies.set('name', 'value', { expires: 365 });
+Cookies.get('name'); // => 'value'
+Cookies.remove('name');
+```
+
+### path
+
+A [`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) indicating the path where the cookie is visible.
+
+**Default:** `/`
+
+**Examples:**
+
+```javascript
+Cookies.set('name', 'value', { path: '' });
+Cookies.get('name'); // => 'value'
+Cookies.remove('name', { path: '' });
+```
+
+**Note regarding Internet Explorer:**
+
+> Due to an obscure bug in the underlying WinINET InternetGetCookie implementation, IE’s document.cookie will not return a cookie if it was set with a path attribute containing a filename.
+
+(From [Internet Explorer Cookie Internals (FAQ)](http://blogs.msdn.com/b/ieinternals/archive/2009/08/20/wininet-ie-cookie-internals-faq.aspx))
+
+This means one cannot set a path using `path: window.location.pathname` in case such pathname contains a filename like so: `/check.html` (or at least, such cookie cannot be read correctly).
+
+### domain
+
+A [`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) indicating a valid domain where the cookie should be visible. The cookie will also be visible to all subdomains.
+
+**Default:** Cookie is visible only to the domain or subdomain of the page where the cookie was created, except for Internet Explorer (see below).
+
+**Examples:**
+
+Assuming a cookie that is being created on `site.com`:
+
+```javascript
+Cookies.set('name', 'value', { domain: 'subdomain.site.com' });
+Cookies.get('name'); // => undefined (need to read at 'subdomain.site.com')
+```
+
+**Note regarding Internet Explorer default behavior:**
+
+> Q3: If I don’t specify a DOMAIN attribute (for) a cookie, IE sends it to all nested subdomains anyway?  
+> A: Yes, a cookie set on example.com will be sent to sub2.sub1.example.com.  
+> Internet Explorer differs from other browsers in this regard.
+
+(From [Internet Explorer Cookie Internals (FAQ)](http://blogs.msdn.com/b/ieinternals/archive/2009/08/20/wininet-ie-cookie-internals-faq.aspx))
+
+This means that if you omit the `domain` attribute, it will be visible for a subdomain in IE.
+
+### secure
+
+Either `true` or `false`, indicating if the cookie transmission requires a secure protocol (https).
+
+**Default:** No secure protocol requirement.
+
+**Examples:**
+
+```javascript
+Cookies.set('name', 'value', { secure: true });
+Cookies.get('name'); // => 'value'
+Cookies.remove('name');
+```
+
+## Converters
+
+### Read
+
+Create a new instance of the api that overrides the default decoding implementation.  
+All get methods that rely in a proper decoding to work, such as `Cookies.get()` and `Cookies.get('name')`, will run the converter first for each cookie.  
+The returning String will be used as the cookie value.
+
+Example from reading one of the cookies that can only be decoded using the `escape` function:
+
+```javascript
+document.cookie = 'escaped=%u5317';
+document.cookie = 'default=%E5%8C%97';
+var cookies = Cookies.withConverter(function (value, name) {
+    if ( name === 'escaped' ) {
+        return unescape(value);
+    }
+});
+cookies.get('escaped'); // 北
+cookies.get('default'); // 北
+cookies.get(); // { escaped: '北', default: '北' }
+```
+
+### Write
+
+Create a new instance of the api that overrides the default encoding implementation:
+
+```javascript
+Cookies.withConverter({
+    read: function (value, name) {
+        // Read converter
+    },
+    write: function (value, name) {
+        // Write converter
+    }
+});
+```
+
+## Server-side integration
+
+Check out the [Servers Docs](SERVER_SIDE.md)
+
+## Contributing
+
+Check out the [Contributing Guidelines](CONTRIBUTING.md)
+
+## Security
+
+For vulnerability reports, send an e-mail to `jscookie at gmail dot com`
+
+## Manual release steps
+
+* Increment the "version" attribute of `package.json`
+* Increment the version number in the `src/js.cookie.js` file
+* If `major` bump, update jsDelivr CDN major version link on README
+* Commit with the message "Release version x.x.x"
+* Create version tag in git
+* Create a github release and upload the minified file
+* Change the `latest` tag pointer to the latest commit
+  * `git tag -f latest`
+  * `git push <remote> :refs/tags/latest`
+  * `git push origin master --tags`
+* Release on npm
+
+## Authors
+
+* [Klaus Hartl](https://github.com/carhartl)
+* [Fagner Brack](https://github.com/FagnerMartinsBrack)
+* And awesome [contributors](https://github.com/js-cookie/js-cookie/graphs/contributors)
diff --git a/SERVER_SIDE.md b/SERVER_SIDE.md
new file mode 100644
index 0000000..35fb25b
--- /dev/null
+++ b/SERVER_SIDE.md
@@ -0,0 +1,107 @@
+# Server-side integration
+
+There are some servers that are not compliant with the [RFC 6265](http://tools.ietf.org/html/rfc6265). For those, some characters that are not encoded by JavaScript Cookie might be treated differently.
+
+Here we document the most important server-side peculiarities and their workarounds. Feel free to send a [Pull Request](https://github.com/js-cookie/js-cookie/blob/master/CONTRIBUTING.md#pull-requests) if you see something that can be improved.
+
+*Disclaimer: This documentation is entirely based on community provided information. The examples below should be used only as a reference.*
+
+## PHP
+
+In PHP, `setcookie()` function encodes cookie values using `urlencode()` function, which applies `%`-encoding but also encodes spaces as `+` signs, [for historical reasons](http://php.net/manual/en/function.urlencode.php#function.urlencode). When cookies are read back via `$_COOKIE` or `filter_input(INPUT_COOKIE)`, they would go trough a decoding process which decodes `%`-encoded sequences and also converts `+` signs back to spaces. However, the plus (`+`) sign is valid cookie character  [...]
+
+This presents two types of problems:
+
+1. PHP writes a cookie via `setcookie()` and all spaces get converted to `+` signs. JavaScript Cookie read `+` signs and uses them literally, since it is a valid cookie character.
+2. JavaScript Cookie writes a cookie with a value that contains `+` signs and stores it as is, since it is a valid cookie character. PHP read a cookie and converts `+` signs to spaces.
+
+To make both PHP and JavaScript Cookie play nicely together?
+
+**In PHP**, use `setrawcookie()` instead of `setcookie()`:
+
+```php
+setrawcookie($name, rawurlencode($value));
+```
+
+**In JavaScript**, use a custom converter.
+
+**Example**:
+
+```javascript
+var PHPCookies = Cookies.withConverter({
+    write: function (value) {
+        // Encode all characters according to the "encodeURIComponent" spec
+        return encodeURIComponent(value)
+            // Revert the characters that are unnecessarly encoded but are
+            // allowed in a cookie value, except for the plus sign (%2B)
+            .replace(/%(23|24|26|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
+    },
+    read: function (value) {
+        return value
+            // Decode the plus sign to spaces first, otherwise "legit" encoded pluses
+            // will be replaced incorrectly
+            .replace(/\+/g, ' ')
+            // Decode all characters according to the "encodeURIComponent" spec
+            .replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent);
+    }
+});
+```
+
+Rack seems to have [a similar problem](https://github.com/js-cookie/js-cookie/issues/70#issuecomment-132503017).
+
+## Tomcat
+
+### Version >= 7.x
+
+It seems that there is a situation where Tomcat does not [read the parens correctly](https://github.com/js-cookie/js-cookie/issues/92#issue-107743407). To fix this you need to write a custom write converter.
+
+**Example**:
+
+```javascript
+var TomcatCookies = Cookies.withConverter({
+  write: function (value) {
+      // Encode all characters according to the "encodeURIComponent" spec
+      return encodeURIComponent(value)
+          // Revert the characters that are unnecessarly encoded but are
+          // allowed in a cookie value
+          .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent)
+          // Encode the parens that are interpreted incorrectly by Tomcat
+          .replace(/[\(\)]/g, escape);
+  }
+});
+```
+
+### Version >= 8.0.15
+
+Since Tomcat 8.0.15, it is possible to configure RFC 6265 compliance by changing your `conf/context.xml` file and adding the new [CookieProcessor](https://tomcat.apache.org/tomcat-8.0-doc/config/cookie-processor.html) nested inside the Context element. It would be like this:
+
+```xml
+<Context>
+  <CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor"/>
+</context>
+```
+And you're all done.
+
+Alternatively, you can check the [Java Cookie](https://github.com/js-cookie/java-cookie) project, which integrates nicely with JavaScript Cookie.
+
+## JBoss 7.1.1
+
+It seems that the servlet implementation of JBoss 7.1.1 [does not read some characters correctly](https://github.com/js-cookie/js-cookie/issues/70#issuecomment-148944674), even though they are allowed as per [RFC 6265](https://tools.ietf.org/html/rfc6265#section-4.1.1). To fix this you need to write a custom converter to send those characters correctly.
+
+**Example**:
+
+```javascript
+var JBossCookies = Cookies.withConverter({
+    write: function (value) {
+        // Encode all characters according to the "encodeURIComponent" spec
+        return encodeURIComponent(value)
+            // Revert the characters that are unnecessarly encoded but are
+            // allowed in a cookie value
+            .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent)
+            // Encode again the characters that are not allowed in JBoss 7.1.1, like "[" and "]":
+            .replace(/[\[\]]/g, encodeURIComponent);
+    }
+});
+```
+
+Alternatively, you can check the [Java Cookie](https://github.com/js-cookie/java-cookie) project, which integrates nicely with JavaScript Cookie.
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..d7ca68b
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,18 @@
+{
+  "name": "js-cookie",
+  "license": "MIT",
+  "main": [
+    "src/js.cookie.js"
+  ],
+  "ignore": [
+    "travis.sh",
+    "test",
+    "Gruntfile.js",
+    "package.json",
+    ".gitignore",
+    ".jshintignore",
+    ".jshintrc",
+    ".tm_properties",
+    ".travis.yml"
+  ]
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..1979a9d
--- /dev/null
+++ b/package.json
@@ -0,0 +1,49 @@
+{
+  "name": "js-cookie",
+  "version": "2.2.0",
+  "description": "A simple, lightweight JavaScript API for handling cookies",
+  "main": "src/js.cookie.js",
+  "directories": {
+    "test": "test"
+  },
+  "keywords": [
+    "jquery-plugin",
+    "cookie",
+    "cookies",
+    "browser",
+    "amd",
+    "commonjs",
+    "client",
+    "js-cookie",
+    "browserify"
+  ],
+  "scripts": {
+    "test": "grunt test"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/js-cookie/js-cookie.git"
+  },
+  "files": [
+    "src/**/*.js",
+    "SERVER_SIDE.md",
+    "CONTRIBUTING.md"
+  ],
+  "author": "Klaus Hartl",
+  "license": "MIT",
+  "devDependencies": {
+    "grunt": "1.0.1",
+    "grunt-compare-size": "0.4.2",
+    "grunt-contrib-connect": "1.0.2",
+    "grunt-contrib-jshint": "1.1.0",
+    "grunt-contrib-nodeunit": "1.0.0",
+    "grunt-contrib-qunit": "2.0.0",
+    "grunt-contrib-uglify": "2.3.0",
+    "grunt-contrib-watch": "1.0.0",
+    "grunt-jscs": "3.0.1",
+    "grunt-saucelabs": "9.0.0",
+    "gzip-js": "0.3.2",
+    "qunitjs": "1.23.1",
+    "requirejs": "2.3.5"
+  }
+}
diff --git a/src/.jshintrc b/src/.jshintrc
new file mode 100644
index 0000000..764d692
--- /dev/null
+++ b/src/.jshintrc
@@ -0,0 +1,13 @@
+{
+	"browser": true,
+	"camelcase": true,
+	"quotmark": "single",
+	"globals": {
+		"define": true,
+		"module": true,
+		"require": true,
+		"escape": true
+	},
+
+	"extends": "../.jshintrc"
+}
diff --git a/src/js.cookie.js b/src/js.cookie.js
new file mode 100644
index 0000000..9a0945e
--- /dev/null
+++ b/src/js.cookie.js
@@ -0,0 +1,165 @@
+/*!
+ * JavaScript Cookie v2.2.0
+ * https://github.com/js-cookie/js-cookie
+ *
+ * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
+ * Released under the MIT license
+ */
+;(function (factory) {
+	var registeredInModuleLoader = false;
+	if (typeof define === 'function' && define.amd) {
+		define(factory);
+		registeredInModuleLoader = true;
+	}
+	if (typeof exports === 'object') {
+		module.exports = factory();
+		registeredInModuleLoader = true;
+	}
+	if (!registeredInModuleLoader) {
+		var OldCookies = window.Cookies;
+		var api = window.Cookies = factory();
+		api.noConflict = function () {
+			window.Cookies = OldCookies;
+			return api;
+		};
+	}
+}(function () {
+	function extend () {
+		var i = 0;
+		var result = {};
+		for (; i < arguments.length; i++) {
+			var attributes = arguments[ i ];
+			for (var key in attributes) {
+				result[key] = attributes[key];
+			}
+		}
+		return result;
+	}
+
+	function init (converter) {
+		function api (key, value, attributes) {
+			var result;
+			if (typeof document === 'undefined') {
+				return;
+			}
+
+			// Write
+
+			if (arguments.length > 1) {
+				attributes = extend({
+					path: '/'
+				}, api.defaults, attributes);
+
+				if (typeof attributes.expires === 'number') {
+					var expires = new Date();
+					expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
+					attributes.expires = expires;
+				}
+
+				// We're using "expires" because "max-age" is not supported by IE
+				attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
+
+				try {
+					result = JSON.stringify(value);
+					if (/^[\{\[]/.test(result)) {
+						value = result;
+					}
+				} catch (e) {}
+
+				if (!converter.write) {
+					value = encodeURIComponent(String(value))
+						.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
+				} else {
+					value = converter.write(value, key);
+				}
+
+				key = encodeURIComponent(String(key));
+				key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
+				key = key.replace(/[\(\)]/g, escape);
+
+				var stringifiedAttributes = '';
+
+				for (var attributeName in attributes) {
+					if (!attributes[attributeName]) {
+						continue;
+					}
+					stringifiedAttributes += '; ' + attributeName;
+					if (attributes[attributeName] === true) {
+						continue;
+					}
+					stringifiedAttributes += '=' + attributes[attributeName];
+				}
+				return (document.cookie = key + '=' + value + stringifiedAttributes);
+			}
+
+			// Read
+
+			if (!key) {
+				result = {};
+			}
+
+			// To prevent the for loop in the first place assign an empty array
+			// in case there are no cookies at all. Also prevents odd result when
+			// calling "get()"
+			var cookies = document.cookie ? document.cookie.split('; ') : [];
+			var rdecode = /(%[0-9A-Z]{2})+/g;
+			var i = 0;
+
+			for (; i < cookies.length; i++) {
+				var parts = cookies[i].split('=');
+				var cookie = parts.slice(1).join('=');
+
+				if (!this.json && cookie.charAt(0) === '"') {
+					cookie = cookie.slice(1, -1);
+				}
+
+				try {
+					var name = parts[0].replace(rdecode, decodeURIComponent);
+					cookie = converter.read ?
+						converter.read(cookie, name) : converter(cookie, name) ||
+						cookie.replace(rdecode, decodeURIComponent);
+
+					if (this.json) {
+						try {
+							cookie = JSON.parse(cookie);
+						} catch (e) {}
+					}
+
+					if (key === name) {
+						result = cookie;
+						break;
+					}
+
+					if (!key) {
+						result[name] = cookie;
+					}
+				} catch (e) {}
+			}
+
+			return result;
+		}
+
+		api.set = api;
+		api.get = function (key) {
+			return api.call(api, key);
+		};
+		api.getJSON = function () {
+			return api.apply({
+				json: true
+			}, [].slice.call(arguments));
+		};
+		api.defaults = {};
+
+		api.remove = function (key, attributes) {
+			api(key, '', extend(attributes, {
+				expires: -1
+			}));
+		};
+
+		api.withConverter = init;
+
+		return api;
+	}
+
+	return init(function () {});
+}));
diff --git a/test/.jshintrc b/test/.jshintrc
new file mode 100644
index 0000000..be085f0
--- /dev/null
+++ b/test/.jshintrc
@@ -0,0 +1,18 @@
+{
+	"browser": true,
+	"qunit": true,
+
+	"-W053": true,
+	"-W097": true, // disable warning for 'Use the function form of "use strict".'
+
+	"extends": "../.jshintrc",
+	"globals": {
+		"require": true,
+		"unescape": true,
+		"lifecycle": true,
+		"using": true,
+		"quoted": true,
+		"addEvent": true,
+	  	"loadFileSync": true
+	}
+}
diff --git a/test/amd-config.js b/test/amd-config.js
new file mode 100644
index 0000000..d9bd2f6
--- /dev/null
+++ b/test/amd-config.js
@@ -0,0 +1,9 @@
+/*jshint unused:false */
+
+var require = {
+	paths: {
+		'qunit': [
+			'../node_modules/qunitjs/qunit/qunit'
+		]
+	}
+};
diff --git a/test/amd.html b/test/amd.html
new file mode 100644
index 0000000..babead2
--- /dev/null
+++ b/test/amd.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8">
+		<title>JavaScript Cookie Test Suite - AMD</title>
+		<link href="../node_modules/qunitjs/qunit/qunit.css" rel="stylesheet">
+		<script src="amd-config.js"></script>
+		<script src="../node_modules/requirejs/require.js"></script>
+		<script src="amd.js"></script>
+	</head>
+	<body>
+		<div id="qunit"></div>
+		<div id="qunit-fixture"></div>
+	</body>
+</html>
diff --git a/test/amd.js b/test/amd.js
new file mode 100644
index 0000000..5f655f1
--- /dev/null
+++ b/test/amd.js
@@ -0,0 +1,14 @@
+require(['qunit'], function (QUnit) {
+	QUnit.module('amd');
+
+	QUnit.start();
+	QUnit.test('module loading', function (assert) {
+		assert.expect(1);
+		var done = assert.async();
+		require(['/src/js.cookie.js'], function (Cookies) {
+			assert.ok(!!Cookies.get, 'should load the api');
+			done();
+		});
+	});
+
+});
diff --git a/test/encoding.html b/test/encoding.html
new file mode 100644
index 0000000..a2f898b
--- /dev/null
+++ b/test/encoding.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8">
+		<title>JavaScript Cookie Test Suite - Encoding</title>
+		<link href="../node_modules/qunitjs/qunit/qunit.css" rel="stylesheet">
+		<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
+		<script src="../src/js.cookie.js"></script>
+		<script src="utils.js"></script>
+		<script src="encoding.js"></script>
+	</head>
+	<body>
+		<div id="qunit"></div>
+		<div id="qunit-fixture">
+			<iframe id="request_target"></iframe>
+		</div>
+	</body>
+</html>
diff --git a/test/encoding.js b/test/encoding.js
new file mode 100644
index 0000000..75c600a
--- /dev/null
+++ b/test/encoding.js
@@ -0,0 +1,628 @@
+QUnit.module('cookie-value', lifecycle);
+
+QUnit.test('cookie-value with double quotes', function (assert) {
+	assert.expect(1);
+	using(assert)
+	.setCookie('c', '"')
+	.then(function (decodedValue) {
+		assert.strictEqual(decodedValue, '"', 'should print the quote character');
+	});
+});
+
+QUnit.test('cookie-value with double quotes in the left', function (assert) {
+	assert.expect(1);
+	using(assert)
+	.setCookie('c', '"content')
+	.then(function (decodedValue) {
+		assert.strictEqual(decodedValue, '"content', 'should print the quote character');
+	});
+});
+
+QUnit.test('cookie-value with double quotes in the right', function (assert) {
+	assert.expect(1);
+	using(assert)
+	.setCookie('c', 'content"')
+	.then(function (decodedValue) {
+		assert.strictEqual(decodedValue, 'content"', 'should print the quote character');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-value " "', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', ' ')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, ' ', 'should handle the whitespace character');
+		assert.strictEqual(plainValue, 'c=%20', 'whitespace is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-value ","', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', ',')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, ',', 'should handle the comma character');
+		assert.strictEqual(plainValue, 'c=%2C', 'comma is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-value ";"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', ';')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, ';', 'should handle the semicolon character');
+		assert.strictEqual(plainValue, 'c=%3B', 'semicolon is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-value "\\"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '\\')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '\\', 'should handle the backslash character');
+		assert.strictEqual(plainValue, 'c=%5C', 'backslash is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - characters not allowed in the cookie-value should be replaced globally', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', ';;')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, ';;', 'should handle multiple not allowed characters');
+		assert.strictEqual(plainValue, 'c=%3B%3B', 'should replace multiple not allowed characters');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "#"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '#')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '#', 'should handle the sharp character');
+		assert.strictEqual(plainValue, 'c=#', 'sharp is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "$"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '$')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '$', 'should handle the dollar sign character');
+		assert.strictEqual(plainValue, 'c=$', 'dollar sign is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "%"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '%')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '%', 'should handle the percent character');
+		assert.strictEqual(plainValue, 'c=%25', 'percent is allowed, but need to be escaped');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "&"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '&')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '&', 'should handle the ampersand character');
+		assert.strictEqual(plainValue, 'c=&', 'ampersand is allowed, should not encode');
+	});
+});
+
+// github.com/carhartl/jquery-cookie/pull/62
+QUnit.test('RFC 6265 - character allowed in the cookie-value "+"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '+')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '+', 'should handle the plus character');
+		assert.strictEqual(plainValue, 'c=+', 'plus is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value ":"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', ':')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, ':', 'should handle the colon character');
+		assert.strictEqual(plainValue, 'c=:', 'colon is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "<"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '<')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '<', 'should handle the less-than character');
+		assert.strictEqual(plainValue, 'c=<', 'less-than is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value ">"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '>')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '>', 'should handle the greater-than character');
+		assert.strictEqual(plainValue, 'c=>', 'greater-than is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "="', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '=')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '=', 'should handle the equal sign character');
+		assert.strictEqual(plainValue, 'c==', 'equal sign is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "/"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '/')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '/', 'should handle the slash character');
+		assert.strictEqual(plainValue, 'c=/', 'slash is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "?"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '?')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '?', 'should handle the question mark character');
+		assert.strictEqual(plainValue, 'c=?', 'question mark is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "@"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '@')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '@', 'should handle the at character');
+		assert.strictEqual(plainValue, 'c=@', 'at is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "["', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '[')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '[', 'should handle the opening square bracket character');
+		assert.strictEqual(plainValue, 'c=[', 'opening square bracket is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "]"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', ']')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, ']', 'should handle the closing square bracket character');
+		assert.strictEqual(plainValue, 'c=]', 'closing square bracket is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "^"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '^')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '^', 'should handle the caret character');
+		assert.strictEqual(plainValue, 'c=^', 'caret is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "`"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '`')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '`', 'should handle the grave accent character');
+		assert.strictEqual(plainValue, 'c=`', 'grave accent is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "{"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '{')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '{', 'should handle the opening curly bracket character');
+		assert.strictEqual(plainValue, 'c={', 'opening curly bracket is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "}"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '}')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '}', 'should handle the closing curly bracket character');
+		assert.strictEqual(plainValue, 'c=}', 'closing curly bracket is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-value "|"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '|')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '|', 'should handle the pipe character');
+		assert.strictEqual(plainValue, 'c=|', 'pipe is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - characters allowed in the cookie-value should globally not be encoded', function (assert) {
+	assert.expect(1);
+	using(assert)
+	.setCookie('c', '{{')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(plainValue, 'c={{', 'should not encode all the character occurrences');
+	});
+});
+
+QUnit.test('cookie-value - 2 bytes character (ã)', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', 'ã')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'ã', 'should handle the ã character');
+		assert.strictEqual(plainValue, 'c=%C3%A3', 'should encode the ã character');
+	});
+});
+
+QUnit.test('cookie-value - 3 bytes character (₯)', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '₯')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '₯', 'should handle the ₯ character');
+		assert.strictEqual(plainValue, 'c=%E2%82%AF', 'should encode the ₯ character');
+	});
+});
+
+QUnit.test('cookie-value - 4 bytes character (𩸽)', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('c', '𩸽')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, '𩸽', 'should handle the 𩸽 character');
+		assert.strictEqual(plainValue, 'c=%F0%A9%B8%BD', 'should encode the 𩸽 character');
+	});
+});
+
+QUnit.module('cookie-name', lifecycle);
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "("', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('(', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the opening parens character');
+		assert.strictEqual(plainValue, '%28=v', 'opening parens is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name ")"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie(')', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the closing parens character');
+		assert.strictEqual(plainValue, '%29=v', 'closing parens is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - should replace parens globally', function (assert) {
+	assert.expect(1);
+	using(assert)
+	.setCookie('(())', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(plainValue, '%28%28%29%29=v', 'encode with global replace');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "<"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('<', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the less-than character');
+		assert.strictEqual(plainValue, '%3C=v', 'less-than is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name ">"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('>', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the greater-than character');
+		assert.strictEqual(plainValue, '%3E=v', 'greater-than is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "@"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('@', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the at character');
+		assert.strictEqual(plainValue, '%40=v', 'at is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name ","', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie(',', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the comma character');
+		assert.strictEqual(plainValue, '%2C=v', 'comma is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name ";"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie(';', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the semicolon character');
+		assert.strictEqual(plainValue, '%3B=v', 'semicolon is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name ":"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie(':', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the colon character');
+		assert.strictEqual(plainValue, '%3A=v', 'colon is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "\\"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('\\', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the backslash character');
+		assert.strictEqual(plainValue, '%5C=v', 'backslash is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "\""', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('"', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the double quote character');
+		assert.strictEqual(plainValue, '%22=v', 'double quote is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "/"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('/', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the slash character');
+		assert.strictEqual(plainValue, '%2F=v', 'slash is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "["', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('[', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the opening square brackets character');
+		assert.strictEqual(plainValue, '%5B=v', 'opening square brackets is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "]"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie(']', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the closing square brackets character');
+		assert.strictEqual(plainValue, '%5D=v', 'closing square brackets is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "?"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('?', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the question mark character');
+		assert.strictEqual(plainValue, '%3F=v', 'question mark is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "="', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('=', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the equal sign character');
+		assert.strictEqual(plainValue, '%3D=v', 'equal sign is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "{"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('{', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the opening curly brackets character');
+		assert.strictEqual(plainValue, '%7B=v', 'opening curly brackets is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "}"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('}', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the closing curly brackets character');
+		assert.strictEqual(plainValue, '%7D=v', 'closing curly brackets is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name "\\t"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('	', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the horizontal tab character');
+		assert.strictEqual(plainValue, '%09=v', 'horizontal tab is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character not allowed in the cookie-name " "', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie(' ', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the whitespace character');
+		assert.strictEqual(plainValue, '%20=v', 'whitespace is not allowed, need to encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-name "#"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('#', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the sharp character');
+		assert.strictEqual(plainValue, '#=v', 'sharp is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-name "$"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('$', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the dollar sign character');
+		assert.strictEqual(plainValue, '$=v', 'dollar sign is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in cookie-name "%"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('%', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the percent character');
+		assert.strictEqual(plainValue, '%25=v', 'percent is allowed, but need to be escaped');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-name "&"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('&', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the ampersand character');
+		assert.strictEqual(plainValue, '&=v', 'ampersand is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-name "+"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('+', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the plus character');
+		assert.strictEqual(plainValue, '+=v', 'plus is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-name "^"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('^', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the caret character');
+		assert.strictEqual(plainValue, '^=v', 'caret is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-name "`"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('`', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the grave accent character');
+		assert.strictEqual(plainValue, '`=v', 'grave accent is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - character allowed in the cookie-name "|"', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('|', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the pipe character');
+		assert.strictEqual(plainValue, '|=v', 'pipe is allowed, should not encode');
+	});
+});
+
+QUnit.test('RFC 6265 - characters allowed in the cookie-name should globally not be encoded', function (assert) {
+	assert.expect(1);
+	using(assert)
+	.setCookie('||', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(plainValue, '||=v', 'should not encode all character occurrences');
+	});
+});
+
+QUnit.test('cookie-name - 2 bytes characters', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('ã', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the ã character');
+		assert.strictEqual(plainValue, '%C3%A3=v', 'should encode the ã character');
+	});
+});
+
+QUnit.test('cookie-name - 3 bytes characters', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('₯', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should handle the ₯ character');
+		assert.strictEqual(plainValue, '%E2%82%AF=v', 'should encode the ₯ character');
+	});
+});
+
+QUnit.test('cookie-name - 4 bytes characters', function (assert) {
+	assert.expect(2);
+	using(assert)
+	.setCookie('𩸽', 'v')
+	.then(function (decodedValue, plainValue) {
+		assert.strictEqual(decodedValue, 'v', 'should_handle the 𩸽 character');
+		assert.strictEqual(plainValue, '%F0%A9%B8%BD=v', 'should encode the 𩸽 character');
+	});
+});
diff --git a/test/environment-with-amd-and-umd.html b/test/environment-with-amd-and-umd.html
new file mode 100644
index 0000000..9e444f5
--- /dev/null
+++ b/test/environment-with-amd-and-umd.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8">
+		<title>JavaScript Cookie Test Suite - Environment with AMD and UMD</title>
+		<link href="../node_modules/qunitjs/qunit/qunit.css" rel="stylesheet">
+		<script src="amd-config.js"></script>
+		<script src="../node_modules/requirejs/require.js"></script>
+		<script src="environment-with-amd-and-umd.js"></script>
+	</head>
+	<body>
+		<div id="qunit"></div>
+		<div id="qunit-fixture"></div>
+	</body>
+</html>
diff --git a/test/environment-with-amd-and-umd.js b/test/environment-with-amd-and-umd.js
new file mode 100644
index 0000000..b4f3250
--- /dev/null
+++ b/test/environment-with-amd-and-umd.js
@@ -0,0 +1,28 @@
+require(['qunit'], function (QUnit) {
+	QUnit.start();
+
+	QUnit.module('Environment with AMD and UMD', {
+		beforeEach: function () {
+			window.exports = {};
+			window.module = {
+				exports: window.exports
+			};
+		},
+		afterEach: function () {
+			delete window.module;
+		}
+	});
+
+	QUnit.test('js-cookie need to register itself in AMD and UMD', function (assert) {
+		assert.expect(2);
+		var done = assert.async();
+		require(['/src/js.cookie.js'], function () {
+			var actual = typeof window.module.exports;
+			var expected = 'function';
+			assert.strictEqual(actual, expected, 'should register a function in module.exports');
+			assert.notOk(!!window.Cookies, 'should not register globally in AMD/UMD environments');
+			done();
+		});
+	});
+
+});
diff --git a/test/index.html b/test/index.html
new file mode 100644
index 0000000..39db738
--- /dev/null
+++ b/test/index.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8">
+		<title>JavaScript Cookie Test Suite</title>
+		<link href="../node_modules/qunitjs/qunit/qunit.css" rel="stylesheet">
+		<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
+		<script>Cookies = 'existent global'</script>
+		<script src="../build/js.cookie.min.js"></script>
+		<script src="polyfill.js"></script>
+		<script src="utils.js"></script>
+		<script src="tests.js"></script>
+	</head>
+	<body>
+		<div id="qunit"></div>
+		<div id="qunit-fixture"></div>
+	</body>
+</html>
diff --git a/test/malformed_cookie.html b/test/malformed_cookie.html
new file mode 100644
index 0000000..dac4043
--- /dev/null
+++ b/test/malformed_cookie.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<title></title>
+		<script src="../build/js.cookie.min.js"></script>
+		<script>
+			try {
+				Object.defineProperty(document, "cookie", { get: function() { return "first=one; ; second=two"; } });
+				window.testValue = Cookies.get("second");
+				window.ok = true;
+			} catch (er) {
+			}
+		</script>
+	</head>
+	<body>
+	</body>
+</html>
diff --git a/test/missing_semicolon.html b/test/missing_semicolon.html
new file mode 100644
index 0000000..385efd5
--- /dev/null
+++ b/test/missing_semicolon.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title></title>
+    <link href="../node_modules/qunitjs/qunit/qunit.css" rel="stylesheet">
+    <script src="../node_modules/qunitjs/qunit/qunit.js"></script>
+    <script src="utils.js"></script>
+    <script>
+        (function() {
+            var contents = window.loadFileSync('../build/js.cookie.min.js');
+
+            if (contents !== null) {
+                var script = document.createElement('script');
+                script.innerHTML = '(function (){ return {}; })() ' + contents;
+                document.getElementsByTagName('head')[0].appendChild(script);
+            }
+        })();
+    </script>
+</head>
+<body>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test/node.js b/test/node.js
new file mode 100644
index 0000000..af2d42d
--- /dev/null
+++ b/test/node.js
@@ -0,0 +1,29 @@
+/*jshint node:true */
+exports.node = {
+	should_load_js_cookie: function (test) {
+		test.expect(1);
+		var Cookies = require('../src/js.cookie');
+		test.ok(!!Cookies.get, 'should load the Cookies API');
+		test.done();
+	},
+	should_not_throw_error_for_set_call_in_node: function (test) {
+		test.expect(0);
+		var Cookies = require('../src/js.cookie');
+		Cookies.set('anything');
+		Cookies.set('anything', { path: '' });
+		test.done();
+	},
+	should_not_throw_error_for_get_call_in_node: function (test) {
+		test.expect(0);
+		var Cookies = require('../src/js.cookie');
+		Cookies.get('anything');
+		test.done();
+	},
+	should_not_throw_error_for_remove_call_in_node: function (test) {
+		test.expect(0);
+		var Cookies = require('../src/js.cookie');
+		Cookies.remove('anything');
+		Cookies.remove('anything', { path: '' });
+		test.done();
+	}
+};
diff --git a/test/polyfill.js b/test/polyfill.js
new file mode 100644
index 0000000..d086513
--- /dev/null
+++ b/test/polyfill.js
@@ -0,0 +1,11 @@
+// Object.keys()
+// developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
+Object.keys||(Object.keys=function(){"use strict";var a=Object.prototype.hasOwnProperty,b=!{toString:null}.propertyIsEnumerable("toString"),c=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],d=c.length;return function(e){if("object"!=typeof e&&("function"!=typeof e||null===e))throw new TypeError("Object.keys called on non-object");var g,h,f=[];for(g in e)a.call(e,g)&&f.push(g);if(b)for(h=0;d>h;h++)a.call(e,c[h])&&f.push(c[h]);r [...]
+
+// Array.forEach()
+// developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
+Array.prototype.forEach||(Array.prototype.forEach=function(a,b){var c,d;if(null==this)throw new TypeError(" this is null or not defined");var e=Object(this),f=e.length>>>0;if("function"!=typeof a)throw new TypeError(a+" is not a function");for(arguments.length>1&&(c=b),d=0;f>d;){var g;d in e&&(g=e[d],a.call(c,g,d,e)),d++}});
+
+// JSON
+// github.com/douglascrockford/JSON-js/tree/c07c287e39ab5a1726818e0436490bf071b7c838
+"object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(a){return 10>a?"0"+a:a}function this_value(){return this.valueOf()}function quote(a){return escapable.lastIndex=0,escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return"string"==typeof b?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function str(a,b){var c,d,e,f,h,g=gap,i=b[a];switch(i&&"object"==typeof i&&"function"==typeof i.toJSON&&(i=i.toJSON(a)),"function"==typeof rep&&( [...]
\ No newline at end of file
diff --git a/test/tests.js b/test/tests.js
new file mode 100644
index 0000000..85ab57f
--- /dev/null
+++ b/test/tests.js
@@ -0,0 +1,476 @@
+'use strict';
+
+/*global lifecycle: true*/
+
+QUnit.module('read', lifecycle);
+
+QUnit.test('simple value', function (assert) {
+	assert.expect(1);
+	document.cookie = 'c=v';
+	assert.strictEqual(Cookies.get('c'), 'v', 'should return value');
+});
+
+QUnit.test('empty value', function (assert) {
+	assert.expect(1);
+	// IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, which
+	// resulted in a bug while reading such a cookie.
+	Cookies.set('c', '');
+	assert.strictEqual(Cookies.get('c'), '', 'should return value');
+});
+
+QUnit.test('not existing', function (assert) {
+	assert.expect(1);
+	assert.strictEqual(Cookies.get('whatever'), undefined, 'return undefined');
+});
+
+// github.com/carhartl/jquery-cookie/issues/50
+QUnit.test('equality sign in cookie value', function (assert) {
+	assert.expect(1);
+	Cookies.set('c', 'foo=bar');
+	assert.strictEqual(Cookies.get('c'), 'foo=bar', 'should include the entire value');
+});
+
+// github.com/carhartl/jquery-cookie/issues/215
+QUnit.test('percent character in cookie value', function (assert) {
+	assert.expect(1);
+	document.cookie = 'bad=foo%';
+	assert.strictEqual(Cookies.get('bad'), 'foo%', 'should read the percent character');
+});
+
+QUnit.test('percent character in cookie value mixed with encoded values', function (assert) {
+	assert.expect(1);
+	document.cookie = 'bad=foo%bar%22baz%bax%3D';
+	assert.strictEqual(Cookies.get('bad'), 'foo%bar"baz%bax=', 'should read the percent character');
+});
+
+// github.com/carhartl/jquery-cookie/pull/88
+// github.com/carhartl/jquery-cookie/pull/117
+QUnit.test('malformed cookie value in IE', function (assert) {
+	assert.expect(1);
+	var done = assert.async();
+	// Sandbox in an iframe so that we can poke around with document.cookie.
+	var iframe = document.createElement('iframe');
+	iframe.src = 'malformed_cookie.html';
+	addEvent(iframe, 'load', function () {
+		if (iframe.contentWindow.ok) {
+			assert.strictEqual(iframe.contentWindow.testValue, 'two', 'reads all cookie values, skipping duplicate occurences of "; "');
+		} else {
+			// Skip the test where we can't stub document.cookie using
+			// Object.defineProperty. Seems to work fine in
+			// Chrome, Firefox and IE 8+.
+			assert.ok(true, 'N/A');
+		}
+		done();
+	});
+	document.body.appendChild(iframe);
+});
+
+// github.com/js-cookie/js-cookie/pull/171
+QUnit.test('missing leading semicolon', function (assert) {
+	assert.expect(1);
+	var done = assert.async();
+	// Sandbox in an iframe so that we can poke around with document.cookie.
+	var iframe = document.createElement('iframe');
+	var loadedSuccessfully = true;
+	iframe.src = 'missing_semicolon.html';
+
+	addEvent(iframe, 'load', function () {
+		iframe.contentWindow.onerror = function () {
+			loadedSuccessfully = false;
+		};
+		assert.strictEqual(loadedSuccessfully, true, 'can\'t throw Object is not a function error');
+		done();
+	});
+	document.body.appendChild(iframe);
+});
+
+QUnit.test('Call to read all when there are cookies', function (assert) {
+	Cookies.set('c', 'v');
+	Cookies.set('foo', 'bar');
+	assert.deepEqual(Cookies.get(), { c: 'v', foo: 'bar' }, 'returns object containing all cookies');
+});
+
+QUnit.test('Call to read all when there are no cookies at all', function (assert) {
+	assert.deepEqual(Cookies.get(), {}, 'returns empty object');
+});
+
+QUnit.test('RFC 6265 - reading cookie-octet enclosed in DQUOTE', function (assert) {
+	assert.expect(1);
+	document.cookie = 'c="v"';
+	assert.strictEqual(Cookies.get('c'), 'v', 'should simply ignore quoted strings');
+});
+
+// github.com/js-cookie/js-cookie/issues/196
+QUnit.test('Call to read cookie when there is another unrelated cookie with malformed encoding in the name', function (assert) {
+	assert.expect(2);
+	document.cookie = 'BS%BS=1';
+	document.cookie = 'c=v';
+	assert.strictEqual(Cookies.get('c'), 'v', 'should not throw a URI malformed exception when retrieving a single cookie');
+	assert.deepEqual(Cookies.get(), { c: 'v' }, 'should not throw a URI malformed exception when retrieving all cookies');
+	document.cookie = 'BS%BS=1; expires=Thu, 01 Jan 1970 00:00:00 GMT';
+});
+
+// github.com/js-cookie/js-cookie/pull/62
+QUnit.test('Call to read cookie when there is another unrelated cookie with malformed encoding in the value', function (assert) {
+	assert.expect(2);
+	document.cookie = 'invalid=%A1';
+	document.cookie = 'c=v';
+	assert.strictEqual(Cookies.get('c'), 'v', 'should not throw a URI malformed exception when retrieving a single cookie');
+	assert.deepEqual(Cookies.get(), { c: 'v' }, 'should not throw a URI malformed exception when retrieving all cookies');
+	Cookies.withConverter(unescape).remove('invalid');
+});
+
+// github.com/js-cookie/js-cookie/issues/145
+QUnit.test('Call to read cookie when passing an Object Literal as the second argument', function (assert) {
+	assert.expect(1);
+	Cookies.get('name', { path: '' });
+	assert.strictEqual(document.cookie, '', 'should not create a cookie');
+});
+
+// github.com/js-cookie/js-cookie/issues/238
+QUnit.test('Call to read cookie when there is a window.json variable globally', function (assert) {
+	assert.expect(1);
+	window.json = true;
+	Cookies.set('boolean', true);
+	assert.strictEqual(typeof Cookies.get('boolean'), 'string', 'should not change the returned type');
+	// IE 6-8 throw an exception if trying to delete a window property
+	// See stackoverflow.com/questions/1073414/deleting-a-window-property-in-ie/1824228
+	try {
+		delete window.json;
+	} catch (e) {}
+});
+
+QUnit.module('write', lifecycle);
+
+QUnit.test('String primitive', function (assert) {
+	assert.expect(1);
+	Cookies.set('c', 'v');
+	assert.strictEqual(Cookies.get('c'), 'v', 'should write value');
+});
+
+QUnit.test('String object', function (assert) {
+	assert.expect(1);
+	Cookies.set('c', new String('v'));
+	assert.strictEqual(Cookies.get('c'), 'v', 'should write value');
+});
+
+QUnit.test('value "[object Object]"', function (assert) {
+	assert.expect(1);
+	Cookies.set('c', '[object Object]');
+	assert.strictEqual(Cookies.get('c'), '[object Object]', 'should write value');
+});
+
+QUnit.test('number', function (assert) {
+	assert.expect(1);
+	Cookies.set('c', 1234);
+	assert.strictEqual(Cookies.get('c'), '1234', 'should write value');
+});
+
+QUnit.test('null', function (assert) {
+	assert.expect(1);
+	Cookies.set('c', null);
+	assert.strictEqual(Cookies.get('c'), 'null', 'should write value');
+});
+
+QUnit.test('undefined', function (assert) {
+	assert.expect(1);
+	Cookies.set('c', undefined);
+	assert.strictEqual(Cookies.get('c'), 'undefined', 'should write value');
+});
+
+QUnit.test('expires option as days from now', function (assert) {
+	assert.expect(1);
+	var sevenDaysFromNow = new Date();
+	sevenDaysFromNow.setDate(sevenDaysFromNow.getDate() + 21);
+	var expected = 'expires=' + sevenDaysFromNow.toUTCString();
+	var actual = Cookies.set('c', 'v', { expires: 21 });
+	assert.ok(actual.indexOf(expected) !== -1, quoted(actual) + ' includes ' + quoted(expected));
+});
+
+// github.com/carhartl/jquery-cookie/issues/246
+QUnit.test('expires option as fraction of a day', function (assert) {
+	assert.expect(1);
+
+	var findValueForAttributeName = function (createdCookie, attributeName) {
+		var pairs = createdCookie.split('; ');
+		var foundAttributeValue;
+		pairs.forEach(function (pair) {
+			if (pair.split('=')[0] === attributeName) {
+				foundAttributeValue = pair.split('=')[1];
+			}
+		});
+		return foundAttributeValue;
+	};
+	var now = new Date();
+	var stringifiedDate = findValueForAttributeName(Cookies.set('c', 'v', { expires: 0.5 }), 'expires');
+	var expires = new Date(stringifiedDate);
+
+	// When we were using Date.setDate() fractions have been ignored
+	// and expires resulted in the current date. Allow 1000 milliseconds
+	// difference for execution time because new Date() can be different,
+	// even when it's run synchronously.
+	// See https://github.com/js-cookie/js-cookie/commit/ecb597b65e4c477baa2b30a2a5a67fdaee9870ea#commitcomment-20146048.
+	var assertion = expires.getTime() > now.getTime() + 1000;
+	var message = quoted(expires.getTime()) + ' should be greater than ' + quoted(now.getTime());
+	assert.ok(assertion, message);
+});
+
+QUnit.test('expires option as Date instance', function (assert) {
+	assert.expect(1);
+	var sevenDaysFromNow = new Date();
+	sevenDaysFromNow.setDate(sevenDaysFromNow.getDate() + 7);
+	var expected = 'expires=' + sevenDaysFromNow.toUTCString();
+	var actual = Cookies.set('c', 'v', { expires: sevenDaysFromNow });
+	assert.ok(actual.indexOf(expected) !== -1, quoted(actual) + ' includes ' + quoted(expected));
+});
+
+QUnit.test('return value', function (assert) {
+	assert.expect(1);
+	var expected = 'c=v';
+	var actual = Cookies.set('c', 'v').substring(0, expected.length);
+	assert.strictEqual(actual, expected, 'should return written cookie string');
+});
+
+QUnit.test('default path attribute', function (assert) {
+	assert.expect(1);
+	assert.ok(Cookies.set('c', 'v').match(/path=\//), 'should read the default path');
+});
+
+QUnit.test('API for changing defaults', function (assert) {
+	assert.expect(3);
+
+	Cookies.defaults.path = '/foo';
+	assert.ok(Cookies.set('c', 'v').match(/path=\/foo/), 'should use attributes from defaults');
+	Cookies.remove('c', { path: '/foo' });
+
+	assert.ok(Cookies.set('c', 'v', { path: '/bar' }).match(/path=\/bar/), 'attributes argument has precedence');
+	Cookies.remove('c', { path: '/bar' });
+
+	delete Cookies.defaults.path;
+	assert.ok(Cookies.set('c', 'v').match(/path=\//), 'should roll back to the default path');
+});
+
+QUnit.test('true secure value', function (assert) {
+	assert.expect(1);
+	var expected = 'c=v; path=/; secure';
+	var actual = Cookies.set('c', 'v', {secure: true});
+	assert.strictEqual(actual, expected, 'should add secure attribute');
+});
+
+// github.com/js-cookie/js-cookie/pull/54
+QUnit.test('false secure value', function (assert) {
+	assert.expect(1);
+	var expected = 'c=v; path=/';
+	var actual = Cookies.set('c', 'v', {secure: false});
+	assert.strictEqual(actual, expected, 'false should not modify path in cookie string');
+});
+
+// github.com/js-cookie/js-cookie/issues/276
+QUnit.test('unofficial attribute', function (assert) {
+	assert.expect(1);
+	var expected = 'c=v; path=/; unofficial=anything';
+	var actual = Cookies.set('c', 'v', {
+		unofficial: 'anything'
+	});
+	assert.strictEqual(expected, actual, 'should write the cookie string with unofficial attribute');
+});
+
+QUnit.test('undefined attribute value', function (assert) {
+	assert.expect(5);
+	assert.strictEqual(Cookies.set('c', 'v', {
+		expires: undefined
+	}), 'c=v; path=/', 'should not write undefined expires attribute');
+	assert.strictEqual(Cookies.set('c', 'v', {
+		path: undefined
+	}), 'c=v', 'should not write undefined path attribute');
+	assert.strictEqual(Cookies.set('c', 'v', {
+		domain: undefined
+	}), 'c=v; path=/', 'should not write undefined domain attribute');
+	assert.strictEqual(Cookies.set('c', 'v', {
+		secure: undefined
+	}), 'c=v; path=/', 'should not write undefined secure attribute');
+	assert.strictEqual(Cookies.set('c', 'v', {
+		unofficial: undefined
+	}), 'c=v; path=/', 'should not write undefined unofficial attribute');
+});
+
+QUnit.module('remove', lifecycle);
+
+QUnit.test('deletion', function (assert) {
+	assert.expect(1);
+	Cookies.set('c', 'v');
+	Cookies.remove('c');
+	assert.strictEqual(document.cookie, '', 'should delete the cookie');
+});
+
+QUnit.test('with attributes', function (assert) {
+	assert.expect(1);
+	var attributes = { path: '/' };
+	Cookies.set('c', 'v', attributes);
+	Cookies.remove('c', attributes);
+	assert.strictEqual(document.cookie, '', 'should delete the cookie');
+});
+
+QUnit.test('passing attributes reference', function (assert) {
+	assert.expect(1);
+	var attributes = { path: '/' };
+	Cookies.set('c', 'v', attributes);
+	Cookies.remove('c', attributes);
+	assert.deepEqual(attributes, { path: '/' }, 'won\'t alter attributes object');
+});
+
+QUnit.module('converters', lifecycle);
+
+// github.com/carhartl/jquery-cookie/pull/166
+QUnit.test('provide a way for decoding characters encoded by the escape function', function (assert) {
+	assert.expect(1);
+	document.cookie = 'c=%u5317%u4eac';
+	assert.strictEqual(Cookies.withConverter(unescape).get('c'), '北京', 'should convert chinese characters correctly');
+});
+
+QUnit.test('should decode a malformed char that matches the decodeURIComponent regex', function (assert) {
+	assert.expect(1);
+	document.cookie = 'c=%E3';
+	var cookies = Cookies.withConverter(unescape);
+	assert.strictEqual(cookies.get('c'), 'ã', 'should convert the character correctly');
+	cookies.remove('c', {
+		path: ''
+	});
+});
+
+QUnit.test('should be able to conditionally decode a single malformed cookie', function (assert) {
+	assert.expect(4);
+	var cookies = Cookies.withConverter(function (value, name) {
+		if (name === 'escaped') {
+			return unescape(value);
+		}
+	});
+
+	document.cookie = 'escaped=%u5317';
+	assert.strictEqual(cookies.get('escaped'), '北', 'should use a custom method for escaped cookie');
+
+	document.cookie = 'encoded=%E4%BA%AC';
+	assert.strictEqual(cookies.get('encoded'), '京', 'should use the default encoding for the rest');
+
+	assert.deepEqual(cookies.get(), {
+		escaped: '北',
+		encoded: '京'
+	}, 'should retrieve everything');
+
+	Object.keys(cookies.get()).forEach(function (name) {
+		cookies.remove(name, {
+			path: ''
+		});
+	});
+	assert.strictEqual(document.cookie, '', 'should remove everything');
+});
+
+// github.com/js-cookie/js-cookie/issues/70
+QUnit.test('should be able to create a write decoder', function (assert) {
+	assert.expect(1);
+	Cookies.withConverter({
+		write: function (value) {
+			return value.replace('+', '%2B');
+		}
+	}).set('c', '+');
+	assert.strictEqual(document.cookie, 'c=%2B', 'should call the write converter');
+});
+
+QUnit.test('should be able to use read and write decoder', function (assert) {
+	assert.expect(1);
+	document.cookie = 'c=%2B';
+	var cookies = Cookies.withConverter({
+		read: function (value) {
+			return value.replace('%2B', '+');
+		}
+	});
+	assert.strictEqual(cookies.get('c'), '+', 'should call the read converter');
+});
+
+QUnit.module('JSON handling', lifecycle);
+
+QUnit.test('Number', function (assert) {
+	assert.expect(2);
+	Cookies.set('c', 1);
+	assert.strictEqual(Cookies.getJSON('c'), 1, 'should handle a Number');
+	assert.strictEqual(Cookies.get('c'), '1', 'should return a String');
+});
+
+QUnit.test('Boolean', function (assert) {
+	assert.expect(2);
+	Cookies.set('c', true);
+	assert.strictEqual(Cookies.getJSON('c'), true, 'should handle a Boolean');
+	assert.strictEqual(Cookies.get('c'), 'true', 'should return a Boolean');
+});
+
+QUnit.test('Array Literal', function (assert) {
+	assert.expect(2);
+	Cookies.set('c', ['v']);
+	assert.deepEqual(Cookies.getJSON('c'), ['v'], 'should handle Array Literal');
+	assert.strictEqual(Cookies.get('c'), '["v"]', 'should return a String');
+});
+
+QUnit.test('Array Constructor', function (assert) {
+	/*jshint -W009 */
+	assert.expect(2);
+	var value = new Array();
+	value[0] = 'v';
+	Cookies.set('c', value);
+	assert.deepEqual(Cookies.getJSON('c'), ['v'], 'should handle Array Constructor');
+	assert.strictEqual(Cookies.get('c'), '["v"]', 'should return a String');
+});
+
+QUnit.test('Object Literal', function (assert) {
+	assert.expect(2);
+	Cookies.set('c', {k: 'v'});
+	assert.deepEqual(Cookies.getJSON('c'), {k: 'v'}, 'should handle Object Literal');
+	assert.strictEqual(Cookies.get('c'), '{"k":"v"}', 'should return a String');
+});
+
+QUnit.test('Object Constructor', function (assert) {
+	/*jshint -W010 */
+	assert.expect(2);
+	var value = new Object();
+	value.k = 'v';
+	Cookies.set('c', value);
+	assert.deepEqual(Cookies.getJSON('c'), {k: 'v'}, 'should handle Object Constructor');
+	assert.strictEqual(Cookies.get('c'), '{"k":"v"}', 'should return a String');
+});
+
+QUnit.test('Use String(value) for unsupported objects that do not stringify into JSON', function (assert) {
+	assert.expect(2);
+	Cookies.set('date', new Date(2015, 4, 13, 0, 0, 0, 0));
+	assert.strictEqual(Cookies.get('date').indexOf('"'), -1, 'should not quote the stringified Date object');
+	assert.strictEqual(Cookies.getJSON('date').indexOf('"'), -1, 'should not quote the stringified Date object');
+});
+
+QUnit.test('Call to read all cookies with mixed json', function (assert) {
+	Cookies.set('c', { foo: 'bar' });
+	Cookies.set('c2', 'v');
+	assert.deepEqual(Cookies.getJSON(), { c: { foo: 'bar' }, c2: 'v' }, 'returns JSON parsed cookies');
+	assert.deepEqual(Cookies.get(), { c: '{"foo":"bar"}', c2: 'v' }, 'returns unparsed cookies');
+});
+
+QUnit.test('Cookies with escaped quotes in json using raw converters', function (assert) {
+	Cookies.withConverter({
+		read: function (value) {
+			return value;
+		},
+		write: function (value) {
+			return value;
+		}
+	}).set('c', '"{ \\"foo\\": \\"bar\\" }"');
+	assert.strictEqual(Cookies.getJSON('c'), '{ "foo": "bar" }', 'returns JSON parsed cookie');
+	assert.strictEqual(Cookies.get('c'), '{ \\"foo\\": \\"bar\\" }', 'returns unparsed cookie with enclosing quotes removed');
+});
+
+QUnit.module('noConflict', lifecycle);
+
+QUnit.test('do not conflict with existent globals', function (assert) {
+	assert.expect(2);
+	var Cookies = window.Cookies.noConflict();
+	Cookies.set('c', 'v');
+	assert.strictEqual(Cookies.get('c'), 'v', 'should work correctly');
+	assert.strictEqual(window.Cookies, 'existent global', 'should restore the original global');
+	window.Cookies = Cookies;
+});
diff --git a/test/utils.js b/test/utils.js
new file mode 100644
index 0000000..d1abc7e
--- /dev/null
+++ b/test/utils.js
@@ -0,0 +1,126 @@
+// https://github.com/axemclion/grunt-saucelabs#test-result-details-with-qunit
+(function () {
+	'use strict';
+
+	var log = [];
+
+	QUnit.done(function (test_results) {
+		var tests = [];
+		for (var i = 0, len = log.length; i < len; i++) {
+			var details = log[i];
+			tests.push({
+				name: details.name,
+				result: details.result,
+				expected: details.expected,
+				actual: details.actual,
+				source: details.source
+			});
+		}
+		test_results.tests = tests;
+		// Required for exposing test results to the Sauce Labs API.
+		// Can be removed when the following issue is fixed:
+		// https://github.com/axemclion/grunt-saucelabs/issues/84
+		window.global_test_results = test_results;
+	});
+
+	QUnit.testStart(function (testDetails) {
+		QUnit.log(function (details) {
+			if (!details.result) {
+				details.name = testDetails.name;
+				log.push(details);
+			}
+		});
+	});
+
+	window.lifecycle = {
+		afterEach: function () {
+			// Remove the cookies created using js-cookie default attributes
+			Object.keys(Cookies.get()).forEach(Cookies.remove);
+			// Remove the cookies created using browser default attributes
+			Object.keys(Cookies.get()).forEach(function (cookie) {
+				Cookies.remove(cookie, {
+					path: ''
+				});
+			});
+		}
+	};
+
+	window.addEvent = function (element, eventName, fn) {
+		var method = 'addEventListener';
+		if (element.attachEvent) {
+			eventName = 'on' + eventName;
+			method = 'attachEvent';
+		}
+		element[ method ](eventName, fn);
+	};
+
+	window.using = function (assert) {
+		function getQuery(key) {
+			var queries = location.href.split('?')[1];
+			if (!queries) {
+				return;
+			}
+			var pairs = queries.split(/&|=/);
+			var indexBaseURL = pairs.indexOf(key);
+			var result = pairs[indexBaseURL + 1];
+			if (result) {
+				return decodeURIComponent(result);
+			}
+		}
+		function setCookie(name, value) {
+			return {
+				then: function (callback) {
+					var iframe = document.getElementById('request_target');
+					var serverURL = getQuery('integration_baseurl');
+					Cookies.set(name, value);
+					if (!serverURL) {
+						callback(Cookies.get(name), document.cookie);
+					} else {
+						var requestURL = [
+							serverURL,
+							'encoding?',
+							'name=' + encodeURIComponent(name),
+							'&value=' + encodeURIComponent(value)
+						].join('');
+						var done = assert.async();
+						addEvent(iframe, 'load', function () {
+							var iframeDocument = iframe.contentWindow.document;
+							var root = iframeDocument.documentElement;
+							var content = root.textContent;
+							if (!content) {
+								ok(false, [
+									'"' + requestURL + '"',
+									'content should not be empty'
+								].join(' '));
+								done();
+								return;
+							}
+							try {
+								var result = JSON.parse(content);
+								callback(result.value, iframeDocument.cookie);
+							} finally {
+								done();
+							}
+						});
+						iframe.src = requestURL;
+					}
+				}
+			};
+		}
+		return {
+			setCookie: setCookie
+		};
+	};
+
+	window.loadFileSync = function (path) {
+		var xhr = new XMLHttpRequest();
+		xhr.open('GET', path, false);
+		xhr.send(null);
+		return xhr.status === 200 ? xhr.responseText : null;
+	};
+
+	window.quoted = function (input) {
+		return '"' + input + '"';
+	};
+
+}());
diff --git a/travis.sh b/travis.sh
new file mode 100755
index 0000000..375b035
--- /dev/null
+++ b/travis.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+if [ -z "$SAUCE_ACCESS_KEY" ]; then
+  npm test
+else
+  grunt ci --verbose
+fi

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



More information about the Pkg-javascript-commits mailing list