mirror of
https://github.com/pebble-dev/clay.git
synced 2026-08-30 05:46:57 -04:00
tests complete for ClayConfig and ClayItem
This commit is contained in:
+111
-80
@@ -30,90 +30,11 @@ var componentStore = require('./component-registry');
|
||||
function ClayConfig(settings, config, $rootContainer) {
|
||||
var self = this;
|
||||
|
||||
self.test = Math.random();
|
||||
|
||||
var _settings = _.copyObj(settings);
|
||||
var _items = [];
|
||||
var _itemsById = {};
|
||||
var _itemsByAppKey = {};
|
||||
|
||||
self.EVENTS = {
|
||||
/**
|
||||
* Called before framework has initialized. This is when you would attach your
|
||||
* custom components.
|
||||
* @const
|
||||
*/
|
||||
BEFORE_BUILD: 'BEFORE_BUILD',
|
||||
|
||||
/**
|
||||
* Called after the config has been parsed and all components have their initial value
|
||||
* set
|
||||
* @const
|
||||
*/
|
||||
AFTER_BUILD: 'AFTER_BUILD'
|
||||
};
|
||||
utils.updateProperties(self.EVENTS, {writable: false});
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {ClayItem}
|
||||
*/
|
||||
self.getItemByAppKey = function(key) {
|
||||
return _itemsByAppKey[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {ClayItem}
|
||||
*/
|
||||
self.getItemById = function(key) {
|
||||
return _itemsById[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {[ClayItem]}
|
||||
*/
|
||||
self.getItemsByType = function(type) {
|
||||
return _items.filter(function(item) {
|
||||
return item.config.type === type;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {object}
|
||||
*/
|
||||
self.getSettings = function() {
|
||||
_.eachObj(_itemsByAppKey, function(appKey, item) {
|
||||
_settings[appKey] = item.get();
|
||||
});
|
||||
return _settings;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a component to Clay. This must be called prior to .build();
|
||||
* @param {{}} component - the clay component to register
|
||||
* @param {string} component.name - the name of the component
|
||||
* @param {string} component.template - HTML template to use for the component
|
||||
* @param {{}} component.manipulator - methods to attach to the component
|
||||
* @param {function} component.manipulator.set - set manipulator method
|
||||
* @param {function} component.manipulator.get - get manipulator method
|
||||
* @param {{}} component.defaults - template defaults
|
||||
* @param {function} [component.initialize] - method to scaffold the component
|
||||
*/
|
||||
self.registerComponent = function(component) {
|
||||
componentStore[component.name] = component;
|
||||
};
|
||||
|
||||
self.build = function() {
|
||||
self.trigger(self.EVENTS.BEFORE_BUILD);
|
||||
// initialize the config
|
||||
_addItems(config, $rootContainer);
|
||||
self.trigger(self.EVENTS.AFTER_BUILD);
|
||||
};
|
||||
|
||||
// attach event methods
|
||||
ClayEvents.call(self, $rootContainer);
|
||||
var _isBuilt = false;
|
||||
|
||||
/**
|
||||
* Add item(s) to the config
|
||||
@@ -153,6 +74,116 @@ function ClayConfig(settings, config, $rootContainer) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} fnName
|
||||
* @private
|
||||
*/
|
||||
var _checkBuilt = function(fnName) {
|
||||
if (!_isBuilt) {
|
||||
throw new Error(
|
||||
'ClayConfig not built. build() must be run before ' +
|
||||
'you can run ' + fnName + '()'
|
||||
);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
self.EVENTS = {
|
||||
/**
|
||||
* Called before framework has initialized. This is when you would attach your
|
||||
* custom components.
|
||||
* @const
|
||||
*/
|
||||
BEFORE_BUILD: 'BEFORE_BUILD',
|
||||
|
||||
/**
|
||||
* Called after the config has been parsed and all components have their initial
|
||||
* value set
|
||||
* @const
|
||||
*/
|
||||
AFTER_BUILD: 'AFTER_BUILD'
|
||||
};
|
||||
utils.updateProperties(self.EVENTS, {writable: false});
|
||||
|
||||
/**
|
||||
* @returns {ClayItem}
|
||||
*/
|
||||
self.getAllItems = function() {
|
||||
_checkBuilt('getAllItems');
|
||||
return _items;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {ClayItem}
|
||||
*/
|
||||
self.getItemByAppKey = function(key) {
|
||||
_checkBuilt('getItemByAppKey');
|
||||
return _itemsByAppKey[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {ClayItem}
|
||||
*/
|
||||
self.getItemById = function(key) {
|
||||
_checkBuilt('getItemById');
|
||||
return _itemsById[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {[ClayItem]}
|
||||
*/
|
||||
self.getItemsByType = function(type) {
|
||||
_checkBuilt('getItemsByType');
|
||||
return _items.filter(function(item) {
|
||||
return item.config.type === type;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {object}
|
||||
*/
|
||||
self.getSettings = function() {
|
||||
_checkBuilt('getSettings');
|
||||
_.eachObj(_itemsByAppKey, function(appKey, item) {
|
||||
_settings[appKey] = item.get();
|
||||
});
|
||||
return _settings;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a component to Clay. This must be called prior to .build();
|
||||
* @param {{}} component - the clay component to register
|
||||
* @param {string} component.name - the name of the component
|
||||
* @param {string} component.template - HTML template to use for the component
|
||||
* @param {{}} component.manipulator - methods to attach to the component
|
||||
* @param {function} component.manipulator.set - set manipulator method
|
||||
* @param {function} component.manipulator.get - get manipulator method
|
||||
* @param {{}} component.defaults - template defaults
|
||||
* @param {function} [component.initialize] - method to scaffold the component
|
||||
*/
|
||||
self.registerComponent = function(component) {
|
||||
componentStore[component.name] = component;
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the config page. This must be run before any of the get methods can be run
|
||||
* @returns {ClayConfig}
|
||||
*/
|
||||
self.build = function() {
|
||||
self.trigger(self.EVENTS.BEFORE_BUILD);
|
||||
_addItems(config, $rootContainer);
|
||||
_isBuilt = true;
|
||||
self.trigger(self.EVENTS.AFTER_BUILD);
|
||||
return self;
|
||||
};
|
||||
|
||||
// attach event methods
|
||||
ClayEvents.call(self, $rootContainer);
|
||||
|
||||
// prevent external modifications of properties
|
||||
utils.updateProperties(self, { writable: false, configurable: false });
|
||||
|
||||
|
||||
@@ -15,6 +15,12 @@ function ClayItem(config) {
|
||||
var self = this;
|
||||
|
||||
var _itemType = componentRegistry[config.type];
|
||||
|
||||
if (!_itemType) {
|
||||
throw new Error('the component: ' + config.type + ' is not registered. ' +
|
||||
'Make sure to register it with ClayConfig.registerComponent()');
|
||||
}
|
||||
|
||||
var _templateData = _.extend({}, _itemType.defaults, config);
|
||||
|
||||
/** @type {string|null} */
|
||||
|
||||
+49
-14
@@ -1,19 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('../src/scripts/vendor/minified/minified')._;
|
||||
var $ = require('../src/scripts/vendor/minified/minified').$;
|
||||
var HTML = require('../src/scripts/vendor/minified/minified').HTML;
|
||||
var ClayItem = require('../src/scripts/lib/clay-item');
|
||||
var ClayConfig = require('../src/scripts/lib/clay-config');
|
||||
var idCounter = 0;
|
||||
|
||||
var componentRegistry = require('../src/scripts/lib/component-registry');
|
||||
|
||||
// add some components to the registry to test
|
||||
componentRegistry.text = require('../src/scripts/components/text');
|
||||
componentRegistry.input = require('../src/scripts/components/input');
|
||||
componentRegistry.toggle = require('../src/scripts/components/toggle');
|
||||
componentRegistry.footer = require('../src/scripts/components/footer');
|
||||
componentRegistry.select = require('../src/scripts/components/select');
|
||||
|
||||
/**
|
||||
* @param {string} type
|
||||
* @param {{}} [config]
|
||||
* @param {string|{}} config
|
||||
* @returns {{}}
|
||||
*/
|
||||
function configItem(type, config) {
|
||||
module.exports.configItem = function(config) {
|
||||
if (typeof config === 'string') {
|
||||
config = { type: config };
|
||||
}
|
||||
|
||||
var basic = {
|
||||
type: type,
|
||||
label: type + '-label',
|
||||
label: config.type + '-label',
|
||||
appKey: 'appKey-' + idCounter,
|
||||
id: 'id-' + idCounter
|
||||
};
|
||||
@@ -21,17 +34,39 @@ function configItem(type, config) {
|
||||
idCounter++;
|
||||
|
||||
return _.extend({}, basic, config);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} type
|
||||
* @param {{}} [config]
|
||||
* @param {string|{}} [config]
|
||||
* @returns {ClayItem}
|
||||
*/
|
||||
function clayItem(type, config) {
|
||||
return new ClayItem(configItem(type, config));
|
||||
}
|
||||
module.exports.clayItem = function(config) {
|
||||
return new ClayItem(module.exports.configItem(config));
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {[]} types
|
||||
* @returns {*}
|
||||
*/
|
||||
module.exports.config = function(types) {
|
||||
return types.map(function(item) {
|
||||
return Array.isArray(item) ?
|
||||
{type: 'section', items: module.exports.config(item)} :
|
||||
module.exports.configItem(item);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {[]} types
|
||||
* @param {boolean} [noBuild=false] - don't run the build method on the result
|
||||
* @param {{}} [settings] - settings to pass to constructor
|
||||
* @returns {ClayConfig}
|
||||
*/
|
||||
module.exports.clayConfig = function(types, noBuild, settings) {
|
||||
var clayConfig = new ClayConfig(
|
||||
settings || {},
|
||||
module.exports.config(types), $(HTML('<div>'))
|
||||
);
|
||||
return noBuild ? clayConfig : clayConfig.build();
|
||||
};
|
||||
|
||||
module.exports.configItem = configItem;
|
||||
module.exports.clayItem = clayItem;
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
'use strict';
|
||||
|
||||
var assert = require('chai').assert;
|
||||
var sinon = require('sinon');
|
||||
var textComponent = require('../../../src/scripts/components/text');
|
||||
var componentRegistry = require('../../../src/scripts/lib/component-registry');
|
||||
var checkReadOnly = require('../../test-utils').checkReadOnly;
|
||||
var fixtures = require('../../fixture');
|
||||
|
||||
describe('ClayConfig', function() {
|
||||
it('defines read-only properties', function() {
|
||||
var properties = [
|
||||
'EVENTS',
|
||||
'getItemByAppKey',
|
||||
'getItemById',
|
||||
'getItemsByType',
|
||||
'getSettings',
|
||||
'registerComponent',
|
||||
'build',
|
||||
'on',
|
||||
'one',
|
||||
'off',
|
||||
'trigger'
|
||||
];
|
||||
var clayConfig = fixtures.clayConfig(['input']);
|
||||
checkReadOnly(clayConfig, properties);
|
||||
});
|
||||
|
||||
describe('throws when trying to run methods before being built', function() {
|
||||
[
|
||||
'getItemByAppKey',
|
||||
'getItemById',
|
||||
'getItemsByType',
|
||||
'getSettings'
|
||||
].forEach(function(method) {
|
||||
it('.' + method + '()', function() {
|
||||
var clayConfig = fixtures.clayConfig(['input', 'text'], true);
|
||||
assert.throws(clayConfig[method], new RegExp(method));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getAllItems()', function() {
|
||||
it('returns an array of all the items', function() {
|
||||
var config = fixtures.config(['input', 'text', ['input']]);
|
||||
var clayConfig = fixtures.clayConfig(config);
|
||||
var allItems = clayConfig.getAllItems();
|
||||
assert.strictEqual(allItems.length, 3);
|
||||
assert.deepEqual(allItems[0].config, config[0]);
|
||||
assert.deepEqual(allItems[1].config, config[1]);
|
||||
assert.deepEqual(allItems[2].config, config[2].items[0]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getItemByAppKey()', function() {
|
||||
it('it returns the correct item', function() {
|
||||
var config = fixtures.config([
|
||||
{type: 'input', appKey: 'test-app-key'},
|
||||
{type: 'input', appKey: undefined}
|
||||
]);
|
||||
var clayConfig = fixtures.clayConfig(config);
|
||||
assert.deepEqual(clayConfig.getItemByAppKey('test-app-key').config, config[0]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getItemById()', function() {
|
||||
it('it returns the correct item', function() {
|
||||
var config = fixtures.config([
|
||||
{type: 'input', id: 'test-id'},
|
||||
{type: 'input', id: undefined}
|
||||
]);
|
||||
var clayConfig = fixtures.clayConfig(config);
|
||||
assert.deepEqual(clayConfig.getItemById('test-id').config, config[0]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getItemsByType()', function() {
|
||||
it('it returns the correct items', function() {
|
||||
var config = fixtures.config(['input', 'text', 'input']);
|
||||
var clayConfig = fixtures.clayConfig(config);
|
||||
assert.deepEqual(clayConfig.getItemsByType('input')[0].config, config[0]);
|
||||
assert.deepEqual(clayConfig.getItemsByType('input')[1].config, config[2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getSettings()', function() {
|
||||
it('returns the correct settings', function() {
|
||||
var clayConfig = fixtures.clayConfig(
|
||||
[
|
||||
{type: 'input', appKey: 'test1', value: 'not this'},
|
||||
{type: 'select', appKey: 'test2', options: [
|
||||
{label: 'label-1', value: 'val-1'},
|
||||
{label: 'label-2', value: 'val-2'}
|
||||
]},
|
||||
{type: 'toggle', appKey: 'test3'}
|
||||
],
|
||||
false,
|
||||
{
|
||||
test1: 'val-1' // set one of the values via settings
|
||||
}
|
||||
);
|
||||
|
||||
clayConfig.getItemByAppKey('test2').set('val-2');
|
||||
clayConfig.getItemByAppKey('test3').set(true);
|
||||
|
||||
assert.deepEqual(clayConfig.getSettings(), {
|
||||
test1: 'val-1',
|
||||
test2: 'val-2',
|
||||
test3: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.registerComponent()', function() {
|
||||
it('adds the component to the registry', function(done) {
|
||||
delete componentRegistry.text;
|
||||
assert.typeOf(componentRegistry.text, 'undefined');
|
||||
var clayConfig = fixtures.clayConfig(['text'], true);
|
||||
|
||||
clayConfig.on(clayConfig.EVENTS.BEFORE_BUILD, function() {
|
||||
clayConfig.registerComponent(textComponent);
|
||||
});
|
||||
|
||||
clayConfig.on(clayConfig.EVENTS.AFTER_BUILD, function() {
|
||||
assert.strictEqual(this.getAllItems()[0].config.type, 'text');
|
||||
done();
|
||||
});
|
||||
|
||||
clayConfig.build();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.build()', function() {
|
||||
it('dispatches the BEFORE_BUILD event at the right time', function(done) {
|
||||
var clayConfig = fixtures.clayConfig(['input', 'text', 'input'], true);
|
||||
clayConfig.on(clayConfig.EVENTS.BEFORE_BUILD, function() {
|
||||
|
||||
// this should throw because the config has not been built yet
|
||||
assert.throws(clayConfig.getAllItems);
|
||||
done();
|
||||
});
|
||||
clayConfig.build();
|
||||
});
|
||||
|
||||
it('dispatches the AFTER_BUILD event at the right time', function(done) {
|
||||
var clayConfig = fixtures.clayConfig(['input', 'text', 'input'], true);
|
||||
clayConfig.on(clayConfig.EVENTS.AFTER_BUILD, function() {
|
||||
|
||||
// this should not throw because the config has been built
|
||||
assert.doesNotThrow(clayConfig.getAllItems);
|
||||
done();
|
||||
});
|
||||
clayConfig.build();
|
||||
});
|
||||
});
|
||||
});
|
||||
+10
-22
@@ -2,31 +2,12 @@
|
||||
|
||||
var assert = require('chai').assert;
|
||||
var sinon = require('sinon');
|
||||
var checkReadOnly = require('../../test-utils').checkReadOnly;
|
||||
var ClayItem = require('../../../src/scripts/lib/clay-item');
|
||||
var clayItemFixture = require('../../fixture').clayItem;
|
||||
var configItemFixture = require('../../fixture').configItem;
|
||||
var componentRegistry = require('../../../src/scripts/lib/component-registry');
|
||||
|
||||
// add some components to the registry to test
|
||||
componentRegistry.text = require('../../../src/scripts/components/text');
|
||||
componentRegistry.input = require('../../../src/scripts/components/input');
|
||||
componentRegistry.toggle = require('../../../src/scripts/components/toggle');
|
||||
componentRegistry.footer = require('../../../src/scripts/components/footer');
|
||||
componentRegistry.select = require('../../../src/scripts/components/select');
|
||||
|
||||
/**
|
||||
* @param {Object} object
|
||||
* @param {Array} properties
|
||||
*/
|
||||
function checkReadOnly(object, properties) {
|
||||
properties.forEach(function(property) {
|
||||
assert.strictEqual(
|
||||
Object.getOwnPropertyDescriptor(object, property).writable,
|
||||
false
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
describe('ClayItem', function() {
|
||||
it('defines read-only properties', function() {
|
||||
var properties = [
|
||||
@@ -53,6 +34,13 @@ describe('ClayItem', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('throws if a component is not in the registry', function() {
|
||||
var config = configItemFixture('fake');
|
||||
/* eslint-disable no-new */
|
||||
assert.throws(function() { new ClayItem(config); }, /fake/);
|
||||
/* eslint-enable no-new */
|
||||
});
|
||||
|
||||
describe('.id', function() {
|
||||
it('sets id if config has id', function() {
|
||||
var config = configItemFixture('input');
|
||||
@@ -61,7 +49,7 @@ describe('ClayItem', function() {
|
||||
});
|
||||
|
||||
it('sets id to null if there is no id in the config', function() {
|
||||
var clayItem = clayItemFixture('input', {id: undefined});
|
||||
var clayItem = clayItemFixture({type: 'input', id: undefined});
|
||||
assert.strictEqual(clayItem.id, null);
|
||||
});
|
||||
});
|
||||
@@ -74,7 +62,7 @@ describe('ClayItem', function() {
|
||||
});
|
||||
|
||||
it('sets appKey to null if there is no appKey in the config', function() {
|
||||
var clayItem = clayItemFixture('input', {appKey: undefined});
|
||||
var clayItem = clayItemFixture({type: 'input', appKey: undefined});
|
||||
assert.strictEqual(clayItem.appKey, null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
var assert = require('chai').assert;
|
||||
|
||||
/**
|
||||
* @param {Object} object
|
||||
* @param {Array} properties
|
||||
*/
|
||||
module.exports.checkReadOnly = function(object, properties) {
|
||||
properties.forEach(function(property) {
|
||||
assert.strictEqual(
|
||||
Object.getOwnPropertyDescriptor(object, property).writable,
|
||||
false
|
||||
);
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user