[Edit] Add tests for updated capabilities

Add tests for capabilities which have been updated to work
when only a model (and not whole objects) are cached; that
change was introduced to prevent misbehavior of the Remove
action in Edit mode, WTD-473.
This commit is contained in:
Victor Woeltjen 2015-01-27 12:18:28 -08:00
parent 3135174491
commit be34e7fa9a
7 changed files with 190 additions and 46 deletions

View File

@ -89,7 +89,7 @@ define(
}
// Wrap all methods; return only editable domain objects.
Object.keys(contextCapability).forEach(wrapFunction);
Object.keys(contextCapability).forEach(wrapMethod);
return capability;
};

View File

@ -13,12 +13,14 @@ define(
[
'../capabilities/EditablePersistenceCapability',
'../capabilities/EditableContextCapability',
'../capabilities/EditableCompositionCapability',
'../capabilities/EditorCapability',
'./EditableDomainObjectCache'
],
function (
EditablePersistenceCapability,
EditableContextCapability,
EditableCompositionCapability,
EditorCapability,
EditableDomainObjectCache
) {
@ -27,7 +29,7 @@ define(
var capabilityFactories = {
persistence: EditablePersistenceCapability,
context: EditableContextCapability,
composition: EditableContextCapability,
composition: EditableCompositionCapability,
editor: EditorCapability
};

View File

@ -0,0 +1,54 @@
/*global define,describe,it,expect,beforeEach,jasmine*/
define(
["../../src/capabilities/EditableCompositionCapability"],
function (EditableCompositionCapability) {
"use strict";
describe("An editable composition capability", function () {
var mockContext,
mockEditableObject,
mockDomainObject,
mockTestObject,
someValue,
mockFactory,
capability;
beforeEach(function () {
// EditableContextCapability should watch ALL
// methods for domain objects, so give it an
// arbitrary interface to wrap.
mockContext =
jasmine.createSpyObj("context", [ "getDomainObject" ]);
mockTestObject = jasmine.createSpyObj(
"domainObject",
[ "getId", "getModel", "getCapability" ]
);
mockFactory =
jasmine.createSpyObj("factory", ["getEditableObject"]);
someValue = { x: 42 };
mockContext.getDomainObject.andReturn(mockTestObject);
mockFactory.getEditableObject.andReturn(someValue);
capability = new EditableCompositionCapability(
mockContext,
mockEditableObject,
mockDomainObject,
mockFactory
);
});
// Most behavior is tested for EditableLookupCapability,
// so just verify that this isse
it("presumes non-idempotence of its wrapped capability", function () {
expect(capability.getDomainObject())
.toEqual(capability.getDomainObject());
expect(mockContext.getDomainObject.calls.length).toEqual(2);
});
});
}
);

View File

@ -11,63 +11,40 @@ define(
mockDomainObject,
mockTestObject,
someValue,
factory,
mockFactory,
capability;
beforeEach(function () {
// EditableContextCapability should watch ALL
// methods for domain objects, so give it an
// arbitrary interface to wrap.
mockContext = jasmine.createSpyObj(
"context",
[
"getSomething",
"getDomainObject",
"getDomainObjectArray"
]
);
mockContext =
jasmine.createSpyObj("context", [ "getDomainObject" ]);
mockTestObject = jasmine.createSpyObj(
"domainObject",
[ "getId", "getModel", "getCapability" ]
);
factory = {
getEditableObject: function (v) {
return {
isFromTestFactory: true,
calledWith: v
};
}
};
mockFactory =
jasmine.createSpyObj("factory", ["getEditableObject"]);
someValue = { x: 42 };
mockContext.getSomething.andReturn(someValue);
mockContext.getDomainObject.andReturn(mockTestObject);
mockContext.getDomainObjectArray.andReturn([mockTestObject]);
mockFactory.getEditableObject.andReturn(someValue);
capability = new EditableContextCapability(
mockContext,
mockEditableObject,
mockDomainObject,
factory
mockFactory
);
});
it("wraps retrieved domain objects", function () {
var object = capability.getDomainObject();
expect(object.isFromTestFactory).toBe(true);
expect(object.calledWith).toEqual(mockTestObject);
});
it("wraps retrieved domain object arrays", function () {
var object = capability.getDomainObjectArray()[0];
expect(object.isFromTestFactory).toBe(true);
expect(object.calledWith).toEqual(mockTestObject);
});
it("does not wrap non-domain-objects", function () {
expect(capability.getSomething()).toEqual(someValue);
it("presumes idempotence of its wrapped capability", function () {
expect(capability.getDomainObject())
.toEqual(capability.getDomainObject());
expect(mockContext.getDomainObject.calls.length).toEqual(1);
});
});

View File

@ -0,0 +1,102 @@
/*global define,describe,it,expect,beforeEach,jasmine*/
define(
["../../src/capabilities/EditableLookupCapability"],
function (EditableLookupCapability) {
"use strict";
describe("An editable lookup capability", function () {
var mockContext,
mockEditableObject,
mockDomainObject,
mockTestObject,
someValue,
factory,
capability;
beforeEach(function () {
// EditableContextCapability should watch ALL
// methods for domain objects, so give it an
// arbitrary interface to wrap.
mockContext = jasmine.createSpyObj(
"context",
[
"getSomething",
"getDomainObject",
"getDomainObjectArray"
]
);
mockTestObject = jasmine.createSpyObj(
"domainObject",
[ "getId", "getModel", "getCapability" ]
);
factory = {
getEditableObject: function (v) {
return {
isFromTestFactory: true,
calledWith: v
};
}
};
someValue = { x: 42 };
mockContext.getSomething.andReturn(someValue);
mockContext.getDomainObject.andReturn(mockTestObject);
mockContext.getDomainObjectArray.andReturn([mockTestObject]);
capability = new EditableLookupCapability(
mockContext,
mockEditableObject,
mockDomainObject,
factory,
false
);
});
it("wraps retrieved domain objects", function () {
var object = capability.getDomainObject();
expect(object.isFromTestFactory).toBe(true);
expect(object.calledWith).toEqual(mockTestObject);
});
it("wraps retrieved domain object arrays", function () {
var object = capability.getDomainObjectArray()[0];
expect(object.isFromTestFactory).toBe(true);
expect(object.calledWith).toEqual(mockTestObject);
});
it("does not wrap non-domain-objects", function () {
expect(capability.getSomething()).toEqual(someValue);
});
it("caches idempotent lookups", function () {
capability = new EditableLookupCapability(
mockContext,
mockEditableObject,
mockDomainObject,
factory,
true // idempotent
);
expect(capability.getDomainObject())
.toEqual(capability.getDomainObject());
expect(mockContext.getDomainObject.calls.length).toEqual(1);
});
it("does not cache non-idempotent lookups", function () {
capability = new EditableLookupCapability(
mockContext,
mockEditableObject,
mockDomainObject,
factory,
false // Not idempotent
);
expect(capability.getDomainObject())
.toEqual(capability.getDomainObject());
expect(mockContext.getDomainObject.calls.length).toEqual(2);
});
});
}
);

View File

@ -24,9 +24,10 @@ define(
};
}
function WrapObject(domainObject) {
function WrapObject(domainObject, model) {
var result = Object.create(domainObject);
result.wrapped = true;
result.wrappedModel = model;
captured.wraps = (captured.wraps || 0) + 1;
return result;
}
@ -49,24 +50,30 @@ define(
expect(wrappedObject.getId()).toEqual(domainObject.getId());
});
it("only wraps objects once", function () {
it("wraps objects repeatedly, wraps models once", function () {
var domainObject = new TestObject('test-id'),
wrappedObject;
wrappedObjects = [];
// Verify precondition
expect(captured.wraps).toBeUndefined();
// Invoke a few more times; expect count not to increment
wrappedObject = cache.getEditableObject(domainObject);
expect(captured.wraps).toEqual(1);
wrappedObject = cache.getEditableObject(domainObject);
expect(captured.wraps).toEqual(1);
wrappedObject = cache.getEditableObject(domainObject);
wrappedObjects.push(cache.getEditableObject(domainObject));
expect(captured.wraps).toEqual(1);
wrappedObjects.push(cache.getEditableObject(domainObject));
expect(captured.wraps).toEqual(2);
wrappedObjects.push(cache.getEditableObject(domainObject));
expect(captured.wraps).toEqual(3);
// Verify that the last call still gave us a wrapped object
expect(wrappedObject.wrapped).toBeTruthy();
expect(wrappedObject.getId()).toEqual(domainObject.getId());
expect(wrappedObjects[0].wrapped).toBeTruthy();
expect(wrappedObjects[0].getId()).toEqual(domainObject.getId());
// Verify that objects are distinct but models are identical
expect(wrappedObjects[0].wrappedModel)
.toBe(wrappedObjects[1].wrappedModel);
expect(wrappedObjects[0]).not
.toBe(wrappedObjects[1]);
});
it("saves objects that have been marked dirty", function () {

View File

@ -8,7 +8,9 @@
"actions/PropertiesDialog",
"actions/RemoveAction",
"actions/SaveAction",
"capabilities/EditableCompositionCapability",
"capabilities/EditableContextCapability",
"capabilities/EditableLookupCapability",
"capabilities/EditablePersistenceCapability",
"capabilities/EditorCapability",
"objects/EditableDomainObject",