diff --git a/platform/commonUI/edit/src/EditRepresenter.js b/platform/commonUI/edit/src/EditRepresenter.js index 9db1327b1d..c08832dc17 100644 --- a/platform/commonUI/edit/src/EditRepresenter.js +++ b/platform/commonUI/edit/src/EditRepresenter.js @@ -5,17 +5,15 @@ define( function () { "use strict"; - function EditRepresenter($q, scope, element, attrs) { + function EditRepresenter($q, scope) { var watches = [], domainObject, key; function doPersist(model) { - return $q.when(function () { - return domainObject.useCapability("mutation", function () { - return model; - }); - }).then(function (result) { + return $q.when(domainObject.useCapability("mutation", function () { + return model; + })).then(function (result) { return result && domainObject.getCapability("persistence").persist(); }); @@ -23,12 +21,13 @@ define( function update() { var model = scope.model, - configuration = scope.configuration, - key = scope.key; + configuration = scope.configuration; if (domainObject && domainObject.hasCapability("persistence")) { - model.configuration = model.configuration || {}; - model.configuration[key] = configuration; + if (key && configuration) { + model.configuration = model.configuration || {}; + model.configuration[key] = configuration; + } doPersist(model); } } diff --git a/platform/commonUI/edit/test/EditRepresenterSpec.js b/platform/commonUI/edit/test/EditRepresenterSpec.js index b3361392f4..126507461b 100644 --- a/platform/commonUI/edit/test/EditRepresenterSpec.js +++ b/platform/commonUI/edit/test/EditRepresenterSpec.js @@ -6,6 +6,91 @@ define( "use strict"; describe("The Edit mode representer", function () { + var mockQ, + mockScope, + testRepresentation, + mockDomainObject, + mockPersistence, + representer; + + function mockPromise(value) { + return { + then: function (callback) { + return mockPromise(callback(value)); + } + }; + } + + beforeEach(function () { + mockQ = { when: mockPromise }; + mockScope = jasmine.createSpyObj("$scope", ["$watch"]); + testRepresentation = { key: "test" }; + mockDomainObject = jasmine.createSpyObj("domainObject", [ + "getId", + "getModel", + "getCapability", + "useCapability", + "hasCapability" + ]); + mockPersistence = + jasmine.createSpyObj("persistence", ["persist"]); + + mockDomainObject.hasCapability.andReturn(true); + mockDomainObject.useCapability.andReturn(true); + mockDomainObject.getCapability.andReturn(mockPersistence); + + representer = new EditRepresenter(mockQ, mockScope); + representer.represent(testRepresentation, mockDomainObject); + }); + + it("watches for changes in view configuration", function () { + // Should watch the configuration field, + // provided by mct-representation + expect(mockScope.$watch).toHaveBeenCalledWith( + "configuration", + jasmine.any(Function), + true // should be a deep watch + ); + }); + + it("watches for changes in domain object model", function () { + // Should watch the model field, + // provided by mct-representation + expect(mockScope.$watch).toHaveBeenCalledWith( + "model", + jasmine.any(Function), + true // should be a deep watch + ); + }); + + it("mutates and persists upon observed changes", function () { + mockScope.model = { someKey: "some value" }; + mockScope.configuration = { someConfiguration: "something" }; + + mockScope.$watch.mostRecentCall.args[1].call(); + + // Should have mutated the object... + expect(mockDomainObject.useCapability).toHaveBeenCalledWith( + "mutation", + jasmine.any(Function) + ); + + // ... and should have persisted the mutation + expect(mockPersistence.persist).toHaveBeenCalled(); + + // Finally, check that the provided mutation function + // includes both model and configuratioon + expect( + mockDomainObject.useCapability.mostRecentCall.args[1]() + ).toEqual({ + someKey: "some value", + configuration: { + test: { someConfiguration: "something" } + } + }); + }); + + }); } ); \ No newline at end of file diff --git a/platform/commonUI/general/test/MCTDragSpec.js b/platform/commonUI/general/test/MCTDragSpec.js index 162ea7692c..a5805e1f6b 100644 --- a/platform/commonUI/general/test/MCTDragSpec.js +++ b/platform/commonUI/general/test/MCTDragSpec.js @@ -5,7 +5,125 @@ define( function (MCTDrag) { "use strict"; + var JQLITE_METHODS = [ "on", "off", "find" ]; + describe("The mct-drag directive", function () { + var mockDocument, + mockScope, + mockElement, + testAttrs, + mockBody, + mctDrag; + + function testEvent(x, y) { + return { + pageX: x, + pageY: y, + preventDefault: jasmine.createSpy("preventDefault") + }; + } + + beforeEach(function () { + mockDocument = + jasmine.createSpyObj("$document", JQLITE_METHODS); + mockScope = + jasmine.createSpyObj("$scope", [ "$eval", "$apply" ]); + mockElement = + jasmine.createSpyObj("element", JQLITE_METHODS); + mockBody = + jasmine.createSpyObj("body", JQLITE_METHODS); + + testAttrs = { + mctDragDown: "starting a drag", + mctDrag: "continuing a drag", + mctDragUp: "ending a drag" + }; + + mockDocument.find.andReturn(mockBody); + + mctDrag = new MCTDrag(mockDocument); + mctDrag.link(mockScope, mockElement, testAttrs); + }); + + it("is valid as an attribute", function () { + expect(mctDrag.restrict).toEqual("A"); + }); + + it("listens for mousedown on its element", function () { + expect(mockElement.on).toHaveBeenCalledWith( + "mousedown", + jasmine.any(Function) + ); + + // Verify no interactions with body as well + expect(mockBody.on).not.toHaveBeenCalled(); + }); + + it("invokes mctDragDown when dragging begins", function () { + mockElement.on.mostRecentCall.args[1](testEvent(42, 60)); + expect(mockScope.$eval).toHaveBeenCalledWith( + testAttrs.mctDragDown, + { delta: [0, 0] } + ); + }); + + it("listens for mousemove after dragging begins", function () { + mockElement.on.mostRecentCall.args[1](testEvent(42, 60)); + expect(mockBody.on).toHaveBeenCalledWith( + "mousemove", + jasmine.any(Function) + ); + expect(mockBody.on).toHaveBeenCalledWith( + "mouseup", + jasmine.any(Function) + ); + }); + + it("invokes mctDrag expression during drag", function () { + mockElement.on.mostRecentCall.args[1](testEvent(42, 60)); + + // Find and invoke the mousemove listener + mockBody.on.calls.forEach(function (call) { + if (call.args[0] === 'mousemove') { + call.args[1](testEvent(52, 200)); + } + }); + + // Should have passed that delta to mct-drag expression + expect(mockScope.$eval).toHaveBeenCalledWith( + testAttrs.mctDrag, + { delta: [10, 140] } + ); + }); + + it("invokes mctDragUp expression after drag", function () { + mockElement.on.mostRecentCall.args[1](testEvent(42, 60)); + + // Find and invoke the mousemove listener + mockBody.on.calls.forEach(function (call) { + if (call.args[0] === 'mousemove') { + call.args[1](testEvent(52, 200)); + } + }); + // Find and invoke the mousemove listener + mockBody.on.calls.forEach(function (call) { + if (call.args[0] === 'mouseup') { + call.args[1](testEvent(40, 71)); + } + }); + + // Should have passed that delta to mct-drag-up expression + // and that delta should have been relative to the + // initial position + expect(mockScope.$eval).toHaveBeenCalledWith( + testAttrs.mctDragUp, + { delta: [-2, 11] } + ); + + // Should also have unregistered listeners + expect(mockBody.off).toHaveBeenCalled(); + }); + }); } ); \ No newline at end of file diff --git a/platform/representation/test/gestures/GestureRepresenterSpec.js b/platform/representation/test/gestures/GestureRepresenterSpec.js index ce677c940b..37930750f2 100644 --- a/platform/representation/test/gestures/GestureRepresenterSpec.js +++ b/platform/representation/test/gestures/GestureRepresenterSpec.js @@ -6,31 +6,56 @@ define( "use strict"; describe("A gesture representer", function () { + var mockGestureService, + mockGestureHandle, + mockScope, + mockElement, + representer; -// it("attaches declared gestures, and detaches on refresh", function () { -// mctRepresentation.link(mockScope, mockElement); -// -// mockScope.key = "uvw"; -// mockScope.domainObject = mockDomainObject; -// -// // Trigger the watch -// mockScope.$watch.mostRecentCall.args[1](); -// -// expect(mockGestureService.attachGestures).toHaveBeenCalledWith( -// mockElement, -// mockDomainObject, -// [ "testGesture", "otherTestGesture" ] -// ); -// -// expect(mockGestureHandle.destroy).not.toHaveBeenCalled(); -// -// // Refresh, expect a detach -// mockScope.key = "abc"; -// mockScope.$watch.mostRecentCall.args[1](); -// -// // Should have destroyed those old gestures -// expect(mockGestureHandle.destroy).toHaveBeenCalled(); -// }); + beforeEach(function () { + mockGestureService = jasmine.createSpyObj( + "gestureService", + [ "attachGestures" ] + ); + mockGestureHandle = jasmine.createSpyObj( + "gestureHandle", + [ "destroy" ] + ); + + mockElement = { someKey: "some value" }; + + mockGestureService.attachGestures.andReturn(mockGestureHandle); + + representer = new GestureRepresenter( + mockGestureService, + undefined, // Scope is not used + mockElement + ); + }); + + it("attaches declared gestures, and detaches on request", function () { + // Pass in some objects, which we expect to be passed into the + // gesture service accordingly. + var domainObject = { someOtherKey: "some other value" }, + representation = { gestures: ["a", "b", "c"] }; + + representer.represent(representation, domainObject); + + expect(mockGestureService.attachGestures).toHaveBeenCalledWith( + mockElement, + domainObject, + [ "a", "b", "c" ] + ); + + // Should not have been destroyed yet... + expect(mockGestureHandle.destroy).not.toHaveBeenCalled(); + + // Destroy + representer.destroy(); + + // Should have destroyed those old gestures + expect(mockGestureHandle.destroy).toHaveBeenCalled(); + }); }); }