Enable changing Task structure
Provide unit-tests for verifying that Task structure depends both on parent Workflow type and on Task type. This commits also depends on a change made to Barricade.js library: now it passes the parameters of a parent container to the children containers, which add new elements to it via prototype inheritance. Closes-Bug: #1446230 Implements: blueprint merlin-unittests Change-Id: Ic4c0539297d6df9a0b1450a824eeca4749455cfd
This commit is contained in:
parent
05f4f22b9e
commit
0b92f674a4
|
@ -21,7 +21,7 @@
|
||||||
function getWorkbookNextIDSuffix(base) {
|
function getWorkbookNextIDSuffix(base) {
|
||||||
var containerName = base + 's',
|
var containerName = base + 's',
|
||||||
regexp = /(workflow|action)([0-9]+)/,
|
regexp = /(workflow|action)([0-9]+)/,
|
||||||
container = workbook.get(containerName);
|
container = $scope.workbook.get(containerName);
|
||||||
if ( !container ) {
|
if ( !container ) {
|
||||||
throw 'Base should be either "action" or "workflow"!';
|
throw 'Base should be either "action" or "workflow"!';
|
||||||
}
|
}
|
||||||
|
@ -33,13 +33,15 @@
|
||||||
$scope.addAction = function() {
|
$scope.addAction = function() {
|
||||||
var nextSuffix = getWorkbookNextIDSuffix(baseActionId),
|
var nextSuffix = getWorkbookNextIDSuffix(baseActionId),
|
||||||
newID = baseActionId + nextSuffix;
|
newID = baseActionId + nextSuffix;
|
||||||
workbook.get('actions').push({name: 'Action ' + nextSuffix}, {id: newID});
|
$scope.workbook.get('actions').push(
|
||||||
|
{name: 'Action ' + nextSuffix}, {id: newID});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.addWorkflow = function() {
|
$scope.addWorkflow = function() {
|
||||||
var nextSuffix = getWorkbookNextIDSuffix(baseWorkflowId),
|
var nextSuffix = getWorkbookNextIDSuffix(baseWorkflowId),
|
||||||
newID = baseWorkflowId + nextSuffix;
|
newID = baseWorkflowId + nextSuffix;
|
||||||
workbook.get('workflows').push({name: 'Workflow ' + nextSuffix}, {id: newID});
|
$scope.workbook.get('workflows').push(
|
||||||
|
{name: 'Workflow ' + nextSuffix}, {id: newID});
|
||||||
};
|
};
|
||||||
|
|
||||||
}])
|
}])
|
||||||
|
|
|
@ -197,6 +197,15 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
models.Task = fields.frozendict.extend({
|
models.Task = fields.frozendict.extend({
|
||||||
|
create: function(json, parameters) {
|
||||||
|
var self = fields.frozendict.create.call(this, json, parameters);
|
||||||
|
self.on('childChange', function(child, op) {
|
||||||
|
if ( child === self.get('type') && op !== 'id' ) {
|
||||||
|
self.emit('change', 'taskType');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return self;
|
||||||
|
},
|
||||||
_getPrettyJSON: function() {
|
_getPrettyJSON: function() {
|
||||||
var json = fields.frozendict._getPrettyJSON.apply(this, arguments);
|
var json = fields.frozendict._getPrettyJSON.apply(this, arguments);
|
||||||
delete json.name;
|
delete json.name;
|
||||||
|
@ -219,32 +228,27 @@
|
||||||
},
|
},
|
||||||
'type': {
|
'type': {
|
||||||
'@class': fields.string.extend({}, {
|
'@class': fields.string.extend({}, {
|
||||||
'@enum': ['Action-based', 'Workflow-based'],
|
'@enum': [{
|
||||||
|
value: 'action', label: 'Action-based'
|
||||||
|
}, {
|
||||||
|
value: 'workflow', label: 'Workflow-based'
|
||||||
|
}],
|
||||||
|
'@default': 'action',
|
||||||
'@meta': {
|
'@meta': {
|
||||||
'index': 1,
|
'index': 1,
|
||||||
'row': 0
|
'row': 0
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
'action': {
|
'description': {
|
||||||
'@class': fields.string.extend({}, {
|
'@class': fields.text.extend({}, {
|
||||||
'@meta': {
|
'@meta': {
|
||||||
'index': 2,
|
'index': 1,
|
||||||
'row': 1
|
'row': 1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
'input': {
|
'input': {
|
||||||
'@class': fields.dictionary.extend({}, {
|
|
||||||
'@meta': {
|
|
||||||
'index': 3
|
|
||||||
},
|
|
||||||
'?': {
|
|
||||||
'@class': fields.string
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
'publish': {
|
|
||||||
'@class': fields.dictionary.extend({}, {
|
'@class': fields.dictionary.extend({}, {
|
||||||
'@meta': {
|
'@meta': {
|
||||||
'index': 4
|
'index': 4
|
||||||
|
@ -254,35 +258,12 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
'on-error': {
|
'publish': {
|
||||||
'@class': fields.list.extend({}, {
|
'@class': fields.dictionary.extend({}, {
|
||||||
'@meta': {
|
'@meta': {
|
||||||
'title': 'On error',
|
|
||||||
'index': 5
|
'index': 5
|
||||||
},
|
},
|
||||||
'*': {
|
'?': {
|
||||||
'@class': fields.string
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
'on-success': {
|
|
||||||
'@class': fields.list.extend({}, {
|
|
||||||
'@meta': {
|
|
||||||
'title': 'On success',
|
|
||||||
'index': 6
|
|
||||||
},
|
|
||||||
'*': {
|
|
||||||
'@class': fields.string
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
'on-complete': {
|
|
||||||
'@class': fields.list.extend({}, {
|
|
||||||
'@meta': {
|
|
||||||
'title': 'On complete',
|
|
||||||
'index': 7
|
|
||||||
},
|
|
||||||
'*': {
|
|
||||||
'@class': fields.string
|
'@class': fields.string
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -300,7 +281,7 @@
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
'@meta': {
|
'@meta': {
|
||||||
'index': 8
|
'index': 9
|
||||||
},
|
},
|
||||||
'@required': false,
|
'@required': false,
|
||||||
'wait-before': {
|
'wait-before': {
|
||||||
|
@ -366,6 +347,94 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
models.ReverseWFTask = models.Task.extend({}, {
|
||||||
|
'requires': {
|
||||||
|
'@class': fields.string.extend({}, {
|
||||||
|
'@meta': {
|
||||||
|
'row': 2,
|
||||||
|
'index': 3
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
models.DirectWFTask = models.Task.extend({}, {
|
||||||
|
'on-error': {
|
||||||
|
'@class': fields.list.extend({}, {
|
||||||
|
'@meta': {
|
||||||
|
'title': 'On error',
|
||||||
|
'index': 6
|
||||||
|
},
|
||||||
|
'*': {
|
||||||
|
'@class': fields.string
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
'on-success': {
|
||||||
|
'@class': fields.list.extend({}, {
|
||||||
|
'@meta': {
|
||||||
|
'title': 'On success',
|
||||||
|
'index': 7
|
||||||
|
},
|
||||||
|
'*': {
|
||||||
|
'@class': fields.string
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
'on-complete': {
|
||||||
|
'@class': fields.list.extend({}, {
|
||||||
|
'@meta': {
|
||||||
|
'title': 'On complete',
|
||||||
|
'index': 8
|
||||||
|
},
|
||||||
|
'*': {
|
||||||
|
'@class': fields.string
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
models.ActionTaskMixin = Barricade.Blueprint.create(function() {
|
||||||
|
return this.extend({}, {
|
||||||
|
'action': {
|
||||||
|
'@class': fields.string.extend({}, {
|
||||||
|
'@meta': {
|
||||||
|
'row': 1,
|
||||||
|
'index': 2
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
models.WorkflowTaskMixin = Barricade.Blueprint.create(function() {
|
||||||
|
return this.extend({}, {
|
||||||
|
'workflow': {
|
||||||
|
'@class': fields.string.extend({}, {
|
||||||
|
'@meta': {
|
||||||
|
'row': 1,
|
||||||
|
'index': 2
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var taskTypes = {
|
||||||
|
'direct': models.DirectWFTask,
|
||||||
|
'reverse': models.ReverseWFTask,
|
||||||
|
'action': models.ActionTaskMixin,
|
||||||
|
'workflow': models.WorkflowTaskMixin
|
||||||
|
};
|
||||||
|
|
||||||
|
function TaskFactory(json, parameters) {
|
||||||
|
var type = json.type || 'action',
|
||||||
|
baseClass = taskTypes[parameters.wfType],
|
||||||
|
mixinClass = taskTypes[type],
|
||||||
|
taskClass = mixinClass.call(baseClass);
|
||||||
|
return taskClass.create(json, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
models.Workflow = fields.frozendict.extend({
|
models.Workflow = fields.frozendict.extend({
|
||||||
create: function(json, parameters) {
|
create: function(json, parameters) {
|
||||||
var self = fields.frozendict.create.call(this, json, parameters);
|
var self = fields.frozendict.create.call(this, json, parameters);
|
||||||
|
@ -423,13 +492,29 @@
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
'tasks': {
|
'tasks': {
|
||||||
'@class': fields.dictionary.extend({}, {
|
'@class': fields.dictionary.extend({
|
||||||
|
create: function(json, parameters) {
|
||||||
|
var self = fields.dictionary.create.call(this, json, parameters);
|
||||||
|
self.on('childChange', function(child, op) {
|
||||||
|
if ( op === 'taskType' ) {
|
||||||
|
var taskId = child.getID(),
|
||||||
|
params = child._parameters,
|
||||||
|
taskPos = self.getPosByID(taskId),
|
||||||
|
taskData = child.toJSON();
|
||||||
|
params.id = taskId;
|
||||||
|
self.set(taskPos, TaskFactory(taskData, params));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
'@meta': {
|
'@meta': {
|
||||||
'index': 5,
|
'index': 5,
|
||||||
'group': true
|
'group': true
|
||||||
},
|
},
|
||||||
'?': {
|
'?': {
|
||||||
'@class': models.Task
|
'@class': models.Task,
|
||||||
|
'@factory': TaskFactory
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -481,6 +566,7 @@
|
||||||
|
|
||||||
function workflowFactory(json, parameters) {
|
function workflowFactory(json, parameters) {
|
||||||
var type = json.type || 'direct';
|
var type = json.type || 'direct';
|
||||||
|
parameters.wfType = type;
|
||||||
return workflowTypes[type].create(json, parameters);
|
return workflowTypes[type].create(json, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,11 +625,11 @@
|
||||||
if ( op === 'workflowType' ) {
|
if ( op === 'workflowType' ) {
|
||||||
var workflowId = child.getID(),
|
var workflowId = child.getID(),
|
||||||
workflowPos = self.getPosByID(workflowId),
|
workflowPos = self.getPosByID(workflowId),
|
||||||
workflowData = child.toJSON(),
|
params = child._parameters,
|
||||||
newType = child.get('type').get(),
|
workflowData = child.toJSON();
|
||||||
newWorkflow = workflowTypes[newType].create(
|
params.wfType = child.type;
|
||||||
workflowData, {id: workflowId});
|
params.id = workflowId;
|
||||||
self.set(workflowPos, newWorkflow);
|
self.set(workflowPos, workflowFactory(workflowData, params));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return self;
|
return self;
|
||||||
|
|
|
@ -0,0 +1,223 @@
|
||||||
|
|
||||||
|
/* Copyright (c) 2014 Mirantis, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
not use this file except in compliance with the License. You may obtain
|
||||||
|
a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
*/
|
||||||
|
describe('workbook model logic', function() {
|
||||||
|
var models, utils, workbook;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
module('mistral');
|
||||||
|
inject(function($injector) {
|
||||||
|
models = $injector.get('mistral.workbook.models');
|
||||||
|
utils = $injector.get('merlin.utils');
|
||||||
|
});
|
||||||
|
workbook = models.Workbook.create();
|
||||||
|
});
|
||||||
|
|
||||||
|
function getWorkflow(workflowID) {
|
||||||
|
return workbook.get('workflows').getByID(workflowID);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('defines workflow structure transformations:', function() {
|
||||||
|
var workflowID = 'workflow1';
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
workbook.get('workflows').push({name: 'Workflow 1'}, {id: workflowID});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("new workflow starts as a 'direct' workflow and has proper structure", function() {
|
||||||
|
var workflow = getWorkflow(workflowID);
|
||||||
|
|
||||||
|
expect(workflow.get('type').get()).toEqual('direct');
|
||||||
|
expect(workflow.instanceof(models.DirectWorkflow)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("after setting type to 'reverse' the workflow structure changes to the proper one", function() {
|
||||||
|
getWorkflow(workflowID).get('type').set('reverse');
|
||||||
|
|
||||||
|
expect(getWorkflow(workflowID).instanceof(models.ReverseWorkflow)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("changing 'reverse' type to 'direct' again causes workflow structure to properly change", function() {
|
||||||
|
getWorkflow(workflowID).get('type').set('reverse');
|
||||||
|
getWorkflow(workflowID).get('type').set('direct');
|
||||||
|
|
||||||
|
expect(getWorkflow(workflowID).instanceof(models.DirectWorkflow)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('defines task structure transformations', function() {
|
||||||
|
var workflowID = 'workflow1',
|
||||||
|
taskID = 'task1';
|
||||||
|
|
||||||
|
function getTask(taskID) {
|
||||||
|
return getWorkflow(workflowID).get('tasks').getByID(taskID);
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
workbook.get('workflows').push({name: 'Workflow 1'}, {id: workflowID});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("which start with the 'direct' workflow:", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
var workflow = getWorkflow(workflowID),
|
||||||
|
params = workflow._parameters;
|
||||||
|
workflow.get('tasks').push({name: 'Task 1'}, utils.extend(params, {id: taskID}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("new task starts as an 'action'-based one and has proper structure", function() {
|
||||||
|
expect(getTask(taskID).get('type').get()).toEqual('action');
|
||||||
|
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("changing task type from 'action' to 'workflow' causes proper structure changes", function() {
|
||||||
|
getTask(taskID).get('type').set('workflow');
|
||||||
|
|
||||||
|
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("changing workflow type to 'reverse' causes the proper changes to its tasks", function() {
|
||||||
|
getWorkflow(workflowID).get('type').set('reverse');
|
||||||
|
|
||||||
|
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||||
|
|
||||||
|
getTask(taskID).get('type').set('workflow');
|
||||||
|
|
||||||
|
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("changing workflow type from 'reverse' to 'direct' causes the proper changes to its tasks", function() {
|
||||||
|
getWorkflow(workflowID).get('type').set('reverse');
|
||||||
|
getWorkflow(workflowID).get('type').set('direct');
|
||||||
|
|
||||||
|
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||||
|
|
||||||
|
getTask(taskID).get('type').set('workflow');
|
||||||
|
|
||||||
|
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("which start with the 'reverse' workflow:", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
var workflow;
|
||||||
|
getWorkflow(workflowID).get('type').set('reverse');
|
||||||
|
workflow = getWorkflow(workflowID);
|
||||||
|
workflow.get('tasks').push(
|
||||||
|
{name: 'Task 1'}, utils.extend(workflow._parameters, {id: taskID}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("new task starts as an 'action'-based one and has proper structure", function() {
|
||||||
|
expect(getTask(taskID).get('type').get()).toEqual('action');
|
||||||
|
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("changing task type from 'action' to 'workflow' causes proper structure changes", function() {
|
||||||
|
getTask(taskID).get('type').set('workflow');
|
||||||
|
|
||||||
|
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("changing workflow type to 'direct' causes the proper changes to its tasks", function() {
|
||||||
|
getWorkflow(workflowID).get('type').set('direct');
|
||||||
|
|
||||||
|
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||||
|
|
||||||
|
getTask(taskID).get('type').set('workflow');
|
||||||
|
|
||||||
|
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("changing workflow type from 'direct' to 'reverse' causes the proper changes to its tasks", function() {
|
||||||
|
getWorkflow(workflowID).get('type').set('direct');
|
||||||
|
getWorkflow(workflowID).get('type').set('reverse');
|
||||||
|
|
||||||
|
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||||
|
|
||||||
|
getTask(taskID).get('type').set('workflow');
|
||||||
|
|
||||||
|
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||||
|
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('defines top-level actions available to user:', function() {
|
||||||
|
var $scope;
|
||||||
|
|
||||||
|
beforeEach(inject(function(_$controller_) {
|
||||||
|
var $controller = _$controller_;
|
||||||
|
$scope = {};
|
||||||
|
$controller('workbookCtrl', {$scope: $scope});
|
||||||
|
$scope.workbook = workbook;
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("'Add Action' action", function() {
|
||||||
|
it('adds a new Action', function() {
|
||||||
|
$scope.addAction();
|
||||||
|
|
||||||
|
expect(workbook.get('actions').get(0)).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates action with predefined name', function() {
|
||||||
|
$scope.addAction();
|
||||||
|
|
||||||
|
expect(workbook.get('actions').get(0).get('name').get()).toBeGreaterThan('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates actions with different names on 2 successive calls', function() {
|
||||||
|
$scope.addAction();
|
||||||
|
$scope.addAction();
|
||||||
|
|
||||||
|
expect(workbook.get('actions').get(0).get('name').get()).not.toEqual(
|
||||||
|
workbook.get('actions').get(1).get('name').get())
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("'Add Workflow' action", function() {
|
||||||
|
it('adds a new Workflow', function() {
|
||||||
|
$scope.addWorkflow();
|
||||||
|
|
||||||
|
expect(workbook.get('workflows').get(0)).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates workflow with predefined name', function() {
|
||||||
|
$scope.addWorkflow();
|
||||||
|
|
||||||
|
expect(workbook.get('workflows').get(0).get('name').get()).toBeGreaterThan('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates workflows with different names on 2 successive calls', function() {
|
||||||
|
$scope.addWorkflow();
|
||||||
|
$scope.addWorkflow();
|
||||||
|
|
||||||
|
expect(workbook.get('workflows').get(0).get('name').get()).not.toEqual(
|
||||||
|
workbook.get('workflows').get(1).get('name').get())
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
});
|
|
@ -33,22 +33,27 @@ module.exports = function (config) {
|
||||||
],
|
],
|
||||||
|
|
||||||
files: [
|
files: [
|
||||||
'./bower_components/angular/angular.js',
|
'bower_components/angular/angular.js',
|
||||||
'./bower_components/angular-mocks/angular-mocks.js',
|
'bower_components/angular-mocks/angular-mocks.js',
|
||||||
'./merlin/static/merlin/js/lib/underscore-min.js',
|
'merlin/static/merlin/js/lib/underscore-min.js',
|
||||||
'./merlin/static/merlin/js/merlin.init.js',
|
'merlin/static/merlin/js/merlin.init.js',
|
||||||
'./merlin/static/merlin/js/merlin.templates.js',
|
'merlin/static/merlin/js/merlin.templates.js',
|
||||||
'./merlin/static/merlin/js/merlin.directives.js',
|
'merlin/static/merlin/js/merlin.directives.js',
|
||||||
'./merlin/static/merlin/js/merlin.filters.js',
|
'merlin/static/merlin/js/merlin.filters.js',
|
||||||
'./merlin/static/merlin/js/merlin.field.models.js',
|
'merlin/static/merlin/js/merlin.field.models.js',
|
||||||
'./merlin/static/merlin/js/merlin.panel.models.js',
|
'merlin/static/merlin/js/merlin.panel.models.js',
|
||||||
'./merlin/static/merlin/js/merlin.utils.js',
|
'merlin/static/merlin/js/merlin.utils.js',
|
||||||
'./merlin/static/merlin/js/lib/angular-filter.js',
|
'merlin/static/merlin/js/lib/angular-filter.js',
|
||||||
'./merlin/static/merlin/js/lib/barricade.js',
|
'merlin/static/merlin/js/lib/barricade.js',
|
||||||
'./merlin/static/merlin/js/lib/js-yaml.js',
|
'merlin/static/merlin/js/lib/js-yaml.js',
|
||||||
'merlin/test/js/utilsSpec.js',
|
'merlin/test/js/utilsSpec.js',
|
||||||
'merlin/test/js/templatesSpec.js',
|
'merlin/test/js/templatesSpec.js',
|
||||||
'merlin/test/js/filtersSpec.js'
|
'merlin/test/js/filtersSpec.js',
|
||||||
|
|
||||||
|
'extensions/mistral/static/mistral/js/mistral.init.js',
|
||||||
|
'extensions/mistral/static/mistral/js/mistral.workbook.models.js',
|
||||||
|
'extensions/mistral/static/mistral/js/mistral.workbook.controllers.js',
|
||||||
|
'extensions/mistral/test/js/workbookSpec.js'
|
||||||
],
|
],
|
||||||
|
|
||||||
exclude: [
|
exclude: [
|
||||||
|
|
|
@ -47,11 +47,12 @@ var Barricade = (function () {
|
||||||
*/
|
*/
|
||||||
create: function (f) {
|
create: function (f) {
|
||||||
return function g() {
|
return function g() {
|
||||||
if (!Object.prototype.hasOwnProperty.call(this, '_parents')) {
|
var result = f.apply(this, arguments) || this;
|
||||||
Object.defineProperty(this, '_parents', {value: []});
|
if (!Object.prototype.hasOwnProperty.call(result, '_parents')) {
|
||||||
|
Object.defineProperty(result, '_parents', {value: []});
|
||||||
}
|
}
|
||||||
this._parents.push(g);
|
result._parents.push(g);
|
||||||
return f.apply(this, arguments);
|
return result;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -547,7 +548,7 @@ var Barricade = (function () {
|
||||||
create: function (json, parameters) {
|
create: function (json, parameters) {
|
||||||
var self = this.extend({}),
|
var self = this.extend({}),
|
||||||
schema = self._schema,
|
schema = self._schema,
|
||||||
isUsed;
|
isUsed, id;
|
||||||
|
|
||||||
self._parameters = parameters = parameters || {};
|
self._parameters = parameters = parameters || {};
|
||||||
|
|
||||||
|
@ -570,7 +571,10 @@ var Barricade = (function () {
|
||||||
Enumerated.call(self, schema['@enum']);
|
Enumerated.call(self, schema['@enum']);
|
||||||
}
|
}
|
||||||
|
|
||||||
Identifiable.call(self, parameters.id);
|
if ( Object.hasOwnProperty.call(parameters, 'id') ) {
|
||||||
|
id = parameters.id;
|
||||||
|
}
|
||||||
|
Identifiable.call(self, id);
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
},
|
},
|
||||||
|
@ -871,10 +875,10 @@ var Barricade = (function () {
|
||||||
* @memberof Barricade.Arraylike
|
* @memberof Barricade.Arraylike
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_sift: function (json) {
|
_sift: function (json, parameters) {
|
||||||
return json.map(function (el) {
|
return json.map(function (el) {
|
||||||
return this._keyClassCreate(
|
return this._keyClassCreate(
|
||||||
this._elSymbol, this._elementClass, el);
|
this._elSymbol, this._elementClass, el, parameters);
|
||||||
}, this);
|
}, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1030,11 +1034,11 @@ var Barricade = (function () {
|
||||||
* @memberof Barricade.ImmutableObject
|
* @memberof Barricade.ImmutableObject
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_sift: function (json) {
|
_sift: function (json, parameters) {
|
||||||
var self = this;
|
var self = this;
|
||||||
return this.getKeys().reduce(function (objOut, key) {
|
return this.getKeys().reduce(function (objOut, key) {
|
||||||
objOut[key] =
|
objOut[key] = self._keyClassCreate(
|
||||||
self._keyClassCreate(key, self._keyClasses[key], json[key]);
|
key, self._keyClasses[key], json[key], parameters);
|
||||||
return objOut;
|
return objOut;
|
||||||
}, {});
|
}, {});
|
||||||
},
|
},
|
||||||
|
@ -1171,10 +1175,12 @@ var Barricade = (function () {
|
||||||
* @memberof Barricade.MutableObject
|
* @memberof Barricade.MutableObject
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_sift: function (json) {
|
_sift: function (json, parameters) {
|
||||||
return Object.keys(json).map(function (key) {
|
return Object.keys(json).map(function (key) {
|
||||||
return this._keyClassCreate(this._elSymbol, this._elementClass,
|
var params = Object.create(parameters);
|
||||||
json[key], {id: key});
|
params.id = key;
|
||||||
|
return this._keyClassCreate(
|
||||||
|
this._elSymbol, this._elementClass, json[key], params);
|
||||||
}, this);
|
}, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@
|
||||||
modelMixin.call(self, 'list');
|
modelMixin.call(self, 'list');
|
||||||
|
|
||||||
self.add = function() {
|
self.add = function() {
|
||||||
self.push();
|
self.push(undefined, parameters);
|
||||||
};
|
};
|
||||||
self.getValues = function() {
|
self.getValues = function() {
|
||||||
return self.toArray();
|
return self.toArray();
|
||||||
|
@ -181,7 +181,7 @@
|
||||||
} else { // usually, it's either frozendict inside or string
|
} else { // usually, it's either frozendict inside or string
|
||||||
newValue = '';
|
newValue = '';
|
||||||
}
|
}
|
||||||
self.push(newValue, {id: newID});
|
self.push(newValue, utils.extend(self._parameters, {id: newID}));
|
||||||
_items[newID] = self.getByID(newID);
|
_items[newID] = self.getByID(newID);
|
||||||
};
|
};
|
||||||
self.getValues = function() {
|
self.getValues = function() {
|
||||||
|
|
|
@ -82,6 +82,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extend(proto, extension) {
|
||||||
|
var newObj;
|
||||||
|
proto = (proto !== undefined ? proto : null);
|
||||||
|
newObj = Object.create(proto);
|
||||||
|
Object.keys(extension).forEach(function(key) {
|
||||||
|
newObj[key] = extension[key];
|
||||||
|
});
|
||||||
|
return newObj;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getMeta: getMeta,
|
getMeta: getMeta,
|
||||||
getNewId: getNewId,
|
getNewId: getNewId,
|
||||||
|
@ -89,6 +99,7 @@
|
||||||
makeTitle: makeTitle,
|
makeTitle: makeTitle,
|
||||||
getNextIDSuffix: getNextIDSuffix,
|
getNextIDSuffix: getNextIDSuffix,
|
||||||
enhanceItemWithID: enhanceItemWithID,
|
enhanceItemWithID: enhanceItemWithID,
|
||||||
|
extend: extend,
|
||||||
pop: pop
|
pop: pop
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -27,7 +27,41 @@ describe('merlin.utils', function() {
|
||||||
expect(array.condense()).toEqual([1, 0, 15, 7, 8]);
|
expect(array.condense()).toEqual([1, 0, 15, 7, 8]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
function extend(proto, extension) {
|
||||||
|
var newObj;
|
||||||
|
proto = (proto !== undefined ? proto : null);
|
||||||
|
newObj = Object.create(proto);
|
||||||
|
Object.keys(extension).forEach(function(key) {
|
||||||
|
newObj[key] = extension[key];
|
||||||
|
});
|
||||||
|
return newObj;
|
||||||
|
}
|
||||||
|
describe('extend function', function() {
|
||||||
|
var obj;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
obj = {
|
||||||
|
'key1': 10,
|
||||||
|
'key2': 20
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesn't remove existing keys from the resulting object", function() {
|
||||||
|
var newObj = extend(obj, {'key3': 30});
|
||||||
|
expect(newObj.key1).toBe(10);
|
||||||
|
expect(newObj.key3).toBe(30);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('overrides keys with the same names as the ones in extension', function() {
|
||||||
|
var newObj = extend(obj, {'key2': 40});
|
||||||
|
expect(newObj.key2).toBe(40);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesn't touch the original object, even the keys with the same names", function() {
|
||||||
|
var newObj = extend(obj, {'key2': 40, 'key4': 50});
|
||||||
|
expect(obj.key1).toBe(10);
|
||||||
|
expect(obj.key2).toBe(20);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue