Commit 26da0784 authored by Pascal Hartig's avatar Pascal Hartig

flight: upgrade to 1.1, karma test infrastructure

parent 28e16092
......@@ -2,12 +2,16 @@
'use strict';
define([
'flight/component',
'flight/lib/component',
'../store'
], function (defineComponent, dataStore) {
function stats() {
this.defaultAttrs({
dataStore: dataStore
});
this.recount = function () {
var todos = dataStore.all();
var todos = this.attr.dataStore.all();
var all = todos.length;
var remaining = todos.reduce(function (memo, each) {
return memo += each.completed ? 0 : 1;
......
......@@ -2,14 +2,17 @@
'use strict';
define([
'flight/component',
'flight/lib/component',
'../store'
], function (defineComponent, dataStore) {
function todos() {
var filter;
this.defaultAttrs({
dataStore: dataStore
});
this.add = function (e, data) {
var todo = dataStore.save({
var todo = this.attr.dataStore.save({
title: data.title,
completed: false
});
......@@ -18,7 +21,7 @@ define([
};
this.remove = function (e, data) {
var todo = dataStore.destroy(data.id);
var todo = this.attr.dataStore.destroy(data.id);
this.trigger('dataTodoRemoved', todo);
};
......@@ -32,15 +35,15 @@ define([
};
this.update = function (e, data) {
dataStore.save(data);
this.attr.dataStore.save(data);
};
this.toggleCompleted = function (e, data) {
var eventType;
var todo = dataStore.get(data.id);
var todo = this.attr.dataStore.get(data.id);
todo.completed = !todo.completed;
dataStore.save(todo);
this.attr.dataStore.save(todo);
eventType = filter ? 'dataTodoRemoved' : 'dataTodoToggled';
......@@ -48,7 +51,7 @@ define([
};
this.toggleAllCompleted = function (e, data) {
dataStore.updateAll({ completed: data.completed });
this.attr.dataStore.updateAll({ completed: data.completed });
this.trigger('dataTodoToggledAll', { todos: this.find(filter) });
};
......@@ -66,18 +69,18 @@ define([
var todos;
if (filter) {
todos = dataStore.find(function (each) {
todos = this.attr.dataStore.find(function (each) {
return (typeof each[filter] !== 'undefined') ? each.completed : !each.completed;
});
} else {
todos = dataStore.all();
todos = this.attr.dataStore.all();
}
return todos;
};
this.clearCompleted = function () {
dataStore.destroyAll({ completed: true });
this.attr.dataStore.destroyAll({ completed: true });
this.trigger('uiFilterRequested', { filter: filter });
this.trigger('dataClearedCompleted');
......
......@@ -6,20 +6,13 @@ require.config({
jquery: 'bower_components/jquery/jquery',
es5shim: 'bower_components/es5-shim/es5-shim',
es5sham: 'bower_components/es5-shim/es5-sham',
text: 'bower_components/requirejs-text/text'
},
map: {
'*': {
'flight/component': 'bower_components/flight/lib/component',
'depot': 'bower_components/depot/depot'
}
text: 'bower_components/requirejs-text/text',
flight: 'bower_components/flight',
depot: 'bower_components/depot/depot'
},
shim: {
'bower_components/flight/lib/index': {
deps: ['jquery', 'es5shim', 'es5sham']
},
'app/js/app': {
deps: ['bower_components/flight/lib/index']
deps: ['jquery', 'es5shim', 'es5sham']
}
}
});
......
......@@ -2,7 +2,7 @@
'use strict';
define([
'flight/component'
'flight/lib/component'
], function (defineComponent) {
function mainSelector() {
this.toggle = function (e, data) {
......
......@@ -2,7 +2,7 @@
'use strict';
define([
'flight/component'
'flight/lib/component'
], function (defineComponent) {
function newItem() {
var ENTER_KEY = 13;
......
......@@ -2,7 +2,7 @@
'use strict';
define([
'flight/component',
'flight/lib/component',
'./with_filters',
'text!app/templates/stats.html',
'../utils'
......
......@@ -2,7 +2,7 @@
'use strict';
define([
'flight/component',
'flight/lib/component',
'text!app/templates/todo.html',
'../utils'
], function (defineComponent, todoTmpl, utils) {
......
......@@ -2,7 +2,7 @@
'use strict';
define([
'flight/component'
'flight/lib/component'
], function (defineComponent) {
function toggleAll() {
this.toggleAllComplete = function () {
......
......@@ -4,10 +4,14 @@
"dependencies": {
"depot": "~0.1.4",
"es5-shim": "git://github.com/kriskowal/es5-shim.git#2.0.0",
"flight": "~1.0.4",
"flight": "~1.1.0",
"jquery": "1.8.3",
"requirejs": "~2.1.5",
"todomvc-common": "~0.1.4",
"requirejs-text": "~2.0.10"
},
"devDependencies": {
"jasmine-flight": "~2.1.0",
"jasmine-jquery": "~1.5.8"
}
}
define(
[
'./utils',
'./registry',
'./debug'
],
function(utils, registry, debug) {
//common mixin allocates basic functionality - used by all component prototypes
//callback context is bound to component
var componentId = 0;
function teardownInstance(instanceInfo){
instanceInfo.events.slice().forEach(function(event) {
var args = [event.type];
event.element && args.unshift(event.element);
(typeof event.callback == 'function') && args.push(event.callback);
this.off.apply(this, args);
}, instanceInfo.instance);
}
function checkSerializable(type, data) {
try {
window.postMessage(data, '*');
} catch(e) {
console.log('unserializable data for event',type,':',data);
throw new Error(
["The event", type, "on component", this.toString(), "was triggered with non-serializable data"].join(" ")
);
}
}
function withBase() {
// delegate trigger, bind and unbind to an element
// if $element not supplied, use component's node
// other arguments are passed on
// event can be either a string specifying the type
// of the event, or a hash specifying both the type
// and a default function to be called.
this.trigger = function() {
var $element, type, data, event, defaultFn;
var lastIndex = arguments.length - 1, lastArg = arguments[lastIndex];
if (typeof lastArg != "string" && !(lastArg && lastArg.defaultBehavior)) {
lastIndex--;
data = lastArg;
}
if (lastIndex == 1) {
$element = $(arguments[0]);
event = arguments[1];
} else {
$element = this.$node;
event = arguments[0];
}
if (event.defaultBehavior) {
defaultFn = event.defaultBehavior;
event = $.Event(event.type);
}
type = event.type || event;
if (debug.enabled && window.postMessage) {
checkSerializable.call(this, type, data);
}
if (typeof this.attr.eventData === 'object') {
data = $.extend(true, {}, this.attr.eventData, data);
}
$element.trigger((event || type), data);
if (defaultFn && !event.isDefaultPrevented()) {
(this[defaultFn] || defaultFn).call(this);
}
return $element;
};
this.on = function() {
var $element, type, callback, originalCb;
var lastIndex = arguments.length - 1, origin = arguments[lastIndex];
if (typeof origin == "object") {
//delegate callback
originalCb = utils.delegate(
this.resolveDelegateRules(origin)
);
} else {
originalCb = origin;
}
if (lastIndex == 2) {
$element = $(arguments[0]);
type = arguments[1];
} else {
$element = this.$node;
type = arguments[0];
}
if (typeof originalCb != 'function' && typeof originalCb != 'object') {
throw new Error("Unable to bind to '" + type + "' because the given callback is not a function or an object");
}
callback = originalCb.bind(this);
callback.target = originalCb;
// if the original callback is already branded by jQuery's guid, copy it to the context-bound version
if (originalCb.guid) {
callback.guid = originalCb.guid;
}
$element.on(type, callback);
// get jquery's guid from our bound fn, so unbinding will work
originalCb.guid = callback.guid;
return callback;
};
this.off = function() {
var $element, type, callback;
var lastIndex = arguments.length - 1;
if (typeof arguments[lastIndex] == "function") {
callback = arguments[lastIndex];
lastIndex -= 1;
}
if (lastIndex == 1) {
$element = $(arguments[0]);
type = arguments[1];
} else {
$element = this.$node;
type = arguments[0];
}
return $element.off(type, callback);
};
this.resolveDelegateRules = function(ruleInfo) {
var rules = {};
Object.keys(ruleInfo).forEach(function(r) {
if (!(r in this.attr)) {
throw new Error('Component "' + this.toString() + '" wants to listen on "' + r + '" but no such attribute was defined.');
}
rules[this.attr[r]] = ruleInfo[r];
}, this);
return rules;
};
this.defaultAttrs = function(defaults) {
utils.push(this.defaults, defaults, true) || (this.defaults = defaults);
};
this.select = function(attributeKey) {
return this.$node.find(this.attr[attributeKey]);
};
this.initialize = function(node, attrs) {
attrs = attrs || {};
this.identity = componentId++;
if (!node) {
throw new Error("Component needs a node");
}
if (node.jquery) {
this.node = node[0];
this.$node = node;
} else {
this.node = node;
this.$node = $(node);
}
//merge defaults with supplied options
//put options in attr.__proto__ to avoid merge overhead
var attr = Object.create(attrs);
for (var key in this.defaults) {
if (!attrs.hasOwnProperty(key)) {
attr[key] = this.defaults[key];
}
}
this.attr = attr;
Object.keys(this.defaults || {}).forEach(function(key) {
if (this.defaults[key] === null && this.attr[key] === null) {
throw new Error('Required attribute "' + key + '" not specified in attachTo for component "' + this.toString() + '".');
}
}, this);
return this;
}
this.teardown = function() {
teardownInstance(registry.findInstanceInfo(this));
};
}
return withBase;
});
......@@ -12,31 +12,15 @@ define(
'./advice',
'./utils',
'./compose',
'./base',
'./registry',
'./logger',
'../tools/debug/debug'
'./debug'
],
function(advice, utils, compose, registry, withLogging, debug) {
function(advice, utils, compose, withBase, registry, withLogging, debug) {
var functionNameRegEx = /function (.*?)\s?\(/;
var componentId = 0;
function teardownInstance(instanceInfo){
instanceInfo.events.slice().forEach(function(event) {
var args = [event.type];
event.element && args.unshift(event.element);
(typeof event.callback == 'function') && args.push(event.callback);
this.off.apply(this, args);
}, instanceInfo.instance);
}
function teardown() {
teardownInstance(registry.findInstanceInfo(this));
}
//teardown for all instances of this constructor
function teardownAll() {
......@@ -59,143 +43,6 @@ define(
}
}
//common mixin allocates basic functionality - used by all component prototypes
//callback context is bound to component
function withBaseComponent() {
// delegate trigger, bind and unbind to an element
// if $element not supplied, use component's node
// other arguments are passed on
// event can be either a string specifying the type
// of the event, or a hash specifying both the type
// and a default function to be called.
this.trigger = function() {
var $element, type, data, event, defaultFn;
var lastIndex = arguments.length - 1, lastArg = arguments[lastIndex];
if (typeof lastArg != "string" && !(lastArg && lastArg.defaultBehavior)) {
lastIndex--;
data = lastArg;
}
if (lastIndex == 1) {
$element = $(arguments[0]);
event = arguments[1];
} else {
$element = this.$node;
event = arguments[0];
}
if (event.defaultBehavior) {
defaultFn = event.defaultBehavior;
event = $.Event(event.type);
}
type = event.type || event;
if (debug.enabled && window.postMessage) {
checkSerializable.call(this, type, data);
}
if (typeof this.attr.eventData === 'object') {
data = $.extend(true, {}, this.attr.eventData, data);
}
$element.trigger((event || type), data);
if (defaultFn && !event.isDefaultPrevented()) {
(this[defaultFn] || defaultFn).call(this);
}
return $element;
};
this.on = function() {
var $element, type, callback, originalCb;
var lastIndex = arguments.length - 1, origin = arguments[lastIndex];
if (typeof origin == "object") {
//delegate callback
originalCb = utils.delegate(
this.resolveDelegateRules(origin)
);
} else {
originalCb = origin;
}
if (lastIndex == 2) {
$element = $(arguments[0]);
type = arguments[1];
} else {
$element = this.$node;
type = arguments[0];
}
if (typeof originalCb != 'function' && typeof originalCb != 'object') {
throw new Error("Unable to bind to '" + type + "' because the given callback is not a function or an object");
}
callback = originalCb.bind(this);
callback.target = originalCb;
// if the original callback is already branded by jQuery's guid, copy it to the context-bound version
if (originalCb.guid) {
callback.guid = originalCb.guid;
}
$element.on(type, callback);
// get jquery's guid from our bound fn, so unbinding will work
originalCb.guid = callback.guid;
return callback;
};
this.off = function() {
var $element, type, callback;
var lastIndex = arguments.length - 1;
if (typeof arguments[lastIndex] == "function") {
callback = arguments[lastIndex];
lastIndex -= 1;
}
if (lastIndex == 1) {
$element = $(arguments[0]);
type = arguments[1];
} else {
$element = this.$node;
type = arguments[0];
}
return $element.off(type, callback);
};
this.resolveDelegateRules = function(ruleInfo) {
var rules = {};
Object.keys(ruleInfo).forEach(function(r) {
if (!r in this.attr) {
throw new Error('Component "' + this.toString() + '" wants to listen on "' + r + '" but no such attribute was defined.');
}
rules[this.attr[r]] = ruleInfo[r];
}, this);
return rules;
};
this.defaultAttrs = function(defaults) {
utils.push(this.defaults, defaults, true) || (this.defaults = defaults);
};
this.select = function(attributeKey) {
return this.$node.find(this.attr[attributeKey]);
};
this.initialize = $.noop;
this.teardown = teardown;
}
function attachTo(selector/*, options args */) {
// unpacking arguments by hand benchmarked faster
var l = arguments.length;
......@@ -216,7 +63,7 @@ define(
return;
}
new this(node, options);
(new this).initialize(node, options);
}.bind(this));
}
......@@ -229,64 +76,26 @@ define(
var mixins = new Array(l + 3); //add three for common mixins
for (var i = 0; i < l; i++) mixins[i] = arguments[i];
Component.toString = function() {
var Component = function() {};
Component.toString = Component.prototype.toString = function() {
var prettyPrintMixins = mixins.map(function(mixin) {
if (mixin.name == null) {
//function name property not supported by this browser, use regex
var m = mixin.toString().match(functionNameRegEx);
return (m && m[1]) ? m[1] : "";
} else {
return (mixin.name != "withBaseComponent") ? mixin.name : "";
return (mixin.name != "withBase") ? mixin.name : "";
}
}).filter(Boolean).join(', ');
return prettyPrintMixins;
};
if (debug.enabled) {
Component.describe = Component.toString();
Component.describe = Component.prototype.describe = Component.toString();
}
//'options' is optional hash to be merged with 'defaults' in the component definition
function Component(node, options) {
options = options || {};
this.identity = componentId++;
if (!node) {
throw new Error("Component needs a node");
}
if (node.jquery) {
this.node = node[0];
this.$node = node;
} else {
this.node = node;
this.$node = $(node);
}
this.toString = Component.toString;
if (debug.enabled) {
this.describe = this.toString();
}
//merge defaults with supplied options
//put options in attr.__proto__ to avoid merge overhead
var attr = Object.create(options);
for (var key in this.defaults) {
if (!options.hasOwnProperty(key)) {
attr[key] = this.defaults[key];
}
}
this.attr = attr;
Object.keys(this.defaults || {}).forEach(function(key) {
if (this.defaults[key] === null && this.attr[key] === null) {
throw new Error('Required attribute "' + key + '" not specified in attachTo for component "' + this.toString() + '".');
}
}, this);
this.initialize.call(this, options);
}
Component.attachTo = attachTo;
Component.teardownAll = teardownAll;
......@@ -294,7 +103,7 @@ define(
if (debug.enabled) {
mixins.unshift(withLogging);
}
mixins.unshift(withBaseComponent, advice.withAdvice, registry.withRegistration);
mixins.unshift(withBase, advice.withAdvice, registry.withRegistration);
compose.mixin(Component.prototype, mixins);
return Component;
......
......@@ -10,7 +10,7 @@ define(
[
'./utils',
'../tools/debug/debug'
'./debug'
],
function(util, debug) {
......
"use strict";
define(
[
'../../lib/registry',
'../../lib/utils'
],
function(registry, utils) {
define([], function() {
var logFilter;
......
......@@ -207,7 +207,7 @@ define(
};
this.withRegistration = function() {
this.before('initialize', function() {
this.after('initialize', function() {
registry.addInstance(this);
});
......
// Karma configuration file
//
// For all available config options and default values, see:
// https://github.com/karma-runner/karma/blob/stable/lib/config.js#L54
module.exports = function (config) {
'use strict';
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
// loaded without require
'bower_components/es5-shim/es5-shim.js',
'bower_components/es5-shim/es5-sham.js',
'bower_components/jquery/jquery.js',
'bower_components/jasmine-flight/lib/jasmine-flight.js',
'bower_components/jasmine-jquery/lib/jasmine-jquery.js',
// hack to load RequireJS after the shim libs
'node_modules/karma-requirejs/lib/require.js',
'node_modules/karma-requirejs/lib/adapter.js',
// loaded with require
{ pattern: 'bower_components/flight/**/*.js', included: false },
{ pattern: 'bower_components/depot/**/*.js', included: false },
{ pattern: 'bower_components/requirejs-text/text.js', included: false },
{ pattern: 'app/**/*.js', included: false },
{ pattern: 'app/**/*.html', included: false },
{ pattern: 'test/spec/**/*_spec.js', included: false },
{ pattern: 'test/fixture/*.html', included: false },
// Entry point for karma.
'test/test-main.js',
{ pattern: 'test/mock/*.js', included: true }
],
// list of files to exclude
exclude: [],
// use dots reporter, as travis terminal does not support escaping sequences
// possible values: 'dots', 'progress'
// CLI --reporters progress
reporters: ['dots'],
// enable / disable watching file and executing tests whenever any file changes
// CLI --auto-watch --no-auto-watch
autoWatch: true,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
// CLI --browsers Chrome, Firefox, Safari
browsers: ['Chrome', 'Firefox'],
// If browser does not capture in given timeout [ms], kill it
// CLI --capture-timeout 5000
captureTimeout: 20000,
// Auto run tests on start (when browsers are captured) and exit
// CLI --single-run --no-single-run
singleRun: false,
plugins: [
'karma-jasmine',
'karma-requirejs',
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-ie-launcher',
'karma-phantomjs-launcher',
'karma-safari-launcher'
]
});
};
{
"name": "flight-todomvc",
"version": "0.0.0",
"devDependencies": {
"karma": "~0.10.1",
"karma-jasmine": "~0.1.0",
"karma-requirejs": "~0.1.0",
"karma-chrome-launcher": "~0.1.0",
"karma-ie-launcher": "~0.1.1",
"karma-firefox-launcher": "~0.1.0",
"karma-phantomjs-launcher": "~0.1.0",
"karma-safari-launcher": "~0.1.1"
},
"scripts": {
"test": "karma start --browsers Firefox --single-run"
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment