app-test.js revision d89a7d2fca300684fcbe3426f41ed30d106d17ec
var ArrayAssert = Y.ArrayAssert,
ObjectAssert = Y.ObjectAssert,
// -- Global Suite -------------------------------------------------------------
// -- Model Suite --------------------------------------------------------------
// -- Model: Lifecycle ---------------------------------------------------------
name: 'Lifecycle',
'destroy() should destroy the model instance': function () {
};
},
'destroy() should call a callback if provided as the only arg': function () {
method: 'callback',
args : []
});
},
'destroy() should call a callback if provided as the second arg': function () {
method: 'callback',
args : []
});
},
'destroy() should delete the model if the `delete` option is truthy': function () {
var calls = 0,
method: 'callback',
args : []
});
calls += 1;
callback();
};
},
'destroy() should remove the model from all lists': function () {
}
}));
// -- Model: Attributes and Properties -----------------------------------------
name: 'Attributes and Properties',
setUp: function () {
idAttribute: 'customId'
}, {
ATTRS: {
}
});
},
tearDown: function () {
delete this.TestModel;
},
'Attributes should be settable at instantiation time': function () {
},
'Custom id attribute should be settable at instantiation time': function () {
var model;
// We need to set and get the id and customId attributes in various
// orders to ensure there are no issues due to the attributes being
// lazily added.
},
'`id` attribute should be an alias for the custom id attribute': function () {
var calls = 0,
calls += 1;
});
},
'`changed` property should be a hash of attributes that have changed since last save() or load()': function () {
},
'clientId attribute should be automatically generated': function () {
},
'`lastChange` property should contain attributes that changed in the last `change` event': function () {
},
'`lists` property should be an array of ModelList instances that contain this model': function () {
var calls = 0,
lists = [
];
function onChange() {
calls += 1;
}
}
}));
// -- Model: Methods -----------------------------------------------------------
name: 'Methods',
setUp: function () {
ATTRS: {
}
});
},
tearDown: function () {
delete this.TestModel;
},
'generateClientId() should generate a unique client id': function () {
},
'getAsHTML() should return an HTML-escaped attribute value': function () {
var value = '<div id="foo">hello!</div>',
},
'getAsURL() should return a URL-encoded attribute value': function () {
var value = 'foo & bar = baz',
},
'isModified() should return true if the model is new': function () {
},
'isModified() should return true if the model has changed since it was last saved': function () {
},
'isNew() should return true if the model is new': function () {
},
'load() should delegate to sync()': function () {
var calls = 0,
opts = {};
calls += 1;
callback();
};
},
'load() should reset this.changed when loading succeeds': function () {
},
'load() should be chainable and should call the callback if one was provided': function () {
var calls = 0,
calls += 1;
}));
calls += 1;
}));
},
'parse() should parse a JSON string and return an object': function () {
},
'parse() should not try to parse non-strings': function () {
},
'save() should delegate to sync()': function () {
var calls = 0,
opts = {};
calls += 1;
// Give the model an id so it will no longer be new.
};
calls += 1;
};
},
'save() should reset this.changed when saving succeeds': function () {
},
'save() should be chainable and should call the callback if one was provided': function () {
var calls = 0,
calls += 1;
}));
calls += 1;
}));
},
'set() should set the value of a single attribute': function () {
},
'setAttrs() should set the values of multiple attributes': function () {
},
'sync() should just call the supplied callback by default': function () {
var calls = 0,
calls += 1;
});
},
"toJSON() should return a copy of the model's attributes, minus excluded ones": function () {
// When there's a custom id attribute, the 'id' attribute should be
// excluded.
idAttribute: 'customId'
}, {
ATTRS: {
}
});
},
'undo() should revert the previous change to the model': function () {
},
'undo() should revert only the specified attributes when attributes are specified': function () {
},
'undo() should pass options to setAttrs()': function () {
var calls = 0,
calls += 1;
});
},
'undo() should do nothing when there is no previous change to revert': function () {
});
},
'validate() should be a noop function by default': function () {
},
'validate() should only be called on save()': function () {
var calls = 0,
calls += 1;
};
},
'a validation failure should abort a save() call': function () {
var calls = 0,
errors = 0,
saveCallbacks = 0;
calls += 1;
return 'OMG invalid!';
};
};
errors += 1;
});
saveCallbacks += 1;
});
}
}));
// -- Model: Events ------------------------------------------------------------
name: 'Events',
setUp: function () {
ATTRS: {
}
});
},
tearDown: function () {
delete this.TestModel;
},
'`change` event should contain coalesced attribute changes': function () {
var calls = 0,
calls += 1;
});
foo: 'foo',
bar: 'bar'
}, {src: 'test'});
},
'`change` event should not fire when the _silent_ option is truthy': function () {
});
},
'`error` event should fire when validation fails': function () {
var calls = 0,
return 'ERROR. ERROR. DOES NOT COMPUTE.';
};
calls += 1;
});
},
'`error` event should fire when parsing fails': function () {
var calls = 0,
calls += 1;
});
},
'`error` event should fire when a load operation fails': function () {
var calls = 0,
calls += 1;
});
};
},
'`error` event should fire when a save operation fails': function () {
var calls = 0,
calls += 1;
});
};
},
'`load` event should fire after a successful load operation': function () {
var calls = 0,
calls += 1;
Assert.areSame('bar', model.get('foo'), 'load event should fire after attribute changes are applied');
});
callback(null, '{"foo": "bar"}');
};
});
},
'`save` event should fire after a successful save operation': function () {
var calls = 0,
calls += 1;
Assert.areSame('bar', model.get('foo'), 'save event should fire after attribute changes are applied');
});
callback(null, '{"foo": "bar"}');
};
});
}
}));
// -- ModelList Suite ----------------------------------------------------------
// -- ModelList: Lifecycle -----------------------------------------------------
name: 'Lifecycle',
setUp: function () {
},
tearDown: function () {
delete this.list;
},
'ModelLists should have a `model` property': function () {
},
'destructor should detach all models from the list': function () {
}
}));
// -- ModelList: Methods -------------------------------------------------------
name: 'Methods',
setUp: function () {
ATTRS: {
}
});
this.createList = function (modelClass) {
};
this.createModel = function (config) {
};
},
tearDown: function () {
delete this.createList;
delete this.createModel;
delete this.TestList;
delete this.TestModel;
},
'add() should add a model to the list': function () {
var list = this.createList(),
model = this.createModel(),
},
'add() should add an array of models to the list': function () {
var list = this.createList(),
},
'comparator() should be undefined by default': function () {
},
'models should be added in the proper position based on the comparator': function () {
var list = this.createList();
};
},
'create() should create or update a model, then add it to the list': function () {
var list = this.createList(),
model = this.createModel();
},
'create() should call the callback if one is provided': function () {
var calls = 0,
list = this.createList();
calls += 1;
});
},
'create() should pass an error to the callback if one occurs': function () {
var calls = 0,
list = this.createList(),
model = this.createModel();
callback('Oh noes!');
};
calls += 1;
});
},
'filter() should filter the list and return an array': function () {
var list = this.createList(),
});
},
'filter() should accept a custom `this` object': function () {
var list = this.createList(),
obj = {};
}, obj);
},
'filter() should return an empty array if the callback never returns a truthy value': function () {
var list = this.createList();
},
'get() should return an array of attribute values from all models in the list': function () {
var list = this.createList();
},
'get() should return a list attribute if there is one': function () {
var list = this.createList();
},
'getAsHTML() should return an array of HTML-escaped attribute values': function () {
var list = this.createList();
},
'getAsHTML() should return a list attribute if there is one': function () {
var list = this.createList();
},
'getAsURL() should return an array of URL-encoded attribute values': function () {
var list = this.createList();
},
'getAsURL() should return a list attribute if there is one': function () {
var list = this.createList();
},
'getByClientId() should look up a model by its clientId': function () {
var list = this.createList(),
},
'getById() should look up a model by its id': function () {
var list = this.createList(),
},
'getById() should work with numeric ids': function () {
var list = this.createList(),
},
'getById() should work with custom ids': function () {
idAttribute: 'customId'
}, {
ATTRS: {
}
}),
},
'invoke() should call the named method on every model in the list': function () {
var list = this.createList(),
ArrayAssert.itemsAreSame(list.toArray(), results, 'invoke should return an array of return values');
},
'item() should return the model at the specified index': function () {
var list = this.createList();
},
'load() should delegate to sync()': function () {
var calls = 0,
list = this.createList(),
opts = {};
calls += 1;
callback();
};
},
'load() should be chainable and should call the callback if one was provided': function () {
var calls = 0,
list = this.createList();
calls += 1;
}));
calls += 1;
}));
},
'map() should execute a function on every model in the list and return an array of return values': function () {
var list = this.createList(),
obj = {},
}, obj);
},
'parse() should parse a JSON string and return an object': function () {
var list = this.createList(),
},
'parse() should not try to parse non-strings': function () {
var list = this.createList(),
},
'reset() should replace all models in the list': function () {
var list = this.createList(),
// Removed models should be cleanly detached.
// And we should be able to re-add them.
},
'reset() should sort the new models in the list': function () {
var list = this.createList();
};
]);
},
'reset() with no args should clear the list': function () {
var list = this.createList(),
},
'remove() should remove a single model from the list': function () {
var list = this.createList();
},
'remove() should remove an array of models from the list': function () {
var list = this.createList(),
},
// 'set() should set a single attribute value on all models in the list': function () {
//
// },
//
// 'setAttrs() should set multiple attribute values on all models in the list': function () {
//
// },
'sort() should re-sort the list': function () {
var list = this.createList();
};
},
'sync() should just call the supplied callback by default': function () {
var calls = 0,
list = this.createList();
calls += 1;
});
},
'toArray() should return an array containing all the models in the list': function () {
var list = this.createList(),
},
'toJSON() should return an array of model hashes': function () {
var list = this.createList(),
}
}));
// -- ModelList: Events --------------------------------------------------------
name: 'Events',
setUp: function () {
ATTRS: {
}
});
this.createList = function (modelClass) {
};
this.createModel = function (config) {
};
},
tearDown: function () {
delete this.createList;
delete this.createModel;
delete this.TestList;
delete this.TestModel;
},
'`add` event should fire when a model is added': function () {
var calls = 0,
list = this.createList(),
model = this.createModel();
calls += 1;
});
calls += 1;
});
},
'`add` event should be preventable': function () {
var calls = 0,
list = this.createList();
calls += 1;
e.preventDefault();
});
});
},
'`add` event should not fire when a model is added silently': function () {
var list = this.createList();
});
},
'`change` event should bubble up from models': function () {
var calls = 0,
list = this.createList(),
calls += 1;
});
},
'`error` event should bubble up from models': function () {
var calls = 0,
list = this.createList(),
return 'fail!';
}
};
calls += 1;
});
},
'`error` event should fire when a duplicate model is added': function () {
var calls = 0,
list = this.createList(),
model = this.createModel();
calls += 1;
});
},
"`error` event should fire when a model that isn't in the list is removed": function () {
var calls = 0,
list = this.createList(),
model = this.createModel();
calls += 1;
});
},
"`error` event should fire when a sync layer response can't be parsed": function () {
var calls = 0,
list = this.createList(),
response = 'foo bar baz';
calls += 1;
});
},
'`reset` event should fire when the list is reset or sorted': function () {
var calls = 0,
list = this.createList(),
calls += 1;
});
calls += 1;
});
};
},
'`reset` event facade should contain sorted models': function () {
var calls = 0,
list = this.createList();
};
var values = [];
calls += 1;
});
});
]);
},
'`reset` event should be preventable': function () {
var calls = 0,
list = this.createList();
calls += 1;
e.preventDefault();
});
});
},
'`reset` event should not fire when the list is reset silently': function () {
var list = this.createList();
});
},
'`remove` event should fire when a model is removed': function () {
var calls = 0,
list = this.createList(),
calls += 1;
});
calls += 1;
});
},
'`remove` event should be preventable': function () {
var calls = 0,
list = this.createList();
calls += 1;
e.preventDefault();
});
});
},
'`remove` event should not fire when a model is removed silently': function () {
var list = this.createList();
});
}
}));
// -- Router Suite ---------------------------------------------------------
name: 'Router',
setUp: function () {
if (!html5) {
}
},
tearDown: function () {
if (html5) {
} else {
}
}
});
// -- Router: Lifecycle ----------------------------------------------------
name: 'Lifecycle',
tearDown: function () {
delete this.router;
},
'initializer should set attributes based on config options': function () {
html5: false,
root: '/foo',
routes: [
]
});
},
'subclass with default routes should work': function () {
ATTRS: {
routes: {
value: [
]
}
}
}),
}
}));
// -- Router: Attributes ---------------------------------------------------
name: 'Attributes',
tearDown: function () {
delete this.router;
},
'`html5` attribute should have a default value': function () {
},
'`root` attribute should have a default value': function () {
},
'`routes` attribute should have a default value': function () {
},
'setting the `routes` attribute should reset all routes': function () {
]);
}
}));
// -- Router: Events -------------------------------------------------------
name: 'Events',
tearDown: function () {
delete this.router;
},
'`ready` event should fire when the router is ready to dispatch': function () {
var test = this,
on: {
ready: function (e) {
});
}
}
});
this.wait(1000);
},
'`ready` event should set e.dispatched to true if called after dispatch': function () {
var test = this,
on: {
initializedChange: function () {
this._dispatch('/fake', {});
},
ready: function (e) {
});
}
}
});
this.wait(1000);
}
}));
// -- Router: Methods ------------------------------------------------------
name: 'Methods',
tearDown: function () {
delete this.router;
},
'route() should add a route': function () {
function two() {}
},
'match() should return an array of routes that match the given path': function () {
function one () {}
function two() {}
function three() {}
},
'hasRoute() should return `true` if one or more routes match the given path': function () {
function noop () {}
},
'hasRoute() should support full URLs': function () {
function noop () {}
},
'dispatch() should dispatch to the first route that matches the current URL': function () {
var test = this,
});
setTimeout(function () {
}, 1);
this.wait(1000);
},
'dispatch() should upgrade hash URLs to HTML5 URLs in HTML5 browsers': function () {
if (!html5) {
return;
}
var test = this,
});
});
this.wait(500);
},
'removeRoot() should remove the root URL from a given path': function () {
},
'removeRoot() should strip the "http://foo.com" portion of the URL, if any': function () {
},
'replace() should replace the current history entry': function () {
var test = this,
});
});
// Wrapped in a setTimeout to make the async test work on iOS<5, which
// performs this action synchronously.
setTimeout(function () {
}, 1);
this.wait(1000);
},
'save() should create a new history entry': function () {
var test = this,
});
});
// Wrapped in a setTimeout to make the async test work on iOS<5, which
// performs this action synchronously.
setTimeout(function () {
}, 1);
this.wait(1000);
},
'consecutive save() calls should dispatch to the correct routes': function () {
var paths = [],
test = this,
});
});
});
});
// Wrapped in a setTimeout to make the async test work on iOS<5, which
// performs this action synchronously.
setTimeout(function () {
}, 1);
this.wait(2000);
},
'_joinURL() should normalize / separators': function () {
},
'_dispatch() should pass `src` through to request object passed to route handlers': function () {
calls = 0,
src = 'API';
});
}
}));
// -- Router: Routes -------------------------------------------------------
name: 'Routes',
tearDown: function () {
delete this.router;
delete this.router2;
},
'routes should be called in the context of the router': function () {
var calls = 0,
});
calls += 1;
};
},
'routes should receive a request object, response object, and `next` function as params': function () {
var calls = 0,
calls += 1;
});
// Duckpunching _getQuery so we can test req.query.
return 'bar=baz%20quux&moo';
};
},
'request object should contain captured route parameters': function () {
var calls = 0,
calls += 1;
});
calls += 1;
});
calls += 1;
});
},
'calling `res()` should have the same result as calling `next()`': function () {
var calls = 0;
calls += 1;
res();
});
calls += 1;
next();
});
calls += 1;
});
},
'calling `next()` should pass control to the next matching route': function () {
var calls = 0,
calls += 1;
next();
});
calls += 1;
next();
});
calls += 1;
});
calls += 1;
});
},
'"*" should be a catch-all route': function () {
var calls = 0,
calls += 1;
});
},
'multiple routers should be able to coexist and have duplicate route handlers': function () {
var calls = 0,
calls += 1;
});
calls += 1;
});
this.wait(function () {
}, 200);
}
}));
// -- View Suite ---------------------------------------------------------------
// -- View: Lifecycle ----------------------------------------------------------
name: 'Lifecycle',
'container should be a <div> node by default': function () {
},
'events property should be an empty object by default': function () {
},
'model attribute should be null by default': function () {
},
'initializer should allow setting a model reference at init': function () {
},
'initializer should allow setting a model list reference at init': function () {
},
'initializer should allow setting a template at init': function () {
var template = {},
},
'initializer should call create() to create the container node': function () {
var calls = 0,
calls += 1;
}
});
},
'initializer should call attachEvents()': function () {
var calls = 0,
attachEvents: function (events) {
calls += 1;
// Ensure that events specified at instantiation time are
// merged into any default events, rather than overwriting
// all default events.
}
});
},
'destructor should remove the container from the DOM': function () {
}
}));
name: 'Methods',
'create() should create and return a container node': function () {
},
'remove() should remove the container node from the DOM': function () {
},
'render() should be a chainable noop': function () {
}
}));
}, '@VERSION@', {
});