[Core] Add specs for action support

Add specs for core components for dealing with actions;
part of ongoing platform/core transition, WTD-573.
This commit is contained in:
Victor Woeltjen 2014-11-21 13:26:02 -08:00
parent 41ecb1f8c2
commit 342832a4bc
6 changed files with 252 additions and 4 deletions

View File

@ -32,7 +32,7 @@ define(
// declarative bindings, as well as context, // declarative bindings, as well as context,
// unless the action has defined its own. // unless the action has defined its own.
if (!action.getMetadata) { if (!action.getMetadata) {
metadata = Object.create(Action.definition); metadata = Object.create(Action.definition || {});
metadata.context = context; metadata.context = context;
action.getMetadata = function () { action.getMetadata = function () {
return metadata; return metadata;

View File

@ -20,13 +20,14 @@ define(
// it emits a log message whenever performed. // it emits a log message whenever performed.
function addLogging(action) { function addLogging(action) {
var logAction = Object.create(action), var logAction = Object.create(action),
domainObject = metadata = action.getMetadata() || {},
action.getMetadata().context.domainObject; context = metadata.context || {},
domainObject = context.domainObject;
logAction.perform = function () { logAction.perform = function () {
$log.info([ $log.info([
"Performing action ", "Performing action ",
action.getMetadata().key, metadata.key,
" upon ", " upon ",
domainObject && domainObject.getId() domainObject && domainObject.getId()
].join("")); ].join(""));

View File

@ -9,7 +9,45 @@ define(
"use strict"; "use strict";
describe("Action aggregator", function () { describe("Action aggregator", function () {
var mockAggregators,
aggregator;
function createMockActionProvider(actions, i) {
var spy = jasmine.createSpyObj("agg" + i, [ "getActions" ]);
spy.getActions.andReturn(actions);
return spy;
}
beforeEach(function () {
mockAggregators = [
["a", "b"],
["c"],
["d", "e", "f"]
].map(createMockActionProvider);
aggregator = new ActionAggregator(mockAggregators);
});
it("consolidates results from aggregated services", function () {
expect(aggregator.getActions()).toEqual(
["a", "b", "c", "d", "e", "f"]
);
});
it("passes context along to all aggregated services", function () {
var context = { domainObject: "something" };
// Verify precondition
mockAggregators.forEach(function (mockAgg) {
expect(mockAgg.getActions).not.toHaveBeenCalled();
});
aggregator.getActions(context);
// All services should have been called with this context
mockAggregators.forEach(function (mockAgg) {
expect(mockAgg.getActions).toHaveBeenCalledWith(context);
});
});
}); });
} }
); );

View File

@ -9,6 +9,70 @@ define(
"use strict"; "use strict";
describe("The action capability", function () { describe("The action capability", function () {
var mockQ,
mockAction,
mockActionService,
mockDomainObject,
capability;
beforeEach(function () {
mockAction = jasmine.createSpyObj(
"action",
[ "perform", "getMetadata" ]
);
mockActionService = jasmine.createSpyObj(
"actionService",
[ "getActions" ]
);
mockQ = jasmine.createSpyObj(
"$q",
[ "when" ]
);
mockDomainObject = jasmine.createSpyObj(
"domainObject",
[ "getId", "getModel", "getCapability", "hasCapability", "useCapability" ]
);
mockActionService.getActions.andReturn([mockAction, {}]);
capability = new ActionCapability(
mockQ,
mockActionService,
mockDomainObject
);
});
it("retrieves action for domain objects from the action service", function () {
// Verify precondition
expect(mockActionService.getActions).not.toHaveBeenCalled();
// Call getActions
expect(capability.getActions("some key")).toEqual([mockAction, {}]);
// Verify interaction
expect(mockActionService.getActions).toHaveBeenCalledWith({
key: "some key",
domainObject: mockDomainObject
});
});
it("promises the result of performed actions", function () {
var mockPromise = jasmine.createSpyObj("promise", [ "then" ]);
mockQ.when.andReturn(mockPromise);
mockAction.perform.andReturn("the action's result");
// Verify precondition
expect(mockAction.perform).not.toHaveBeenCalled();
// Perform via capability
expect(capability.perform()).toEqual(mockPromise);
// Verify that the action's result is what was wrapped
expect(mockQ.when).toHaveBeenCalledWith("the action's result");
});
}); });
} }

View File

@ -9,6 +9,112 @@ define(
"use strict"; "use strict";
describe("The action provider", function () { describe("The action provider", function () {
var actions,
actionProvider;
function SimpleAction() {
return { perform: function () { return "simple"; } };
}
function CategorizedAction() {
return { perform: function () { return "categorized"; } };
}
CategorizedAction.category = "someCategory";
function KeyedAction() {
return { perform: function () { return "keyed"; } };
}
KeyedAction.key = "someKey";
function CategorizedKeyedAction() {
return { perform: function () { return "both"; } };
}
CategorizedKeyedAction.key = "someKey";
CategorizedKeyedAction.category = "someCategory";
function MetadataAction() {
return {
perform: function () { return "metadata"; },
getMetadata: function () { return "custom metadata"; }
};
}
MetadataAction.key = "metadata";
beforeEach(function () {
actions = [
SimpleAction,
CategorizedAction,
KeyedAction,
CategorizedKeyedAction,
MetadataAction
];
actionProvider = new ActionProvider(actions);
});
it("exposes provided action extensions", function () {
var provided = actionProvider.getActions();
// Should have gotten all actions
expect(provided.length).toEqual(actions.length);
// Verify that this was the action we expected
expect(provided[0].perform()).toEqual("simple");
});
it("matches provided actions by key", function () {
var provided = actionProvider.getActions({ key: "someKey" });
// Only two should have matched
expect(provided.length).toEqual(2);
// Verify that this was the action we expected
expect(provided[0].perform()).toEqual("keyed");
});
it("matches provided actions by category", function () {
var provided = actionProvider.getActions({ category: "someCategory" });
// Only two should have matched
expect(provided.length).toEqual(2);
// Verify that this was the action we expected
expect(provided[0].perform()).toEqual("categorized");
});
it("matches provided actions by both category and key", function () {
var provided = actionProvider.getActions({
category: "someCategory",
key: "someKey"
});
// Only two should have matched
expect(provided.length).toEqual(1);
// Verify that this was the action we expected
expect(provided[0].perform()).toEqual("both");
});
it("adds a getMetadata method when none is defined", function () {
var provided = actionProvider.getActions({
category: "someCategory",
key: "someKey"
});
// Should be defined, even though the action didn't define this
expect(provided[0].getMetadata).toBeDefined();
// Should have static fields, plus context
expect(provided[0].getMetadata().context).toEqual({
key: "someKey",
category: "someCategory"
});
});
it("does not override defined getMetadata methods", function () {
var provided = actionProvider.getActions({ key: "metadata" });
expect(provided[0].getMetadata()).toEqual("custom metadata");
});
}); });
} }

View File

@ -9,6 +9,45 @@ define(
"use strict"; "use strict";
describe("The logging action decorator", function () { describe("The logging action decorator", function () {
var mockLog,
mockAction,
mockActionService,
decorator;
beforeEach(function () {
mockAction = jasmine.createSpyObj(
"action",
[ "perform", "getMetadata" ]
);
mockActionService = jasmine.createSpyObj(
"actionService",
[ "getActions" ]
);
mockLog = jasmine.createSpyObj(
"$log",
[ "error", "warn", "info", "debug" ]
);
mockActionService.getActions.andReturn([mockAction]);
decorator = new LoggingActionDecorator(
mockLog,
mockActionService
);
});
it("logs when actions are performed", function () {
// Verify precondition
expect(mockLog.info).not.toHaveBeenCalled();
// Perform an action, retrieved through the decorator
decorator.getActions()[0].perform();
// That should have been logged.
expect(mockLog.info).toHaveBeenCalled();
});
}); });
} }