[Core] Complete spec for capailities

Complete specs for capabilities introduced in platform/core,
part of ongoing transition of this bundle. WTD-573.
This commit is contained in:
Victor Woeltjen 2014-11-21 16:59:03 -08:00
parent 2b82262775
commit 99f9203e71
7 changed files with 214 additions and 7 deletions

View File

@ -14,7 +14,7 @@
"provides": "capabilityService", "provides": "capabilityService",
"type": "provider", "type": "provider",
"implementation": "capabilities/CoreCapabilityProvider.js", "implementation": "capabilities/CoreCapabilityProvider.js",
"depends": [ "capabilities[]" ] "depends": [ "capabilities[]", "$log" ]
}, },
{ {
"provides": "modelService", "provides": "modelService",
@ -131,7 +131,8 @@
}, },
{ {
"key": "delegation", "key": "delegation",
"implementation": "capabilities/DelegationCapability.js" "implementation": "capabilities/DelegationCapability.js",
"depends": [ "$q" ]
} }
], ],
"roots": [ "roots": [

View File

@ -18,7 +18,7 @@ define(
* *
* @constructor * @constructor
*/ */
function CoreCapabilityProvider(capabilities) { function CoreCapabilityProvider(capabilities, $log) {
// Filter by invoking the capability's appliesTo method // Filter by invoking the capability's appliesTo method
function filterCapabilities(model) { function filterCapabilities(model) {
return capabilities.filter(function (capability) { return capabilities.filter(function (capability) {
@ -32,7 +32,11 @@ define(
function packageCapabilities(capabilities) { function packageCapabilities(capabilities) {
var result = {}; var result = {};
capabilities.forEach(function (capability) { capabilities.forEach(function (capability) {
if (capability.key) {
result[capability.key] = capability; result[capability.key] = capability;
} else {
$log.warn("No key defined for capability; skipping.");
}
}); });
return result; return result;
} }

View File

@ -1,4 +1,4 @@
/*global define,Promise*/ /*global define*/
/** /**
* Module defining DelegationCapability. Created by vwoeltje on 11/18/14. * Module defining DelegationCapability. Created by vwoeltje on 11/18/14.
@ -27,7 +27,7 @@ define(
* @param domainObject * @param domainObject
* @constructor * @constructor
*/ */
function DelegationCapability(domainObject) { function DelegationCapability($q, domainObject) {
var delegateCapabilities = {}, var delegateCapabilities = {},
type = domainObject.getCapability("type"); type = domainObject.getCapability("type");
@ -52,7 +52,7 @@ define(
promiseChildren().then( promiseChildren().then(
filterObjectsWithCapability(capability) filterObjectsWithCapability(capability)
) : ) :
[]; $q.when([]);
} }
// Generate set for easy lookup of capability delegation // Generate set for easy lookup of capability delegation

View File

@ -9,6 +9,62 @@ define(
"use strict"; "use strict";
describe("The core capability provider", function () { describe("The core capability provider", function () {
var mockLog,
provider;
function BasicCapability() { return; }
BasicCapability.key = "basic";
function ApplicableCapability() { return; }
ApplicableCapability.key = "applicable";
ApplicableCapability.appliesTo = function (model) {
return !model.isNotApplicable;
};
function KeylessCapability() { return; }
beforeEach(function () {
mockLog = jasmine.createSpyObj(
"$log",
["error", "warn", "info", "debug"]
);
provider = new CoreCapabilityProvider([
BasicCapability,
ApplicableCapability,
KeylessCapability
], mockLog);
});
it("returns capabilities for models, from extensions", function () {
expect(provider.getCapabilities({})).toEqual({
basic: BasicCapability,
applicable: ApplicableCapability
});
});
it("filters out capabilities which do not apply to models", function () {
expect(provider.getCapabilities({ isNotApplicable: true })).toEqual({
basic: BasicCapability
});
});
it("logs a warning when capability extensions have not defined keys", function () {
// Verify precondition
expect(mockLog.warn).not.toHaveBeenCalled();
provider.getCapabilities({});
expect(mockLog.warn).toHaveBeenCalled();
});
it("does not log a warning when all capability extensions are valid", function () {
KeylessCapability.key = "someKey";
provider.getCapabilities({});
expect(mockLog.warn).not.toHaveBeenCalled();
});
}); });
} }

View File

@ -9,7 +9,71 @@ define(
"use strict"; "use strict";
describe("The delegation capability", function () { describe("The delegation capability", function () {
var captured,
typeDef = {},
type,
capabilities,
children = [],
object = {},
delegation;
function capture(k) { return function (v) { captured[k] = v; }; }
function TestDomainObject(caps, id) {
return {
getId: function () {
return id;
},
getCapability: function (name) {
return caps[name];
},
useCapability: function (name) {
return this.getCapability(name).invoke();
},
hasCapability: function (name) {
return this.getCapability(name) !== undefined;
}
};
}
function mockPromise(value) {
return {
then: function (callback) {
return value.then ?
value : mockPromise(callback(value));
}
};
}
beforeEach(function () {
captured = {};
typeDef = {};
typeDef.delegates = [ "foo" ];
type = { getDefinition: function () { return typeDef; } };
children = [];
capabilities = {
type: type,
composition: { invoke: function () { return mockPromise(children); } }
};
object = new TestDomainObject(capabilities);
delegation = new DelegationCapability({ when: mockPromise }, object);
});
it("provides a list of children which expose a desired capability", function () {
children = [
new TestDomainObject({ foo: true }, 'has-capability'),
new TestDomainObject({ }, 'does-not-have-capability')
];
// Look up delegates
delegation.getDelegates('foo').then(capture('delegates'));
// Expect only the first child to be a delegate
expect(captured.delegates.length).toEqual(1);
expect(captured.delegates[0].getId()).toEqual('has-capability');
});
}); });
} }
); );

View File

@ -9,7 +9,50 @@ define(
"use strict"; "use strict";
describe("The mutation capability", function () { describe("The mutation capability", function () {
var testModel,
domainObject = { getModel: function () { return testModel; } },
mutation;
function mockPromise(value) {
return {
then: function (callback) {
return (value && value.then) ?
value : mockPromise(callback(value));
}
};
}
beforeEach(function () {
testModel = { number: 6 };
mutation = new MutationCapability(
{ when: mockPromise }, // $q
domainObject
);
});
it("allows mutation of a model", function () {
mutation.invoke(function (m) {
m.number = m.number * 7;
});
expect(testModel.number).toEqual(42);
});
it("allows setting a model", function () {
mutation.invoke(function (m) {
return { someKey: "some value" };
});
expect(testModel.number).toBeUndefined();
expect(testModel.someKey).toEqual("some value");
});
it("allows model mutation to be aborted", function () {
mutation.invoke(function (m) {
m.number = m.number * 7;
return false; // Should abort change
});
// Number should not have been changed
expect(testModel.number).toEqual(6);
});
}); });
} }
); );

View File

@ -9,6 +9,45 @@ define(
"use strict"; "use strict";
describe("The persistence capability", function () { describe("The persistence capability", function () {
var mockPersistenceService,
mockDomainObject,
id = "object id",
model = { someKey: "some value"},
SPACE = "some space",
persistence;
beforeEach(function () {
mockPersistenceService = jasmine.createSpyObj(
"persistenceService",
[ "updateObject" ]
);
mockDomainObject = {
getId: function () { return id; },
getModel: function () { return model; }
};
persistence = new PersistenceCapability(
mockPersistenceService,
SPACE,
mockDomainObject
);
});
it("makes a call to the persistence service when invoked", function () {
// Verify precondition; no call made during constructor
expect(mockPersistenceService.updateObject).not.toHaveBeenCalled();
persistence.persist();
expect(mockPersistenceService.updateObject).toHaveBeenCalledWith(
SPACE,
id,
model
);
});
it("reports which persistence space an object belongs to", function () {
expect(persistence.getSpace()).toEqual(SPACE);
});
}); });
} }