express-state
Advanced tools
Comparing version 0.0.4 to 1.0.0
@@ -7,2 +7,6 @@ var express = require('express'), | ||
// Extend Express app with Express State's functionality. This adds the | ||
// `app.expose()` and `res.expose()` methods. | ||
state.extend(app); | ||
app.engine('hbs', exphbs()); | ||
@@ -34,4 +38,4 @@ app.set('view engine', 'hbs'); | ||
app.expose('MY APP', 'title', 'app'); | ||
app.expose('MY APP', 'title'); | ||
app.listen(3000); |
Express State Change History | ||
============================ | ||
0.4.0 (2013-07-29) | ||
1.0.0 (2013-08-15) | ||
------------------ | ||
* __[!]__ Changed how this package extends Express. There's now _only_ one way — | ||
to explicitly pass an Express app instance to the `extend()` method: | ||
```javascript | ||
var express = require('express'), | ||
expstate = require('express-state'), | ||
app = express(); | ||
// Extend the Express app with Express State's functionality. | ||
expstate.extend(app); | ||
``` | ||
This new `extend()` implementation uses the | ||
[object branding technique](https://gist.github.com/ericf/6133744). ([#6][]) | ||
* A `TypeError` is now thrown when trying to serialize native build-in | ||
functions. This matches the behavior of `JSON.stringify()` with circular | ||
references. ([#7][]) | ||
* Added documentation in README.md. ([#2][]) | ||
[#2]: https://github.com/yahoo/express-state/issues/2 | ||
[#6]: https://github.com/yahoo/express-state/issues/6 | ||
[#7]: https://github.com/yahoo/express-state/issues/7 | ||
0.0.4 (2013-07-29) | ||
------------------ | ||
* Added `extend()` function which takes an `express` module instance and adds | ||
the `expose()` method to its application and response prototype, if it does | ||
not already exist. | ||
the `expose()` method to its application and response prototypes, if it does | ||
not already exist. ([#5][]) | ||
* Added `augment()` function which takes an Express app instance and adds the | ||
`expose()` method to it application and its response prototype, if it does not | ||
already exist. | ||
`expose()` method to it and its response prototype, if it does not already | ||
exist. ([#5][]) | ||
[#5]: https://github.com/yahoo/express-state/issues/5 | ||
0.0.3 (2013-06-08) | ||
@@ -20,3 +54,3 @@ ------------------ | ||
* Prevented multiple copies of `express-state` from overwriting `expose()` when | ||
it already has been plugged into a copy of `express`. | ||
it already has been plugged into a copy of `express`. ([#4][]) | ||
@@ -26,2 +60,5 @@ * Added Screwdriver CI integration. | ||
[#4]: https://github.com/yahoo/express-state/issues/4 | ||
0.0.2 (2013-05-03) | ||
@@ -28,0 +65,0 @@ ------------------ |
46
index.js
'use strict'; | ||
var express = require('express'), | ||
Exposed = require('./lib/exposed'); | ||
var Exposed = require('./lib/exposed'); | ||
exports.local = 'state'; | ||
exports.namespace = null; | ||
exports.extend = extendApp; | ||
exports.augment = augment; | ||
exports.extend = extend; | ||
function extendApp(app) { | ||
if (app['@state']) { return app; } | ||
extend(express); | ||
// Brand. | ||
Object.defineProperty(app, '@state', {value: true}); | ||
function extend(express) { | ||
var appProto = express.application, | ||
resProto = express.response; | ||
// Protect against multiple express-state module instances augmenting the | ||
// Express `application` and `response` prototypes. | ||
if (typeof appProto.expose === 'function' && | ||
typeof resProto.expose === 'function') { | ||
return; | ||
} | ||
// Modifies Express' `application` and `response` prototypes by adding the | ||
// Modifies the Express `app` and its `response` prototype by adding the | ||
// `expose()` method. | ||
resProto.expose = appProto.expose = expose; | ||
} | ||
app.expose = expose; | ||
app.response.expose = expose; | ||
function augment(app) { | ||
var resProto = app.response; | ||
// Protect against multiple express-state module instances augmenting the | ||
// Express `app` and its `response` prototypes. | ||
if (typeof app.expose === 'function' && | ||
typeof resProto.expose === 'function') { | ||
return; | ||
} | ||
// Modifies the Express `app` and its `response` prototype by adding the | ||
// `expose()` method. | ||
resProto.expose = app.expose = expose; | ||
return app; | ||
} | ||
@@ -62,3 +38,3 @@ | ||
if(!Exposed.isExposed(exposed)) { | ||
if (!Exposed.isExposed(exposed)) { | ||
// Creates a new `Exposed` instance, and links its prototype to the | ||
@@ -65,0 +41,0 @@ // corresponding app exposed object, if one exists. |
@@ -8,6 +8,11 @@ 'use strict'; | ||
function Exposed() { | ||
// Defines a "hidden" property which holds an ordered list of exposed | ||
// namespaces. When new namespaces are exposed, existing ones are examined | ||
// and removed if they are to become noops. | ||
Object.defineProperty(this, '__namespaces__', {value: []}); | ||
Object.defineProperties(this, { | ||
// Brand. | ||
'@exposed': {value: true}, | ||
// Defines a "hidden" property which holds an ordered list of exposed | ||
// namespaces. When new namespaces are exposed, existing ones are | ||
// examined and removed if they are to become noops. | ||
'__namespaces__': {value: []} | ||
}); | ||
} | ||
@@ -32,6 +37,7 @@ | ||
Exposed.isExposed = function (obj) { | ||
// Quack! | ||
return !!(obj && Array.isArray(obj.__namespaces__)); | ||
return !!(obj && obj['@exposed']); | ||
}; | ||
// TODO: Should this be a static method so it doesn't reserve the "add" | ||
// namespace on all Exposed instances? | ||
Exposed.prototype.add = function (namespace, value) { | ||
@@ -38,0 +44,0 @@ var nsRegex = new RegExp('^' + namespace + '(?:$|\\..+)'), |
@@ -5,3 +5,4 @@ 'use strict'; | ||
var PLACE_HOLDER_REGEX = /"@__(FUNCTION|REGEXP)_(\d+)__@"/g; | ||
var IS_NATIVE_CODE_REGEX = /\{\s*\[native code\]\s*\}/g, | ||
PLACE_HOLDER_REGEX = /"@__(FUNCTION|REGEXP)_(\d+)__@"/g; | ||
@@ -38,9 +39,15 @@ function serialize(obj) { | ||
return str.replace(PLACE_HOLDER_REGEX, function (match, type, index) { | ||
switch (type) { | ||
case 'FUNCTION': | ||
return functions[index].toString(); | ||
case 'REGEXP': | ||
if (type === 'REGEXP') { | ||
return regexps[index].toString(); | ||
} | ||
var fn = functions[index], | ||
serializedFn = fn.toString(); | ||
if (IS_NATIVE_CODE_REGEX.test(serializedFn)) { | ||
throw new TypeError('Serializing native function: ' + fn.name); | ||
} | ||
return serializedFn; | ||
}); | ||
} |
{ | ||
"name" : "express-state", | ||
"description": "Share server-side state with the client-side of an Express app via JavaScript.", | ||
"version" : "0.0.4", | ||
"version" : "1.0.0", | ||
"homepage" : "https://github.com/yahoo/express-state", | ||
"keywords": [ | ||
"express", "state", "client", "expose", "data", "config", "javascript", "model", "json" | ||
"express", "state", "client", "expose", "data", | ||
"config", "configuration", "javascript", "model", "json" | ||
], | ||
@@ -10,0 +11,0 @@ |
442
README.md
Express State | ||
============= | ||
Share server-side state with the client-side of an [Express][] app via | ||
JavaScript. | ||
[![Build Status](https://travis-ci.org/yahoo/express-state.png?branch=master)](https://travis-ci.org/yahoo/express-state) | ||
[![Dependency Status](https://gemnasium.com/yahoo/express-state.png)](https://gemnasium.com/yahoo/express-state) | ||
[![npm Version](https://badge.fury.io/js/express-state.png)](https://npmjs.org/package/express-state) | ||
[![Build Status](https://travis-ci.org/yahoo/express-state.png?branch=master)][Build Status] | ||
Share configuration and state data of an [Express][] app with the client-side | ||
via JavaScript. | ||
[Express]: https://github.com/visionmedia/express | ||
[Build Status]: https://travis-ci.org/yahoo/express-state | ||
Goals & Design | ||
-------------- | ||
Goals, Overview & Features | ||
-------------------------- | ||
Express State is designed to make it easy to share configuration and state data | ||
from the server to the client. It can be used to share any data that needs to be | ||
available to the client-side JavaScript code of the an app; e.g., the current | ||
user, a CSRF token, model data, routes, etc. | ||
Progressively enhanced web apps can be built by rendering an app's initial state | ||
on the server and using Express State as the conduit through which the server | ||
passes data and control over to the client-side JavaScript code. | ||
### Overview | ||
Configuration and state data is exposed to client-side JavaScript via two | ||
methods: `app.expose()` and `res.expose()`, both of which make the data | ||
available on a special `state` "locals" object for views/templates to serialize | ||
and embed into HTML pages. | ||
When Views/templates embed this exposed data into an HTML page it is serialized | ||
as literal JavaScript. The JavaScript serialization format is limited to | ||
expressions which initialize namespaces and the exposed data assigned to those | ||
namespaces, which is a superset of JSON that includes regexps and functions. | ||
### Features | ||
Express State was written because of shortcomings with [express-expose][]. The | ||
following is a list features which highlight differences when compared with | ||
express-expose: | ||
- **Uses an efficient and powerful serialization format:** | ||
Literal JavaScript is used to namespace exposed data which is a superset of | ||
JSON and include regexps and functions. This avoids the cost of allocating and | ||
parsing large JSON strings on the client, and enables things like sharing | ||
routes defined as regexps with a client-side URL router. | ||
- **Smart namespacing:** | ||
A root namespace can be set via an app's `state namespace` setting and it will | ||
be prepended to namespaces passed to `expose()` unless they already contain it | ||
or they start with `"window."`. The "global" on to which the namespaces are | ||
created can also be controlled. | ||
- **Precise data value overrides:** | ||
Sub-values within exposed objects can be easily overridden without clobbering | ||
the entire object. Request scoped values can even override data exposed at the | ||
app's scope. | ||
- **Lazy serialization:** | ||
Exposed data objects are stored by reference, making them "live" and allowing | ||
their values to be updated even after the object has been exposed. Only the | ||
namespaces and data which are still reachable after the series of `expose()` | ||
calls will be serialized. Serialization can happen at anytime, on demand, by | ||
calling the `toString()` method on `state` "locals" objects. | ||
- **Explicit extension of each Express app:** Express State's functionality has | ||
to be explicitly added to an Express app via the exported `extend()` function. | ||
This prevents problems in complex apps where multiple versions of Express | ||
and/or multiple Express apps are used. | ||
[app.locals]: http://expressjs.com/api.html#app.locals | ||
[res.locals]: http://expressjs.com/api.html#res.locals | ||
[express-expose]: https://github.com/visionmedia/express-expose | ||
Installation | ||
@@ -31,7 +93,374 @@ ------------ | ||
### Extending an Express App | ||
To use Express State with an Express app, the app must first be extended. Use | ||
the `extend()` method that Express State exports: | ||
```javascript | ||
var express = require('express'), | ||
expstate = require('express-state'), | ||
app = express(); | ||
expstate.extend(app); | ||
``` | ||
Once extended, the app will have the `app.expose()` method, and response objects | ||
will the `res.expose()` method. | ||
**Note:** It's perfectly fine for the same Express app to be extended more than | ||
once, after the first time the app is extended the subsequent `extend()` calls | ||
will be noops. | ||
### Exposing Data | ||
Data can be exposed at two different scopes: the app's scope, and a | ||
request/response's scope via `app.expose()` and `res.expose()` respectively. | ||
Express State uses Express' built-in "locals" system. When data is exposed at | ||
the app's scope a special `app.locals.state` object is created and used as the | ||
backing store for all `app.expose()` calls. Express also merges `app.locals` | ||
with `res.locals` to create the context object in which views/templates are | ||
rendered. This means that, by default, data exposed at the app's scope will also | ||
be present when rendering views/templates for _all_ requests. | ||
Express State sets up a similar relationship using prototypal inheritence where | ||
`res.locals.state` inherits from `app.locals.state`. This means data exposed at | ||
the request scope will also contain exposed data from the app's scope. If values | ||
for the same namespace are exposed at both scopes, the request/response scope | ||
takes precedence and shadows the value at the app's scope. | ||
#### Exposing App Scoped Data | ||
When data which needs to be exposed to the client-side JavaScript code is _not_ | ||
request-specific and should be available to all requests, it should be exposed | ||
at the app's scope using __`app.expose()`__. | ||
The following example exposes a Flickr API key required by Flickr to identify | ||
requests: | ||
```javascript | ||
app.expose({ | ||
api_key: '02348notreal2394879137872358bla' | ||
}, 'MY_APP.Flickr'); | ||
``` | ||
The client-side JavaScript code can now lookup the Flickr API key at | ||
`MY_APP.Flickr.api_key` when it needs to make a request to Flickr's API. | ||
#### Exposing Request Scoped Data | ||
When data which needs to be exposed to the client-side JavaScript _is_ | ||
request-specific, it should be exposed at the request/response's scope using | ||
__`res.expose()`__. | ||
The following example shows how to create a middleware function to expose the | ||
current person's Cross Site Request Forgery (CSRF) token — this is a best | ||
practice where the CSRF is used to validate HTTP requests which mutate state: | ||
```javascript | ||
// Add Express' packaged `cookieParser()`, `session()`, and `csrf()` middleware. | ||
app.use(express.cookieParser()); | ||
app.use(express.session({secret: 'something secure, not this!'})); | ||
app.use(express.csrf()); | ||
// Create a middleware function that will expose the CSRF token for the current | ||
// request only. | ||
app.use(function (req, res, next) { | ||
res.expose(req.session._csrf, 'MY_APP.CSRF_TOKEN'); | ||
next(); | ||
}); | ||
``` | ||
The client-side JavaScript code can now add the `X-CSRF-Token` HTTP header with | ||
the value at `MY_APP.CSRF_TOKEN` to all XHRs it makes to the server. | ||
### Setting a Root Namespace | ||
A common practice is to set a root namespace for an app so all of its exposed | ||
data is contained under one global variable in the client-side JavaScript code. | ||
A root namespace can be setup for an app using the `state namesapce` setting: | ||
```javascript | ||
app.set('state namespace', 'MY_APP'); | ||
``` | ||
Now anytime data is exposed, the root namespace will be prepended unless it | ||
already exists in the `namespace` passed into the `expose()` call or the | ||
passed-in `namespace` starts with `"window."`. | ||
With the above `"MY_APP"` root namespace, the following are all equivalent and | ||
result in `MY_APP.foo === 123` in the client-side JavaScript: | ||
```javascript | ||
// These all have the same result on the client: `MY_APP.foo === 123` | ||
app.expose(123, 'foo'); | ||
app.expose(123, 'MY_APP.foo'); | ||
app.expose(123, 'window.MY_APP.foo'); | ||
``` | ||
Setting a root namespace helps keep code DRY and configurable at the app level | ||
while having the `"window."` escape hatch for data which needs to be exposed at | ||
a specific namespace on the client. | ||
### Overriding Exposed Values | ||
Objects that are exposed through either `expose()` method are stored by | ||
reference, and serialization is done lazily. This means the objects are still | ||
"live" after they've been exposed. An object can be exposed early during the | ||
lifecycle of a request, and updated up until the point the response is sent. | ||
The following is a contrived example, but shows how values can overridden at | ||
any time and at any scope: | ||
```javascript | ||
app.expose({root: '/'}, 'url'); | ||
app.use(function (req, res, next) { | ||
res.expose(req.path, 'url.path'); | ||
res.expose(req.query, 'url.query'); | ||
next(); | ||
}); | ||
``` | ||
On the client, the resulting `url` object would look like the following for a | ||
request to the URL `"/foo?bar=baz"`: | ||
```javascript | ||
{ root: '/', | ||
path: '/foo', | ||
query: { bar: 'baz' } } | ||
``` | ||
Notice how exposing values at the `url.path` and `url.query` namespaces did | ||
_not_ clobber the original `url` object exposed at the app's scope. | ||
However, previously exposed data can be completely clobbered by simply exposing | ||
a new value at the same namespace. When this happens, Express State is smart | ||
enough to know it can release its references to the previous value objects and | ||
not waste CPU and bytes serializing them. | ||
### Serialization | ||
Express State serializes exposed data to literal, executable JavaScript. The | ||
JavaScript produced during serialization is limited to expressions which | ||
initialize namespaces and the exposed data assigned to those namespaces, which | ||
is a superset of JSON that includes regexps and functions. | ||
JavaScript as the serialization format is more powerful and efficient than JSON. | ||
It avoids the cost of allocating and parsing large JSON strings on the client, | ||
and enables things like sharing routes defined as regexps with a client-side URL | ||
router. | ||
The special `app.locals.state` and `res.locals.state` objects contain a custom | ||
`toString()` method implementation which serializes them to JavaScript that is | ||
human readable and can be embedded inside a `<script>` element in an HTML page. | ||
The following example shows a series of `expose()` calls, and the resulting | ||
output from serialization: | ||
```javascript | ||
app.expose({bar: 'bar'}, 'foo'); | ||
app.expose(/baz/, 'foo.baz'); | ||
app.expose(function () { return 'bla'; }, 'a.very.big.ns'); | ||
// Seralize `app.locals.state` and log the result. | ||
console.log(app.locals.state.toString()); | ||
``` | ||
The output of the `console.log()` call would be: | ||
```javascript | ||
(function (g) { | ||
// -- Namespaces -- | ||
g.foo || (g.foo = {}); | ||
g.a || (g.a = {}); | ||
g.a.very || (g.a.very = {}); | ||
g.a.very.big || (g.a.very.big = {}); | ||
// -- Exposed -- | ||
g.foo = {"bar":"bar"}; | ||
g.foo.baz = /baz/; | ||
g.a.very.big.ns = function () { return 'bla'; }; | ||
}(this)); | ||
``` | ||
**Note:** A `TypeError` will be thrown if a native built-in function is being | ||
serialized, like the `Number` constructor. Native built-ins should be called in | ||
wrapper functions, and the wrapper function can be serialized. | ||
### Embedding Data in HTML with Templates | ||
To pass along the exposed configuration and state data to the client-side | ||
JavaScript code it needs to be embedded in the app's HTML pages inside a | ||
`<script>` element. | ||
In Express, `res.render()` is used to render a view/template and send the | ||
response to the client. When rendering, Express sets up a context which is an | ||
object resulting from merging `app.locals` with `res.locals`. This means the | ||
special __`state`__ object is available to the views/templates. | ||
The following example is a basic [Handlebars][] template that renders the | ||
serialized `state` object: | ||
```html | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>Test App</title> | ||
</head> | ||
<body> | ||
<h1>Test App</h1> | ||
<script> | ||
{{{state}}} | ||
</script> | ||
</body> | ||
</html> | ||
``` | ||
**Note:** In this example triple-mustaches (`{{{ }}}`) are used so that | ||
Handlebars does _not_ HTML-escape the value. Handlebars will automatically call | ||
`toString()` method on the special `state` object, which renders the JavaScript. | ||
[Handlebars]: http://handlebarsjs.com/ | ||
Examples | ||
-------- | ||
### [Basic Usage][] | ||
A runnable example of the most basic Express app that uses Express State. | ||
[Basic Usage]: https://github.com/yahoo/express-state/tree/master/examples/basic | ||
API | ||
--- | ||
### Configuration and Defaults | ||
The following properties are exported from the Express State module. Assigning | ||
values to these properties affects all Express apps extended with this Express | ||
State module instance. To set these values for a specific app, use | ||
[App Settings][]. | ||
#### `local = "state"` | ||
A string property name on `app.locals` and `res.locals` where Express State | ||
creates its special objects used to store and serialize exposed data. | ||
By default, Express State will create these objects: | ||
* `app.locals.state` | ||
* `res.locals.state` | ||
#### `namespace = null` | ||
A string root namespace which should be prepended on the namespaces provided to | ||
`app.expose()` and `res.expose()` method calls. By default, no root namespace is | ||
used and namespaces are created directly on the global (`window`) object in the | ||
browser. | ||
See [Setting a Root Namespace][] for more details. | ||
### App Settings | ||
The following settings use the [Express Settings][] feature and only apply to | ||
the app which they are `set()`. These app settings take precedence over Express | ||
State's global configuration settings above. | ||
#### `state local` | ||
A string property name on `app.locals` and `res.locals` where Express State | ||
creates its special objects used to store and serialize exposed data. | ||
By default, no value is set, so Express State's exported `local` configuration | ||
value is used. | ||
The following example sets the locals properties to `app.locals.exposed` and | ||
`res.locals.exposed`: | ||
```javascript | ||
app.set('state local', 'exposed'); | ||
``` | ||
#### `state namespace` | ||
A string root namespace which should be prepended on the namespaces provided to | ||
`app.expose()` and `res.expose()` method calls. By default, no root namespace is | ||
used and namespaces are created directly on the global (`window`) object in the | ||
browser. | ||
The following example sets the root namespace to `"MY_APP"`: | ||
```javascript | ||
app.set('state namespace', 'MY_APP'); | ||
``` | ||
See [Setting a Root Namespace][] for more details. | ||
### Static Methods | ||
#### `extend (app)` | ||
A function exported from the Express State module which extends the | ||
functionality of the specified Express `app` by adding the two `expose()` | ||
methods: `app.expose()` and `res.expose()`. | ||
It's perfectly fine for the same Express app to be extended more than once, | ||
after the first time the app is extended the subsequent `extend()` calls will | ||
be noops. | ||
**Parameters:** | ||
* `app`: Express app instance to extend with Express State's functionality. | ||
See [Extending an Express App][] for more details. | ||
### Methods | ||
#### `app.expose (obj, [namespace], [local])` | ||
#### `res.expose (obj, [namespace], [local])` | ||
The two `expose()` methods behave the same, the only difference is at what scope | ||
the data is exposed, either the app's or at the request's scope. | ||
These two methods are used to expose configuration and state to client-side | ||
JavaScript by making the data available on a special `state` "locals" object for | ||
views/templates to serialize and embed into HTML pages. | ||
**Parameters:** | ||
* `obj`: Any serializable JavaScript object which to expose to the client-side. | ||
* `[namespace]`: Optional string namespace where the `obj` should be exposed. | ||
This namespace will be prefixed with any configured root namespace unless it | ||
already contains the root namespace or starts with `"window."`. | ||
* `[local]`: Optional string name of the "locals" property on which to expose | ||
the `obj`. This is used to specify a locals property other than the | ||
configured or default (`"state"`) one. | ||
**Note:** A `TypeError` will be thrown if a native built-in function is being | ||
serialized, like the `Number` constructor. Native built-ins should be called in | ||
wrapper functions, and the wrapper function can be serialized. | ||
See [Exposing Data][] and [Overriding Exposed Values][] for more details. | ||
[App Settings]: #app-settings | ||
[Express Settings]: http://expressjs.com/api.html#app-settings | ||
[Setting a Root Namespace]: #setting-a-root-namespace | ||
[Extending an Express App]: #extending-an-express-app | ||
[Exposing Data]: #exposing-data | ||
[Overriding Exposed Values]: #overriding-exposed-values | ||
License | ||
@@ -43,2 +472,3 @@ ------- | ||
[LICENSE file]: https://git.corp.yahoo.com/modown/express-state/blob/master/LICENSE |
@@ -28,12 +28,2 @@ /* global describe, it */ | ||
describe('.augment', function () { | ||
it('should have a .augment property', function () { | ||
expect(state).to.have.property('augment'); | ||
}); | ||
it('should respond to .augment()', function () { | ||
expect(state).itself.to.respondTo('augment'); | ||
}); | ||
}); | ||
describe('.extend', function () { | ||
@@ -47,3 +37,12 @@ it('should have a .extend property', function () { | ||
}); | ||
it('should always return the Express app being extended', function () { | ||
var app = {response: {}}; | ||
// Extended twice to make sure an already extended app is still | ||
// returned. | ||
expect(state.extend(app)).to.equal(app); | ||
expect(state.extend(app)).to.equal(app); | ||
}); | ||
}); | ||
}); |
@@ -76,7 +76,7 @@ /* global describe, it, beforeEach, afterEach */ | ||
var exposed = Object.create(null, { | ||
'__namespaces__': {value: []} | ||
'@exposed': {value: true} | ||
}); | ||
expect(Exposed.isExposed(exposed)).to.equal(true); | ||
expect(Exposed.isExposed({'__namespaces__': []})).to.equal(true); | ||
expect(Exposed.isExposed({'@exposed': true})).to.equal(true); | ||
}); | ||
@@ -94,3 +94,3 @@ | ||
expect(Exposed.isExposed([])).to.equal(false); | ||
expect(Exposed.isExposed({'__namespaces__': true})).to.equal(false); | ||
expect(Exposed.isExposed({'@exposed': false})).to.equal(false); | ||
}); | ||
@@ -97,0 +97,0 @@ }); |
@@ -29,53 +29,9 @@ /* global describe, it, beforeEach, afterEach */ | ||
it('should not override `expose()` if it exists', function () { | ||
var expose = function () {}, | ||
express, state; | ||
express = require('express'); | ||
express.application.expose = express.response.expose = expose; | ||
state = require('../'); | ||
expect(express.application.expose).to.equal(expose); | ||
expect(express.response.expose).to.equal(expose); | ||
}); | ||
describe('.extend( express )', function () { | ||
describe('.extend( app )', function () { | ||
it('should add `expose()`', function () { | ||
var express = require('express'), | ||
state = require('../'); | ||
mockery.registerMock('express', createExpressMock()); | ||
express = require('express'); | ||
expect(express.application.expose).to.be.undefined; | ||
expect(express.response.expose).to.be.undefined; | ||
state.extend(express); | ||
expect(express.application).itself.to.respondTo('expose'); | ||
expect(express.response).itself.to.respondTo('expose'); | ||
}); | ||
it('should not override `expose()` if it exists', function () { | ||
var expose = function () {}, | ||
express, state; | ||
express = require('express'); | ||
state = require('../'); | ||
express.application.expose = express.response.expose = expose; | ||
state.extend(express); | ||
expect(express.application.expose).to.equal(expose); | ||
expect(express.response.expose).to.equal(expose); | ||
}); | ||
}); | ||
describe('.augment( app )', function () { | ||
it('should add `expose()`', function () { | ||
var express = require('express'), | ||
state = require('../'), | ||
app = {response: {}}; | ||
state.augment(app); | ||
state.extend(app); | ||
@@ -98,4 +54,10 @@ expect(app).itself.to.respondTo('expose'); | ||
state.augment(app); | ||
// Extend, then override. | ||
state.extend(app); | ||
app.expose = expose; | ||
app.response = {expose: expose}; | ||
// Try to extend again. | ||
state.extend(app); | ||
expect(app.expose).to.equal(expose); | ||
@@ -102,0 +64,0 @@ expect(app.response.expose).to.equal(expose); |
@@ -100,2 +100,9 @@ /* global describe, it, beforeEach */ | ||
}); | ||
it('should throw a TypeError when serializing native built-ins', function () { | ||
var err; | ||
expect(Number.toString()).to.equal('function Number() { [native code] }'); | ||
try { serialize(Number); } catch (e) { err = e; } | ||
expect(err).to.be.an.instanceOf(TypeError); | ||
}); | ||
}); | ||
@@ -102,0 +109,0 @@ |
@@ -14,3 +14,3 @@ /* global describe, it, beforeEach, afterEach */ | ||
beforeEach(function () { | ||
app = express(); | ||
app = state.extend(express()); | ||
}); | ||
@@ -17,0 +17,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
54264
0
473
799