<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * 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.
 */

var createTestProperties = function createTestProperties() {
  if ( ! foam.lookup('test.PropTypeTester', true) ) {
    foam.CLASS({
      name: 'PropTypeTester',
      package: 'test',

      properties: [
        {
          class: 'Date',
          name: 'date',
        },
        {
          class: 'DateTime',
          name: 'dateTime',
        },
        {
          class: 'Long',
          name: 'long',
        },
        {
          class: 'Float',
          name: 'float',
        },
        {
          class: 'Function',
          name: 'func',
        },
        {
          class: 'Blob',
          name: 'blob',
        },
        {
          class: 'StringArray',
          name: 'stringArray',
        },
        {
          class: 'Class',
          name: 'class',
        }
        // TODO: other types, as they gain testable functionality
      ]
    });
  }

  return test.PropTypeTester.create();
}
var createDateTestProperties = function createDateTestProperties() {
  if ( ! foam.lookup('test.DateTypeTester', true) ) {
    foam.CLASS({
      name: 'DateTypeTester',
      package: 'test',

      properties: [
        {
          class: 'Date',
          name: 'date',
        },
        {
          class: 'DateTime',
          name: 'dateTime',
        },
      ]
    });
  }
  return test.DateTypeTester.create();
}

// For tests that rely on asserts firing, make sure they throw so the
// assert can be detected in tests.
var oldAssert;
beforeAll(function() {
  oldAssert = foam.core.FObject.prototype.assert;
  foam.core.FObject.prototype.assert = function(c) { if ( ! c ) throw Array.from(arguments); }
});
afterAll(function() {
  foam.core.FObject.prototype.assert = oldAssert;
})

describe('Date', function() {
  var p;
  var p2;

  beforeEach(function() {
    p = createDateTestProperties();
    p2 = createDateTestProperties();
  });
  afterEach(function() {
    p = null;
    p2 = null;
  });

  it('accepts dates', function() {
    var d = new Date();
    p.date = d;
    expect(p.date).toBe(d);
  });
  it('accepts numbers', function() {
    p.date = 3434;
    expect(p.date).toEqual(new Date(3434));
  });
  it('accepts valid date strings', function() {
    dateStr = "Wed Dec 31 1987 19:00:03 GMT-0500 (EST)";
    p.date = dateStr;
    expect(p.date).toEqual(new Date(dateStr));
  });
  it('accepts invalid date strings, retains invalidity', function() {
    dateStr = "d ";
    p.date = dateStr;
    expect(p.date.toUTCString()).toEqual((new Date(dateStr)).toUTCString());
  });
  it('compares', function() {
    p.date = 55555;
    p2.date = 88888;

    expect(p.compareTo(p2)).toEqual(-1);
    expect(p2.compareTo(p)).toEqual(1);
  });
  it('compares when undefined', function() {
    p2.date = 88888;

    expect(p.compareTo(p2)).toEqual(-1);
    expect(p2.compareTo(p)).toEqual(1);
  });
  it('compares when undefined2', function() {
    p.date = 55555;

    expect(p.compareTo(p2)).toEqual(1);
    expect(p2.compareTo(p)).toEqual(-1);
  });
  it('compares when equal', function() {
    expect(p.compareTo(p2)).toEqual(0);
    expect(p2.compareTo(p)).toEqual(0);

    p.date =  55555;
    p2.date = 55555;
    expect(p.compareTo(p2)).toEqual(0);
    expect(p2.compareTo(p)).toEqual(0);
    expect(p.equals(p2)).toEqual(true);

  });
});

describe('Float', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('accepts ints', function() {
    p.float = 5;
    expect(p.float).toEqual(5);
  });
  it('accepts floats', function() {
    p.float = 456.456332;
    expect(p.float).toEqual(456.456332);
  });
  it('accepts negative floats', function() {
    p.float = -3.948474;
    expect(p.float).toEqual(-3.948474);
  });
  it('accepts string floats', function() {
    p.float = "-3.948474";
    expect(p.float).toEqual(-3.948474);
  });
  it('defaults to 0 if falsey', function() {
    p.float = null;
    expect(p.float).toEqual(0);
    p.float = '';
    expect(p.float).toEqual(0);
    p.float = undefined;
    expect(p.float).toEqual(0);
  });
});

describe('Function', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('defaults to a function', function() {
    expect(typeof p.func).toEqual('function');
    p.func();
  });
  it('accepts functions', function() {
    p.func = function() { return 55; }
    expect(p.func()).toEqual(55);
  });
  it('rejects non functions', function() {
    expect(function() {
      p.func = 'asdlfkjalskdjf';
    }).toThrow();
  });
});

describe('StringArray', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('setting an array to a number throws an exception', function() {
    expect(function() { p.stringArray = 42; }).toThrow();
  });
  it('setting an array to null throws an exception', function() {
    expect(function() { p.stringArray = null; }).toThrow();
  });
  it('setting an array to an object throws an exception', function() {
    expect(function() { p.stringArray = {}; }).toThrow();
  });
  it('is empty array by default', function() {
    expect(p.stringArray).toEqual(undefined);
  });
  it('accepts string in an array', function() {
    p.stringArray = [ "Hello", "I see", "Well" ];
    expect(p.stringArray).toEqual([ "Hello", "I see", "Well" ]);
  });
  it('converts elements to strings', function() {
    var d = new Date();
    var golden = '' + d;

    p.stringArray = [
      { a: 1 },
      2,
      true,
      d,
      'hello'
    ];

    expect(p.stringArray).toEqual([
      '[object Object]',
      '2',
      'true',
      golden,
      'hello'
    ]);
  });
});

describe('Class property', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
    createDateTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('is undefined by default', function() {
    expect(p.class).toBeUndefined();
  });

  it('stores a given model instance', function() {
    p.class = test.DateTypeTester;
    expect(p.class).toBe(test.DateTypeTester);
  });
  it('looks up a model from a string name', function() {
    p.class = 'test.DateTypeTester';
    expect(p.class).toBe('test.DateTypeTester');
    expect(p.class).toBe(test.DateTypeTester);
  });
  it('accepts undefined', function() {
    p.class = 'test.DateTypeTester';
    expect(p.class).toBe('test.DateTypeTester');
    expect(p.class).toBe(test.DateTypeTester);

    p.class = undefined;
    expect(p.class).toBeUndefined();
    expect(p.class).toBeUndefined();
  });

});
<commit_msg>Fixed Class property tests to match the new functionality<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * 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.
 */

var createTestProperties = function createTestProperties() {
  if ( ! foam.lookup('test.PropTypeTester', true) ) {
    foam.CLASS({
      name: 'PropTypeTester',
      package: 'test',

      properties: [
        {
          class: 'Date',
          name: 'date',
        },
        {
          class: 'DateTime',
          name: 'dateTime',
        },
        {
          class: 'Long',
          name: 'long',
        },
        {
          class: 'Float',
          name: 'float',
        },
        {
          class: 'Function',
          name: 'func',
        },
        {
          class: 'Blob',
          name: 'blob',
        },
        {
          class: 'StringArray',
          name: 'stringArray',
        },
        {
          class: 'Class',
          name: 'class',
        }
        // TODO: other types, as they gain testable functionality
      ]
    });
  }

  return test.PropTypeTester.create();
}
var createDateTestProperties = function createDateTestProperties() {
  if ( ! foam.lookup('test.DateTypeTester', true) ) {
    foam.CLASS({
      name: 'DateTypeTester',
      package: 'test',

      properties: [
        {
          class: 'Date',
          name: 'date',
        },
        {
          class: 'DateTime',
          name: 'dateTime',
        },
      ]
    });
  }
  return test.DateTypeTester.create();
}

// For tests that rely on asserts firing, make sure they throw so the
// assert can be detected in tests.
var oldAssert;
beforeAll(function() {
  oldAssert = foam.core.FObject.prototype.assert;
  foam.core.FObject.prototype.assert = function(c) { if ( ! c ) throw Array.from(arguments); }
});
afterAll(function() {
  foam.core.FObject.prototype.assert = oldAssert;
})

describe('Date', function() {
  var p;
  var p2;

  beforeEach(function() {
    p = createDateTestProperties();
    p2 = createDateTestProperties();
  });
  afterEach(function() {
    p = null;
    p2 = null;
  });

  it('accepts dates', function() {
    var d = new Date();
    p.date = d;
    expect(p.date).toBe(d);
  });
  it('accepts numbers', function() {
    p.date = 3434;
    expect(p.date).toEqual(new Date(3434));
  });
  it('accepts valid date strings', function() {
    dateStr = "Wed Dec 31 1987 19:00:03 GMT-0500 (EST)";
    p.date = dateStr;
    expect(p.date).toEqual(new Date(dateStr));
  });
  it('accepts invalid date strings, retains invalidity', function() {
    dateStr = "d ";
    p.date = dateStr;
    expect(p.date.toUTCString()).toEqual((new Date(dateStr)).toUTCString());
  });
  it('compares', function() {
    p.date = 55555;
    p2.date = 88888;

    expect(p.compareTo(p2)).toEqual(-1);
    expect(p2.compareTo(p)).toEqual(1);
  });
  it('compares when undefined', function() {
    p2.date = 88888;

    expect(p.compareTo(p2)).toEqual(-1);
    expect(p2.compareTo(p)).toEqual(1);
  });
  it('compares when undefined2', function() {
    p.date = 55555;

    expect(p.compareTo(p2)).toEqual(1);
    expect(p2.compareTo(p)).toEqual(-1);
  });
  it('compares when equal', function() {
    expect(p.compareTo(p2)).toEqual(0);
    expect(p2.compareTo(p)).toEqual(0);

    p.date =  55555;
    p2.date = 55555;
    expect(p.compareTo(p2)).toEqual(0);
    expect(p2.compareTo(p)).toEqual(0);
    expect(p.equals(p2)).toEqual(true);

  });
});

describe('Float', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('accepts ints', function() {
    p.float = 5;
    expect(p.float).toEqual(5);
  });
  it('accepts floats', function() {
    p.float = 456.456332;
    expect(p.float).toEqual(456.456332);
  });
  it('accepts negative floats', function() {
    p.float = -3.948474;
    expect(p.float).toEqual(-3.948474);
  });
  it('accepts string floats', function() {
    p.float = "-3.948474";
    expect(p.float).toEqual(-3.948474);
  });
  it('defaults to 0 if falsey', function() {
    p.float = null;
    expect(p.float).toEqual(0);
    p.float = '';
    expect(p.float).toEqual(0);
    p.float = undefined;
    expect(p.float).toEqual(0);
  });
});

describe('Function', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('defaults to a function', function() {
    expect(typeof p.func).toEqual('function');
    p.func();
  });
  it('accepts functions', function() {
    p.func = function() { return 55; }
    expect(p.func()).toEqual(55);
  });
  it('rejects non functions', function() {
    expect(function() {
      p.func = 'asdlfkjalskdjf';
    }).toThrow();
  });
});

describe('StringArray', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('setting an array to a number throws an exception', function() {
    expect(function() { p.stringArray = 42; }).toThrow();
  });
  it('setting an array to null throws an exception', function() {
    expect(function() { p.stringArray = null; }).toThrow();
  });
  it('setting an array to an object throws an exception', function() {
    expect(function() { p.stringArray = {}; }).toThrow();
  });
  it('is empty array by default', function() {
    expect(p.stringArray).toEqual(undefined);
  });
  it('accepts string in an array', function() {
    p.stringArray = [ "Hello", "I see", "Well" ];
    expect(p.stringArray).toEqual([ "Hello", "I see", "Well" ]);
  });
  it('converts elements to strings', function() {
    var d = new Date();
    var golden = '' + d;

    p.stringArray = [
      { a: 1 },
      2,
      true,
      d,
      'hello'
    ];

    expect(p.stringArray).toEqual([
      '[object Object]',
      '2',
      'true',
      golden,
      'hello'
    ]);
  });
});

describe('Class property', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
    createDateTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('is undefined by default', function() {
    expect(p.class).toBeUndefined();
  });

  it('stores a given model instance', function() {
    p.class = test.DateTypeTester;
    expect(p.class).toBe(test.DateTypeTester);
  });
  it('looks up a model from a string name', function() {
    p.class = 'test.DateTypeTester';
    expect(p.class).toBe(test.DateTypeTester);
  });
  it('accepts undefined', function() {
    p.class = 'test.DateTypeTester';
    expect(p.class).toBe(test.DateTypeTester);

    p.class = undefined;
    expect(p.class).toBeUndefined();
  });

});
<|endoftext|>


<commit_before>var types = Ext.data.Types;
Ext.define('MilestoneTreeModel', {
	extend: 'Ext.data.TreeModel',
	fields: [
                {name: 'FormattedID', mapping: 'FormattedID', type: types.STRING},
                {name: 'Name', mapping: 'Name', type: types.STRING},
                {name: 'TargetDate', mapping: 'AcceptedDate', type: types.DATE },
                {name: 'TargetProject', mapping: 'TargetProject', type: types.OBJECT},
                {name: 'ValueStream', mapping: 'ValueStream', type: types.STRING},
                {name: 'Visibility', mapping: 'Visibility', type: types.STRING},
                {name: 'Status', mapping: 'Status', type: types.STRING},
                {name: 'DisplayColor', mapping: 'DisplayColor', type: types.STRING},
                {name: 'Notes', mapping: 'Notes', type: types.STRING},
                {name: '_ref', mapping: '_ref', type: types.STRING}
            ],
    hasMany: {model: 'FeatureTreeModel', name:'features', associationKey: 'features'}
});

Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',

    getSettingsFields: function() {
        return [
            {
                name: 'executiveVisibilityOnly',
                xtype: 'rallycheckboxfield',
                fieldLabel: '',
                boxLabel: 'Only show Milestones with Executive Visibility'
            },
            {
                name: 'includeGlobalMilestones',
                xtype: 'rallycheckboxfield',
                fieldLabel: '',
                boxLabel: 'Include global milestones'
            },
            {
                name: 'showNumberOfMonths',
                xtype: 'rallynumberfield',
                fieldLabel: 'Date Range (months)'
            }
        ];
    },

    launch: function() {
        this._getAllChildProjectsForCurrentProject(this.project);
    },

    _getAllChildProjectsForCurrentProject: function(currProject){
        Ext.getBody().mask('Loading...');

        this.allProjectsList = [];
        var that = this;
        var projectStore = Ext.create('Rally.data.wsapi.Store', {
            model: 'Project',
            fetch: ['Name', 'State', 'Parent', 'Children'],
            autoLoad: true,
            compact: false,
            context: {
                workspace: that.getContext().getWorkspace()._Ref,
                projectScopeUp: false,
                projectScopeDown: true
            },
            limit: Infinity,
            filters:[{
                property:'State',
                operator: '=',
                value: 'Open'
            }],
            sorters: [{
                property: 'Name',
                direction: 'ASC'
            }],
            listeners: {
                load: function(projectStore, data, success){
                    //initiatilinzing the list containing the required and all projects.
                    this.requiredProjectsList = [];
                    this.allProjectsColl = data;

                    //identifying the selected project and constructing its reference.
                    var selectedProj = this.getContext().getProject();
                    var selectedProjRef = '/project/' + selectedProj.ObjectID;

                    //registering the selected project reference.
                    this.requiredProjectsList.push(selectedProj.ObjectID);

                    //identifying whether selected project has any children.
                    var selectedProjChildren = selectedProj.Children;
                    if(selectedProjChildren && selectedProjChildren.Count > 0){
                        this._loadAllChildProjectsFromParent(selectedProjRef);
                    }

                    //creating the milestone Store Filter.
                    this._createMilestoneStoreFilter();

                    //creating Milestone store.
                    this._createMilestoneStore();

                },
                scope: this
            }
         });
    },

    _loadAllChildProjectsFromParent: function(parentProjRef) {
        var that = this;

        Ext.Array.each(this.allProjectsColl, function(thisProject) {
            //identifying current project is child of the Project with reference..
            if(thisProject.get('Parent') && thisProject.get('Parent')._ref !== null && thisProject.get('Parent')._ref == parentProjRef){
                that.requiredProjectsList.push(thisProject.data.ObjectID);

                //identifying whether the project as any further children.
                var projChildren = thisProject.get('Children');
                if(projChildren && projChildren.Count > 0){
                    that._loadAllChildProjectsFromParent(thisProject.get('_ref'));
                }
            }
        });
    },

    _createMilestoneStoreFilter: function(){
        this.projectMilestoneFilter =  Ext.create('Rally.data.wsapi.Filter', {
                                    property: 'TargetDate',
                                    operator: '>=',
                                    value: 'today'
                                });

        //only apply filtering on the notes field if configured
        if (this.getSetting('executiveVisibilityOnly')) {
            this.projectMilestoneFilter = this.projectMilestoneFilter.and(Ext.create('Rally.data.wsapi.Filter', {
                                    property: 'c_ExecutiveVisibility',
                                    operator: '=',
                                    value: this.getSetting('executiveVisibilityOnly')
                                }));
        }

        //only filter on date range if configured
        if (this.getSetting('showNumberOfMonths') && this.getSetting('showNumberOfMonths') > 0) {
            var endDate = Rally.util.DateTime.add(new Date(), "month", this.getSetting('showNumberOfMonths'));

            this.projectMilestoneFilter = this.projectMilestoneFilter.and(Ext.create('Rally.data.wsapi.Filter', {
                property: 'TargetDate',
                operator: '<=',
                value: endDate
            }));
        }
    },

    _createMilestoneStore: function() {

        Ext.create("Rally.data.wsapi.Store", {
            model: 'milestone',
            autoLoad: true,
            compact: false,
            listeners: {
                load: function(store, data, success) {
                    this._filterMileStones(data);
                },
                scope: this
            },
            filters : this.projectMilestoneFilter,
            sorters: [
                {
                    property: 'c_ValueStream',
                    direaction: 'ASC'
                },
                {
                    property: 'TargetDate',
                    direction: 'ASC'
                }
            ]
        });
    },

    //Only include milestones based on the current project and it's children
    _filterMileStones: function(milestones) {
        var that = this;

        //Filter out milestone will be stored here
        var filteredMilestonesArr = [];

        Ext.each(milestones, function(milestone, index) {

            if (milestone.data.TargetProject !== null && milestone.data.TargetProject !== "" && (that.requiredProjectsList.indexOf(milestone.data.TargetProject.ObjectID) > -1)) {
                filteredMilestonesArr.push(milestone);
            }

            //If including global milestones, get milestones where TargetProject is not specific as well
            if (that.getSetting('includeGlobalMilestones') && milestone.data.TargetProject === null){
                filteredMilestonesArr.push(milestone);
            }
        });

        this._organiseMilestoneBasedOnValuestream(filteredMilestonesArr);
    },

    _organiseMilestoneBasedOnValuestream: function(filteredMilestonesArr){
        this.valueStreamMilestoneColl = [];
        this.valueStreamColl = [];
        var nonVSCount = 0;
        var that = this;

        Ext.Array.each(filteredMilestonesArr, function(thisData){
            var valuestream = thisData.get('c_ValueStream');

            if(valuestream !== null && valuestream !== ''){
                if(that.valueStreamColl.length === 0){
                    that.valueStreamColl.push(valuestream);
                }
                else if(that.valueStreamColl.length > 0 && that.valueStreamColl.indexOf(valuestream) === -1){
                    that.valueStreamColl.push(valuestream);
                }
            }
            else{
                nonVSCount++;
            }
        });

        this.valueStreamColl.sort();

        if(nonVSCount > 0) {
            this.valueStreamColl.push('N/A');
        }

        Ext.Array.each(this.valueStreamColl, function(valuestream) {
            var milestoneColl = that._getAllAssociatedMilestones(valuestream, filteredMilestonesArr);

            that.valueStreamMilestoneColl.push({
                key: valuestream,
                value: milestoneColl
            });
        });

        this._createValueStreamMilestonesTreeNode();
    },

    _createValueStreamMilestonesTreeNode: function(){

        var valueStreamRootNode = Ext.create('MilestoneTreeModel',{
                    Name: 'ValueStream Root',
                    text: 'ValueStream Root',
                    root: true,
                    expandable: true,
                    expanded: true
                });

        this._createValueStreamNodesAlongWithAssociatedChildMilestoneNodes(valueStreamRootNode);

        this._createValueStreamMilestoneGrid(valueStreamRootNode);

    },

    _createValueStreamMilestoneGrid: function(valueStreamRootNode){

       var milestoneValueStreamTreeStore = Ext.create('Ext.data.TreeStore', {
            model: 'MilestoneTreeModel',
            root: valueStreamRootNode
        });

       var valuestreamMilestoneTreePanel = Ext.create('Ext.tree.Panel', {
            store: milestoneValueStreamTreeStore,
            useArrows: true,
            rowLines: true,
            displayField: 'Name',
            rootVisible: false,
            width: this.getWidth(true),
            height: this.getHeight(true), // Extra scroll for individual sections:
            viewConfig: {
                getRowClass: function(record, index) {
                    var nameRecord = Ext.String.format("{0}", record.get('Name'));
                    if(nameRecord && nameRecord.search('valuestream:') === -1){
                        return 'row-child';
                    }
                    return 'row-parent';
                }
            },
            columns: [{
                          xtype: 'treecolumn',
                          text: 'Name',
                          dataIndex: 'Name',
                          resizeable: true,
                          flex: 3,
                          minWidth:200,
                          //width : 300,
                          renderer: function(value,style,item,rowIndex) {
                                var link = Ext.String.format("{0}", value);
                                if(link.search('valuestream:') === -1){
                                    var ref = item.get('_ref');
                                    link = Ext.String.format("{0}", value, Rally.nav.Manager.getDetailUrl(ref));
                                }
                                else{
                                    var onlyName = link.replace('valuestream:', '');
                                    link= Ext.String.format("{0}", onlyName);
                                }

                                return link;
                            }
                    },
                    {
                        text: 'Project',
                        dataIndex: 'TargetProject',
                        flex: 2,
                        hidden: true
                    },
                    {
                        text: 'Target Date',
                        dataIndex: 'TargetDate',
                        flex: 1,
                        renderer: function(value){
                            if(value)
                                return Rally.util.DateTime.format(value, 'M Y');
                        }
                    },
                    {
                        text: 'Status',
                        dataIndex: 'DisplayColor',
                        flex: 1,
                        renderer: function(value){
                            if(value){
                                var colorHtml = Ext.String.format("

", value);
                                return colorHtml;
                            }
                        }
                    },
                    {
                        text: 'Notes',
                        dataIndex: 'Notes',
                        flex: 5
                    }
                ]
        });

        this.add(valuestreamMilestoneTreePanel);

        Ext.getBody().unmask();
    },

    _createValueStreamNodesAlongWithAssociatedChildMilestoneNodes: function(valustreamRootNode){
        var that = this;

        Ext.Array.each(this.valueStreamMilestoneColl, function(thisData) {
            var valueStreamNode = that._createValueStreamNode(thisData.key);

            Ext.Array.each(thisData.value, function(thisMilestoneData) {
                var milestoneNode = that._createMilestoneNode(thisMilestoneData);
                valueStreamNode.appendChild(milestoneNode);
            });

            valustreamRootNode.appendChild(valueStreamNode);
        });
    },

    _createValueStreamNode: function(valuestreamData){
        var valueStreamLable = 'valuestream: ' + valuestreamData;
        var valustreamTreeNode = Ext.create('MilestoneTreeModel',{
                    Name: valueStreamLable,
                    leaf: false,
                    expandable: true,
                    expanded: true,
                    iconCls :'no-icon'
                });

        return  valustreamTreeNode;
    },

    _createMilestoneNode: function(milestoneData){
        var targetProjectName = milestoneData.get('TargetProject') !== null ?  milestoneData.get('TargetProject')._refObjectName : 'Global';

        var milestoneTreeNode = Ext.create('MilestoneTreeModel',{
            FormattedID: milestoneData.get('FormattedID'),
            Name: milestoneData.get('Name'),
            TargetDate: milestoneData.get('TargetDate'),
            TargetProject: targetProjectName,
            DisplayColor: milestoneData.get('DisplayColor'),
            Notes: milestoneData.get('Notes'),
            _ref: milestoneData.get('_ref'),
            leaf: true,
            expandable: false,
            expanded: false,
            iconCls :'no-icon'
        });

        return milestoneTreeNode;
    },

    _getAllAssociatedMilestones: function(valuestream, milestoneStoreData){
        var milestoneColl = [];
        var that = this;

        Ext.Array.each(milestoneStoreData, function(milestone) {
            var vsRecord = milestone.get('c_ValueStream');
            vsRecord = (vsRecord !== null && vsRecord !== '') ? vsRecord : 'N/A';

            if(vsRecord === valuestream){
                milestoneColl.push(milestone);
            }
        });

        return milestoneColl;
    }
});<commit_msg>US80985: Add Story Count and Story Accepted Count for milestones (Soumya)<commit_after>var types = Ext.data.Types;
Ext.define('MilestoneTreeModel', {
	extend: 'Ext.data.TreeModel',
	fields: [
                {name: 'FormattedID', mapping: 'FormattedID', type: types.STRING},
                {name: 'Name', mapping: 'Name', type: types.STRING},
                {name: 'TargetDate', mapping: 'AcceptedDate', type: types.DATE },
                {name: 'TargetProject', mapping: 'TargetProject', type: types.OBJECT},
                {name: 'ValueStream', mapping: 'ValueStream', type: types.STRING},
                {name: 'Visibility', mapping: 'Visibility', type: types.STRING},
                {name: 'Status', mapping: 'Status', type: types.STRING},
                {name: 'DisplayColor', mapping: 'DisplayColor', type: types.STRING},
                {name: 'Notes', mapping: 'Notes', type: types.STRING},
                {name: '_ref', mapping: '_ref', type: types.STRING},
                {name: 'AcceptedLeafStoryCount', mapping: 'AcceptedLeafStoryCount', type: types.STRING},
                {name: 'LeafStoryCount', mapping: 'LeafStoryCount', type: types.STRING}
            ],
    hasMany: {model: 'FeatureTreeModel', name:'features', associationKey: 'features'}
});

Ext.define('MilestoneDataModel', {
    extend: 'Ext.data.Model',
    fields: [
                {name: 'FormattedID', mapping: 'FormattedID', type: types.STRING},
                {name: 'Name', mapping: 'Name', type: types.STRING},
                {name: 'TargetDate', mapping: 'AcceptedDate', type: types.DATE },
                {name: 'TargetProject', mapping: 'TargetProject', type: types.OBJECT},
                {name: 'ValueStream', mapping: 'ValueStream', type: types.STRING},
                {name: 'Visibility', mapping: 'Visibility', type: types.STRING},
                {name: 'Status', mapping: 'Status', type: types.STRING},
                {name: 'DisplayColor', mapping: 'DisplayColor', type: types.STRING},
                {name: 'Notes', mapping: 'Notes', type: types.STRING},
                {name: '_ref', mapping: '_ref', type: types.STRING},
                {name: 'AcceptedLeafStoryCount', mapping: 'AcceptedLeafStoryCount', type: types.INT},
                {name: 'LeafStoryCount', mapping: 'LeafStoryCount', type: types.INT}
            ]
});

Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',

    getSettingsFields: function() {
        return [
            {
                name: 'executiveVisibilityOnly',
                xtype: 'rallycheckboxfield',
                fieldLabel: '',
                boxLabel: 'Only show Milestones with Executive Visibility'
            },
            {
                name: 'includeGlobalMilestones',
                xtype: 'rallycheckboxfield',
                fieldLabel: '',
                boxLabel: 'Include global milestones'
            },
            {
                name: 'showNumberOfMonths',
                xtype: 'rallynumberfield',
                fieldLabel: 'Date Range (months)'
            }
        ];
    },

    launch: function() {
        this._getAllChildProjectsForCurrentProject(this.project);
    },

    _getAllChildProjectsForCurrentProject: function(currProject){
        Ext.getBody().mask('Loading...');

        this.allProjectsList = [];
        var that = this;
        var projectStore = Ext.create('Rally.data.wsapi.Store', {
            model: 'Project',
            fetch: ['Name', 'State', 'Parent', 'Children'],
            autoLoad: true,
            compact: false,
            context: {
                workspace: that.getContext().getWorkspace()._Ref,
                projectScopeUp: false,
                projectScopeDown: true
            },
            limit: Infinity,
            filters:[{
                property:'State',
                operator: '=',
                value: 'Open'
            }],
            sorters: [{
                property: 'Name',
                direction: 'ASC'
            }],
            listeners: {
                load: function(projectStore, data, success){
                    //initiatilinzing the list containing the required and all projects.
                    this.requiredProjectsList = [];
                    this.allProjectsColl = data;

                    //identifying the selected project and constructing its reference.
                    var selectedProj = this.getContext().getProject();
                    var selectedProjRef = '/project/' + selectedProj.ObjectID;

                    //registering the selected project reference.
                    this.requiredProjectsList.push(selectedProj.ObjectID);

                    //identifying whether selected project has any children.
                    var selectedProjChildren = selectedProj.Children;
                    if(selectedProjChildren && selectedProjChildren.Count > 0){
                        this._loadAllChildProjectsFromParent(selectedProjRef);
                    }

                    //creating the milestone Store Filter.
                    this._createMilestoneStoreFilter();

                    //creating Milestone store.
                    this._createMilestoneStore();

                },
                scope: this
            }
         });
    },

    _loadAllChildProjectsFromParent: function(parentProjRef) {
        var that = this;

        Ext.Array.each(this.allProjectsColl, function(thisProject) {
            //identifying current project is child of the Project with reference..
            if(thisProject.get('Parent') && thisProject.get('Parent')._ref !== null && thisProject.get('Parent')._ref == parentProjRef){
                that.requiredProjectsList.push(thisProject.data.ObjectID);

                //identifying whether the project as any further children.
                var projChildren = thisProject.get('Children');
                if(projChildren && projChildren.Count > 0){
                    that._loadAllChildProjectsFromParent(thisProject.get('_ref'));
                }
            }
        });
    },

    _createMilestoneStoreFilter: function(){
        this.projectMilestoneFilter =  Ext.create('Rally.data.wsapi.Filter', {
                                    property: 'TargetDate',
                                    operator: '>=',
                                    value: 'today'
                                });

        //only apply filtering on the notes field if configured
        if (this.getSetting('executiveVisibilityOnly')) {
            this.projectMilestoneFilter = this.projectMilestoneFilter.and(Ext.create('Rally.data.wsapi.Filter', {
                                    property: 'c_ExecutiveVisibility',
                                    operator: '=',
                                    value: this.getSetting('executiveVisibilityOnly')
                                }));
        }

        //only filter on date range if configured
        if (this.getSetting('showNumberOfMonths') && this.getSetting('showNumberOfMonths') > 0) {
            var endDate = Rally.util.DateTime.add(new Date(), "month", this.getSetting('showNumberOfMonths'));

            this.projectMilestoneFilter = this.projectMilestoneFilter.and(Ext.create('Rally.data.wsapi.Filter', {
                property: 'TargetDate',
                operator: '<=',
                value: endDate
            }));
        }
    },

    _createMilestoneStore: function() {

        Ext.create("Rally.data.wsapi.Store", {
            model: 'milestone',
            autoLoad: true,
            compact: false,
            listeners: {
                load: function(store, data, success) {
                    this._filterMileStones(data);
                },
                scope: this
            },
            filters : this.projectMilestoneFilter,
            sorters: [
                {
                    property: 'c_ValueStream',
                    direction: 'ASC'
                },
                {
                    property: 'TargetDate',
                    direction: 'ASC'
                }
            ]
        });
    },

    //Only include milestones based on the current project and it's children
    _filterMileStones: function(milestones) {
        var that = this;

        //Filter out milestone will be stored here
        var filteredMilestonesArr = [];

        Ext.each(milestones, function(milestone, index) {

            if (milestone.data.TargetProject !== null && milestone.data.TargetProject !== "" && (that.requiredProjectsList.indexOf(milestone.data.TargetProject.ObjectID) > -1)) {
                filteredMilestonesArr.push(milestone);
            }

            //If including global milestones, get milestones where TargetProject is not specific as well
            if (that.getSetting('includeGlobalMilestones') && milestone.data.TargetProject === null){
                filteredMilestonesArr.push(milestone);
            }
        });

        this._loadArtifactsForMilestones(filteredMilestonesArr);
        //this._organiseMilestoneBasedOnValuestream(filteredMilestonesArr);
    },

    _loadArtifactsForMilestones: function(milestoneArr){
        var that = this;

        this._loadArtifacts(milestoneArr).then({
                success: function(records){
                    that.milestoneDataArray = [];

                    Ext.Array.each(records, function(record, index){
                        var storyCountInfo = that._computeArtifactsAssociation(record);
                        //console.log('Milestone: [',  me.milestoneNameList[index] + '] has : (', storyCountInfo.acceptedCount + '/', storyCountInfo.storyCount + ') stories done.');
                        var milestoneRec = milestoneArr[index];

                        var milestoneCustomData = that._createCustomMilestoneData(milestoneRec, storyCountInfo);
                        that.milestoneDataArray.push(milestoneCustomData);
                    });

                    //console.log('Milestone Artifact Data list: ', that.milestoneDataArray);

                    that._organiseMilestoneBasedOnValuestream(that.milestoneDataArray);
                },
                failure: function(error){
                    console.log('There are some errors');
                    Ext.getBody().unmask();
                },
            scope: that
            });
    },

    _createCustomMilestoneData: function(milestoneItem, storyCountInfo){
        var milestoneData = Ext.create('MilestoneDataModel', {
            FormattedID : milestoneItem.get('FormattedID'),
            Name: milestoneItem.get('Name'),
            TargetDate : milestoneItem.get('TargetDate'),
            TargetProject : milestoneItem.get('Name'),
            ValueStream: milestoneItem.get('c_ValueStream'),
            Visibility: milestoneItem.get('c_ExecutiveVisibility'),
            Status: milestoneItem.get('c_Test'),
            DisplayColor: milestoneItem.get('DisplayColor'),
            Notes: milestoneItem.get('Notes'),
            _ref: milestoneItem.get('_ref'),
            AcceptedLeafStoryCount: storyCountInfo.acceptedCount,
            LeafStoryCount: storyCountInfo.storyCount
        });

        return milestoneData;
    },

    _loadArtifacts: function(milestoneList){
        var promises = [];
        var that = this;

        Ext.Array.each(milestoneList, function(milestone){

            var artifactStore = Ext.create('Rally.data.wsapi.artifact.Store', {
                    models: ['portfolioitem/feature', 'defect', 'userstory'],
                    context: {
                        workspace: that.getContext().getWorkspace()._Ref,
                        limit: Infinity,
                        projectScopeUp: false,
                        projectScopeDown: true
                    },
                    filters: [
                        {
                            property: 'Milestones.ObjectID',
                            operator: '=',
                            value: milestone.get('ObjectID')
                        }
                    ]
            });

            promises.push(that._loadArtifactStore(artifactStore));

        });

        return Deft.Promise.all(promises);
    },

    _loadArtifactStore: function(store){
        var deferred;
        deferred = Ext.create('Deft.Deferred');

        store.load({
                callback: function(records, operation, success) {
                  if (success) {
                    deferred.resolve(records);
                  } else {
                    deferred.reject("Error loading Companies.");
                  }
                }
            });

        return deferred.promise;
    },

    _computeArtifactsAssociation: function(artifactColl){
        var storyCountInfo = {
            storyCount: 0,
            acceptedCount: 0
        };
        var leafStoryCount = 0, acceptedLeafStoryCount = 0;

        Ext.Array.each(artifactColl, function(item){
            var itemType = item.get('_type');
            var scheduleState = item.get('ScheduleState');

            if (itemType == 'hierarchicalrequirement' || itemType == 'defect') {
                leafStoryCount += 1;

                if (scheduleState == 'Accepted') {
                    acceptedLeafStoryCount += 1;
                }
            }
            else {
                leafStoryCount += item.get('LeafStoryCount');
                acceptedLeafStoryCount += item.get('AcceptedLeafStoryCount');
            }

        });

        storyCountInfo.storyCount = leafStoryCount;
        storyCountInfo.acceptedCount = acceptedLeafStoryCount;

        return storyCountInfo;
    },

    _organiseMilestoneBasedOnValuestream: function(filteredMilestonesArr){
        this.valueStreamMilestoneColl = [];
        this.valueStreamColl = [];
        var nonVSCount = 0;
        var that = this;

        Ext.Array.each(filteredMilestonesArr, function(thisData){
            var valuestream = thisData.get('ValueStream');

            if(valuestream !== null && valuestream !== ''){
                if(that.valueStreamColl.length === 0){
                    that.valueStreamColl.push(valuestream);
                }
                else if(that.valueStreamColl.length > 0 && that.valueStreamColl.indexOf(valuestream) === -1){
                    that.valueStreamColl.push(valuestream);
                }
            }
            else{
                nonVSCount++;
            }
        });

        this.valueStreamColl.sort();

        if(nonVSCount > 0) {
            this.valueStreamColl.push('N/A');
        }

        Ext.Array.each(this.valueStreamColl, function(valuestream) {
            var milestoneColl = that._getAllAssociatedMilestones(valuestream, filteredMilestonesArr);

            that.valueStreamMilestoneColl.push({
                key: valuestream,
                value: milestoneColl
            });
        });

        this._createValueStreamMilestonesTreeNode();
    },

    _createValueStreamMilestonesTreeNode: function(){

        var valueStreamRootNode = Ext.create('MilestoneTreeModel',{
                    Name: 'ValueStream Root',
                    text: 'ValueStream Root',
                    root: true,
                    expandable: true,
                    expanded: true
                });

        this._createValueStreamNodesAlongWithAssociatedChildMilestoneNodes(valueStreamRootNode);

        this._createValueStreamMilestoneGrid(valueStreamRootNode);

    },

    _createValueStreamMilestoneGrid: function(valueStreamRootNode){

       var milestoneValueStreamTreeStore = Ext.create('Ext.data.TreeStore', {
            model: 'MilestoneTreeModel',
            root: valueStreamRootNode
        });

       var valuestreamMilestoneTreePanel = Ext.create('Ext.tree.Panel', {
            store: milestoneValueStreamTreeStore,
            useArrows: true,
            rowLines: true,
            displayField: 'Name',
            rootVisible: false,
            width: this.getWidth(true),
            height: this.getHeight(true), // Extra scroll for individual sections:
            viewConfig: {
                getRowClass: function(record, index) {
                    var nameRecord = Ext.String.format("{0}", record.get('Name'));
                    if(nameRecord && nameRecord.search('valuestream:') === -1){
                        return 'row-child';
                    }
                    return 'row-parent';
                }
            },
            columns: [{
                          xtype: 'treecolumn',
                          text: 'Name',
                          dataIndex: 'Name',
                          resizeable: true,
                          flex: 3,
                          minWidth:200,
                          //width : 300,
                          renderer: function(value,style,item,rowIndex) {
                                var link = Ext.String.format("{0}", value);
                                if(link.search('valuestream:') === -1){
                                    var ref = item.get('_ref');
                                    link = Ext.String.format("{0}", value, Rally.nav.Manager.getDetailUrl(ref));
                                }
                                else{
                                    var onlyName = link.replace('valuestream:', '');
                                    link= Ext.String.format("{0}", onlyName);
                                }

                                return link;
                            }
                    },
                    {
                        text: 'Project',
                        dataIndex: 'TargetProject',
                        flex: 2,
                        hidden: true
                    },
                    {
                        text: 'Target Date',
                        dataIndex: 'TargetDate',
                        flex: 1,
                        renderer: function(value){
                            if(value)
                                return Rally.util.DateTime.format(value, 'M Y');
                        }
                    },
                    {
                        text: 'Accepted Count',
                        dataIndex: 'AcceptedLeafStoryCount',
                        flex: 1
                    },
                    {
                        text: 'Story Count',
                        dataIndex: 'LeafStoryCount',
                        flex: 1
                    },
                    {
                        text: 'Status',
                        dataIndex: 'DisplayColor',
                        flex: 1,
                        renderer: function(value){
                            if(value){
                                var colorHtml = Ext.String.format("

", value);
                                return colorHtml;
                            }
                        }
                    },
                    {
                        text: 'Notes',
                        dataIndex: 'Notes',
                        flex: 5
                    }
                ]
        });

        this.add(valuestreamMilestoneTreePanel);

        Ext.getBody().unmask();
    },

    _createValueStreamNodesAlongWithAssociatedChildMilestoneNodes: function(valustreamRootNode){
        var that = this;

        Ext.Array.each(this.valueStreamMilestoneColl, function(thisData) {
            var valueStreamNode = that._createValueStreamNode(thisData.key);

            Ext.Array.each(thisData.value, function(thisMilestoneData) {
                var milestoneNode = that._createMilestoneNode(thisMilestoneData);
                valueStreamNode.appendChild(milestoneNode);
            });

            valustreamRootNode.appendChild(valueStreamNode);
        });
    },

    _createValueStreamNode: function(valuestreamData){
        var valueStreamLable = 'valuestream: ' + valuestreamData;
        var valustreamTreeNode = Ext.create('MilestoneTreeModel',{
                    Name: valueStreamLable,
                    AcceptedLeafStoryCount: '',
                    LeafStoryCount: '',
                    leaf: false,
                    expandable: true,
                    expanded: true,
                    iconCls :'no-icon'
                });

        return  valustreamTreeNode;
    },

    _createMilestoneNode: function(milestoneData){
        var targetProjectName = milestoneData.get('TargetProject') !== null ?  milestoneData.get('TargetProject')._refObjectName : 'Global';

        var milestoneTreeNode = Ext.create('MilestoneTreeModel',{
            FormattedID: milestoneData.get('FormattedID'),
            Name: milestoneData.get('Name'),
            TargetDate: milestoneData.get('TargetDate'),
            TargetProject: targetProjectName,
            DisplayColor: milestoneData.get('DisplayColor'),
            Notes: milestoneData.get('Notes'),
            _ref: milestoneData.get('_ref'),
            AcceptedLeafStoryCount: milestoneData.get('AcceptedLeafStoryCount').toString(),
            LeafStoryCount: milestoneData.get('LeafStoryCount').toString(),
            leaf: true,
            expandable: false,
            expanded: false,
            iconCls :'no-icon'
        });

        return milestoneTreeNode;
    },

    _getAllAssociatedMilestones: function(valuestream, milestoneStoreData){
        var milestoneColl = [];
        var that = this;

        Ext.Array.each(milestoneStoreData, function(milestone) {
            var vsRecord = milestone.get('ValueStream');
            vsRecord = (vsRecord !== null && vsRecord !== '') ? vsRecord : 'N/A';

            if(vsRecord === valuestream){
                milestoneColl.push(milestone);
            }
        });

        return milestoneColl;
    }
});<|endoftext|>


<commit_before>/*global define */

/**
 * The main module that defines the public interface for BBT,
 * a made-up library to demonstrate how to construct a source from components.
 */
define(function (require) {
    'use strict';

    var $ = require('jquery');
    var convert = require('BBT/convert');
    var FileSaver = require('FileSaver');

    var Axis = require('BBT/Visualization/Axis');
    var H1 = require('BBT/Visualization/H1');

    var JamesRandom = require('BBT/Generation/Random/JamesRandom');
    var RandBinomial = require('BBT/Generation/Random/RandBinomial');

    //Return the module value.
    return {
        version: '0.0.1, jQuery version is: ' + $.fn.jquery,
        convert: convert,
        FileSaver: FileSaver,

        Axis: Axis,
        H1: H1,

        JamesRandom: JamesRandom,
        RandBinomial: RandBinomial
    };
});
<commit_msg>Adding new modules<commit_after>/*global define */

/**
 * The main module that defines the public interface for BBT,
 * a made-up library to demonstrate how to construct a source from components.
 */
define(function (require) {
    'use strict';

    var $ = require('jquery');
    var convert = require('BBT/convert');
    var FileSaver = require('FileSaver');

    var Axis = require('BBT/Visualization/Axis');
    var H1 = require('BBT/Visualization/H1');

    var JamesRandom = require('BBT/Generation/Random/JamesRandom');
    var RandBinomial = require('BBT/Generation/Random/RandBinomial');
    var RandBreitWigner = require('BBT/Generation/Random/RandBreitWigner');

    //Return the module value.
    return {
        version: '0.0.1, jQuery version is: ' + $.fn.jquery,
        convert: convert,
        FileSaver: FileSaver,

        Axis: Axis,
        H1: H1,

        JamesRandom: JamesRandom,
        RandBinomial: RandBinomial,
        RandBreitWigner: RandBreitWigner
    };
});
<|endoftext|>


<commit_before>const expect = chai.expect
import {describe, it} from 'mocha'
import {changeValue, updateValidationResults, validate, CHANGE_VALUE, VALIDATION_RESOLVED} from 'ember-frost-bunsen/actions'

describe('changeValue action', function () {
  it(`returns a dispatcher action with type "${CHANGE_VALUE}"`, function () {
    const action = changeValue('some.path', 'value')

    expect(action).to.eql({
      type: CHANGE_VALUE,
      bunsenId: 'some.path',
      value: 'value'
    })
  })
})

describe('validate action', function () {
  const SCHEMA_WITH_DEFAULTS = {
    type: 'object',
    properties: {
      firstName: {
        type: 'string',
        default: 'Bruce'
      },
      lastName: {
        type: 'string',
        default: 'Wayne'
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      },
      onlyChild: {
        type: 'boolean',
        default: true
      },
      age: {
        type: 'number',
        title: 'Age'
      }
    },
    required: ['lastName']
  }
  const SCHEMA_WITH_OBJECT_DEFAULTS = {
    type: 'object',
    properties: {
      firstName: {
        type: 'string',
        default: 'Bruce'
      },
      lastName: {
        type: 'string',
        default: 'Wayne'
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      },
      onlyChild: {
        type: 'boolean',
        default: true
      },
      age: {
        type: 'number',
        title: 'Age'
      }
    },
    required: ['lastName'],
    default: {
      firstName: 'Clark',
      lastName: 'Kent',
      alias: 'Superman'
    }
  }
  const SCHEMA_WITH_DEEP_DEFAULTS = {
    type: 'object',
    properties: {
      someotherProp: {
        type: 'object',
        properties: {
          name: {
            type: 'object',
            properties: {
              firstName: {
                type: 'string',
                default: 'Bruce'
              },
              lastName: {
                type: 'string',
                default: 'Wayne'
              }
            }
          }
        }
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      }
    },
    required: ['alias']
  }

  const SCHEMA_WITH_REFS = {
    type: 'object',
    properties: {
      hero: {
        type: 'object',
        '$ref': '#/definitions/superhero'
      }
    },
    required: ['hero'],
    definitions: {
      superhero: {
        type: 'object',
        properties: {
          firstName: {
            type: 'string',
            default: 'Bruce'
          },
          lastName: {
            type: 'string',
            default: 'Wayne'
          },
          alias: {
            type: 'string',
            title: 'Nickname',
            default: 'Batman'
          }
        }
      }
    }
  }

  const SCHEMA_WITH_NO_DEFAULTS = {
    type: 'object',
    properties: {
      someotherProp: {
        type: 'object',
        properties: {
          name: {
            type: 'object',
            properties: {
              firstName: {
                type: 'string'
              },
              lastName: {
                type: 'string'
              }
            }
          }
        }
      },
      alias: {
        type: 'string',
        title: 'Nickname'
      }
    }
  }

  function getDefaultValue (path, initialValue, schema) {
    const thunk = validate(path, initialValue, schema, [])
    const defaultValue = {}

    thunk(function (action) {
      _.assign(defaultValue, action.value)
    }, function () { return {} })

    return defaultValue
  }
  it('fills in defaults', function () {
    const defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_DEFAULTS)
    expect(defaultValue).to.eql({
      firstName: 'Bruce',
      lastName: 'Wayne',
      alias: 'Batman',
      onlyChild: true
    })
  })

  it('fills in defaults for specific values', function () {
    const defaultValue = getDefaultValue('someotherProp.name', {}, SCHEMA_WITH_DEEP_DEFAULTS)

    expect(defaultValue).to.eql({
      firstName: 'Bruce',
      lastName: 'Wayne'
    })
  })

  it('handles defaults in deep objects', function () {
    const defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_DEEP_DEFAULTS)
    expect(defaultValue).to.eql({
      someotherProp: {
        name: {
          firstName: 'Bruce',
          lastName: 'Wayne'
        }
      },
      alias: 'Batman'
    })
  })

  it('handles defaults for objects', function () {
    const defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_OBJECT_DEFAULTS)
    expect(defaultValue).to.eql({
      firstName: 'Clark',
      lastName: 'Kent',
      alias: 'Superman',
      onlyChild: true
    })
  })

  it('handles defaults in refs', function () {
    const defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_REFS)
    console.log(defaultValue)
    expect(defaultValue).to.eql({
      hero: {
        firstName: 'Bruce',
        lastName: 'Wayne',
        alias: 'Batman'
      }
    })
  })

  it('handles a schema with no defaults', function () {
    const defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_NO_DEFAULTS)
    console.log(defaultValue)
    expect(defaultValue).to.eql({})
  })
})
<commit_msg>Added check for validation promise resolution in the case that there are no validators.<commit_after>const expect = chai.expect
import {describe, it} from 'mocha'
import {changeValue, validate, CHANGE_VALUE, VALIDATION_RESOLVED} from 'ember-frost-bunsen/actions'
import _ from 'lodash'

describe('changeValue action', function () {
  it(`returns a dispatcher action with type "${CHANGE_VALUE}"`, function () {
    const action = changeValue('some.path', 'value')

    expect(action).to.eql({
      type: CHANGE_VALUE,
      bunsenId: 'some.path',
      value: 'value'
    })
  })
})

describe('validate action', function () {
  const SCHEMA_WITH_DEFAULTS = {
    type: 'object',
    properties: {
      firstName: {
        type: 'string',
        default: 'Bruce'
      },
      lastName: {
        type: 'string',
        default: 'Wayne'
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      },
      onlyChild: {
        type: 'boolean',
        default: true
      },
      age: {
        type: 'number',
        title: 'Age'
      }
    },
    required: ['lastName']
  }
  const SCHEMA_WITH_OBJECT_DEFAULTS = {
    type: 'object',
    properties: {
      firstName: {
        type: 'string',
        default: 'Bruce'
      },
      lastName: {
        type: 'string',
        default: 'Wayne'
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      },
      onlyChild: {
        type: 'boolean',
        default: true
      },
      age: {
        type: 'number',
        title: 'Age'
      }
    },
    required: ['lastName'],
    default: {
      firstName: 'Clark',
      lastName: 'Kent',
      alias: 'Superman'
    }
  }
  const SCHEMA_WITH_DEEP_DEFAULTS = {
    type: 'object',
    properties: {
      someotherProp: {
        type: 'object',
        properties: {
          name: {
            type: 'object',
            properties: {
              firstName: {
                type: 'string',
                default: 'Bruce'
              },
              lastName: {
                type: 'string',
                default: 'Wayne'
              }
            }
          }
        }
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      }
    },
    required: ['alias']
  }

  const SCHEMA_WITH_REFS = {
    type: 'object',
    properties: {
      hero: {
        type: 'object',
        '$ref': '#/definitions/superhero'
      }
    },
    required: ['hero'],
    definitions: {
      superhero: {
        type: 'object',
        properties: {
          firstName: {
            type: 'string',
            default: 'Bruce'
          },
          lastName: {
            type: 'string',
            default: 'Wayne'
          },
          alias: {
            type: 'string',
            title: 'Nickname',
            default: 'Batman'
          }
        }
      }
    }
  }

  const SCHEMA_WITH_NO_DEFAULTS = {
    type: 'object',
    properties: {
      someotherProp: {
        type: 'object',
        properties: {
          name: {
            type: 'object',
            properties: {
              firstName: {
                type: 'string'
              },
              lastName: {
                type: 'string'
              }
            }
          }
        }
      },
      alias: {
        type: 'string',
        title: 'Nickname'
      }
    }
  }

  function getDefaultValue (path, initialValue, schema) {
    const thunk = validate(path, initialValue, schema, [])
    const defaultValue = {}

    thunk(function (action) {
      _.assign(defaultValue, action.value)
    }, function () { return {} })

    return defaultValue
  }
  it('fills in defaults', function () {
    const defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_DEFAULTS)
    expect(defaultValue).to.eql({
      firstName: 'Bruce',
      lastName: 'Wayne',
      alias: 'Batman',
      onlyChild: true
    })
  })

  it('fills in defaults for specific values', function () {
    const defaultValue = getDefaultValue('someotherProp.name', {}, SCHEMA_WITH_DEEP_DEFAULTS)

    expect(defaultValue).to.eql({
      firstName: 'Bruce',
      lastName: 'Wayne'
    })
  })

  it('handles defaults in deep objects', function () {
    const defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_DEEP_DEFAULTS)
    expect(defaultValue).to.eql({
      someotherProp: {
        name: {
          firstName: 'Bruce',
          lastName: 'Wayne'
        }
      },
      alias: 'Batman'
    })
  })

  it('handles defaults for objects', function () {
    const defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_OBJECT_DEFAULTS)
    expect(defaultValue).to.eql({
      firstName: 'Clark',
      lastName: 'Kent',
      alias: 'Superman',
      onlyChild: true
    })
  })

  it('handles defaults in refs', function () {
    const defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_REFS)
    console.log(defaultValue)
    expect(defaultValue).to.eql({
      hero: {
        firstName: 'Bruce',
        lastName: 'Wayne',
        alias: 'Batman'
      }
    })
  })

  it('handles a schema with no defaults', function () {
    const defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_NO_DEFAULTS)
    console.log(defaultValue)
    expect(defaultValue).to.eql({})
  })

  function getState () {
    return {
      get value () {
        return {}
      }
    }
  }

  it('resolves if no validators are given', function () {
    let thunk = validate(null, {}, SCHEMA_WITH_DEFAULTS, [])
    thunk(function (action) {
      if (action.type === VALIDATION_RESOLVED) {
        expect(action.errors).to.eql([])
      }
    }, getState)
  })
})
<|endoftext|>


<commit_before>import cascada from 'cascada';
import { module, test } from 'qunit';
let parse = cascada.parse;
let t = cascada.types;

module('Unit | Cascada');

test('it accepts at-rules', function(assert) {
  var ss = parse("@media print {}");
  assert.strictEqual(ss.rules.length, 1);
  assert.strictEqual(ss.rules[0].type, 'AtRule');
  assert.strictEqual(ss.rules[0].name, 'media');
});

test('it accepts style rules', function (assert) {
  var ss = parse(".foo .bar {}");
  assert.strictEqual(ss.rules.length, 1);
  assert.strictEqual(ss.rules[0].type, 'StyleRule');
  assert.deepEqual(ss.rules[0].selectors, ['.foo .bar']);
});

test('it accepts declarations in style rules', function (assert) {
  var ss = parse("a { color: red; }");
  assert.strictEqual(ss.rules.length, 1);
  assert.strictEqual(ss.rules[0].type, 'StyleRule');
  assert.deepEqual(ss.rules[0].selectors, ['a']);
  assert.strictEqual(ss.rules[0].body.length, 1);
  assert.deepEqual(ss.rules[0].body[0], {
    type: 'StylePropertyDeclaration',
    important: false,
    name: 'color',
    values: [ t.ident('red') ]
  });
});

test('it accepts multiple component values in a declaration', function (assert) {
  var ss = parse("a { color: red blue; }");
  assert.strictEqual(ss.rules.length, 1);
  assert.strictEqual(ss.rules[0].type, 'StyleRule');
  assert.deepEqual(ss.rules[0].selectors, ['a']);
  assert.strictEqual(ss.rules[0].body.length, 1);
  assert.deepEqual(ss.rules[0].body[0], {
    type: 'StylePropertyDeclaration',
    important: false,
    name: 'color',
    values: [ t.ident('red'), t.ws(), t.ident('blue') ]
  });
});

test('accepts nested function values in style rules', function(assert) {
  var ss = parse("a { color: rgba(255, 123, 17, var(--alpha)); }");
  assert.strictEqual(ss.rules.length, 1);
  assert.strictEqual(ss.rules[0].type, 'StyleRule');
  assert.deepEqual(ss.rules[0].selectors, ['a']);
  assert.strictEqual(ss.rules[0].body.length, 1);
  assert.deepEqual(ss.rules[0].body[0], {
    type: 'StylePropertyDeclaration',
    important: false,
    name: 'color',
    values: [
      t.func('rgba', [
        t.number(255), t.comma(), t.ws(),
        t.number(123), t.comma(), t.ws(),
        t.number(17), t.comma(), t.ws(),
        t.func('var', [ t.ident('--alpha') ]),
      ])
    ]
  });
});
<commit_msg>fix imports for tests<commit_after>import t, { parse } from 'cascada';
import { module, test } from 'qunit';

module('Unit | Cascada');

test('it accepts at-rules', function(assert) {
  var ss = parse("@media print {}");
  assert.strictEqual(ss.rules.length, 1);
  assert.strictEqual(ss.rules[0].type, 'AtRule');
  assert.strictEqual(ss.rules[0].name, 'media');
});

test('it accepts style rules', function (assert) {
  var ss = parse(".foo .bar {}");
  assert.strictEqual(ss.rules.length, 1);
  assert.strictEqual(ss.rules[0].type, 'StyleRule');
  assert.deepEqual(ss.rules[0].selectors, ['.foo .bar']);
});

test('it accepts declarations in style rules', function (assert) {
  var ss = parse("a { color: red; }");
  assert.strictEqual(ss.rules.length, 1);
  assert.strictEqual(ss.rules[0].type, 'StyleRule');
  assert.deepEqual(ss.rules[0].selectors, ['a']);
  assert.strictEqual(ss.rules[0].body.length, 1);
  assert.deepEqual(ss.rules[0].body[0], {
    type: 'StylePropertyDeclaration',
    important: false,
    name: 'color',
    values: [ t.ident('red') ]
  });
});

test('it accepts multiple component values in a declaration', function (assert) {
  var ss = parse("a { color: red blue; }");
  assert.strictEqual(ss.rules.length, 1);
  assert.strictEqual(ss.rules[0].type, 'StyleRule');
  assert.deepEqual(ss.rules[0].selectors, ['a']);
  assert.strictEqual(ss.rules[0].body.length, 1);
  assert.deepEqual(ss.rules[0].body[0], {
    type: 'StylePropertyDeclaration',
    important: false,
    name: 'color',
    values: [ t.ident('red'), t.ws(), t.ident('blue') ]
  });
});

test('accepts nested function values in style rules', function(assert) {
  var ss = parse("a { color: rgba(255, 123, 17, var(--alpha)); }");
  assert.strictEqual(ss.rules.length, 1);
  assert.strictEqual(ss.rules[0].type, 'StyleRule');
  assert.deepEqual(ss.rules[0].selectors, ['a']);
  assert.strictEqual(ss.rules[0].body.length, 1);
  assert.deepEqual(ss.rules[0].body[0], {
    type: 'StylePropertyDeclaration',
    important: false,
    name: 'color',
    values: [
      t.func('rgba', [
        t.number(255), t.comma(), t.ws(),
        t.number(123), t.comma(), t.ws(),
        t.number(17), t.comma(), t.ws(),
        t.func('var', [ t.ident('--alpha') ]),
      ])
    ]
  });
});
<|endoftext|>


<commit_before>'use strict';

/* eslint-disable import/no-extraneous-dependencies, global-require */

const minimatch = require('minimatch');

function ensureArray(as) {
  return !as || Array.isArray(as) ? as : [as];
}

const cloptions = require('minimist')(process.argv.slice(2), {
  alias: {
    b: 'browsers',
    f: 'files',
    d: 'debug',
    v: 'verbose',
  },
  boolean: ['debug', 'verbose'],
});

module.exports = function (config) {
  config.set({
    basePath: '..',

    frameworks: ['mocha', 'sinon-chai'],

    files: (() => {
      const list = ensureArray(cloptions.files || [
        'tests/remainders.js', // For generatoring coverage report for untested files
        'tests/spec/**/*.js',
      ]);
      const htmlFiles = list.filter(file => minimatch(file, 'src/components/**/*.html'));
      if (htmlFiles.length > 0) {
        const explanationArgs = htmlFiles.map(file => `-f ${file}`).join(' ');
        // eslint-disable-next-line no-console
        console.warn('WARNING: The given files contain component sample HTML.');
        // eslint-disable-next-line no-console
        console.warn(`You may have wanted:\n\tgulp test:a11y ${explanationArgs}`);
      }
      list.unshift('demo/polyfills/index.js');
      return list;
    })(),

    exclude: [],

    preprocessors: {
      'tests/remainders.js': ['webpack', 'sourcemap'], // For generatoring coverage report for untested files
      'tests/spec/**/*.js': ['webpack', 'sourcemap'],
      'demo/polyfills/**/*.js': ['webpack', 'sourcemap'],
    },

    webpack: {
      devtool: 'inline-source-maps',
      module: {
        rules: [
          {
            test: /\.js?$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'babel-loader',
                options: {
                  presets: [
                    [
                      'env',
                      {
                        modules: false,
                        chrome: 'latest',
                        edge: 'latest',
                        firefox: 'latest',
                        safari: 'latest',
                        ie: '11',
                        ios: 'latest',
                      },
                    ],
                  ],
                  plugins: [
                    'transform-class-properties',
                    ['transform-runtime', { polyfill: false }],
                  ].concat(cloptions.debug ? [] : [
                    [
                      'istanbul',
                      {
                        include: [
                          'src/components/**/*.js',
                        ],
                      },
                    ],
                  ]),
                },
              },
            ],
          },
          {
            test: /\.html?$/,
            exclude: /node_modules/,
            use: ['html-loader'],
          },
        ],
      },
    },

    webpackMiddleware: {
      noInfo: !cloptions.verbose,
      stats: cloptions.verbose ? {
        colors: true,
      } : {},
    },

    customLaunchers: {
      Chrome_Travis: {
        base: 'Chrome',
        flags: ['--no-sandbox'],
      },
    },

    plugins: [
      require('karma-mocha'),
      require('karma-sinon-chai'),
      require('karma-sourcemap-loader'),
      require('karma-mocha-reporter'),
      require('karma-coverage'),
      require('karma-webpack'),
      require('karma-phantomjs-launcher'),
      require('karma-chrome-launcher'),
      require('karma-firefox-launcher'),
      require('karma-safari-launcher'),
      require('karma-ie-launcher'),
    ],

    reporters: (() => {
      const reporters = ['mocha'];
      if (!cloptions.debug) {
        reporters.push('coverage');
      }
      return reporters;
    })(),

    coverageReporter: Object.assign({
      dir: 'tests/coverage',
      reporters: [
        { type: 'html' },
        { type: 'text' },
      ],
    }, cloptions.files ? {} : {
      check: {
        each: {
          statements: 40,
          branches: 40,
          functions: 40,
          lines: 40,
          excludes: [
            // Files in this exclude list are of either:
            // - Not meeting the code coverage standard set here, which shouldn't have happened
            // - Very browser dependent code that wouldn't get code coverage unless we run the suite with Sauce Labs
            // That said, new files should never be added, except for misc code that is very broser-specific
            'src/components/accordion/accordion.js',
            'src/components/copy-button/copy-button.js',
            'src/components/detail-page-header/detail-page-header.js',
            'src/components/inline-left-nav/inline-left-nav.js',
            'src/components/pagination/pagination.js',
            'src/components/search/search-with-options.js',
            'src/components/unified-header/left-nav.js',
            'src/components/unified-header/profile-switcher.js',
            'src/globals/js/misc/resize.js',
          ],
        },
      },
    }),

    port: 9876,

    colors: true,

    logLevel: config.LOG_INFO,

    autoWatch: true,
    autoWatchBatchDelay: 400,

    browsers: (Array.isArray(cloptions.browsers) ? cloptions.browsers : [cloptions.browsers || 'PhantomJS'])
      .map(browser => browser + (browser === 'Chrome' && process.env.TRAVIS ? '_Travis' : '')),

    singleRun: false,

    concurrency: Infinity,
  });
};
<commit_msg>fix(travis): sync karma.conf.js with interior-left-nav rename (#2444)<commit_after>'use strict';

/* eslint-disable import/no-extraneous-dependencies, global-require */

const minimatch = require('minimatch');

function ensureArray(as) {
  return !as || Array.isArray(as) ? as : [as];
}

const cloptions = require('minimist')(process.argv.slice(2), {
  alias: {
    b: 'browsers',
    f: 'files',
    d: 'debug',
    v: 'verbose',
  },
  boolean: ['debug', 'verbose'],
});

module.exports = function (config) {
  config.set({
    basePath: '..',

    frameworks: ['mocha', 'sinon-chai'],

    files: (() => {
      const list = ensureArray(cloptions.files || [
        'tests/remainders.js', // For generatoring coverage report for untested files
        'tests/spec/**/*.js',
      ]);
      const htmlFiles = list.filter(file => minimatch(file, 'src/components/**/*.html'));
      if (htmlFiles.length > 0) {
        const explanationArgs = htmlFiles.map(file => `-f ${file}`).join(' ');
        // eslint-disable-next-line no-console
        console.warn('WARNING: The given files contain component sample HTML.');
        // eslint-disable-next-line no-console
        console.warn(`You may have wanted:\n\tgulp test:a11y ${explanationArgs}`);
      }
      list.unshift('demo/polyfills/index.js');
      return list;
    })(),

    exclude: [],

    preprocessors: {
      'tests/remainders.js': ['webpack', 'sourcemap'], // For generatoring coverage report for untested files
      'tests/spec/**/*.js': ['webpack', 'sourcemap'],
      'demo/polyfills/**/*.js': ['webpack', 'sourcemap'],
    },

    webpack: {
      devtool: 'inline-source-maps',
      module: {
        rules: [
          {
            test: /\.js?$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'babel-loader',
                options: {
                  presets: [
                    [
                      'env',
                      {
                        modules: false,
                        chrome: 'latest',
                        edge: 'latest',
                        firefox: 'latest',
                        safari: 'latest',
                        ie: '11',
                        ios: 'latest',
                      },
                    ],
                  ],
                  plugins: [
                    'transform-class-properties',
                    ['transform-runtime', { polyfill: false }],
                  ].concat(cloptions.debug ? [] : [
                    [
                      'istanbul',
                      {
                        include: [
                          'src/components/**/*.js',
                        ],
                      },
                    ],
                  ]),
                },
              },
            ],
          },
          {
            test: /\.html?$/,
            exclude: /node_modules/,
            use: ['html-loader'],
          },
        ],
      },
    },

    webpackMiddleware: {
      noInfo: !cloptions.verbose,
      stats: cloptions.verbose ? {
        colors: true,
      } : {},
    },

    customLaunchers: {
      Chrome_Travis: {
        base: 'Chrome',
        flags: ['--no-sandbox'],
      },
    },

    plugins: [
      require('karma-mocha'),
      require('karma-sinon-chai'),
      require('karma-sourcemap-loader'),
      require('karma-mocha-reporter'),
      require('karma-coverage'),
      require('karma-webpack'),
      require('karma-phantomjs-launcher'),
      require('karma-chrome-launcher'),
      require('karma-firefox-launcher'),
      require('karma-safari-launcher'),
      require('karma-ie-launcher'),
    ],

    reporters: (() => {
      const reporters = ['mocha'];
      if (!cloptions.debug) {
        reporters.push('coverage');
      }
      return reporters;
    })(),

    coverageReporter: Object.assign({
      dir: 'tests/coverage',
      reporters: [
        { type: 'html' },
        { type: 'text' },
      ],
    }, cloptions.files ? {} : {
      check: {
        each: {
          statements: 40,
          branches: 40,
          functions: 40,
          lines: 40,
          excludes: [
            // Files in this exclude list are of either:
            // - Not meeting the code coverage standard set here, which shouldn't have happened
            // - Very browser dependent code that wouldn't get code coverage unless we run the suite with Sauce Labs
            // That said, new files should never be added, except for misc code that is very broser-specific
            'src/components/accordion/accordion.js',
            'src/components/copy-button/copy-button.js',
            'src/components/detail-page-header/detail-page-header.js',
            'src/components/interior-left-nav/interior-left-nav.js',
            'src/components/pagination/pagination.js',
            'src/components/search/search-with-options.js',
            'src/components/unified-header/left-nav.js',
            'src/components/unified-header/profile-switcher.js',
            'src/globals/js/misc/resize.js',
          ],
        },
      },
    }),

    port: 9876,

    colors: true,

    logLevel: config.LOG_INFO,

    autoWatch: true,
    autoWatchBatchDelay: 400,

    browsers: (Array.isArray(cloptions.browsers) ? cloptions.browsers : [cloptions.browsers || 'PhantomJS'])
      .map(browser => browser + (browser === 'Chrome' && process.env.TRAVIS ? '_Travis' : '')),

    singleRun: false,

    concurrency: Infinity,
  });
};
<|endoftext|>